001/*
002 *  Copyright 2010 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.repository.site;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Comparator;
021import java.util.List;
022import java.util.stream.Collectors;
023import java.util.stream.Stream;
024
025import org.apache.avalon.framework.configuration.Configurable;
026import org.apache.avalon.framework.configuration.Configuration;
027import org.apache.avalon.framework.configuration.ConfigurationException;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.apache.avalon.framework.thread.ThreadSafe;
032import org.apache.excalibur.source.SourceResolver;
033
034import org.ametys.core.util.I18nUtils;
035import org.ametys.core.util.I18nizableTextKeyComparator;
036import org.ametys.runtime.i18n.I18nizableText;
037import org.ametys.runtime.model.CategorizedElementDefinitionHelper;
038import org.ametys.runtime.model.CategorizedElementDefinitionWrapperComparator;
039import org.ametys.runtime.model.ElementDefinition;
040import org.ametys.runtime.model.View;
041import org.ametys.runtime.plugin.component.PluginAware;
042import org.ametys.web.site.SiteConfigurationExtensionPoint;
043import org.ametys.web.site.SiteParameterWrapper;
044
045/**
046 * Type of site which is retrieved from a XML configuration.
047 */
048public class DefaultSiteType implements SiteType, Configurable, PluginAware, ThreadSafe, Serviceable
049{
050    private static final String __FAMILY_ID = "SiteTypes";
051    
052    private static final String __GENERAL_INFORMATIONS_I18N_KEY = "PLUGINS_WEB_SITE_INFORMATION_CATEGORY";
053    
054    /** Plugin name. */
055    protected String _pluginName;
056    /** Site type id. */
057    protected String _id;
058    /** Site type name. */
059    protected String _name;
060    /** Label. */
061    protected I18nizableText _label;
062    /** Description. */
063    protected I18nizableText _description;
064    /** Glyph icon */
065    protected String _iconGlyph;
066    /** Small icon URI 16x16. */
067    protected String _smallIcon;
068    /** Medium icon URI 32x32. */
069    protected String _mediumIcon;
070    /** Large icon URI 48x48. */
071    protected String _largeIcon;
072    /** The model items of this site type */
073    protected List<ElementDefinition> _parameters = new ArrayList<>();
074    /** The site type view, built from site parameter categories and groups */
075    protected View _view;
076    
077    /** The source resolver */
078    protected SourceResolver _srcResolver;
079    /** The site configuration extension point */
080    protected SiteConfigurationExtensionPoint _siteConfigurationExtensionPoint;
081    /** Component gathering utility methods for internationalizable text translation {@link I18nUtils} */
082    protected I18nUtils _i18nUtils;
083    
084    /** The parameter wrappers available for this site type **/
085    private Collection<SiteParameterWrapper> _parameterWrappers = new ArrayList<>();
086
087    public void service(ServiceManager smanager) throws ServiceException
088    {
089        _srcResolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE);
090        _siteConfigurationExtensionPoint = (SiteConfigurationExtensionPoint) smanager.lookup(SiteConfigurationExtensionPoint.ROLE);
091        _i18nUtils = (I18nUtils) smanager.lookup(I18nUtils.ROLE);
092    }
093    
094    public void configure(Configuration configuration) throws ConfigurationException
095    {
096        _name = configuration.getChild("name").getValue();
097        
098        _label = _parseI18nizableText(configuration, "label");
099        _description = _parseI18nizableText(configuration, "description");
100        
101        _iconGlyph = configuration.getChild("icons").getChild("glyph").getValue(null);
102        
103        _smallIcon = _parseIcon(configuration.getChild("icons"), "small");
104        _mediumIcon = _parseIcon(configuration.getChild("icons"), "medium");
105        _largeIcon = _parseIcon(configuration.getChild("icons"), "large");
106    }
107    
108    public String getId()
109    {
110        return _id;
111    }
112    
113    public String getFamilyId()
114    {
115        return __FAMILY_ID;
116    }
117    
118    public String getName()
119    {
120        return _name;
121    }
122    
123    public I18nizableText getLabel()
124    {
125        return _label;
126    }
127    
128    public I18nizableText getDescription()
129    {
130        return _description;
131    }
132    
133    public String getIconGlyph()
134    {
135        return _iconGlyph;
136    }
137    
138    public String getLargeIcon()
139    {
140        return _largeIcon;
141    }
142
143    public String getMediumIcon()
144    {
145        return _mediumIcon;
146    }
147    
148    public String getSmallIcon()
149    {
150        return _smallIcon;
151    }
152    
153    public String getPluginName()
154    {
155        return _pluginName;
156    }
157
158    public void setPluginInfo(String pluginName, String featureName, String id)
159    {
160        _id = id;
161        _pluginName = pluginName;
162    }
163    
164    public synchronized Collection<ElementDefinition> getModelItems()
165    {
166        if (_parameters.isEmpty())
167        {
168            _parameters = _getParameterWrappers()
169                    .map(SiteParameterWrapper::getDefinition)
170                    .collect(Collectors.toList());
171        }
172        
173        return _parameters;
174    }
175    
176    public synchronized View getView()
177    {
178        if (_view == null)
179        {
180            Collection<SiteParameterWrapper> wrappers = _getParameterWrappers()
181                    .filter(wrapper -> !Site.ILLUSTRATION_PARAMETER.equals(wrapper.getDefinition().getName()))
182                    .collect(Collectors.toList());
183            
184            Comparator<I18nizableText> categoriesComparator = new I18nizableTextTranslationComparator();
185            Comparator<I18nizableText> groupsComparator = new I18nizableTextKeyComparator();
186            Comparator<SiteParameterWrapper> elementsComparator = new SiteConfigurationParametersComparator();
187            
188            _view = CategorizedElementDefinitionHelper.buildViewFromCategories(wrappers, categoriesComparator, groupsComparator, elementsComparator);
189        }
190        
191        return _view;
192    }
193    
194    private synchronized Stream<SiteParameterWrapper> _getParameterWrappers()
195    {
196        if (_parameterWrappers.isEmpty())
197        {
198            for (String extensionId : _siteConfigurationExtensionPoint.getExtensionsIds())
199            {
200                SiteParameterWrapper wrapper = _siteConfigurationExtensionPoint.getExtension(extensionId);
201                // Filter site parameters for this type
202                if (wrapper.isInSiteType(this.getName()))
203                {
204                    @SuppressWarnings("unchecked")
205                    SiteParameterWrapper copy = new SiteParameterWrapper<>(wrapper);
206                    
207                    // Set the model to each definition
208                    copy.getDefinition().setModel(this);
209                    
210                    _parameterWrappers.add(copy);
211                }
212            }
213        }
214        
215        return _parameterWrappers.stream();
216    }
217    
218    /**
219     * Parse an i18n text.
220     * @param config the configuration to use.
221     * @param name the child name.
222     * @return the i18n text.
223     * @throws ConfigurationException if the configuration is not valid.
224     */
225    protected I18nizableText _parseI18nizableText(Configuration config, String name) throws ConfigurationException
226    {
227        return I18nizableText.parseI18nizableText(config.getChild(name), "plugin." + _pluginName, "");
228    }
229    
230    /**
231     * Parse an icon path
232     * @param configuration the configuration to use
233     * @param name the child name.
234     * @return The icon path
235     * @throws ConfigurationException if the configuration is not valid.
236     */
237    protected String _parseIcon (Configuration configuration, String name) throws ConfigurationException
238    {
239        Configuration iconConfig = configuration.getChild(name, false);
240        if (iconConfig != null)
241        {
242            String pluginName = iconConfig.getAttribute("plugin", _pluginName);
243            return "/plugins/" + pluginName + "/resources/" + iconConfig.getValue();
244        }
245        
246        return "/plugins/web/resources/img/sitetype/icon-" + name + ".png";
247    }
248    
249    /**
250     * I18nizableText comparator for site parameters
251     * General information category is the first one, then sort  the I18nizableText with their translation
252     */
253    class I18nizableTextTranslationComparator implements Comparator<I18nizableText>
254    {
255        @Override
256        public int compare(I18nizableText t1, I18nizableText t2)
257        {
258            // The general informations category always goes first
259            if (t1.getKey().equals(__GENERAL_INFORMATIONS_I18N_KEY))
260            {
261                if (t2.getKey().equals(__GENERAL_INFORMATIONS_I18N_KEY))
262                {
263                    return 0;
264                }
265                return -1;
266            }
267
268            if (t2.getKey().equals(__GENERAL_INFORMATIONS_I18N_KEY))
269            {
270                return 1;
271            }
272            
273            String tt1 = _i18nUtils.translate(t1);
274            if (tt1 == null)
275            {
276                return -1;
277            }
278            
279            String tt2 = _i18nUtils.translate(t2);
280            if (tt2 == null)
281            {
282                return 1;
283            }
284            
285            return tt1.compareTo(tt2);
286        }
287    }
288
289    /**
290     * Comparator for the site parameter wrappers using their position
291     * If no position is set, keep the order of arrival in the configuration
292     */
293    class SiteConfigurationParametersComparator extends CategorizedElementDefinitionWrapperComparator<SiteParameterWrapper>
294    {
295        @Override
296        protected int compareWrappersWithSamePositions(SiteParameterWrapper wrapper1, SiteParameterWrapper wrapper2)
297        {
298            // Keep the order of arrival in the configuration
299            return 1;
300        }
301    }
302}