001/* 002 * Copyright 2018 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.model; 017 018import java.util.HashMap; 019import java.util.List; 020import java.util.Map; 021import java.util.UUID; 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.avalon.framework.service.ServiceManager; 027import org.apache.commons.lang3.tuple.Pair; 028 029import org.ametys.runtime.i18n.I18nizableText; 030import org.ametys.runtime.model.disableconditions.DisableConditions; 031import org.ametys.runtime.model.type.ModelItemTypeExtensionPoint; 032import org.ametys.runtime.parameter.DefaultValidator; 033import org.ametys.runtime.parameter.Validator; 034import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 035 036/** 037 * {@link ElementDefinition} parser from an XML configuration. 038 * @param <D> The type of disable conditions managed by the parsed item 039 */ 040public abstract class AbstractElementDefinitionParser<D extends DisableConditions> extends AbstractModelItemParser<D> 041{ 042 private ThreadSafeComponentManager<Enumerator> _enumeratorManager; 043 private ThreadSafeComponentManager<Validator> _validatorManager; 044 private final Map<String, ElementDefinition> _validatorsToLookup = new HashMap<>(); 045 private final Map<String, ElementDefinition> _enumeratorsToLookup = new HashMap<>(); 046 047 /** 048 * Creates an element definition parser. 049 * @param modelItemTypeExtensionPoint the extension point to use to get available element types 050 * @param disableConditionsManager the disable conditions component manager 051 * @param enumeratorManager the enumerator component manager. 052 * @param validatorManager the validator component manager. 053 */ 054 public AbstractElementDefinitionParser(ModelItemTypeExtensionPoint modelItemTypeExtensionPoint, ThreadSafeComponentManager<DisableConditions> disableConditionsManager, ThreadSafeComponentManager<Enumerator> enumeratorManager, ThreadSafeComponentManager<Validator> validatorManager) 055 { 056 super(modelItemTypeExtensionPoint, disableConditionsManager); 057 _enumeratorManager = enumeratorManager; 058 _validatorManager = validatorManager; 059 } 060 061 @Override 062 @SuppressWarnings("unchecked") 063 public <T extends ModelItem> T parse(ServiceManager serviceManager, String pluginName, String catalog, Configuration definitionConfig, Model model, ModelItemGroup parent) throws ConfigurationException 064 { 065 ElementDefinition definition = (ElementDefinition) super.parse(serviceManager, pluginName, catalog, definitionConfig, model, parent); 066 067 definition.setParsedDefaultValues(_parseDefaultValues(definitionConfig, definition)); 068 definition.setMultiple(ItemParserHelper.parseMultiple(definitionConfig)); 069 070 _parseAndSetEnumerator(pluginName, catalog, definition, definitionConfig); 071 _parseAndSetValidator(pluginName, definition, definitionConfig); 072 073 return (T) definition; 074 } 075 076 @Override 077 protected ElementDefinition _createModelItem(Configuration definitionConfig) throws ConfigurationException 078 { 079 return new DefaultElementDefinition(); 080 } 081 082 /** 083 * Parses the default values. 084 * @param definitionConfig the element definition configuration. 085 * @param definition the element definition. 086 * @return the default values and their types or <code>null</code> if none default value is defined. 087 * @throws ConfigurationException if the configuration is not valid. 088 */ 089 protected List<Pair<String, Object>> _parseDefaultValues(Configuration definitionConfig, ElementDefinition definition) throws ConfigurationException 090 { 091 return ItemParserHelper.parseDefaultValues(definitionConfig, definition, ItemParserHelper::parseDefaultValue); 092 } 093 094 /** 095 * Parses the enumerator. 096 * @param pluginName the plugin name. 097 * @param catalog the catalog 098 * @param definition the element definition. 099 * @param definitionConfig the element definition configuration. 100 * @throws ConfigurationException if the configuration is not valid. 101 */ 102 @SuppressWarnings("unchecked") 103 protected void _parseAndSetEnumerator(String pluginName, String catalog, ElementDefinition definition, Configuration definitionConfig) throws ConfigurationException 104 { 105 Configuration enumeratorConfig = definitionConfig.getChild("enumeration", false); 106 107 if (enumeratorConfig != null) 108 { 109 Configuration customEnumerator = enumeratorConfig.getChild("custom-enumerator", false); 110 111 if (customEnumerator != null) 112 { 113 final String enumeratorClassName = customEnumerator.getAttribute("class"); 114 final String enumeratorRole = definition.getPath() + "$" + UUID.randomUUID().toString(); 115 116 try 117 { 118 Class enumeratorClass = Class.forName(enumeratorClassName); 119 _enumeratorManager.addComponent(pluginName, null, enumeratorRole, enumeratorClass, definitionConfig); 120 } 121 catch (Exception e) 122 { 123 throw new ConfigurationException("Unable to instantiate enumerator for class: " + enumeratorClassName, e); 124 } 125 126 // This enumerator will be affected later when enumeratorManager 127 // will be initialized in lookupComponents() call 128 _enumeratorsToLookup.put(enumeratorRole, definition); 129 130 // Add the custom enumerator information to the element definition 131 definition.setCustomEnumerator(enumeratorClassName); 132 definition.setEnumeratorConfiguration(customEnumerator); 133 } 134 else 135 { 136 StaticEnumerator staticEnumerator = new StaticEnumerator(); 137 138 for (Configuration entryConfig : enumeratorConfig.getChildren("entry")) 139 { 140 Configuration valueConfiguration = entryConfig.getChild("value"); 141 Object value = definition.getType().parseConfiguration(valueConfiguration); 142 I18nizableText label = null; 143 144 if (entryConfig.getChild("label", false) != null) 145 { 146 label = _parseI18nizableText(entryConfig, catalog, "label"); 147 } 148 149 staticEnumerator.add(label, value); 150 } 151 152 definition.setEnumerator(staticEnumerator); 153 } 154 } 155 } 156 157 /** 158 * Parses the validator. 159 * @param pluginName the plugin name. 160 * @param definition the element definition. 161 * @param definitionConfig the element definition configuration. 162 * @throws ConfigurationException if the configuration is not valid. 163 */ 164 @SuppressWarnings("unchecked") 165 protected void _parseAndSetValidator(String pluginName, ElementDefinition definition, Configuration definitionConfig) throws ConfigurationException 166 { 167 Configuration validatorConfig = definitionConfig.getChild("validation", false); 168 169 if (validatorConfig != null) 170 { 171 Configuration customValidator = validatorConfig.getChild("custom-validator", false); 172 String validatorClassName; 173 174 if (customValidator != null) 175 { 176 validatorClassName = customValidator.getAttribute("class"); 177 178 // Add the custom validator information to the element definition 179 definition.setCustomValidator(validatorClassName); 180 definition.setValidatorConfiguration(customValidator); 181 } 182 else 183 { 184 validatorClassName = DefaultValidator.class.getName(); 185 } 186 187 final String validatorRole = definition.getPath() + "$" + UUID.randomUUID().toString(); 188 189 try 190 { 191 Class validatorClass = Class.forName(validatorClassName); 192 _validatorManager.addComponent(pluginName, null, validatorRole, validatorClass, definitionConfig); 193 } 194 catch (Exception e) 195 { 196 throw new ConfigurationException("Unable to instantiate validator for class: " + validatorClassName, e); 197 } 198 199 // Will be affected later when validatorManager will be initialized 200 // in lookupComponents() call 201 _validatorsToLookup.put(validatorRole, definition); 202 } 203 } 204 205 @Override 206 @SuppressWarnings("unchecked") 207 public void lookupComponents() throws Exception 208 { 209 super.lookupComponents(); 210 211 _validatorManager.initialize(); 212 _enumeratorManager.initialize(); 213 214 for (Map.Entry<String, ElementDefinition> entry : _validatorsToLookup.entrySet()) 215 { 216 String validatorRole = entry.getKey(); 217 ElementDefinition definition = entry.getValue(); 218 219 try 220 { 221 definition.setValidator(_validatorManager.lookup(validatorRole)); 222 } 223 catch (ComponentException e) 224 { 225 throw new Exception("Unable to lookup validator role: '" + validatorRole + "' for parameter: " + definition, e); 226 } 227 } 228 229 for (Map.Entry<String, ElementDefinition> entry : _enumeratorsToLookup.entrySet()) 230 { 231 String enumeratorRole = entry.getKey(); 232 ElementDefinition definition = entry.getValue(); 233 234 try 235 { 236 definition.setEnumerator(_enumeratorManager.lookup(enumeratorRole)); 237 } 238 catch (ComponentException e) 239 { 240 throw new Exception("Unable to lookup enumerator role: '" + enumeratorRole + "' for parameter: " + definition, e); 241 } 242 } 243 } 244}