001/*
002 *  Copyright 2014 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.web.clientsideelement.styles;
017
018import java.io.InputStream;
019import java.util.Collections;
020import java.util.Date;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.avalon.framework.configuration.Configuration;
026import org.apache.avalon.framework.configuration.ConfigurationException;
027import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.commons.lang3.StringUtils;
031import org.apache.excalibur.source.Source;
032import org.apache.excalibur.source.SourceResolver;
033
034import org.ametys.cms.clientsideelement.styles.StaticHTMLEditorStyleExtension;
035import org.ametys.cms.clientsideelement.styles.Style;
036import org.ametys.cms.clientsideelement.styles.StyleCategory;
037import org.ametys.web.repository.site.Site;
038import org.ametys.web.repository.site.SiteManager;
039
040/**
041 * Based on a configuration like the StaticHTMLEditorStyleExtension but the file is located inside the current skin directory (skin/conf/edition-styles.xml).
042 */
043public class SkinHTMLEditorStyleExtension extends StaticHTMLEditorStyleExtension
044{
045    /** The assocation skinId lastUpdateDate ; to know for a given skin when its conf file was read for the last time */
046    protected Map<String, Long> _lastUpdates = new HashMap<>();
047    /** The assocation skinId Style ; to know for a given skin its style */
048    protected Map<String, StyleCategory> _paraStyleCategories = new HashMap<>();
049    /** The assocation skinId Style ; to know for a given skin its style */
050    protected Map<String, StyleCategory> _tableStyleCategories = new HashMap<>();
051    /** The assocation skinId Style ; to know for a given skin its style */
052    protected Map<String, StyleCategory> _imageStyleCategories = new HashMap<>();
053    /** The assocation skinId Style ; to know for a given skin its style */
054    protected Map<String, StyleCategory> _linkStyleCategories = new HashMap<>();
055    /** The assocation skinId Style ; to know for a given skin its style */
056    protected Map<String, StyleCategory> _ulStyleCategories = new HashMap<>();
057    /** The assocation skinId Style ; to know for a given skin its style */
058    protected Map<String, StyleCategory> _olStyleCategories = new HashMap<>();
059    
060    /** The excalibur source resolver */
061    protected SourceResolver _sourceResolver;
062    /** The sites manager */
063    protected SiteManager _siteManager;
064    
065    @Override
066    public void service(ServiceManager manager) throws ServiceException
067    {
068        super.service(manager);
069        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
070        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
071    }
072    
073    @Override
074    public void configure(Configuration configuration) throws ConfigurationException
075    {
076        // Do nothing
077    }
078    
079    @Override
080    protected String _getImport(Configuration configuration, Map<String, Object> contextualParameters)
081    {
082        String siteId = (String) contextualParameters.get("siteName");
083        if (siteId == null)
084        {
085            getLogger().info("Cannot determine the current skin because cannot determine current site. Continue as if there is no HTML skin styles.");
086            return null;
087        }
088
089        Site site = _siteManager.getSite(siteId);
090        String skinId = site.getSkinId();
091
092        String boFileLocation = "/skins/" + skinId + "/resources/";
093        
094        String uri = configuration.getValue(null);
095        return StringUtils.isBlank(uri) ? null : boFileLocation + uri;
096    }
097
098    
099    @Override
100    public StyleCategory getPara(Map<String, Object> contextualParameters)
101    {
102        String currentSkin = _updateStyleCategories(contextualParameters);
103        return _paraStyleCategories.get(currentSkin);
104    }
105    @Override
106    public StyleCategory getImage(Map<String, Object> contextualParameters)
107    {
108        String currentSkin = _updateStyleCategories(contextualParameters);
109        return _imageStyleCategories.get(currentSkin);
110    }
111    @Override
112    public StyleCategory getLink(Map<String, Object> contextualParameters)
113    {
114        String currentSkin = _updateStyleCategories(contextualParameters);
115        return _linkStyleCategories.get(currentSkin);
116    }
117    @Override
118    public StyleCategory getOrderedList(Map<String, Object> contextualParameters)
119    {
120        String currentSkin = _updateStyleCategories(contextualParameters);
121        return _olStyleCategories.get(currentSkin);
122    }
123    @Override
124    public StyleCategory getTable(Map<String, Object> contextualParameters)
125    {
126        String currentSkin = _updateStyleCategories(contextualParameters);
127        return _tableStyleCategories.get(currentSkin);
128    }
129    @Override
130    public StyleCategory getUnorderedList(Map<String, Object> contextualParameters)
131    {
132        String currentSkin = _updateStyleCategories(contextualParameters);
133        return _ulStyleCategories.get(currentSkin);
134    }
135    
136    /**
137     * Update if necessary the values associated with the current skin
138     * @param contextualParameters Contextuals parameters transmitted by the environment.
139     * @return The current skin 
140     */
141    protected String _updateStyleCategories(Map<String, Object> contextualParameters)
142    {
143        String siteId = (String) contextualParameters.get("siteName");
144        if (siteId == null)
145        {
146            getLogger().info("Cannot determine the current skin because cannot determine current site. Continue as if there is no HTML skin styles.");
147            return null;
148        }
149
150        Site site = _siteManager.getSite(siteId);
151        String skinId = site.getSkinId();
152
153        String url = "skin:" + skinId + "://conf/edition-styles.xml"; 
154        
155        Source configurationFile = null;
156        try
157        {
158            configurationFile = _sourceResolver.resolveURI(url);
159            if (configurationFile.exists())
160            {
161                Long lastUpdate = _lastUpdates.get(skinId);
162                
163                if (lastUpdate == null || lastUpdate < configurationFile.getLastModified())
164                {
165                    try (InputStream is = configurationFile.getInputStream())
166                    {
167                        Configuration configuration = new DefaultConfigurationBuilder().build(is);
168                        
169                        StyleCategory paraStyleCategory = _configureStyleCategory(configuration.getChild("para"), "skin." + skinId, null, contextualParameters);
170                        StyleCategory imageStyleCategory = _configureStyleCategory(configuration.getChild("image"), "skin." + skinId, IMAGE_DEFAULT_ICONS, contextualParameters);
171                        StyleCategory tableStyleCategory = _configureStyleCategory(configuration.getChild("table"), "skin." + skinId, TABLE_DEFAULT_ICONS, contextualParameters);
172                        StyleCategory linkStyleCategory = _configureStyleCategory(configuration.getChild("link"), "skin." + skinId, LINK_DEFAULT_ICONS, contextualParameters);
173                        StyleCategory ulStyleCategory = _configureStyleCategory(configuration.getChild("unorderedlist"), "skin." + skinId, UL_DEFAULT_ICONS, contextualParameters);
174                        StyleCategory olStyleCategory = _configureStyleCategory(configuration.getChild("orderedlist"), "skin." + skinId, OL_DEFAULT_ICONS, contextualParameters);
175                        
176                        _paraStyleCategories.put(skinId, paraStyleCategory);
177                        _imageStyleCategories.put(skinId, imageStyleCategory);
178                        _tableStyleCategories.put(skinId, tableStyleCategory);
179                        _linkStyleCategories.put(skinId, linkStyleCategory);
180                        _ulStyleCategories.put(skinId, ulStyleCategory);
181                        _olStyleCategories.put(skinId, olStyleCategory);
182                        
183                        _lastUpdates.put(skinId, configurationFile.getLastModified());
184                    }
185                }
186            }
187            else
188            {
189                _defaultValues(skinId);
190            }
191        }
192        catch (Exception e)
193        {
194            _defaultValues(skinId);
195            if (getLogger().isWarnEnabled())
196            {
197                getLogger().warn("Cannot read the configuration file " + url + ". Continue as if file was not existing", e);
198            }
199        }
200        
201        return skinId;
202    }
203    
204    /**
205     * Set default values for the given skin
206     * @param skinId The skin
207     */
208    protected void _defaultValues(String skinId)
209    {
210        List<Style> emptyList = Collections.emptyList();
211        _paraStyleCategories.put(skinId, new StyleCategory(null, null, emptyList));
212        _lastUpdates.put(skinId, new Date().getTime());
213    }
214}