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