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 serviceManager the service manager 048 * @param pluginName the plugin name declaring this item. 049 * @param itemConfig the XML configuration of the model item. 050 * @param model the model which defines the model item 051 * @param parent the parent of the model item to create. Can be null if the model item to parse has no parent 052 * @return the parsed model item. 053 * @throws ConfigurationException if the configuration is not valid. 054 */ 055 public ModelItem parse(ServiceManager serviceManager, String pluginName, Configuration itemConfig, Model model, ModelItemGroup parent) throws ConfigurationException 056 { 057 ModelItem modelItem = _createModelItem(itemConfig); 058 059 modelItem.setModel(model); 060 if (parent != null) 061 { 062 parent.addChild(modelItem); 063 } 064 065 modelItem.setName(_parseName(itemConfig)); 066 modelItem.setLabel(_parseI18nizableText(itemConfig, pluginName, "label")); 067 modelItem.setDescription(_parseI18nizableText(itemConfig, pluginName, "description")); 068 modelItem.setType(_parseType(itemConfig)); 069 070 return modelItem; 071 } 072 073 /** 074 * Create the model item to populate it. 075 * @param itemConfig the model item configuration to use. 076 * @return the item instantiated. 077 * @throws ConfigurationException if the configuration is not valid. 078 */ 079 protected abstract ModelItem _createModelItem(Configuration itemConfig) throws ConfigurationException; 080 081 /** 082 * Parses the name of the model item. 083 * @param itemConfig the model item configuration to use. 084 * @return the name of the model item. 085 * @throws ConfigurationException if the configuration is not valid. 086 */ 087 protected String _parseName(Configuration itemConfig) throws ConfigurationException 088 { 089 String itemName = itemConfig.getAttribute(_getNameConfigurationAttribute()); 090 091 if (!itemName.matches("^[a-zA-Z]((?!__)[a-zA-Z0-9_\\.-])*$")) 092 { 093 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); 094 } 095 096 return itemName; 097 } 098 099 /** 100 * Retrieves the name of the configuration attribute that contains the name of the model item 101 * @return the name of the configuration attribute that contains the name of the model item 102 */ 103 protected String _getNameConfigurationAttribute() 104 { 105 return "name"; 106 } 107 108 /** 109 * Parses an i18n text. 110 * @param config the configuration to use. 111 * @param pluginName the current plugin name. 112 * @param name the child name. 113 * @return the i18n text. 114 * @throws ConfigurationException if the configuration is not valid. 115 */ 116 protected I18nizableText _parseI18nizableText(Configuration config, String pluginName, String name) throws ConfigurationException 117 { 118 return I18nizableText.parseI18nizableText(config.getChild(name), "plugin." + pluginName); 119 } 120 121 /** 122 * Parses the type. 123 * @param config the model item configuration to use. 124 * @return the type. 125 * @throws ConfigurationException if the configuration is not valid. 126 */ 127 protected ModelItemType _parseType(Configuration config) throws ConfigurationException 128 { 129 String typeId = config.getAttribute("type"); 130 131 if (!_modelItemTypeExtensionPoint.hasExtension(typeId)) 132 { 133 String modelItemName = _parseName(config); 134 String availableTypes = StringUtils.join(_modelItemTypeExtensionPoint.getExtensionsIds(), ", "); 135 UnknownTypeException ute = new UnknownTypeException("The type '" + typeId + "' is not available for the extension point '" + _modelItemTypeExtensionPoint + "'. Available types are: '" + availableTypes + "'."); 136 throw new ConfigurationException("Unable to find the type '" + typeId + "' defined on the item '" + modelItemName + "'.", ute); 137 } 138 139 return _modelItemTypeExtensionPoint.getExtension(typeId); 140 } 141}