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("plugin." + pluginName, rightConfiguration, "Declared by plugin '" + pluginName + "'");
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 defaultCatalog The default catalog.
084     * @param configuration The configuration of the extension
085     * @param message Declaration origin (for debug purpose)
086     * @return The created right
087     * @throws ConfigurationException if configuration if not complete
088     */
089    protected Right addRight(String defaultCatalog, Configuration configuration, String message) throws ConfigurationException
090    {
091        String id = configuration.getAttribute("id", "");
092        if (id.length() == 0)
093        {
094            throw new ConfigurationException("Right declaration is incorrect since no 'Id' attribute is specified (or may be empty)", configuration);
095        }
096
097        I18nizableText i18nLabel = I18nizableText.parseI18nizableText(configuration.getChild("label", false), defaultCatalog);
098        if (i18nLabel == null)
099        {
100            throw new ConfigurationException("Right declaration is incorrect since no 'label' element is specified (or may be empty)", configuration);
101        }
102        
103        I18nizableText i18nDescription = I18nizableText.parseI18nizableText(configuration.getChild("description", false), defaultCatalog);
104        if (i18nDescription == null)
105        {
106            throw new ConfigurationException("Right declaration is incorrect since no 'description' element is specified (or may be empty)", configuration);
107        }
108        
109        I18nizableText i18nCategory = I18nizableText.parseI18nizableText(configuration.getChild("category", false), defaultCatalog);
110        if (i18nCategory == null)
111        {
112            throw new ConfigurationException("Right declaration is incorrect since no 'category' element is specified (or may be empty)", configuration);
113        }
114        
115        if (_rights.containsKey(id))
116        {
117            Right right = _rights.get(id);
118            throw new ConfigurationException("Right with id '" + id + "' is already declared : '" + right.getDeclaration() + "'. This second declaration is ignored.", configuration);
119        }
120        
121        if (getLogger().isDebugEnabled())
122        {
123            getLogger().debug("Adding right ID : " + id);
124        }
125
126        Right right = new Right(id, i18nLabel, i18nDescription, i18nCategory, message);
127        if (_rights.containsKey(id))
128        {
129            Right oldright = _rights.get(id);
130            throw new IllegalArgumentException("Right with id '" + id + "' is already declared : '" + oldright.getDeclaration() + "'. This second declaration is ignored.");
131        }
132        _rights.put(id, right);
133        
134        return right;
135    }
136    
137    /**
138     * Declare a new right as used. Use this method to add a right programmatically.
139     * @param defaultCatalog The default catalog.
140     * @param configuration The configuration of the extension
141     * @return The created right
142     */
143    public Right addRight(String defaultCatalog, Configuration configuration) throws ConfigurationException
144    {
145        return addRight(defaultCatalog, configuration, "Declared by API");
146    }
147    
148    /**
149     * Declare a new right as used. Use this method to add a right programmatically.
150     * @param id The id of the right (not null or empty)
151     * @param labelKey The label of the right (i18n key) (not null or empty)
152     * @param descriptionKey The description of the right (i18n key) (not null or empty)
153     * @param categoryKey The category of the right (i18n key) (not null or empty)
154     * @return The created right
155     * @throws IllegalArgumentException if the id is already declared
156     */
157    public Right addRight(String id, I18nizableText labelKey, I18nizableText descriptionKey,  I18nizableText categoryKey) throws IllegalArgumentException
158    {
159        if (getLogger().isDebugEnabled())
160        {
161            getLogger().debug("Adding right from API with ID : " + id);
162        }
163
164        if (_rights.containsKey(id))
165        {
166            Right right = _rights.get(id);
167            throw new IllegalArgumentException("Right with id '" + id + "' is already declared : '" + right.getDeclaration() + "'. The application cannot be run.");
168        }
169
170        Right right = new Right(id, labelKey, descriptionKey, categoryKey, "Declared by API");
171        _rights.put(id, right);
172        
173        return right;
174    }
175    
176    /**
177     * Remove a right from the list of used rights
178     * @param id id of the right to remove
179     */
180    public void removeRight(String id)
181    {
182        if (getLogger().isDebugEnabled())
183        {
184            getLogger().debug("Removing right with ID : " + id + "from API");
185        }
186        
187        _rights.remove(id);
188    }
189    
190    public Right getExtension(String id)
191    {
192        return _rights.get(id);
193    }
194
195    public Set<String> getExtensionsIds()
196    {
197        return new HashSet<>(_rights.keySet());
198    }
199
200    public void initializeExtensions() throws Exception
201    {
202        // empty
203    }
204    
205    /**
206     * SAX all managed rights
207     * 
208     * @param handler the handler receiving SAX events
209     * @throws SAXException if something wrong occurs
210     */
211    public void toSAX (ContentHandler handler) throws SAXException
212    {
213        for (String id : _rights.keySet())
214        {
215            Right right = _rights.get(id);
216            right.toSAX(handler);
217        }
218    }
219}