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.core.ui;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022import java.util.Set;
023
024import org.apache.avalon.framework.configuration.Configurable;
025import org.apache.avalon.framework.configuration.Configuration;
026import org.apache.avalon.framework.configuration.ConfigurationException;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030import org.apache.commons.lang.StringUtils;
031
032import org.ametys.core.right.RightManager;
033import org.ametys.core.right.RightManager.RightResult;
034import org.ametys.core.user.CurrentUserProvider;
035import org.ametys.core.user.UserIdentity;
036import org.ametys.plugins.core.ui.util.ConfigurationHelper;
037import org.ametys.runtime.plugin.component.AbstractLogEnabled;
038import org.ametys.runtime.plugin.component.PluginAware;
039
040
041/**
042 * This implementation creates an element from a static configuration
043 */
044public class StaticFileImportsClientSideElement extends AbstractLogEnabled implements ClientSideElement, Configurable, PluginAware, Serviceable
045{
046    /** The current user provider */
047    protected CurrentUserProvider _currentUserProvider;
048    /** The rights manager */
049    protected RightManager _rightManager;
050    /** The element id */
051    protected String _id;
052    /** The script configured */
053    protected Script _script;
054    /** The right configured. Can be null */
055    protected Map<String, String> _rights;
056    /** The righs mode to associate rights AND or OR */
057    protected String _rightsMode;
058    /** The dependencies, as an associ*/
059    protected Map<String, List<String>> _dependencies;
060    
061    /** The name of the plugin that declared the element */
062    protected String _pluginName;
063    /** The name of the feature that declared the element */
064    protected String _featureName;
065    
066    
067    @Override
068    public void service(ServiceManager smanager) throws ServiceException
069    {
070        _currentUserProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE);
071        _rightManager = (RightManager) smanager.lookup(RightManager.ROLE);
072    }
073    
074    @Override
075    public void setPluginInfo(String pluginName, String featureName, String id)
076    {
077        _id = id;
078        _pluginName = pluginName;
079        _featureName = featureName;
080    }
081    
082    @Override
083    public void configure(Configuration configuration) throws ConfigurationException
084    {
085        if (getLogger().isDebugEnabled())
086        {
087            getLogger().debug("Configuring element '" + _id + "'");
088        }
089        
090        _script = _configureScript(configuration);
091        _rights = _configureRights(configuration);
092        _rightsMode = _configureRightsMode(configuration);
093        _dependencies = _configureDependencies(configuration);
094    }
095    
096    /**
097     * Configure the script
098     * @param configuration the global configuration
099     * @return The script created
100     * @throws ConfigurationException The configuration is incorrect
101     */
102    protected Script _configureScript(Configuration configuration) throws ConfigurationException
103    {
104        List<ScriptFile> scriptsImports = _configureImports(configuration.getChild("scripts"));
105        List<ScriptFile> cssImports = _configureImports(configuration.getChild("css"));
106        
107        return new Script(this.getId(), "", scriptsImports, cssImports, new HashMap<>());
108    }
109    
110    /**
111     * Configure the import part
112     * @param configuration The imports configuration
113     * @return The set of the complete url of imported file
114     * @throws ConfigurationException If an error occurs
115     */
116    protected List<ScriptFile> _configureImports(Configuration configuration) throws ConfigurationException
117    {
118        return ConfigurationHelper.parsePluginResourceList(configuration, getPluginName(), getLogger());
119    }
120    
121    /**
122     * Configure the right following the configuration
123     * 
124     * @param configuration The root configuration
125     * @return The right name or null.
126     * @throws ConfigurationException if a right element is present but empty
127     */
128    protected Map<String, String> _configureRights(Configuration configuration) throws ConfigurationException
129    {
130        Map<String, String> rights = new HashMap<>();
131        
132        Configuration[] rightsConf;
133        if (configuration.getChild("rights", false) != null)
134        {
135            rightsConf = configuration.getChild("rights").getChildren("right");
136        }
137        else
138        {
139            rightsConf = configuration.getChildren("right");
140        }
141        
142        for (Configuration rightConf : rightsConf)
143        {
144            String right = rightConf.getValue("");
145            if (right.length() != 0)
146            {
147                String prefix = rightConf.getAttribute("context-prefix", null);
148                String[] rightIds = right.split("\\|");
149                for (String rightId : rightIds)
150                {
151                    rights.put(rightId, prefix);
152                }
153            }
154            else
155            {
156                String message = "The optional right element is empty.";
157                getLogger().error(message);
158                throw new ConfigurationException(message, configuration);
159            }
160        }
161        
162        return rights;
163    }
164    
165    /**
166     * Configure the mode to associate rights AND or OR
167     * @param configuration The configuration of rights mode.
168     * @return AND or OR (default value)
169     * @throws ConfigurationException The configuration is incorrect
170     */
171    protected String _configureRightsMode(Configuration configuration) throws ConfigurationException
172    {
173        return "AND".equals(configuration.getChild("rights").getAttribute("mode", "OR").toUpperCase()) ? "AND" : "OR";
174    }
175    
176    /**
177     * Configure the dependencies following the configuration
178     * 
179     * @param configuration The root configuration
180     * @return The list of dependencies, by extension point.
181     * @throws ConfigurationException if a dependency element is present but empty
182     */
183    protected Map<String, List<String>> _configureDependencies(Configuration configuration) throws ConfigurationException
184    {
185        Map<String, List<String>> dependencies = new HashMap<>();
186        
187        if (configuration.getChild("depends", false) != null)
188        {
189            for (Configuration dependency : configuration.getChild("depends").getChildren())
190            {
191                String extensionPointName = dependency.getName();
192                String dependencyValue = dependency.getValue();
193                
194                if (StringUtils.isEmpty(dependencyValue) || StringUtils.isEmpty(extensionPointName))
195                {
196                    throw new ConfigurationException("Invalid configuration for dependencies", configuration);
197                }
198                
199                if (dependencies.containsKey(extensionPointName))
200                {
201                    List<String> extensions = dependencies.get(extensionPointName);
202                    extensions.add(dependencyValue);
203                }
204                else
205                {
206                    List<String> extensions = new ArrayList<>();
207                    extensions.add(dependencyValue);
208                    dependencies.put(extensionPointName, extensions);
209                }
210            }
211        }
212        
213        return dependencies;
214    }
215    
216    /**
217     * Determine following the right parameter if the user has right to access this feature
218     * 
219     * @param rights The rights (name, context) to check. Can be empty.
220     * @return true if the user has the right or if there is not right and false otherwise
221     */
222    protected boolean hasRight(Map<String, String> rights)
223    {
224        if (rights.isEmpty())
225        {
226            return true;
227        }
228        else
229        {
230            UserIdentity user = _currentUserProvider.getUser();
231            Set<String> rightsToCheck = rights.keySet();
232            for (String rightToCheck : rightsToCheck)
233            {
234                if (StringUtils.isNotEmpty(rightToCheck))
235                {
236                    String rightContext = rights.get(rightToCheck);
237                    // Check right on context/*
238                    if (_rightManager.hasRight(user, rightToCheck, rightContext) == RightResult.RIGHT_ALLOW)
239                    {
240                        if ("OR".equals(_rightsMode))
241                        {
242                            return true;
243                        }
244                    }
245                    else
246                    {
247                        if ("AND".equals(_rightsMode))
248                        {
249                            return false;
250                        }
251                    }
252                }
253            }
254            
255            return "AND".equals(_rightsMode);
256        }
257    }
258    
259    @Override
260    // This method is a shorthand for the getScripts(ignoreRights) and should not be overwritten
261    public final List<Script> getScripts(Map<String, Object> contextParameters)
262    {
263        return getScripts(false, contextParameters);
264    }
265    
266    @Override
267    public List<Script> getScripts(boolean ignoreRights, Map<String, Object> contextParameters)
268    {
269        if (ignoreRights)
270        {
271            List<Script> scripts = new ArrayList<>();
272            scripts.add(_script);
273            return scripts;
274        }
275        
276        if (hasRight(getRights(contextParameters)))
277        {
278            List<Script> scripts = new ArrayList<>();
279            scripts.add(_script);
280            return scripts;
281        }
282        
283        return new ArrayList<>();
284    }
285    
286    @Override
287    public Map<String, String> getRights(Map<String, Object> contextParameters)
288    {
289        return _rights;
290    }
291    
292    @Override
293    public String getPluginName()
294    {
295        return _pluginName;
296    }
297    
298    @Override
299    public String getId()
300    {
301        return _id;
302    }
303    
304    @Override
305    public Map<String, List<String>> getDependencies()
306    {
307        return _dependencies;
308    }
309    
310    @Override
311    public String toString()
312    {
313        return _id + (_dependencies != null && _dependencies.size() > 0 ? " " + _dependencies : "");
314    }
315}