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