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.runtime.parameter;
017
018import java.util.HashMap;
019import java.util.Map;
020import java.util.Map.Entry;
021
022import org.apache.avalon.framework.component.ComponentException;
023import org.apache.avalon.framework.configuration.Configuration;
024import org.apache.avalon.framework.configuration.ConfigurationException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.commons.lang3.StringUtils;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030import org.ametys.plugins.core.ui.util.ConfigurationHelper;
031import org.ametys.runtime.i18n.I18nizableText;
032import org.ametys.runtime.model.ElementDefinitionParser;
033import org.ametys.runtime.plugin.component.ThreadSafeComponentManager;
034
035/**
036 * {@link Parameter} parser from an XML configuration.
037 * @param <P> the actual type of parameter.
038 * @param <T> the actual type of parameter type.
039 * @deprecated Use {@link ElementDefinitionParser} instead
040 */
041@Deprecated
042public abstract class AbstractParameterParser<P extends Parameter<T>, T extends Enum<T>>
043{
044    private static final Logger __LOGGER = LoggerFactory.getLogger(AbstractParameterParser.class);
045    
046    /** The enumerators component manager. */
047    protected ThreadSafeComponentManager<Enumerator> _enumeratorManager;
048    /** The validators component manager. */
049    protected ThreadSafeComponentManager<Validator> _validatorManager;
050    private final Map<P, String> _validatorsToLookup = new HashMap<>();
051    private final Map<P, String> _enumeratorsToLookup = new HashMap<>();
052    
053
054    /**
055     * Creates an AbstractParameterParser.
056     * @param enumeratorManager the enumerator component manager.
057     * @param validatorManager the validator component manager.
058     */
059    public AbstractParameterParser(ThreadSafeComponentManager<Enumerator> enumeratorManager, ThreadSafeComponentManager<Validator> validatorManager)
060    {
061        _enumeratorManager = enumeratorManager;
062        _validatorManager = validatorManager;
063    }
064
065    /**
066     * Parses a parameter from a XML configuration.
067     * @param manager the service manager.
068     * @param pluginName the plugin name declaring this parameter.
069     * @param parameterConfig the XML configuration.
070     * @return the parsed parameter.
071     * @throws ConfigurationException if the configuration is not valid.
072     */
073    public P parseParameter(ServiceManager manager, String pluginName, Configuration parameterConfig) throws ConfigurationException
074    {
075        P parameter = _createParameter(parameterConfig);
076        String parameterId = _parseId(parameterConfig);
077        
078        parameter.setId(parameterId);
079        parameter.setPluginName(pluginName);
080        parameter.setLabel(_parseI18nizableText(parameterConfig, pluginName, "label"));
081        parameter.setDescription(_parseI18nizableText(parameterConfig, pluginName, "description"));
082        parameter.setType(_parseType(parameterConfig));
083        parameter.setWidget(_parseWidget(parameterConfig));
084        parameter.setWidgetParameters(_parseWidgetParameters(parameterConfig, pluginName));
085        _parseAndSetEnumerator(pluginName, parameter, parameterId, parameterConfig);
086        _parseAndSetValidator(pluginName, parameter, parameterId, parameterConfig);
087        parameter.setDefaultValue(_parseDefaultValue(parameterConfig, parameter));
088        
089        _additionalParsing(manager, pluginName, parameterConfig, parameterId, parameter);
090        
091        return parameter;
092    }
093
094    /**
095     * Retrieves local validators and enumerators components and set them into
096     * previous parameter parsed.
097     * @throws Exception if an error occurs.
098     */
099    public void lookupComponents() throws Exception
100    {
101        _validatorManager.initialize();
102        _enumeratorManager.initialize();
103        
104        for (Map.Entry<P, String> entry : _validatorsToLookup.entrySet())
105        {
106            P parameter = entry.getKey();
107            String validatorRole = entry.getValue();
108            
109            try
110            {
111                parameter.setValidator(_validatorManager.lookup(validatorRole));
112            }
113            catch (ComponentException e)
114            {
115                throw new Exception("Unable to lookup validator role: '" + validatorRole + "' for parameter: " + parameter, e);
116            }
117        }
118        
119        for (Map.Entry<P, String> entry : _enumeratorsToLookup.entrySet())
120        {
121            P parameter = entry.getKey();
122            String enumeratorRole = entry.getValue();
123            
124            try
125            {
126                parameter.setEnumerator(_enumeratorManager.lookup(enumeratorRole));
127            }
128            catch (ComponentException e)
129            {
130                throw new Exception("Unable to lookup enumerator role: '" + enumeratorRole + "' for parameter: " + parameter, e);
131            }
132        }
133    }
134
135    /**
136     * Create the parameter to populate it.
137     * @param parameterConfig the parameter configuration to use.
138     * @return the parameter instantiated.
139     * @throws ConfigurationException if the configuration is not valid.
140     */
141    protected abstract P _createParameter(Configuration parameterConfig) throws ConfigurationException;
142    
143    /**
144     * Parses the id.
145     * @param parameterConfig the parameter configuration to use.
146     * @return the id.
147     * @throws ConfigurationException if the configuration is not valid.
148     */
149    protected abstract String _parseId(Configuration parameterConfig) throws ConfigurationException;
150
151    /**
152     * Parses an i18n text.
153     * @param config the configuration to use.
154     * @param pluginName the current plugin name.
155     * @param name the child name.
156     * @return the i18n text.
157     * @throws ConfigurationException if the configuration is not valid.
158     */
159    protected I18nizableText _parseI18nizableText(Configuration config, String pluginName, String name) throws ConfigurationException
160    {
161        return I18nizableText.parseI18nizableText(config.getChild(name), "plugin." + pluginName);
162    }
163
164    /**
165     * Parses the type.
166     * @param parameterConfig the parameter configuration to use.
167     * @return the type.
168     * @throws ConfigurationException if the configuration is not valid.
169     */
170    protected abstract T _parseType(Configuration parameterConfig) throws ConfigurationException;
171
172    /**
173     * Parses the widget.
174     * @param parameterConfig the parameter configuration to use.
175     * @return the widget or <code>null</code> if none defined.
176     * @throws ConfigurationException if the configuration is not valid.
177     */
178    protected String _parseWidget(Configuration parameterConfig) throws ConfigurationException
179    {
180        return parameterConfig.getChild("widget").getValue(null);
181    }
182    
183    /**
184     * Parses the widget's parameters
185     * @param parameterConfig the parameter configuration to use.
186     * @param pluginName the current plugin name.
187     * @return the widget's parameters in a Map
188     * @throws ConfigurationException if the configuration is not valid.
189     */
190    protected Map<String, I18nizableText> _parseWidgetParameters(Configuration parameterConfig, String pluginName) throws ConfigurationException
191    {
192        Map<String, I18nizableText> widgetParams = new HashMap<>();
193        
194        Configuration widgetParamsConfig = parameterConfig.getChild("widget-params", false);
195        if (widgetParamsConfig != null)
196        {
197            Map<String, Object> parsedParams = ConfigurationHelper.parsePluginParameters(widgetParamsConfig, pluginName, __LOGGER);
198            
199            for (Entry<String, Object> param : parsedParams.entrySet())
200            {
201                String paramName = param.getKey();
202                Object value = param.getValue();
203                if (value instanceof I18nizableText)
204                {
205                    widgetParams.put(paramName, (I18nizableText) value);
206                }
207                else if (value instanceof String)
208                {
209                    widgetParams.put(paramName, new I18nizableText((String) value));
210                }
211                else
212                {
213                    __LOGGER.warn("Widget parameter '{}' at location {} is of type [{}] which is not supported. It will be ignored.", paramName, parameterConfig.getLocation(), value.getClass());
214                }
215            }
216        }
217        
218        return widgetParams;
219    }
220
221    /**
222     * Parses the enumerator.
223     * @param pluginName the plugin name.
224     * @param parameter the parameter.
225     * @param parameterId the parameter id.
226     * @param parameterConfig the parameter configuration.
227     * @throws ConfigurationException if the configuration is not valid.
228     */
229    @SuppressWarnings("unchecked")
230    protected void _parseAndSetEnumerator(String pluginName, P parameter, String parameterId, Configuration parameterConfig) throws ConfigurationException
231    {
232        Configuration enumeratorConfig = parameterConfig.getChild("enumeration", false);
233        
234        if (enumeratorConfig != null)
235        {
236            Configuration customEnumerator = enumeratorConfig.getChild("custom-enumerator", false);
237            
238            if (customEnumerator != null)
239            {
240                String enumeratorClassName = customEnumerator.getAttribute("class");
241                
242                try
243                {
244                    Class enumeratorClass = Class.forName(enumeratorClassName);
245                    _enumeratorManager.addComponent(pluginName, null, parameterId, enumeratorClass, parameterConfig);
246                }
247                catch (Exception e)
248                {
249                    throw new ConfigurationException("Unable to instantiate enumerator for class: " + enumeratorClassName, e);
250                }
251
252                // This enumerator will be affected later when validatorManager
253                // will be initialized in lookupComponents() call
254                _enumeratorsToLookup.put(parameter, parameterId);
255                
256            }
257            else
258            {
259                StaticEnumerator staticEnumerator = new StaticEnumerator();
260                
261                for (Configuration entryConfig : enumeratorConfig.getChildren("entry"))
262                {
263                    String value = entryConfig.getChild("value").getValue("");
264                    I18nizableText label = null;
265                    
266                    if (entryConfig.getChild("label", false) != null)
267                    {
268                        label = _parseI18nizableText(entryConfig, pluginName, "label");
269                    }
270                    
271                    staticEnumerator.add(label, value);
272                }
273                
274                parameter.setEnumerator(staticEnumerator);
275            }
276        }
277    }
278
279    /**
280     * Parses the validator.
281     * @param pluginName the plugin name.
282     * @param parameter the parameter.
283     * @param parameterId the parameter id.
284     * @param parameterConfig the parameter configuration.
285     * @throws ConfigurationException if the configuration is not valid.
286     */
287    @SuppressWarnings("unchecked")
288    protected void _parseAndSetValidator(String pluginName, P parameter, String parameterId, Configuration parameterConfig) throws ConfigurationException
289    {
290        Configuration validatorConfig = parameterConfig.getChild("validation", false);
291        
292        if (validatorConfig != null)
293        {
294            String validatorClassName = StringUtils.defaultIfBlank(validatorConfig.getChild("custom-validator").getAttribute("class", ""), DefaultValidator.class.getName());
295            
296            try
297            {
298                Class validatorClass = Class.forName(validatorClassName);
299                _validatorManager.addComponent(pluginName, null, parameterId, validatorClass, parameterConfig);
300            }
301            catch (Exception e)
302            {
303                throw new ConfigurationException("Unable to instantiate validator for class: " + validatorClassName, e);
304            }
305
306            // Will be affected later when validatorManager will be initialized
307            // in lookupComponents() call
308            _validatorsToLookup.put(parameter, parameterId);
309        }
310    }
311
312    /**
313     * Parses the default value.
314     * @param parameterConfig the parameter configuration.
315     * @param parameter the parameter.
316     * @return the default value or <code>null</code> if none defined.
317     * @throws ConfigurationException if the configuration is not valid.
318     */
319    protected abstract Object _parseDefaultValue(Configuration parameterConfig, P parameter) throws ConfigurationException;
320
321    /**
322     * Called for additional parsing.<br>
323     * Default implementation does nothing.
324     * @param manager the sservice manager.
325     * @param pluginName the plugin name.
326     * @param parameterConfig the parameter configuration.
327     * @param parameterId the parameter id.
328     * @param parameter the parameter to populate.
329     * @throws ConfigurationException if the configuration is not valid.
330     */
331    protected void _additionalParsing(ServiceManager manager, String pluginName, Configuration parameterConfig, String parameterId, P parameter) throws ConfigurationException
332    {
333        // Nothing to do
334    }
335}