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.cms.tag;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.avalon.framework.service.ServiceException;
027import org.apache.avalon.framework.service.ServiceManager;
028import org.apache.avalon.framework.service.Serviceable;
029
030import org.ametys.cms.color.AbstractColorsComponent;
031import org.ametys.cms.tag.CMSTag.TagVisibility;
032import org.ametys.runtime.i18n.I18nizableText;
033
034
035/**
036 * Class representing a static tag provider.
037 */
038public class StaticTagProvider extends AbstractTagProvider<CMSTag> implements Serviceable
039{
040    /** List of statically defined ids */
041    protected List<String> _localIds;
042
043    /** The tags */
044    protected Map<String, CMSTag> _tags;
045    
046    /** Target types */
047    protected TagTargetTypeExtensionPoint _targetTypeEP;
048    
049    /** The colors component */
050    protected AbstractColorsComponent _colorsComponent;
051    
052    @Override
053    public void service(ServiceManager smanager) throws ServiceException
054    {
055        _targetTypeEP = (TagTargetTypeExtensionPoint) smanager.lookup(TagTargetTypeExtensionPoint.ROLE);
056        _colorsComponent = (AbstractColorsComponent) smanager.lookup(TagColorsComponent.ROLE);
057    }
058
059    @Override
060    public void configure(Configuration configuration) throws ConfigurationException
061    {
062        super.configure(configuration);
063
064        _localIds = new ArrayList<>();
065        _tags = configureTags(configuration, null, "plugin." + _pluginName);
066    }
067    
068    /**
069     * Returns the list of statically defined ids
070     * @return the list of statically defined ids
071     */
072    public List<String> getLocalIds()
073    {
074        return _localIds;
075    }
076    
077    @Override
078    public Map<String, CMSTag> getTags(Map<String, Object> contextualParameters)
079    {
080        return _tags;
081    }
082    
083    @Override
084    public boolean hasTag(String tagID, Map<String, Object> contextualParameters)
085    {
086        return getTag(tagID, contextualParameters) != null;
087    }
088    
089    @Override
090    public CMSTag getTag(String tagID, Map<String, Object> contextualParameters)
091    {
092        Map<String, CMSTag> tags = getTags(contextualParameters);
093        return tags != null ? _recursiveSearchTags(tags, tagID) : null;
094    }
095    
096    private CMSTag _recursiveSearchTags(Map<String, CMSTag> tags, String tagID)
097    {
098        if (tags.containsKey(tagID))
099        {
100            return tags.get(tagID);
101        }
102        
103        for (CMSTag child : tags.values())
104        {
105            CMSTag tag = _recursiveSearchTags(child.getTags(), tagID);
106            if (tag != null)
107            {
108                return tag;
109            }
110        }
111        
112        return null;
113    }
114
115    @Override
116    public Collection<CMSTag> getTags(String tagID, Map<String, Object> contextualParameters)
117    {
118        CMSTag tag = getTag(tagID, contextualParameters);
119        return tag != null ? tag.getTags().values() : null;
120    }
121    
122    /**
123     * Configure tag from the passed configuration
124     * @param configuration The configuration
125     * @param parent The parent tag if any
126     * @param defaultCatalogue The default catalogue for i18n
127     * @return a Set of {@link Tag}
128     * @throws ConfigurationException If an error occurred
129     */
130    protected Map<String, CMSTag> configureTags (Configuration configuration, CMSTag parent, String defaultCatalogue)  throws ConfigurationException
131    {
132        Map<String, CMSTag> tags = new HashMap<>();
133        
134        Configuration[] tagsConfiguration = configuration.getChildren("tag");
135        for (Configuration tagConfiguration : tagsConfiguration)
136        {
137            String id = tagConfiguration.getAttribute("id");
138            if (!Tag.NAME_PATTERN.matcher(id).matches())
139            {
140                throw new ConfigurationException("Invalid tag ID '" + id + "': it must match the pattern " + Tag.NAME_PATTERN.toString(), configuration);
141            }
142            if (_localIds.contains(id))
143            {
144                throw new ConfigurationException("A tag with the id '" + id + "' already exists", configuration);
145            }
146            _localIds.add(id);
147            
148            TagVisibility visibility = TagVisibility.PUBLIC;
149            if (tagConfiguration.getAttribute("private", "").equals("true"))
150            {
151                visibility = TagVisibility.PRIVATE;
152            }
153            
154            Configuration child = tagConfiguration.getChild("color");
155            String color = child != null ? child.getValue(null) : null;
156            
157            String typeName = tagConfiguration.getAttribute("target", "CONTENT");
158            TagTargetType targetType = _targetTypeEP.getTagTargetType(typeName);
159            
160            I18nizableText label = configureLabel (tagConfiguration, defaultCatalogue);
161            I18nizableText description = configureDescription (tagConfiguration, defaultCatalogue);
162            CMSTag cmsTag = new CMSTag(id, id, parent, label, description, visibility, targetType);
163            CMSTag tag = new ColorableCMSTag(cmsTag, color, _colorsComponent);
164            tags.put(id, tag);
165            
166            // Recursive configuration
167            Map<String, CMSTag> childTags = configureTags(tagConfiguration, tag, defaultCatalogue);
168            tag.setTags(childTags);
169        }
170        
171        return tags;
172    }
173    
174    @Override
175    public List<String> getCSSUrls(Map<String, Object> contextualParameters)
176    {
177        List<String> cssUrls = super.getCSSUrls(contextualParameters);
178        cssUrls.add("/plugins/cms/cms-tags.min.css");
179        return cssUrls;
180    }
181}