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.Map; 020import java.util.UUID; 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; 027 028import org.ametys.runtime.i18n.I18nizableText; 029import org.ametys.runtime.model.ItemParserHelper.ConfigurationAndPluginName; 030import org.ametys.runtime.model.disableconditions.DisableConditions; 031import org.ametys.runtime.model.exception.UnknownTypeException; 032import org.ametys.runtime.model.type.ModelItemType; 033import org.ametys.runtime.model.type.ModelItemTypeExtensionPoint; 034import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 035import org.ametys.runtime.util.ParameterizedTypesHelper; 036 037/** 038 * {@link ModelItem} parser from an XML configuration. 039 * @param <D> The type of disable conditions managed by the parsed item 040 */ 041@SuppressWarnings("unchecked") 042public abstract class AbstractModelItemParser<D extends DisableConditions> 043{ 044 /** The extension point to use to get available model items types */ 045 protected ModelItemTypeExtensionPoint _modelItemTypeExtensionPoint; 046 047 /** The disable conditions component manager */ 048 protected ThreadSafeComponentManager<DisableConditions> _disableConditionsManager; 049 /** The disabled conditions to lookup */ 050 protected final Map<String, ModelItem> _disableConditionsToLookup = new HashMap<>(); 051 052 private Class<D> _disableConditionsType; 053 { 054 _disableConditionsType = ParameterizedTypesHelper.getFirstActualClassArgument(AbstractModelItemParser.class, this.getClass()); 055 } 056 057 /** 058 * Creates a model item parser. 059 * @param modelItemTypeExtensionPoint the extension point to use to get available model items types 060 * @param disableConditionsManager the disable conditions component manager 061 */ 062 public AbstractModelItemParser(ModelItemTypeExtensionPoint modelItemTypeExtensionPoint, ThreadSafeComponentManager<DisableConditions> disableConditionsManager) 063 { 064 _modelItemTypeExtensionPoint = modelItemTypeExtensionPoint; 065 _disableConditionsManager = disableConditionsManager; 066 } 067 068 /** 069 * Parses an element definition from a XML configuration. 070 * @param <T> type of the parsed item 071 * @param serviceManager the service manager 072 * @param pluginName the plugin name declaring this item. 073 * @param itemConfig the XML configuration of the model item. 074 * @param model the model which defines the model item 075 * @param parent the parent of the model item to create. Can be null if the model item to parse has no parent 076 * @return the parsed model item. 077 * @throws ConfigurationException if the configuration is not valid. 078 */ 079 public <T extends ModelItem> T parse(ServiceManager serviceManager, String pluginName, Configuration itemConfig, Model model, ModelItemGroup parent) throws ConfigurationException 080 { 081 return parse(serviceManager, new ConfigurationAndPluginName(itemConfig, pluginName), model, parent); 082 } 083 084 /** 085 * Parses an element definition from a XML configuration. 086 * @param <T> type of the parsed item 087 * @param serviceManager the service manager 088 * @param itemConfigAndPluginName the XML configuration of the model item and the plugin name declaring this item. 089 * @param model the model which defines the model item 090 * @param parent the parent of the model item to create. Can be null if the model item to parse has no parent 091 * @return the parsed model item. 092 * @throws ConfigurationException if the configuration is not valid. 093 */ 094 public <T extends ModelItem> T parse(ServiceManager serviceManager, ConfigurationAndPluginName itemConfigAndPluginName, Model model, ModelItemGroup parent) throws ConfigurationException 095 { 096 return (T) parse(serviceManager, itemConfigAndPluginName.pluginName(), itemConfigAndPluginName.defaultI18nCatalog(), itemConfigAndPluginName.configuration(), model, parent); 097 } 098 099 /** 100 * Parses an element definition from a XML configuration. 101 * @param <T> type of the parsed item 102 * @param serviceManager the service manager 103 * @param pluginName the plugin name declaring this item. 104 * @param catalog the catalog 105 * @param itemConfig the XML configuration of the model item. 106 * @param model the model which defines the model item 107 * @param parent the parent of the model item to create. Can be null if the model item to parse has no parent 108 * @return the parsed model item. 109 * @throws ConfigurationException if the configuration is not valid. 110 */ 111 public <T extends ModelItem> T parse(ServiceManager serviceManager, String pluginName, String catalog, Configuration itemConfig, Model model, ModelItemGroup parent) throws ConfigurationException 112 { 113 ModelItem modelItem = _createModelItem(itemConfig); 114 115 modelItem.setModel(model); 116 if (parent != null) 117 { 118 parent.addChild(modelItem); 119 } 120 121 modelItem.setName(_parseName(itemConfig)); 122 modelItem.setPluginName(pluginName); 123 modelItem.setLabel(_parseI18nizableText(itemConfig, catalog, "label")); 124 modelItem.setDescription(_parseI18nizableText(itemConfig, catalog, "description")); 125 modelItem.setType(_parseType(itemConfig)); 126 127 modelItem.setWidget(_parseWidget(itemConfig)); 128 modelItem.setWidgetParameters(_parseWidgetParameters(itemConfig, pluginName)); 129 130 _parseDisableConditions(itemConfig, pluginName, modelItem); 131 132 return (T) modelItem; 133 } 134 135 /** 136 * Create the model item to populate it. 137 * @param itemConfig the model item configuration to use. 138 * @return the item instantiated. 139 * @throws ConfigurationException if the configuration is not valid. 140 */ 141 protected abstract ModelItem _createModelItem(Configuration itemConfig) throws ConfigurationException; 142 143 /** 144 * Parses the name of the model item. 145 * @param itemConfig the model item configuration to use. 146 * @return the name of the model item. 147 * @throws ConfigurationException if the configuration is not valid. 148 */ 149 protected String _parseName(Configuration itemConfig) throws ConfigurationException 150 { 151 return ItemParserHelper.parseName(itemConfig, _getNameConfigurationAttribute()); 152 } 153 154 /** 155 * Retrieves the name of the configuration attribute that contains the name of the model item 156 * @return the name of the configuration attribute that contains the name of the model item 157 */ 158 protected String _getNameConfigurationAttribute() 159 { 160 return "name"; 161 } 162 163 /** 164 * Parses a mandatory i18n text configuration, throwing an exception if empty. 165 * @param config the configuration to use. 166 * @param catalog the catalog 167 * @param name the child name. 168 * @return the i18n text. 169 * @throws ConfigurationException if the configuration is not valid. 170 */ 171 protected I18nizableText _parseI18nizableText(Configuration config, String catalog, String name) throws ConfigurationException 172 { 173 return I18nizableText.parseI18nizableText(config.getChild(name), catalog); 174 } 175 176 /** 177 * Parse an optional i18n text configuration, with a default i18n text value. 178 * @param config the configuration to use. 179 * @param catalog the catalog 180 * @param name the child name. 181 * @param defaultValueCatalog the catalog of the default i18n text value 182 * @param defaultValue the default i18n text value. 183 * @return the i18n text. 184 */ 185 protected I18nizableText _parseI18nizableText(Configuration config, String catalog, String name, String defaultValueCatalog, String defaultValue) 186 { 187 return I18nizableText.parseI18nizableText(config.getChild(name), catalog, new I18nizableText(defaultValueCatalog, defaultValue)); 188 } 189 190 /** 191 * Parses the type. 192 * @param config the model item configuration to use. 193 * @return the type. 194 * @throws ConfigurationException if the configuration is not valid. 195 */ 196 protected ModelItemType _parseType(Configuration config) throws ConfigurationException 197 { 198 String typeId = config.getAttribute("type"); 199 200 if (!_modelItemTypeExtensionPoint.hasExtension(typeId)) 201 { 202 String modelItemName = _parseName(config); 203 String availableTypes = StringUtils.join(_modelItemTypeExtensionPoint.getExtensionsIds(), ", "); 204 UnknownTypeException ute = new UnknownTypeException("The type '" + typeId + "' is not available for the extension point '" + _modelItemTypeExtensionPoint + "'. Available types are: '" + availableTypes + "'."); 205 throw new ConfigurationException("Unable to find the type '" + typeId + "' defined on the item '" + modelItemName + "'.", ute); 206 } 207 208 return _modelItemTypeExtensionPoint.getExtension(typeId); 209 } 210 211 /** 212 * Parses the disable conditions. 213 * @param pluginName the plugin name. 214 * @param modelItem the model item. 215 * @param definitionConfiguration the configuration of the model item 216 * @throws ConfigurationException if an error occurred 217 */ 218 protected void _parseDisableConditions(Configuration definitionConfiguration, String pluginName, ModelItem modelItem) throws ConfigurationException 219 { 220 Configuration disableConditionsConfiguration = definitionConfiguration.getChild("disable-conditions", false); 221 if (disableConditionsConfiguration != null) 222 { 223 Class<? extends DisableConditions> conditionsClass = _disableConditionsType; 224 final String conditionsRole = conditionsClass + "$" + UUID.randomUUID().toString(); 225 _disableConditionsManager.addComponent(pluginName, null, conditionsRole, conditionsClass, disableConditionsConfiguration); 226 _disableConditionsToLookup.put(conditionsRole, modelItem); 227 } 228 } 229 230 /** 231 * Parses the widget. 232 * @param definitionConfig the element definition configuration to use. 233 * @return the widget or <code>null</code> if none defined. 234 * @throws ConfigurationException if the configuration is not valid. 235 */ 236 protected String _parseWidget(Configuration definitionConfig) throws ConfigurationException 237 { 238 return ItemParserHelper.parseWidget(definitionConfig); 239 } 240 241 /** 242 * Parses the widget's parameters 243 * @param definitionConfig the parameter ele;ent definition to use. 244 * @param pluginName the current plugin name. 245 * @return the widget's parameters in a Map 246 * @throws ConfigurationException if the configuration is not valid. 247 */ 248 protected Map<String, I18nizableText> _parseWidgetParameters(Configuration definitionConfig, String pluginName) throws ConfigurationException 249 { 250 return ItemParserHelper.parseWidgetParameters(definitionConfig, pluginName); 251 } 252 253 /** 254 * Retrieves components and set them into previous parsed model item. 255 * @throws Exception if an error occurs. 256 */ 257 public void lookupComponents() throws Exception 258 { 259 _disableConditionsManager.initialize(); 260 261 for (Map.Entry<String, ModelItem> entry : _disableConditionsToLookup.entrySet()) 262 { 263 String conditionsRole = entry.getKey(); 264 ModelItem modelItem = entry.getValue(); 265 266 try 267 { 268 modelItem.setDisableConditions(_disableConditionsManager.lookup(conditionsRole)); 269 } 270 catch (ComponentException e) 271 { 272 throw new Exception("Unable to lookup disable conditions role: '" + conditionsRole + "' for parameter: " + modelItem, e); 273 } 274 } 275 } 276}