001/* 002 * Copyright 2025 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.trash.model; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.List; 021 022import org.apache.avalon.framework.component.Component; 023import org.apache.avalon.framework.configuration.ConfigurationException; 024import org.apache.avalon.framework.context.Context; 025import org.apache.avalon.framework.context.ContextException; 026import org.apache.avalon.framework.context.Contextualizable; 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030 031import org.ametys.cms.data.holder.DataHolderElementDefinitionParser; 032import org.ametys.plugins.repository.AmetysRepositoryException; 033import org.ametys.plugins.repository.data.type.ModelItemTypeExtensionPoint; 034import org.ametys.plugins.repository.trash.TrashElementType; 035import org.ametys.plugins.repository.trash.TrashElementTypeEnumerator; 036import org.ametys.plugins.repository.trash.TrashElementTypeExtensionPoint; 037import org.ametys.runtime.i18n.I18nizableText; 038import org.ametys.runtime.model.DefaultElementDefinition; 039import org.ametys.runtime.model.ElementDefinition; 040import org.ametys.runtime.model.Enumerator; 041import org.ametys.runtime.model.ItemParserHelper.ConfigurationAndPluginName; 042import org.ametys.runtime.model.Model; 043import org.ametys.runtime.model.ModelItem; 044import org.ametys.runtime.model.disableconditions.DisableConditions; 045import org.ametys.runtime.model.type.ModelItemTypeConstants; 046import org.ametys.runtime.parameter.Validator; 047import org.ametys.runtime.plugin.component.AbstractLogEnabled; 048import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 049 050/** 051 * The model for trash elements. 052 */ 053public class TrashElementModel extends AbstractLogEnabled implements Model, Component, Serviceable, Contextualizable 054{ 055 /** The avalon role */ 056 public static final String ROLE = TrashElementModel.class.getName(); 057 058 /** Item name for the title of the element */ 059 public static final String TITLE = "title"; 060 /** Item name for the type of the element */ 061 public static final String TRASH_TYPE = "trashType"; 062 /** Item name for the author of the deletion */ 063 public static final String AUTHOR = "author"; 064 /** Item name for the deletion date */ 065 public static final String DATE = "date"; 066 /** Item name for the parent path of the object */ 067 public static final String PARENT_PATH = "parentPath"; 068 /** Item name for the reference to the deleted object */ 069 public static final String DELETED_OBJECT = "deletedObject"; 070 /** Item name for the reference to the deleted object */ 071 public static final String HIDDEN = "hidden"; 072 /** Item name for the reference to the linked objects */ 073 public static final String LINKED_OBJECTS = "linkedObjects"; 074 075 /** The trash element type enumerator */ 076 protected TrashElementTypeEnumerator _trashElementTypeEnum; 077 /** The trash element type extension point */ 078 protected TrashElementTypeExtensionPoint _trashElementTypeEP; 079 /** The model item type */ 080 protected ModelItemTypeExtensionPoint _modelAwareItemTypeEP; 081 082 private Collection<? extends ModelItem> _modelItems; 083 084 /** Component manager for the model */ 085 private ThreadSafeComponentManager<Enumerator> _enumeratorsManager; 086 private ThreadSafeComponentManager<DisableConditions> _disableConditionsManager; 087 private ThreadSafeComponentManager<Validator> _validatorsManager; 088 089 /** the avalon context */ 090 private Context _context; 091 092 public void contextualize(Context context) throws ContextException 093 { 094 _context = context; 095 } 096 097 public void service(ServiceManager manager) throws ServiceException 098 { 099 _trashElementTypeEP = (TrashElementTypeExtensionPoint) manager.lookup(TrashElementTypeExtensionPoint.ROLE); 100 _trashElementTypeEnum = (TrashElementTypeEnumerator) manager.lookup(TrashElementTypeEnumerator.ROLE); 101 102 _modelAwareItemTypeEP = (ModelItemTypeExtensionPoint) manager.lookup(ModelItemTypeExtensionPoint.ROLE_MODEL_AWARE_BASIC); 103 104 _enumeratorsManager = new ThreadSafeComponentManager<>(); 105 _enumeratorsManager.setLogger(getLogger()); 106 _enumeratorsManager.contextualize(_context); 107 _enumeratorsManager.service(manager); 108 109 _disableConditionsManager = new ThreadSafeComponentManager<>(); 110 _disableConditionsManager.setLogger(getLogger()); 111 _disableConditionsManager.contextualize(_context); 112 _disableConditionsManager.service(manager); 113 114 _validatorsManager = new ThreadSafeComponentManager<>(); 115 _validatorsManager.setLogger(getLogger()); 116 _validatorsManager.contextualize(_context); 117 _validatorsManager.service(manager); 118 } 119 120 public String getId() 121 { 122 return "TrashElement"; 123 } 124 125 public String getFamilyId() 126 { 127 return "Trash"; 128 } 129 130 public Collection<? extends ModelItem> getModelItems() 131 { 132 if (_modelItems == null) 133 { 134 try 135 { 136 _modelItems = List.copyOf(createModelItems()); 137 } 138 catch (Exception e) 139 { 140 throw new AmetysRepositoryException("An error occurred while create the trash element model", e); 141 } 142 } 143 return _modelItems; 144 } 145 146 /** 147 * Create the model items present in the trash element model 148 * @return the model items 149 * @throws Exception if an occurs when creating the model items 150 */ 151 protected List<ElementDefinition> createModelItems() throws Exception 152 { 153 List<ElementDefinition> items = new ArrayList<>(); 154 155 items.add(_getDefinition(TITLE, ModelItemTypeConstants.STRING_TYPE_ID, false)); 156 ElementDefinition<String> trashType = _getDefinition(TRASH_TYPE, ModelItemTypeConstants.STRING_TYPE_ID, false); 157 trashType.setEnumerator(_trashElementTypeEnum); 158 items.add(trashType); 159 160 items.add(_getDefinition(DATE, ModelItemTypeConstants.DATETIME_TYPE_ID, false)); 161 items.add(_getDefinition(AUTHOR, org.ametys.cms.data.type.ModelItemTypeConstants.USER_ELEMENT_TYPE_ID, false)); 162 items.add(_getDefinition(PARENT_PATH, ModelItemTypeConstants.STRING_TYPE_ID, false)); 163 items.add(_getDefinition(DELETED_OBJECT, ModelItemTypeConstants.STRING_TYPE_ID, false)); 164 items.add(_getDefinition(HIDDEN, ModelItemTypeConstants.BOOLEAN_TYPE_ID, false)); 165 items.add(_getDefinition(LINKED_OBJECTS, ModelItemTypeConstants.STRING_TYPE_ID, true)); 166 167 // There is no check done on the definition path so watch out for conflict 168 items.addAll(_getModelItemsFromType()); 169 170 return items; 171 } 172 173 private List<ElementDefinition> _getModelItemsFromType() throws ConfigurationException, Exception 174 { 175 // Add model items provided by the element types 176 List<ElementDefinition> typeItems = new ArrayList<>(); 177 DataHolderElementDefinitionParser definitionParser = new DataHolderElementDefinitionParser(_modelAwareItemTypeEP, _disableConditionsManager, _enumeratorsManager, _validatorsManager); 178 for (String id :_trashElementTypeEP.getExtensionsIds()) 179 { 180 TrashElementType trashElementType = _trashElementTypeEP.getExtension(id); 181 List<ConfigurationAndPluginName> confs = trashElementType.getAdditionalModelItemsConfigurationAndPluginName(); 182 for (ConfigurationAndPluginName conf:confs) 183 { 184 ElementDefinition item = definitionParser.parse(null, conf.pluginName(), conf.configuration(), this, null); 185 // There is no check done on the definition path so watch out for conflict 186 typeItems.add(item); 187 } 188 } 189 190 definitionParser.lookupComponents(); 191 192 return typeItems; 193 } 194 195 private <T> ElementDefinition<T> _getDefinition(String name, String type, boolean isMultiple) throws ServiceException 196 { 197 DefaultElementDefinition<T> definition = DefaultElementDefinition.of(name, isMultiple, type, ModelItemTypeExtensionPoint.ROLE_MODEL_AWARE_BASIC); 198 definition.setLabel(new I18nizableText("plugin.cms", "PLUGINS_CMS_TRASH_MODEL_" + name.toUpperCase())); 199 definition.setDescription(new I18nizableText("plugin.cms", "PLUGINS_CMS_TRASH_MODEL_" + name.toUpperCase() + "_DESC")); 200 definition.setModel(this); 201 return definition; 202 } 203}