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