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.data.holder.ModelLessDataHolder;
038import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder;
039import org.ametys.web.ObservationConstants;
040import org.ametys.web.repository.page.ModifiablePage;
041import org.ametys.web.repository.page.Page;
042
043/**
044 * Translation page DAO
045 */
046public class TranslationPageDAO extends AbstractLogEnabled implements Serviceable, Component
047{
048    /** Avalon Role */
049    public static final String ROLE = TranslationPageDAO.class.getName();
050
051    private AmetysObjectResolver _resolver;
052    private CurrentUserProvider _currentUserProvider;
053    private ObservationManager _observationManager;
054
055    @Override
056    public void service(ServiceManager smanager) throws ServiceException
057    {
058        _resolver = (AmetysObjectResolver) smanager.lookup(AmetysObjectResolver.ROLE);
059        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
060        _observationManager = (ObservationManager) smanager.lookup(ObservationManager.ROLE);
061    }
062    
063    /**
064     * Set the translations for a specific page
065     * @param pageId The current page id
066     * @param pages the map of translated page
067     * @return The list of updated pages.
068     */
069    public List<String> setTranslations(String pageId, Map<String, Page> pages)
070    {
071        Page currentPage = _resolver.resolveById(pageId);
072        
073        // Get the collection of pages to clean.
074        Set<Page> pagesToClean = new HashSet<>(getTranslations(currentPage).values());
075        
076        // Compute all modified pages to notify the observer.
077        Set<Page> modifiedPages = new HashSet<>(pagesToClean);
078        modifiedPages.addAll(pages.values());
079        
080        // The old pages minus the new ones will be the pages to clean.
081        pagesToClean.removeAll(pages.values());
082        
083        // Clean the old pages: remove the translations metadata.
084        for (Page page : pagesToClean)
085        {
086            if (page instanceof ModifiablePage)
087            {
088                _cleanPage((ModifiablePage) page);
089            }
090        }
091        
092        // Set the translations.
093        for (Page page : pages.values())
094        {
095            if (page instanceof ModifiablePage)
096            {
097                _setTranslations((ModifiablePage) page, pages);
098            }
099        }
100        
101        // Notify observers that page data has been changed
102        
103        List<String> modifiedPageIds = new ArrayList<>();
104        for (Page modifiedPage : modifiedPages)
105        {
106            if (modifiedPage != null)
107            {
108                modifiedPageIds.add(modifiedPage.getId());
109                
110                Map<String, Object> eventParams = new HashMap<>();
111                eventParams.put(ObservationConstants.ARGS_PAGE, modifiedPage);
112
113                _observationManager.notify(new Event(ObservationConstants.EVENT_PAGE_UPDATED, _currentUserProvider.getUser(), eventParams));
114            }
115        }
116        
117        return modifiedPageIds;
118    }
119    
120    /**
121     * Get the translations of a given page.
122     * @param page the page.
123     * @return the translated pages as a Map of pages, indexed by sitemap name (language).
124     */
125    public Map<String, Page> getTranslations(Page page)
126    {
127        Map<String, Page> translations = new HashMap<>();
128        
129        ModelLessDataHolder translationsComposite = page.getComposite(TranslationFlaggingClientSideElement.TRANSLATIONS_META);
130        
131        if (translationsComposite != null)
132        {
133            for (String lang : translationsComposite.getDataNames())
134            {
135                String translatedPageId = translationsComposite.getValue(lang);
136                
137                try
138                {
139                    Page translatedPage = _resolver.resolveById(translatedPageId);
140                    translations.put(lang, translatedPage);
141                }
142                catch (UnknownAmetysObjectException e)
143                {
144                    // Ignore : a removed page should be ignored
145                }
146            }
147        }
148        else
149        {
150            // Ignore : the translations composite doesn't exist, just return an empty map.
151        }        
152        
153        return translations;
154    }
155    
156    /**
157     * Set the translations of a page in its data.
158     * @param page the page.
159     * @param pages the translated pages to set.
160     */
161    protected void _setTranslations(ModifiablePage page, Map<String, Page> pages)
162    {
163        ModifiableModelLessDataHolder translationsComposite = page.getComposite(TranslationFlaggingClientSideElement.TRANSLATIONS_META, true);
164        
165        for (Entry<String, Page> entry : pages.entrySet())
166        {
167            if (!entry.getKey().equals(page.getSitemapName()))
168            {
169                if (entry.getValue() == null)
170                {
171                    // Remove data.
172                    if (translationsComposite.hasValue(entry.getKey()))
173                    {
174                        translationsComposite.removeValue(entry.getKey());
175                    }
176                }
177                else
178                {
179                    translationsComposite.setValue(entry.getKey(), entry.getValue().getId());
180                }
181            }
182        }
183        
184        page.saveChanges();
185    }
186    
187    /**
188     * Clean a page of its translations data.
189     * @param page the page to clean.
190     */
191    protected void _cleanPage(ModifiablePage page)
192    {
193        if (page.hasValue(TranslationFlaggingClientSideElement.TRANSLATIONS_META))
194        {
195            page.removeValue(TranslationFlaggingClientSideElement.TRANSLATIONS_META);
196            page.saveChanges();
197        }
198    }
199}