001/* 002 * Copyright 2022 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.cms.model.properties; 017 018import org.apache.avalon.framework.configuration.Configurable; 019import org.apache.avalon.framework.configuration.Configuration; 020import org.apache.avalon.framework.configuration.ConfigurationException; 021import org.apache.avalon.framework.context.Context; 022import org.apache.avalon.framework.context.ContextException; 023import org.apache.avalon.framework.context.Contextualizable; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027 028import org.ametys.cms.data.ametysobject.ModelAwareDataAwareAmetysObject; 029import org.ametys.cms.data.type.indexing.IndexableElementType; 030import org.ametys.runtime.i18n.I18nizableText; 031import org.ametys.runtime.model.DefaultElementDefinition; 032import org.ametys.runtime.model.Enumerator; 033import org.ametys.runtime.model.ItemParserHelper; 034import org.ametys.runtime.model.ItemParserHelper.ConfigurationAndPluginName; 035import org.ametys.runtime.model.StaticEnumerator; 036import org.ametys.runtime.model.type.ModelItemType; 037import org.ametys.runtime.plugin.ExtensionPoint; 038import org.ametys.runtime.plugin.component.PluginAware; 039import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 040 041/** 042 * Abstract class for single property 043 * @param <T> type of the property values 044 * @param <X> type of ametys object supported by this property 045 */ 046public abstract class AbstractProperty<T, X extends ModelAwareDataAwareAmetysObject> extends DefaultElementDefinition<T> implements Property<T, X>, Configurable, PluginAware, Serviceable, Contextualizable 047{ 048 /** The service manager */ 049 protected ServiceManager _manager; 050 051 /** The avalon context */ 052 protected Context _context; 053 054 /** extension point containing the types available for this property */ 055 protected ExtensionPoint<ModelItemType> _availableTypesExtensionPoint; 056 057 public void service(ServiceManager manager) throws ServiceException 058 { 059 _manager = manager; 060 } 061 062 public void contextualize(Context context) throws ContextException 063 { 064 _context = context; 065 } 066 067 public void configure(Configuration configuration) throws ConfigurationException 068 { 069 setName(_parseName(configuration)); 070 setLabel(_parseLabel(configuration)); 071 setDescription(_parseDescription(configuration)); 072 _parseAndSetEnumerator(configuration, getPluginName()); 073 setMultiple(configuration.getAttributeAsBoolean("multiple", false)); 074 } 075 076 /** 077 * Parses the name of the property 078 * @param configuration the property configuration to use. 079 * @return the name of the property. 080 * @throws ConfigurationException if the configuration is not valid. 081 */ 082 protected String _parseName(Configuration configuration) throws ConfigurationException 083 { 084 return ItemParserHelper.parseName(configuration, _getNameConfigurationAttribute()); 085 } 086 087 /** 088 * Retrieves the name of the configuration attribute that contains the name of the property 089 * @return the name of the configuration attribute that contains the name of the property 090 */ 091 protected String _getNameConfigurationAttribute() 092 { 093 return "name"; 094 } 095 096 /** 097 * Parses the label of the property 098 * @param configuration the property configuration to use. 099 * @return the label of the property. 100 * @throws ConfigurationException if the configuration is not valid. 101 */ 102 protected I18nizableText _parseLabel(Configuration configuration) throws ConfigurationException 103 { 104 return ItemParserHelper.parseI18nizableText(new ConfigurationAndPluginName(configuration, getPluginName()), "label", getName()); 105 } 106 107 /** 108 * Parses the description of the property 109 * @param configuration the property configuration to use. 110 * @return the description of the property. 111 * @throws ConfigurationException if the configuration is not valid. 112 */ 113 protected I18nizableText _parseDescription(Configuration configuration) throws ConfigurationException 114 { 115 return ItemParserHelper.parseI18nizableText(new ConfigurationAndPluginName(configuration, getPluginName()), "description"); 116 } 117 118 /** 119 * Parse the configuration to set the enumerator. 120 * @param configuration The configuration of the property 121 * @param pluginName The plugin name 122 * @throws ConfigurationException if an error occurs 123 */ 124 protected void _parseAndSetEnumerator(Configuration configuration, String pluginName) throws ConfigurationException 125 { 126 ThreadSafeComponentManager<Enumerator> enumeratorManager = new ThreadSafeComponentManager<>(); 127 try 128 { 129 enumeratorManager.setLogger(_logger); 130 enumeratorManager.contextualize(_context); 131 enumeratorManager.service(_manager); 132 133 134 Configuration enumeratorConfig = configuration.getChild("enumeration", false); 135 if (enumeratorConfig != null) 136 { 137 Configuration customEnumerator = enumeratorConfig.getChild("custom-enumerator", false); 138 if (customEnumerator != null) 139 { 140 String enumeratorClassName = customEnumerator.getAttribute("class"); 141 String role = "enumerator"; 142 143 try 144 { 145 @SuppressWarnings("unchecked") 146 Class<Enumerator<T>> enumeratorClass = (Class<Enumerator<T>>) Class.forName(enumeratorClassName); 147 enumeratorManager.addComponent(pluginName, null, role, enumeratorClass, configuration); 148 } 149 catch (Exception e) 150 { 151 throw new ConfigurationException("Unable to instantiate enumerator for class: " + enumeratorClassName, e); 152 } 153 154 enumeratorManager.initialize(); 155 setEnumerator(enumeratorManager.lookup(role)); 156 157 // Add the custom enumerator information to the element definition 158 setCustomEnumerator(enumeratorClassName); 159 setEnumeratorConfiguration(customEnumerator); 160 } 161 else 162 { 163 StaticEnumerator<T> staticEnumerator = new StaticEnumerator<>(); 164 165 for (Configuration entryConfig : enumeratorConfig.getChildren("entry")) 166 { 167 Configuration valueConfiguration = entryConfig.getChild("value"); 168 T value = getType().parseConfiguration(valueConfiguration); 169 I18nizableText label = ItemParserHelper.parseI18nizableText(new ConfigurationAndPluginName(entryConfig, pluginName), "label", (I18nizableText) null); 170 staticEnumerator.add(label, value); 171 } 172 173 setEnumerator(staticEnumerator); 174 } 175 } 176 } 177 catch (Exception e) 178 { 179 throw new ConfigurationException("An error occured while configuring the enumerator of the property " + getName(), e); 180 } 181 finally 182 { 183 enumeratorManager.dispose(); 184 } 185 } 186 187 @Override 188 public void setPluginInfo(String pluginName, String featureName, String id) 189 { 190 setPluginName(pluginName); 191 } 192 193 public boolean isEditable() 194 { 195 return false; 196 } 197 198 public void setAvailableTypeExtensionPoint(ExtensionPoint<ModelItemType> availableTypesExtensionPoint) 199 { 200 _availableTypesExtensionPoint = availableTypesExtensionPoint; 201 } 202 203 @SuppressWarnings("unchecked") 204 @Override 205 public IndexableElementType<T> getType() 206 { 207 return (IndexableElementType<T>) _availableTypesExtensionPoint.getExtension(getTypeId()); 208 } 209 210 /** 211 * Retrieves the id of the property's type 212 * @return the id of the property's type 213 */ 214 protected abstract String getTypeId(); 215}