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.plugins.core.impl.userpref;
017
018import java.util.Collection;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.Map;
022import java.util.regex.Pattern;
023
024import org.apache.avalon.framework.activity.Disposable;
025import org.apache.avalon.framework.configuration.Configurable;
026import org.apache.avalon.framework.configuration.Configuration;
027import org.apache.avalon.framework.configuration.ConfigurationException;
028import org.apache.avalon.framework.context.Context;
029import org.apache.avalon.framework.context.ContextException;
030import org.apache.avalon.framework.context.Contextualizable;
031import org.apache.avalon.framework.service.ServiceException;
032import org.apache.avalon.framework.service.ServiceManager;
033import org.apache.avalon.framework.service.Serviceable;
034import org.apache.commons.lang3.StringUtils;
035
036import org.ametys.core.userpref.UserPreference;
037import org.ametys.core.userpref.UserPreferenceProvider;
038import org.ametys.runtime.parameter.AbstractParameterParser;
039import org.ametys.runtime.parameter.Enumerator;
040import org.ametys.runtime.parameter.ParameterHelper;
041import org.ametys.runtime.parameter.ParameterHelper.ParameterType;
042import org.ametys.runtime.parameter.Validator;
043import org.ametys.runtime.plugin.component.AbstractLogEnabled;
044import org.ametys.runtime.plugin.component.PluginAware;
045import org.ametys.runtime.plugin.component.ThreadSafeComponentManager;
046
047/**
048 * Provides user preferences based on static configuration.
049 */
050public class StaticUserPreferenceProvider extends AbstractLogEnabled implements UserPreferenceProvider, Contextualizable, Serviceable, Configurable, PluginAware, Disposable
051{
052    
053    /** The user preferences, indexed by Id*/
054    protected Map<String, UserPreference> _preferences;
055    
056    /** ComponentManager for {@link Validator}s. */
057    protected ThreadSafeComponentManager<Validator> _validatorManager;
058    
059    /** ComponentManager for {@link Enumerator}s. */
060    protected ThreadSafeComponentManager<Enumerator> _enumeratorManager;
061    
062    /** Avalon service manager */
063    protected ServiceManager _serviceManager;
064    
065    /** Avalon context */
066    protected Context _context;
067    
068    /** The plugin name. */
069    protected String _pluginName;
070    
071    @Override
072    public void setPluginInfo(String pluginName, String featureName, String id)
073    {
074        _pluginName = pluginName;
075    }
076    
077    @Override
078    public void contextualize(Context context) throws ContextException
079    {
080        _context = context;
081    }
082    
083    @Override
084    public void service(ServiceManager manager) throws ServiceException
085    {
086        _serviceManager = manager;
087    }
088    
089    @Override
090    public void dispose()
091    {
092        _validatorManager.dispose();
093        _validatorManager = null;
094        _enumeratorManager.dispose();
095        _enumeratorManager = null;
096    }
097    
098    @Override
099    public void configure(Configuration configuration) throws ConfigurationException
100    {
101        _validatorManager = new ThreadSafeComponentManager<>();
102        _validatorManager.setLogger(getLogger());
103        _validatorManager.contextualize(_context);
104        _validatorManager.service(_serviceManager);
105        
106        _enumeratorManager = new ThreadSafeComponentManager<>();
107        _enumeratorManager.setLogger(getLogger());
108        _enumeratorManager.contextualize(_context);
109        _enumeratorManager.service(_serviceManager);
110        
111        UserPreferenceParser prefParser = new UserPreferenceParser(_enumeratorManager, _validatorManager);
112        
113        _preferences = new HashMap<>();
114        
115        Configuration[] prefConfigurations = configuration.getChildren("param");
116        for (Configuration prefConfiguration : prefConfigurations)
117        {
118            configurePreference(prefParser, prefConfiguration);
119        }
120        
121        try
122        {
123            prefParser.lookupComponents();
124        }
125        catch (Exception e)
126        {
127            throw new ConfigurationException("Unable to lookup parameter local components", configuration, e);
128        }
129    }
130    
131    /**
132     * Configure a user preference.
133     * @param prefParser the preference parser.
134     * @param configuration The preference configuration.
135     * @throws ConfigurationException if configuration is incomplete or invalid.
136     */
137    protected void configurePreference(UserPreferenceParser prefParser, Configuration configuration) throws ConfigurationException
138    {
139        UserPreference preference = prefParser.parseParameter(_serviceManager, _pluginName, configuration);
140        String id = preference.getId();
141        
142        if (_preferences.containsKey(id))
143        {
144            throw new ConfigurationException("The user preference '" + id + "' is already declared. Preference IDs must be unique.", configuration);
145        }
146        
147        _preferences.put(id, preference);
148        
149        if (getLogger().isDebugEnabled())
150        {
151            getLogger().debug("User preference added: " + id);
152        }
153    }
154    
155    @Override
156    public Collection<UserPreference> getPreferences(Map<String, String> context)
157    {
158        Collection<UserPreference> userPrefs = new HashSet<>();
159        
160        String currentWorkspace = context.get(UserPreferenceProvider.CONTEXT_VAR_WORKSPACE);
161        for (UserPreference userPref : _preferences.values())
162        {
163            Pattern workspace = ((StaticUserPreference) userPref).getWorkspace();
164            if (StringUtils.isBlank(currentWorkspace) || workspace == null || workspace.matcher(currentWorkspace).matches())
165            {
166                userPrefs.add(userPref);
167            }
168        }
169        
170        return userPrefs;
171    }
172    
173    /**
174     * A user pref with additionnal static information such as workspace
175     */
176    class StaticUserPreference extends UserPreference
177    {
178        protected Pattern _workspace;
179        
180        public void setWorkspace(Pattern workspace)
181        {
182            _workspace = workspace;
183        }
184        
185        /**
186         * Get the workspace associated to this userpreference if any
187         * @return A pattern or null
188         */
189        public Pattern getWorkspace()
190        {
191            return _workspace;
192        }
193    }
194    
195    /**
196     * Parser for UserPreference.
197     */
198    class UserPreferenceParser extends AbstractParameterParser<UserPreference, ParameterType>
199    {
200        public UserPreferenceParser(ThreadSafeComponentManager<Enumerator> enumeratorManager, ThreadSafeComponentManager<Validator> validatorManager)
201        {
202            super(enumeratorManager, validatorManager);
203        }
204        
205        @Override
206        protected UserPreference _createParameter(Configuration parameterConfig) throws ConfigurationException
207        {
208            return new StaticUserPreference();
209        }
210        
211        @Override
212        protected String _parseId(Configuration parameterConfig) throws ConfigurationException
213        {
214            return parameterConfig.getAttribute("id");
215        }
216        
217        @Override
218        protected ParameterType _parseType(Configuration parameterConfig) throws ConfigurationException
219        {
220            try
221            {
222                return ParameterType.valueOf(parameterConfig.getAttribute("type").toUpperCase());
223            }
224            catch (IllegalArgumentException e)
225            {
226                throw new ConfigurationException("Invalid parameter type", parameterConfig, e);
227            }
228        }
229        
230        @Override
231        protected Object _parseDefaultValue(Configuration parameterConfig, UserPreference preference)
232        {
233            String defaultValue = parameterConfig.getChild("default-value").getValue(null);
234            return ParameterHelper.castValue(defaultValue, preference.getType());
235        }
236        
237        /**
238         * Parse the workspace if any to create a pattern
239         * @param configuration The user pref configuration
240         * @return The pattern or null
241         * @throws ConfigurationException if the configuration is wrong
242         */
243        protected Pattern _parseWorkspace(Configuration configuration) throws ConfigurationException
244        {
245            String value = configuration.getChild("workspace").getValue(null);
246            if (StringUtils.isNotBlank(value))
247            {
248                return Pattern.compile(value);
249            }
250            else
251            {
252                return null;
253            }
254        }
255        
256        @Override
257        protected void _additionalParsing(ServiceManager manager, String pluginName, Configuration preferenceConfig, String parameterId, UserPreference preference) throws ConfigurationException
258        {
259            super._additionalParsing(manager, pluginName, preferenceConfig, parameterId, preference);
260            
261            boolean multiple = preferenceConfig.getAttributeAsBoolean("multiple", false);
262            int order = preferenceConfig.getChild("order").getValueAsInteger(1000);
263            String managerRole = preferenceConfig.getChild("manager-role").getValue(null);
264            boolean privateStatus = preferenceConfig.getAttributeAsBoolean("private", false);
265            Pattern workspace = _parseWorkspace(preferenceConfig);
266            
267            preference.setId(parameterId);
268            preference.setDisplayGroup(_parseI18nizableText(preferenceConfig, pluginName, "group"));
269            preference.setMultiple(multiple);
270            preference.setManagerRole(managerRole);
271            preference.setOrder(order);
272            preference.setPrivate(privateStatus);
273            ((StaticUserPreference) preference).setWorkspace(workspace);
274        }
275    }
276    
277}