001/*
002 *  Copyright 2012 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.core.right;
017
018import java.util.HashMap;
019import java.util.HashSet;
020import java.util.Map;
021import java.util.Set;
022
023import org.apache.avalon.framework.activity.Initializable;
024import org.apache.avalon.framework.component.Component;
025import org.apache.avalon.framework.configuration.Configuration;
026import org.apache.avalon.framework.configuration.ConfigurationException;
027import org.apache.avalon.framework.logger.AbstractLogEnabled;
028import org.apache.avalon.framework.thread.ThreadSafe;
029import org.xml.sax.ContentHandler;
030import org.xml.sax.SAXException;
031
032import org.ametys.runtime.i18n.I18nizableText;
033import org.ametys.runtime.plugin.ExtensionPoint;
034
035
036/**
037 * This extension point handle a list of rights handled by the plugins or the application.
038 */
039public class RightsExtensionPoint extends AbstractLogEnabled implements ExtensionPoint<Right>, Initializable, ThreadSafe, Component
040{
041    /** The avalon role */
042    public static final String ROLE = RightsExtensionPoint.class.getName();
043    
044    /** The map of rightId, Right of declared rights */
045    protected Map<String, Right> _rights;
046
047    public void initialize() throws Exception
048    {
049        _rights = new HashMap<>();
050    }
051    
052    public boolean hasExtension(String id)
053    {
054        return _rights.containsKey(id);
055    }
056
057    public void addExtension(String id, String pluginName, String pluginId, Configuration configuration) throws ConfigurationException
058    {
059        if (getLogger().isDebugEnabled())
060        {
061            getLogger().debug("Adding rights from plugin " + pluginName + "/" + pluginId);
062        }
063
064        Configuration[] rightsConfigurations = configuration.getChildren("right");
065        for (Configuration rightConfiguration : rightsConfigurations)
066        {
067            try
068            {
069                addRight(pluginName, rightConfiguration);
070            }
071            catch (ConfigurationException e)
072            {
073                if (getLogger().isWarnEnabled())
074                {
075                    getLogger().warn("The plugin '" + pluginName + "." + pluginId + "' has a rights extension but has an incorrect configuration", e);
076                }
077            }
078        }
079    }
080    
081    /**
082     * Declare a new right (not as used)
083     * @param pluginName The name of the plugin declaring the extension
084     * @param configuration The configuration of the extension
085     * @throws ConfigurationException if configuration if not complete
086     */
087    protected void addRight(String pluginName, Configuration configuration) throws ConfigurationException
088    {
089        String id = configuration.getAttribute("id", "");
090        if (id.length() == 0)
091        {
092            throw new ConfigurationException("Right declaration is incorrect since no 'Id' attribute is specified (or may be empty)", configuration);
093        }
094
095        String label = configuration.getChild("label").getValue("");
096        if (label.length() == 0)
097        {
098            throw new ConfigurationException("Right declaration is incorrect since no 'label' element is specified (or may be empty)", configuration);
099        }
100        I18nizableText i18nLabel = new I18nizableText("plugin." + pluginName, label);
101        
102        String description = configuration.getChild("description").getValue("");
103        if (description.length() == 0)
104        {
105            throw new ConfigurationException("Right declaration is incorrect since no 'description' element is specified (or may be empty)", configuration);
106        }
107        I18nizableText i18nDescription = new I18nizableText("plugin." + pluginName, description);
108        
109        String category = configuration.getChild("category").getValue("");
110        if (category.length() == 0)
111        {
112            throw new ConfigurationException("Right declaration is incorrect since no 'category' element is specified (or may be empty)", configuration);
113        }
114        I18nizableText i18nCategory = new I18nizableText("plugin." + pluginName, category);
115        
116        if (_rights.containsKey(id))
117        {
118            Right right = _rights.get(id);
119            throw new ConfigurationException("Right with id '" + id + "' is already declared : '" + right.getDeclaration() + "'. This second declaration is ignored.", configuration);
120        }
121        
122        if (getLogger().isDebugEnabled())
123        {
124            getLogger().debug("Adding right ID : " + id);
125        }
126
127        Right right = new Right(id, i18nLabel, i18nDescription, i18nCategory, "Declared by plugin '" + pluginName + "'");
128        if (_rights.containsKey(id))
129        {
130            Right oldright = _rights.get(id);
131            throw new IllegalArgumentException("Right with id '" + id + "' is already declared : '" + oldright.getDeclaration() + "'. This second declaration is ignored.");
132        }
133        _rights.put(id, right);
134    }
135    
136    /**
137     * Declare a new right as used. Use this method to add a right programmatically.
138     * @param id The id of the right (not null or empty)
139     * @param labelKey The label of the right (i18n key) (not null or empty)
140     * @param descriptionKey The description of the right (i18n key) (not null or empty)
141     * @param categoryKey The category of the right (i18n key) (not null or empty)
142     * @throws IllegalArgumentException if the id is already declared
143     */
144    public void addRight(String id, I18nizableText labelKey, I18nizableText descriptionKey,  I18nizableText categoryKey) throws IllegalArgumentException
145    {
146        if (getLogger().isDebugEnabled())
147        {
148            getLogger().debug("Adding right from API with ID : " + id);
149        }
150
151        if (_rights.containsKey(id))
152        {
153            Right right = _rights.get(id);
154            throw new IllegalArgumentException("Right with id '" + id + "' is already declared : '" + right.getDeclaration() + "'. The application cannot be run.");
155        }
156
157        Right right = new Right(id, labelKey, descriptionKey, categoryKey, "Declared by API");
158        _rights.put(id, right);
159    }
160    
161    /**
162     * Remove a right from the list of used rights
163     * @param id id of the right to remove
164     */
165    public void removeRight(String id)
166    {
167        if (getLogger().isDebugEnabled())
168        {
169            getLogger().debug("Removing right with ID : " + id + "from API");
170        }
171        
172        _rights.remove(id);
173    }
174    
175    public Right getExtension(String id)
176    {
177        return _rights.get(id);
178    }
179
180    public Set<String> getExtensionsIds()
181    {
182        return new HashSet<>(_rights.keySet());
183    }
184
185    public void initializeExtensions() throws Exception
186    {
187        // empty
188    }
189    
190    /**
191     * SAX all managed rights
192     * 
193     * @param handler the handler receiving SAX events
194     * @throws SAXException if something wrong occurs
195     */
196    public void toSAX (ContentHandler handler) throws SAXException
197    {
198        for (String id : _rights.keySet())
199        {
200            Right right = _rights.get(id);
201            right.toSAX(handler);
202        }
203    }
204}