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 org.apache.avalon.framework.configuration.Configuration; 019import org.apache.avalon.framework.configuration.ConfigurationException; 020import org.apache.avalon.framework.service.ServiceManager; 021import org.apache.commons.lang3.StringUtils; 022 023import org.ametys.runtime.i18n.I18nizableText; 024import org.ametys.runtime.model.exception.UnknownTypeException; 025import org.ametys.runtime.model.type.ModelItemType; 026import org.ametys.runtime.plugin.component.AbstractThreadSafeComponentExtensionPoint; 027 028/** 029 * {@link ModelItem} parser from an XML configuration. 030 */ 031public abstract class AbstractModelItemParser 032{ 033 /** The extension point to use to get available model items types */ 034 protected AbstractThreadSafeComponentExtensionPoint<? extends ModelItemType> _modelItemTypeExtensionPoint; 035 036 /** 037 * Creates a model item parser. 038 * @param modelItemTypeExtensionPoint the extension point to use to get available model items types 039 */ 040 public AbstractModelItemParser(AbstractThreadSafeComponentExtensionPoint<? extends ModelItemType> modelItemTypeExtensionPoint) 041 { 042 _modelItemTypeExtensionPoint = modelItemTypeExtensionPoint; 043 } 044 045 /** 046 * Parses an element definition from a XML configuration. 047 * @param <T> type of the parsed item 048 * @param serviceManager the service manager 049 * @param pluginName the plugin name declaring this item. 050 * @param itemConfig the XML configuration of the model item. 051 * @param model the model which defines the model item 052 * @param parent the parent of the model item to create. Can be null if the model item to parse has no parent 053 * @return the parsed model item. 054 * @throws ConfigurationException if the configuration is not valid. 055 */ 056 @SuppressWarnings("unchecked") 057 public <T extends ModelItem> T parse(ServiceManager serviceManager, String pluginName, Configuration itemConfig, Model model, ModelItemGroup parent) throws ConfigurationException 058 { 059 return (T) parse(serviceManager, pluginName, "plugin." + pluginName, itemConfig, model, parent); 060 } 061 062 /** 063 * Parses an element definition from a XML configuration. 064 * @param <T> type of the parsed item 065 * @param serviceManager the service manager 066 * @param pluginName the plugin name declaring this item. 067 * @param catalog the catalog 068 * @param itemConfig the XML configuration of the model item. 069 * @param model the model which defines the model item 070 * @param parent the parent of the model item to create. Can be null if the model item to parse has no parent 071 * @return the parsed model item. 072 * @throws ConfigurationException if the configuration is not valid. 073 */ 074 @SuppressWarnings("unchecked") 075 public <T extends ModelItem> T parse(ServiceManager serviceManager, String pluginName, String catalog, Configuration itemConfig, Model model, ModelItemGroup parent) throws ConfigurationException 076 { 077 ModelItem modelItem = _createModelItem(itemConfig); 078 079 modelItem.setModel(model); 080 if (parent != null) 081 { 082 parent.addChild(modelItem); 083 } 084 085 modelItem.setName(_parseName(itemConfig)); 086 modelItem.setLabel(_parseI18nizableText(itemConfig, catalog, "label")); 087 modelItem.setDescription(_parseI18nizableText(itemConfig, catalog, "description")); 088 modelItem.setType(_parseType(itemConfig)); 089 090 return (T) modelItem; 091 } 092 093 /** 094 * Create the model item to populate it. 095 * @param itemConfig the model item configuration to use. 096 * @return the item instantiated. 097 * @throws ConfigurationException if the configuration is not valid. 098 */ 099 protected abstract ModelItem _createModelItem(Configuration itemConfig) throws ConfigurationException; 100 101 /** 102 * Parses the name of the model item. 103 * @param itemConfig the model item configuration to use. 104 * @return the name of the model item. 105 * @throws ConfigurationException if the configuration is not valid. 106 */ 107 protected String _parseName(Configuration itemConfig) throws ConfigurationException 108 { 109 String itemName = itemConfig.getAttribute(_getNameConfigurationAttribute()); 110 111 if (!itemName.matches("^[a-zA-Z]((?!__)[a-zA-Z0-9_\\.-])*$")) 112 { 113 throw new ConfigurationException("Invalid model item name: " + itemName + ". The item name must start with a letter and must contain only letters, digits, underscore, dot or dash characters.", itemConfig); 114 } 115 116 return itemName; 117 } 118 119 /** 120 * Retrieves the name of the configuration attribute that contains the name of the model item 121 * @return the name of the configuration attribute that contains the name of the model item 122 */ 123 protected String _getNameConfigurationAttribute() 124 { 125 return "name"; 126 } 127 128 /** 129 * Parses a mandatory i18n text configuration, throwing an exception if empty. 130 * @param config the configuration to use. 131 * @param catalog the catalog 132 * @param name the child name. 133 * @return the i18n text. 134 * @throws ConfigurationException if the configuration is not valid. 135 */ 136 protected I18nizableText _parseI18nizableText(Configuration config, String catalog, String name) throws ConfigurationException 137 { 138 return I18nizableText.parseI18nizableText(config.getChild(name), catalog); 139 } 140 141 /** 142 * Parse an optional i18n text configuration, with a default i18n text value. 143 * @param config the configuration to use. 144 * @param catalog the catalog 145 * @param name the child name. 146 * @param defaultValueCatalog the catalog of the default i18n text value 147 * @param defaultValue the default i18n text value. 148 * @return the i18n text. 149 */ 150 protected I18nizableText _parseI18nizableText(Configuration config, String catalog, String name, String defaultValueCatalog, String defaultValue) 151 { 152 return I18nizableText.parseI18nizableText(config.getChild(name), catalog, new I18nizableText(defaultValueCatalog, defaultValue)); 153 } 154 155 /** 156 * Parses the type. 157 * @param config the model item configuration to use. 158 * @return the type. 159 * @throws ConfigurationException if the configuration is not valid. 160 */ 161 protected ModelItemType _parseType(Configuration config) throws ConfigurationException 162 { 163 String typeId = config.getAttribute("type"); 164 165 if (!_modelItemTypeExtensionPoint.hasExtension(typeId)) 166 { 167 String modelItemName = _parseName(config); 168 String availableTypes = StringUtils.join(_modelItemTypeExtensionPoint.getExtensionsIds(), ", "); 169 UnknownTypeException ute = new UnknownTypeException("The type '" + typeId + "' is not available for the extension point '" + _modelItemTypeExtensionPoint + "'. Available types are: '" + availableTypes + "'."); 170 throw new ConfigurationException("Unable to find the type '" + typeId + "' defined on the item '" + modelItemName + "'.", ute); 171 } 172 173 return _modelItemTypeExtensionPoint.getExtension(typeId); 174 } 175}