001/* 002 * Copyright 2017 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.plugins.contentio.synchronize; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.LinkedHashMap; 021import java.util.List; 022import java.util.Map; 023import java.util.Objects; 024 025import org.apache.avalon.framework.configuration.Configurable; 026import org.apache.avalon.framework.configuration.Configuration; 027import org.apache.avalon.framework.configuration.ConfigurationException; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031 032import org.ametys.cms.contenttype.ContentType; 033import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 034import org.ametys.cms.repository.ContentDAO; 035import org.ametys.plugins.contentio.synchronize.search.SCCSearchModelConfiguration; 036import org.ametys.plugins.repository.AmetysObjectResolver; 037import org.ametys.runtime.i18n.I18nizableText; 038import org.ametys.runtime.model.ElementDefinition; 039import org.ametys.runtime.model.ModelItem; 040 041/** 042 * Configuration is separated from {@link AbstractSynchronizableContentsCollection} 043 */ 044public abstract class AbstractStaticSynchronizableContentsCollection implements SynchronizableContentsCollection, Configurable, Serviceable 045{ 046 /** The Ametys object resolver */ 047 protected AmetysObjectResolver _resolver; 048 /** The SCC helper */ 049 protected SynchronizableContentsCollectionHelper _sccHelper; 050 /** The content DAO */ 051 protected ContentDAO _contentDAO; 052 /** The content type extension point */ 053 protected ContentTypeExtensionPoint _contentTypeEP; 054 055 /** The id */ 056 protected String _id; 057 /** The label */ 058 protected I18nizableText _label; 059 /** The path to the metadata holding the 'restricted' property */ 060 protected String _restrictedField; 061 /** The handled content type */ 062 protected String _contentType; 063 /** The handled languages */ 064 protected List<String> _languages; 065 /** The id of controller */ 066 protected String _modelId; 067 /** The untyped values of controller's parameters */ 068 protected Map<String, Object> _modelParamValues; 069 /** True if removal sync */ 070 protected boolean _removalSync; 071 /** True to ignore restrictions on attributes while synchronizing */ 072 protected boolean _ignoreRestrictions; 073 /** The name of the workflow */ 074 protected String _workflowName; 075 /** The id of the initial action of the workflow */ 076 protected int _initialActionId; 077 /** The id of the synchronize action of the workflow */ 078 protected int _synchronizeActionId; 079 /** The id of the validate action of the workflow */ 080 protected int _validateActionId; 081 /** The prefix of the contents */ 082 protected String _contentPrefix; 083 /** True to validate contents after import */ 084 protected boolean _validateAfterImport; 085 /** The report mails */ 086 protected String _reportMails; 087 /** The id of the content operator to use */ 088 protected String _synchronizingContentOperator; 089 /** The id of the content operator to use */ 090 protected boolean _synchronizeExistingContentsOnly; 091 /** <code>true</code> to check the collection while synchronizing */ 092 protected boolean _checkCollection; 093 /** List of compatible SCC with the current SCC (excepting the current one) */ 094 protected List<String> _compatibleSCC; 095 /** Search model configuration for search tool */ 096 protected SCCSearchModelConfiguration _searchModelConfiguration; 097 098 public void service(ServiceManager manager) throws ServiceException 099 { 100 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 101 _sccHelper = (SynchronizableContentsCollectionHelper) manager.lookup(SynchronizableContentsCollectionHelper.ROLE); 102 _contentDAO = (ContentDAO) manager.lookup(ContentDAO.ROLE); 103 _contentTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 104 } 105 106 public void configure(Configuration configuration) throws ConfigurationException 107 { 108 configureStaticParams(configuration); 109 configureDataSource(configuration); 110 _searchModelConfiguration = new SCCSearchModelConfiguration(); 111 configureSearchModel(); 112 } 113 114 /** 115 * Called in {@link #configure(Configuration)} for first configurations needed. 116 * @param configuration Configuration to read 117 * @throws ConfigurationException If an error occurs 118 */ 119 protected void configureStaticParams(Configuration configuration) throws ConfigurationException 120 { 121 _id = configuration.getAttribute("id"); 122 _label = I18nizableText.parseI18nizableText(configuration.getChild("label"), null); 123 _contentType = configuration.getChild("contentType").getValue(); 124 _removalSync = configuration.getChild("removalSync").getValueAsBoolean(false); 125 _ignoreRestrictions = configuration.getChild("ignoreRestrictions").getValueAsBoolean(true); 126 _workflowName = configuration.getChild("workflowName").getValue(); 127 _initialActionId = configuration.getChild("initialActionId").getValueAsInteger(); 128 _synchronizeActionId = configuration.getChild("synchronizeActionId").getValueAsInteger(); 129 _validateActionId = configuration.getChild("validateActionId").getValueAsInteger(); 130 _contentPrefix = configuration.getChild("contentPrefix").getValue(); 131 _restrictedField = configuration.getChild("restrictedField").getValue(null); 132 _validateAfterImport = configuration.getChild("validateAfterImport").getValueAsBoolean(false); 133 _reportMails = configuration.getChild("reportMails").getValue(""); 134 _synchronizingContentOperator = configuration.getChild("contentOperator").getValue(); 135 _modelId = configuration.getChild("model").getAttribute("id"); 136 _languages = _parseMultipleValuesConf(configuration.getChild("languages")); 137 _modelParamValues = _parseParameters(configuration.getChild("model")); 138 _synchronizeExistingContentsOnly = configuration.getChild("synchronizeExistingContentsOnly").getValueAsBoolean(false); 139 _checkCollection = configuration.getChild("checkCollection").getValueAsBoolean(true); 140 _compatibleSCC = _parseMultipleValuesConf(configuration.getChild("compatibleSCC")); 141 } 142 143 /** 144 * Configure the data source parameters. 145 * @param configuration Configuration to read 146 * @throws ConfigurationException If an error occurs 147 */ 148 protected abstract void configureDataSource(Configuration configuration) throws ConfigurationException; 149 150 /** 151 * Configure the search model used by SCCSearchTool. 152 */ 153 protected abstract void configureSearchModel(); 154 155 public String getId() 156 { 157 return _id; 158 } 159 160 public I18nizableText getLabel() 161 { 162 return _label; 163 } 164 165 public String getContentType() 166 { 167 return _contentType; 168 } 169 170 public List<String> getLanguages() 171 { 172 return _languages; 173 } 174 175 public String getRestrictedField() 176 { 177 return _restrictedField; 178 } 179 180 public String getSynchronizeCollectionModelId() 181 { 182 return _modelId; 183 } 184 185 public Map<String, Object> getParameterValues() 186 { 187 return _modelParamValues; 188 } 189 190 public boolean removalSync() 191 { 192 return _removalSync; 193 } 194 195 public boolean ignoreRestrictions() 196 { 197 return _ignoreRestrictions; 198 } 199 200 public boolean checkCollection() 201 { 202 return _checkCollection; 203 } 204 205 public List<String> getCompatibleSCC(boolean includeCurrent) 206 { 207 if (includeCurrent) 208 { 209 List<String> compatibleSCC = new ArrayList<>(_compatibleSCC); 210 compatibleSCC.add(getId()); 211 return compatibleSCC; 212 } 213 return _compatibleSCC; 214 } 215 216 public String getWorkflowName() 217 { 218 return _workflowName; 219 } 220 221 public int getInitialActionId() 222 { 223 return _initialActionId; 224 } 225 226 public int getSynchronizeActionId() 227 { 228 return _synchronizeActionId; 229 } 230 231 public int getValidateActionId() 232 { 233 return _validateActionId; 234 } 235 236 public String getContentPrefix() 237 { 238 return _contentPrefix; 239 } 240 241 public boolean validateAfterImport() 242 { 243 return _validateAfterImport; 244 } 245 246 public String getReportMails() 247 { 248 return _reportMails; 249 } 250 251 public String getSynchronizingContentOperator() 252 { 253 return _synchronizingContentOperator; 254 } 255 256 public boolean synchronizeExistingContentsOnly() 257 { 258 return _synchronizeExistingContentsOnly; 259 } 260 261 public SCCSearchModelConfiguration getSearchModelConfiguration() 262 { 263 return _searchModelConfiguration; 264 } 265 266 /** 267 * Parse parameters' values 268 * @param configuration The root configuration 269 * @return The parameters 270 * @throws ConfigurationException if an error occurred 271 */ 272 protected Map<String, Object> _parseParameters(Configuration configuration) throws ConfigurationException 273 { 274 Map<String, Object> values = new LinkedHashMap<>(); 275 276 Configuration[] params = configuration.getChildren("param"); 277 for (Configuration paramConfig : params) 278 { 279 values.put(paramConfig.getAttribute("name"), paramConfig.getValue("")); 280 } 281 return values; 282 } 283 284 /** 285 * Parse multiple values configuration 286 * @param configuration the configuration 287 * @return the list of handled values 288 * @throws ConfigurationException if an error occurred 289 */ 290 protected List<String> _parseMultipleValuesConf(Configuration configuration) throws ConfigurationException 291 { 292 List<String> values = new ArrayList<>(); 293 for (Configuration conf : configuration.getChildren("value")) 294 { 295 values.add(conf.getValue()); 296 } 297 return values; 298 } 299 300 /** 301 * Transform the remote values to take each attribute cardinality into account 302 * @param remoteValues the remote values 303 * @param contentTypeId the content type ID from which attributes come from 304 * @return the transformed values 305 */ 306 protected Map<String, Object> _transformRemoteValuesCardinality(Map<String, List<Object>> remoteValues, String contentTypeId) 307 { 308 ContentType contentType = _contentTypeEP.getExtension(contentTypeId); 309 310 Map<String, Object> transformedContentValues = new HashMap<>(); 311 for (String attributeName : remoteValues.keySet()) 312 { 313 if (contentType.hasModelItem(attributeName)) 314 { 315 List<Object> attributeValues = remoteValues.get(attributeName); 316 Object transformedAttributeValue = attributeValues; 317 318 ModelItem modelItem = contentType.getModelItem(attributeName); 319 if (modelItem instanceof ElementDefinition) 320 { 321 ElementDefinition definition = (ElementDefinition) modelItem; 322 if (!definition.isMultiple()) 323 { 324 transformedAttributeValue = attributeValues.stream() 325 .filter(Objects::nonNull) 326 .findFirst() 327 .orElse(null); 328 } 329 } 330 331 transformedContentValues.put(attributeName, transformedAttributeValue); 332 } 333 } 334 335 return transformedContentValues; 336 } 337}