001/*
002 *  Copyright 2018 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.translationflagging;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.List;
022import java.util.Map;
023import java.util.Map.Entry;
024import java.util.Set;
025
026import org.apache.avalon.framework.component.Component;
027import org.apache.avalon.framework.logger.AbstractLogEnabled;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031
032import org.ametys.core.observation.Event;
033import org.ametys.core.observation.ObservationManager;
034import org.ametys.core.user.CurrentUserProvider;
035import org.ametys.plugins.repository.AmetysObjectResolver;
036import org.ametys.plugins.repository.UnknownAmetysObjectException;
037import org.ametys.plugins.repository.metadata.CompositeMetadata;
038import org.ametys.plugins.repository.metadata.ModifiableCompositeMetadata;
039import org.ametys.plugins.repository.metadata.UnknownMetadataException;
040import org.ametys.web.ObservationConstants;
041import org.ametys.web.repository.page.ModifiablePage;
042import org.ametys.web.repository.page.Page;
043
044/**
045 * Translation page DAO
046 */
047public class TranslationPageDAO extends AbstractLogEnabled implements Serviceable, Component
048{
049    /** Avalon Role */
050    public static final String ROLE = TranslationPageDAO.class.getName();
051
052    private AmetysObjectResolver _resolver;
053    private CurrentUserProvider _currentUserProvider;
054    private ObservationManager _observationManager;
055
056    @Override
057    public void service(ServiceManager smanager) throws ServiceException
058    {
059        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
060        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
061        _observationManager = (ObservationManager) smanager.lookup(ObservationManager.ROLE);
062    }
063    
064    /**
065     * Set the translations for a specific page
066     * @param pageId The current page id
067     * @param pages the map of translated page
068     * @return The list of updated pages.
069     */
070    public List<String> setTranslations(String pageId, Map<String, Page> pages)
071    {
072        Page currentPage = _resolver.resolveById(pageId);
073        
074        // Get the collection of pages to clean.
075        Set<Page> pagesToClean = new HashSet<>(getTranslations(currentPage).values());
076        
077        // Compute all modified pages to notify the observer.
078        Set<Page> modifiedPages = new HashSet<>(pagesToClean);
079        modifiedPages.addAll(pages.values());
080        
081        // The old pages minus the new ones will be the pages to clean.
082        pagesToClean.removeAll(pages.values());
083        
084        // Clean the old pages: remove the translations metadata.
085        for (Page page : pagesToClean)
086        {
087            if (page instanceof ModifiablePage)
088            {
089                _cleanPage((ModifiablePage) page);
090            }
091        }
092        
093        // Set the translations.
094        for (Page page : pages.values())
095        {
096            if (page instanceof ModifiablePage)
097            {
098                _setTranslations((ModifiablePage) page, pages);
099            }
100        }
101        
102        // Notify observers that page data has been changed
103        
104        List<String> modifiedPageIds = new ArrayList<>();
105        for (Page modifiedPage : modifiedPages)
106        {
107            if (modifiedPage != null)
108            {
109                modifiedPageIds.add(modifiedPage.getId());
110                
111                Map<String, Object> eventParams = new HashMap<>();
112                eventParams.put(ObservationConstants.ARGS_PAGE, modifiedPage);
113
114                _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_UPDATED, _currentUserProvider.getUser(), eventParams));
115            }
116        }
117        
118        return modifiedPageIds;
119    }
120    
121    /**
122     * Get the translation of a given page.
123     * @param page the page.
124     * @return the translated pages as a Map of pages, indexed by sitemap name (language).
125     */
126    public Map<String, Page> getTranslations(Page page)
127    {
128        Map<String, Page> translations = new HashMap<>();
129        
130        CompositeMetadata meta = page.getMetadataHolder();
131        
132        try
133        {
134            CompositeMetadata transMeta = meta.getCompositeMetadata(TranslationFlaggingClientSideElement.TRANSLATIONS_META);
135            for (String lang : transMeta.getMetadataNames())
136            {
137                String translatedPageId = transMeta.getString(lang);
138                
139                try
140                {
141                    Page translatedPage = _resolver.resolveById(translatedPageId);
142                    translations.put(lang, translatedPage);
143                }
144                catch (UnknownAmetysObjectException e)
145                {
146                    // Ignore : a removed page should be ignored
147                }
148            }
149        }
150        catch (UnknownMetadataException e)
151        {
152            // Ignore : the translations composite metadata doesn't exist, just return an empty map.
153        }        
154        
155        return translations;
156    }
157    
158    /**
159     * Set the translations of a page in its metadata.
160     * @param page the page.
161     * @param pages the translated pages to set.
162     */
163    protected void _setTranslations(ModifiablePage page, Map<String, Page> pages)
164    {
165        ModifiableCompositeMetadata meta = page.getMetadataHolder();
166        
167        ModifiableCompositeMetadata transMeta = meta.getCompositeMetadata(TranslationFlaggingClientSideElement.TRANSLATIONS_META, true);
168        
169        for (Entry<String, Page> entry : pages.entrySet())
170        {
171            if (!entry.getKey().equals(page.getSitemapName()))
172            {
173                if (entry.getValue() == null)
174                {
175                    // Remove metadata.
176                    if (transMeta.hasMetadata(entry.getKey()))
177                    {
178                        transMeta.removeMetadata(entry.getKey());
179                    }
180                }
181                else
182                {
183                    transMeta.setMetadata(entry.getKey(), entry.getValue().getId());
184                }
185            }
186        }
187        
188        page.saveChanges();
189    }
190    
191    /**
192     * Clean a page of its translations metadata.
193     * @param page the page to clean.
194     */
195    protected void _cleanPage(ModifiablePage page)
196    {
197        ModifiableCompositeMetadata meta = page.getMetadataHolder();
198        
199        if (meta.hasMetadata(TranslationFlaggingClientSideElement.TRANSLATIONS_META))
200        {
201            meta.removeMetadata(TranslationFlaggingClientSideElement.TRANSLATIONS_META);
202            page.saveChanges();
203        }
204    }
205}