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.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022 023import org.apache.avalon.framework.configuration.Configuration; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.cocoon.ProcessingException; 026 027import org.ametys.runtime.config.DisableCondition; 028import org.ametys.runtime.config.DisableConditions; 029import org.ametys.runtime.i18n.I18nizableText; 030import org.ametys.runtime.model.exception.BadItemTypeException; 031import org.ametys.runtime.model.exception.UnknownTypeException; 032import org.ametys.runtime.model.type.ElementType; 033import org.ametys.runtime.model.type.ModelItemType; 034import org.ametys.runtime.parameter.Validator; 035import org.ametys.runtime.plugin.ExtensionPoint; 036 037/** 038 * The definition of a single model item (parameter, attribute) 039 * @param <T> Type of the element value 040 */ 041public class ElementDefinition<T> extends AbstractModelItem 042{ 043 private String _pluginName; 044 private ElementType<T> _type; 045 private String _widget; 046 private Map<String, I18nizableText> _widgetParams; 047 private Enumerator<T> _enumerator; 048 private String _customEnumerator; 049 private Configuration _enumeratorConfiguration; 050 private Validator _validator; 051 private String _customValidator; 052 private Configuration _validatorConfiguration; 053 private T _defaultValue; 054 private boolean _isMultiple; 055 private DisableConditions _disableConditions; 056 057 /** 058 * Default constructor. 059 */ 060 public ElementDefinition() 061 { 062 super(); 063 } 064 065 /** 066 * Constructor used to create simple models and items 067 * @param name the name of the definition 068 * @param isMultiple the element multiple status 069 * @param type the type of the definition 070 */ 071 public ElementDefinition(String name, boolean isMultiple, ElementType<T> type) 072 { 073 super(name); 074 _type = type; 075 _isMultiple = isMultiple; 076 } 077 078 /** 079 * Constructor by copying an existing {@link ElementDefinition}. 080 * @param definitionToCopy The {@link ElementDefinition} to copy 081 */ 082 public ElementDefinition(ElementDefinition<T> definitionToCopy) 083 { 084 super(definitionToCopy); 085 086 // ElementDefinition 087 setPluginName(definitionToCopy.getPluginName()); 088 setType(definitionToCopy.getType()); 089 090 // Widget 091 setWidget(definitionToCopy.getWidget()); 092 setWidgetParameters(definitionToCopy.getWidgetParameters()); 093 094 // Enumerator 095 setEnumerator(definitionToCopy.getEnumerator()); 096 setCustomEnumerator(definitionToCopy.getCustomEnumerator()); 097 setEnumeratorConfiguration(definitionToCopy.getEnumeratorConfiguration()); 098 099 // Validator 100 setValidator(definitionToCopy.getValidator()); 101 setCustomValidator(definitionToCopy.getCustomValidator()); 102 setValidatorConfiguration(definitionToCopy.getValidatorConfiguration()); 103 104 // Other 105 setDefaultValue(definitionToCopy.getDefaultValue()); 106 setMultiple(definitionToCopy.isMultiple()); 107 setDisableConditions(definitionToCopy.getDisableConditions()); 108 } 109 110 /** 111 * Retrieves the name of the plugin declaring this element. 112 * @return the plugin name. 113 */ 114 public String getPluginName() 115 { 116 return _pluginName; 117 } 118 119 /** 120 * Set the name of the plugin declaring this element. 121 * @param pluginName the plugin name. 122 */ 123 public void setPluginName(String pluginName) 124 { 125 _pluginName = pluginName; 126 } 127 128 @Override 129 public ElementType<T> getType() 130 { 131 return _type; 132 } 133 134 @SuppressWarnings("unchecked") 135 public void setType(ModelItemType type) 136 { 137 if (type instanceof ElementType) 138 { 139 _type = (ElementType<T>) type; 140 } 141 else 142 { 143 throw new IllegalArgumentException("Unable to set the type '" + type.getClass() + "' on the element type '" + getName() + "'"); 144 } 145 } 146 147 /** 148 * Retrieves the widget to use for rendering. 149 * @return the widget or <code>null</code> if none is defined. 150 */ 151 public String getWidget() 152 { 153 return _widget; 154 } 155 156 /** 157 * Set the widget. 158 * @param widget the widget. 159 */ 160 public void setWidget(String widget) 161 { 162 _widget = widget; 163 } 164 165 /** 166 * Get the widget's parameters 167 * @return the widget's parameters 168 */ 169 public Map<String, I18nizableText> getWidgetParameters() 170 { 171 return _widgetParams; 172 } 173 174 /** 175 * Set the widget's parameters 176 * @param params the parameters to set 177 */ 178 public void setWidgetParameters (Map<String, I18nizableText> params) 179 { 180 _widgetParams = params; 181 } 182 183 /** 184 * Retrieves the enumerator. 185 * @return the enumerator or <code>null</code> if none is defined. 186 */ 187 public Enumerator<T> getEnumerator() 188 { 189 return _enumerator; 190 } 191 192 /** 193 * Set the enumerator. 194 * @param enumerator the enumerator. 195 */ 196 public void setEnumerator(Enumerator<T> enumerator) 197 { 198 _enumerator = enumerator; 199 } 200 201 /** 202 * Retrieves the custom enumerator's class name 203 * @return the custom enumerator's class name 204 */ 205 public String getCustomEnumerator() 206 { 207 return _customEnumerator; 208 } 209 210 /** 211 * Set the custom enumerator's class name 212 * @param customEnumerator the custom enumerator's class name 213 */ 214 public void setCustomEnumerator(String customEnumerator) 215 { 216 this._customEnumerator = customEnumerator; 217 } 218 219 /** 220 * Retrieves the custom enumerator's configuration 221 * @return the custom enumerator's configuration 222 */ 223 public Configuration getEnumeratorConfiguration() 224 { 225 return _enumeratorConfiguration; 226 } 227 228 /** 229 * Set the custom enumerator's configuration 230 * @param enumeratorConfiguration the custom enumerator's configuration 231 */ 232 public void setEnumeratorConfiguration(Configuration enumeratorConfiguration) 233 { 234 _enumeratorConfiguration = enumeratorConfiguration; 235 } 236 237 /** 238 * Retrieves the validator. 239 * @return the validator or <code>null</code> if none is defined. 240 */ 241 public Validator getValidator() 242 { 243 return _validator; 244 } 245 246 /** 247 * Set the validator. 248 * @param validator the validator. 249 */ 250 public void setValidator(Validator validator) 251 { 252 _validator = validator; 253 } 254 255 /** 256 * Retrieves the custom validator's class name 257 * @return the custom validator's class name 258 */ 259 public String getCustomValidator() 260 { 261 return _customValidator; 262 } 263 264 /** 265 * Set the custom validator's class name 266 * @param customValidator the custom validator's class name 267 */ 268 public void setCustomValidator(String customValidator) 269 { 270 this._customValidator = customValidator; 271 } 272 273 /** 274 * Retrieves the custom validator's configuraiton 275 * @return the custom validator's configuration 276 */ 277 public Configuration getValidatorConfiguration() 278 { 279 return _validatorConfiguration; 280 } 281 282 /** 283 * Set the custom validator's configuration 284 * @param validatorConfiguration the custom validator's configuration 285 */ 286 public void setValidatorConfiguration(Configuration validatorConfiguration) 287 { 288 _validatorConfiguration = validatorConfiguration; 289 } 290 291 /** 292 * Retrieves the default value. 293 * @return the default value or <code>null</code> if none is defined. 294 */ 295 public T getDefaultValue() 296 { 297 return _defaultValue; 298 } 299 300 /** 301 * Set the default value. 302 * @param defaultValue the default value. 303 */ 304 public void setDefaultValue(T defaultValue) 305 { 306 _defaultValue = defaultValue; 307 } 308 309 /** 310 * Test if the element is multiple. 311 * @return <code>true</code> if the metadata is multiple. 312 */ 313 public boolean isMultiple() 314 { 315 return _isMultiple; 316 } 317 318 /** 319 * Set the element multiple status. 320 * @param isMultiple the element multiple status. 321 */ 322 public void setMultiple(boolean isMultiple) 323 { 324 _isMultiple = isMultiple; 325 } 326 327 /** 328 * Retrieves the disable condition. 329 * @return the disable condition or <code>null</code> if none is defined. 330 */ 331 public DisableConditions getDisableConditions() 332 { 333 return _disableConditions; 334 } 335 336 /** 337 * Sets the disable condition. 338 * @param disableConditions the disable condition. 339 */ 340 public void setDisableConditions(DisableConditions disableConditions) 341 { 342 _disableConditions = disableConditions; 343 } 344 345 @Override 346 public Map<String, Object> toJSON() throws ProcessingException 347 { 348 Map<String, Object> result = super.toJSON(); 349 350 result.put("plugin", getPluginName()); 351 result.put("multiple", isMultiple()); 352 353 if (getType() != null) 354 { 355 result.put("type", getType().getId()); 356 result.put("default-value", getType().valueToJSONForClient(getDefaultValue())); 357 } 358 359 360 if (getValidator() != null) 361 { 362 result.put("validation", getValidator().getConfiguration()); 363 } 364 365 if (getEnumerator() != null) 366 { 367 List<Map<String, Object>> enumeration = new ArrayList<>(); 368 369 try 370 { 371 Map<T, I18nizableText> entries = getEnumerator().getTypedEntries(); 372 for (Map.Entry<T, I18nizableText> entry : entries.entrySet()) 373 { 374 Map<String, Object> option = new HashMap<>(); 375 option.put("value", getType().valueToJSONForClient(entry.getKey())); 376 option.put("label", entry.getValue()); 377 enumeration.add(option); 378 } 379 } 380 catch (Exception e) 381 { 382 throw new ProcessingException("Unable to enumerate entries with enumerator: " + getEnumerator(), e); 383 } 384 385 result.put("enumeration", enumeration); 386 result.put("enumerationConfig", getEnumerator().getConfiguration()); 387 } 388 389 result.put("widget", getWidget()); 390 391 Map<String, I18nizableText> widgetParameters = getWidgetParameters(); 392 if (widgetParameters != null && !widgetParameters.isEmpty()) 393 { 394 result.put("widget-params", widgetParameters); 395 } 396 397 if (getDisableConditions() != null) 398 { 399 result.put("disableCondition", _disableConditionstoJSON(getDisableConditions())); 400 } 401 402 return result; 403 } 404 405 /** 406 * Converts the definition's disable conditions in a JSON map 407 * @param disableConditions the disable conditions to convert 408 * @return The definition's disable conditions as a JSON map 409 */ 410 private Map<String, Object> _disableConditionstoJSON(DisableConditions disableConditions) 411 { 412 Map<String, Object> map = new HashMap<>(); 413 414 // Handle simple conditions 415 List<Map<String, String>> disableConditionList = new ArrayList<>(); 416 map.put("condition", disableConditionList); 417 for (DisableCondition disableCondition : disableConditions.getConditions()) 418 { 419 Map<String, String> disableConditionAsMap = _disableConditiontoJSON(disableCondition); 420 disableConditionList.add(disableConditionAsMap); 421 } 422 423 // Handle nested conditions 424 List<Map<String, Object>> disableConditionsList = new ArrayList<>(); 425 map.put("conditions", disableConditionsList); 426 for (DisableConditions subDisableConditions : disableConditions.getSubConditions()) 427 { 428 Map<String, Object> disableConditionsAsMap = _disableConditionstoJSON(subDisableConditions); 429 disableConditionsList.add(disableConditionsAsMap); 430 } 431 432 // Handle type 433 map.put("type", disableConditions.getAssociationType().toString().toLowerCase()); 434 435 return map; 436 } 437 438 private static Map<String, String> _disableConditiontoJSON(DisableCondition disableCondition) 439 { 440 Map<String, String> map = new HashMap<>(); 441 map.put("id", disableCondition.getId()); 442 map.put("operator", disableCondition.getOperator().toString().toLowerCase()); 443 map.put("value", disableCondition.getValue()); 444 return map; 445 } 446 447 /** 448 * Creates an {@link ElementDefinition} 449 * @param name the definition's name 450 * @param isMultiple the definition's cardinality 451 * @param typeId the definition's type identifier 452 * @param availableTypesExtensionPoint the role of the extension point containing all available types for this {@link ElementDefinition} 453 * @return the created {@link ElementDefinition} 454 * @throws UnknownTypeException if the given type identifier is not available in the extension point 455 * @throws BadItemTypeException if the given type identifier can not be used for an {@link ElementDefinition} 456 * @throws ServiceException if an error occurs while getting the extension point of available types 457 */ 458 @SuppressWarnings("unchecked") 459 public static ElementDefinition of(String name, boolean isMultiple, String typeId, String availableTypesExtensionPoint) throws UnknownTypeException, BadItemTypeException, ServiceException 460 { 461 ExtensionPoint<ModelItemType> availableTypes = (ExtensionPoint<ModelItemType>) __serviceManager.lookup(availableTypesExtensionPoint); 462 if (!availableTypes.hasExtension(typeId)) 463 { 464 throw new UnknownTypeException("The type '" + typeId + "' (used for data '" + name + "') is not available for the given extension point."); 465 } 466 else 467 { 468 ModelItemType type = availableTypes.getExtension(typeId); 469 if (!(type instanceof ElementType)) 470 { 471 throw new BadItemTypeException("The type '" + typeId + "' (used for data '" + name + "') can not be used for an element definition."); 472 } 473 else 474 { 475 return new ElementDefinition(name, isMultiple, (ElementType) type); 476 } 477 } 478 } 479}