001/*
002 *  Copyright 2016 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.LinkedHashSet;
020import java.util.Map;
021import java.util.Set;
022
023import org.apache.avalon.framework.component.ComponentException;
024import org.apache.avalon.framework.configuration.Configuration;
025import org.apache.avalon.framework.configuration.ConfigurationException;
026import org.apache.commons.lang3.StringUtils;
027
028import org.ametys.runtime.i18n.I18nizableText;
029import org.ametys.runtime.plugin.component.ThreadSafeComponentManager;
030
031/**
032 * Parameter checker parser from an XML configuration. 
033 */
034public class ParameterCheckerParser
035{
036    /** The parameter checker component manager. */
037    protected ThreadSafeComponentManager<ParameterChecker> _parameterCheckerManager;
038    
039    /** The name of the plugin declaring this parameter checker */
040    protected String _pluginName;
041    
042    private final Map<ParameterCheckerDescriptor, String> _parameterCheckersToLookup = new HashMap<>();
043    
044    /**
045     * Create a parameter checker parser
046     * @param paramCheckerManager the parameter checker.
047     */
048    public ParameterCheckerParser(ThreadSafeComponentManager<ParameterChecker> paramCheckerManager)
049    {
050        _parameterCheckerManager = paramCheckerManager;
051    }
052    
053    /**
054     * Parse a parameter checker from a XML configuration.
055     * @param pluginName the plugin's name declaring this parameter.
056     * @param paramCheckerConfig the XML configuration.
057     * @return the {@link ParameterCheckerDescriptor} for the parsed parameter checker
058     * @throws ConfigurationException if the configuration is not valid.
059     */
060    public ParameterCheckerDescriptor parseParameterChecker(String pluginName, Configuration paramCheckerConfig) throws ConfigurationException
061    {
062        ParameterCheckerDescriptor parameterChecker = _getParameterCheckerDescriptorInstance();
063         
064        String parameterId = paramCheckerConfig.getAttribute("id");
065        String concreteClass = paramCheckerConfig.getAttribute("class");
066
067        Configuration smallIconConfig = paramCheckerConfig.getChild("icon-small");
068        String smallIconPath = smallIconConfig.getValue("");
069        if (StringUtils.isNotEmpty(smallIconPath))
070        {
071            String plugin = smallIconConfig.getAttribute("plugin", pluginName);
072            smallIconPath = "/plugins/" + plugin + "/resources/" + smallIconPath;
073        }
074        
075        Configuration mediumIconConfig = paramCheckerConfig.getChild("icon-medium");
076        String mediumIconPath = mediumIconConfig.getValue("");
077        if (StringUtils.isNotEmpty(mediumIconPath))
078        {
079            String plugin = mediumIconConfig.getAttribute("plugin", pluginName);
080            mediumIconPath = "/plugins/" + plugin + "/resources/" + mediumIconPath;
081        }
082        
083        Configuration largeIconConfig = paramCheckerConfig.getChild("icon-large");
084        String largeIconPath = largeIconConfig.getValue("");
085        if (StringUtils.isNotEmpty(largeIconPath))
086        {
087            String plugin = largeIconConfig.getAttribute("plugin", pluginName);
088            largeIconPath = "/plugins/" + plugin + "/resources/" + largeIconPath;
089        }
090        
091        I18nizableText label = _parseI18nizableText(paramCheckerConfig, pluginName, "label");
092        I18nizableText description = _parseI18nizableText(paramCheckerConfig, pluginName, "description");
093        
094        Configuration uiRefConfig = paramCheckerConfig.getChild("ui-ref");
095        int uiRefOrder = uiRefConfig.getChild("order").getValueAsInteger(1);
096        
097        String uiRefLocation = null;
098        Configuration uiRefLocationConfig = uiRefConfig.getChild("location", false);
099        if (uiRefLocationConfig != null)
100        {
101            uiRefLocation = uiRefLocationConfig.getAttribute("path");
102        }
103        
104        Set<String >linkedParamsPaths = new LinkedHashSet<>();
105        for (Configuration linkedParamConfig : paramCheckerConfig.getChild("linked-params").getChildren("param-ref"))
106        {
107            linkedParamsPaths.add(linkedParamConfig.getAttribute("id"));
108        }
109        
110        parameterChecker.setId(parameterId);
111        parameterChecker.setLabel(label);
112        parameterChecker.setDescription(description);
113        parameterChecker.setClass(concreteClass);
114        parameterChecker.setSmallIconPath(smallIconPath);
115        parameterChecker.setMediumIconPath(mediumIconPath);
116        parameterChecker.setLargeIconPath(largeIconPath);
117        parameterChecker.setUiRefOrder(uiRefOrder);
118        parameterChecker.setUiRefLocation(uiRefLocation);
119
120        parameterChecker.setLinkedParamsPaths(linkedParamsPaths);
121        
122        _setParameterChecker(pluginName, parameterChecker, parameterId, paramCheckerConfig);
123        return parameterChecker;
124    }
125    
126    /**
127     * Sets the parameter checker.
128     * @param pluginName the plugin's name.
129     * @param parameterChecker the parameter checker.
130     * @param parameterCheckerId the parameter chekcer's id.
131     * @param parameterCheckerConfig the parameter checker's configuration.
132     * @throws ConfigurationException if the configuration is not valid.
133     */
134    @SuppressWarnings("unchecked")
135    protected void _setParameterChecker(String pluginName, ParameterCheckerDescriptor parameterChecker, String parameterCheckerId, Configuration parameterCheckerConfig) throws ConfigurationException
136    {
137        if (parameterCheckerConfig != null)
138        {
139            String parameterCheckerClassName = parameterCheckerConfig.getAttribute("class");
140            
141            try
142            {
143                Class parameterCheckerClass = Class.forName(parameterCheckerClassName);
144                _parameterCheckerManager.addComponent(pluginName, null, parameterCheckerId, parameterCheckerClass, parameterCheckerConfig);
145            }
146            catch (Exception e)
147            {
148                throw new ConfigurationException("Unable to instantiate parameter checker for class: " + parameterCheckerClassName, e);
149            }
150
151            // Will be affected later when parameterCheckerManager will be initialized
152            // in lookupComponents() call
153            _parameterCheckersToLookup.put(parameterChecker, parameterCheckerId);
154        }
155    }
156    
157    /**
158     * Retrieves local parameter checkers components and sets them into
159     * the previous parameter checker parsed.
160     * @throws Exception if an error occurs.
161     */
162    public void lookupComponents() throws Exception
163    {
164        _parameterCheckerManager.initialize();
165        
166        for (Map.Entry<ParameterCheckerDescriptor, String> entry : _parameterCheckersToLookup.entrySet())
167        {
168            ParameterCheckerDescriptor parameterChecker = entry.getKey();
169            String parameterCheckerRole = entry.getValue();
170            
171            try
172            {
173                parameterChecker.setParameterChecker(_parameterCheckerManager.lookup(parameterCheckerRole));
174            }
175            catch (ComponentException e)
176            {
177                throw new Exception("Unable to lookup parameter checker role: '" + parameterCheckerRole + "' for parameter: " + parameterChecker, e);
178            }
179        }
180    }
181    
182    /**
183     * Parses an i18n text.
184     * @param config the configuration to use.
185     * @param pluginName the current plugin name.
186     * @param name the child name.
187     * @return the i18n text.
188     * @throws ConfigurationException if the configuration is not valid.
189     */
190    protected I18nizableText _parseI18nizableText(Configuration config, String pluginName, String name) throws ConfigurationException
191    {
192        return I18nizableText.parseI18nizableText(config.getChild(name), "plugin." + pluginName);
193    }
194    
195    /**
196     * Get the parameter checker descriptor instance to use
197     * @return the parameter checker descriptor instance to use
198     */
199    protected ParameterCheckerDescriptor _getParameterCheckerDescriptorInstance()
200    {
201        return new ParameterCheckerDescriptor();
202    }
203}