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 synchronization */ 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 /** Search model configuration for search tool */ 092 protected SCCSearchModelConfiguration _searchModelConfiguration; 093 094 public void service(ServiceManager manager) throws ServiceException 095 { 096 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 097 _sccHelper = (SynchronizableContentsCollectionHelper) manager.lookup(SynchronizableContentsCollectionHelper.ROLE); 098 _contentDAO = (ContentDAO) manager.lookup(ContentDAO.ROLE); 099 _contentTypeEP = (ContentTypeExtensionPoint) manager.lookup(ContentTypeExtensionPoint.ROLE); 100 } 101 102 @Override 103 public void configure(Configuration configuration) throws ConfigurationException 104 { 105 configureStaticParams(configuration); 106 configureDataSource(configuration); 107 _searchModelConfiguration = new SCCSearchModelConfiguration(); 108 configureSearchModel(); 109 } 110 111 /** 112 * Called in {@link #configure(Configuration)} for first configurations needed. 113 * @param configuration Configuration to read 114 * @throws ConfigurationException If an error occurs 115 */ 116 protected void configureStaticParams(Configuration configuration) throws ConfigurationException 117 { 118 _id = configuration.getAttribute("id"); 119 _label = I18nizableText.parseI18nizableText(configuration.getChild("label"), null); 120 _contentType = configuration.getChild("contentType").getValue(); 121 _removalSync = configuration.getChild("removalSync").getValueAsBoolean(false); 122 _ignoreRestrictions = configuration.getChild("ignoreRestrictions").getValueAsBoolean(true); 123 _workflowName = configuration.getChild("workflowName").getValue(); 124 _initialActionId = configuration.getChild("initialActionId").getValueAsInteger(); 125 _synchronizeActionId = configuration.getChild("synchronizeActionId").getValueAsInteger(); 126 _validateActionId = configuration.getChild("validateActionId").getValueAsInteger(); 127 _contentPrefix = configuration.getChild("contentPrefix").getValue(); 128 _restrictedField = configuration.getChild("restrictedField").getValue(null); 129 _validateAfterImport = configuration.getChild("validateAfterImport").getValueAsBoolean(false); 130 _reportMails = configuration.getChild("reportMails").getValue(""); 131 _synchronizingContentOperator = configuration.getChild("contentOperator").getValue(); 132 _modelId = configuration.getChild("model").getAttribute("id"); 133 _languages = _parseLanguages(configuration.getChild("languages")); 134 _modelParamValues = _parseParameters(configuration.getChild("model")); 135 _synchronizeExistingContentsOnly = configuration.getChild("synchronizeExistingContentsOnly").getValueAsBoolean(false); 136 } 137 138 /** 139 * Configure the data source parameters. 140 * @param configuration Configuration to read 141 * @throws ConfigurationException If an error occurs 142 */ 143 protected abstract void configureDataSource(Configuration configuration) throws ConfigurationException; 144 145 /** 146 * Configure the search model used by SCCSearchTool. 147 */ 148 protected abstract void configureSearchModel(); 149 150 @Override 151 public String getId() 152 { 153 return _id; 154 } 155 156 @Override 157 public I18nizableText getLabel() 158 { 159 return _label; 160 } 161 162 @Override 163 public String getContentType() 164 { 165 return _contentType; 166 } 167 168 @Override 169 public List<String> getLanguages() 170 { 171 return _languages; 172 } 173 174 @Override 175 public String getRestrictedField() 176 { 177 return _restrictedField; 178 } 179 180 @Override 181 public String getSynchronizeCollectionModelId() 182 { 183 return _modelId; 184 } 185 186 @Override 187 public Map<String, Object> getParameterValues() 188 { 189 return _modelParamValues; 190 } 191 192 @Override 193 public boolean removalSync() 194 { 195 return _removalSync; 196 } 197 198 @Override 199 public boolean ignoreRestrictions() 200 { 201 return _ignoreRestrictions; 202 } 203 204 @Override 205 public String getWorkflowName() 206 { 207 return _workflowName; 208 } 209 210 @Override 211 public int getInitialActionId() 212 { 213 return _initialActionId; 214 } 215 216 @Override 217 public int getSynchronizeActionId() 218 { 219 return _synchronizeActionId; 220 } 221 222 @Override 223 public int getValidateActionId() 224 { 225 return _validateActionId; 226 } 227 228 @Override 229 public String getContentPrefix() 230 { 231 return _contentPrefix; 232 } 233 234 @Override 235 public boolean validateAfterImport() 236 { 237 return _validateAfterImport; 238 } 239 240 @Override 241 public String getReportMails() 242 { 243 return _reportMails; 244 } 245 246 @Override 247 public String getSynchronizingContentOperator() 248 { 249 return _synchronizingContentOperator; 250 } 251 252 @Override 253 public boolean synchronizeExistingContentsOnly() 254 { 255 return _synchronizeExistingContentsOnly; 256 } 257 258 @Override 259 public SCCSearchModelConfiguration getSearchModelConfiguration() 260 { 261 return _searchModelConfiguration; 262 } 263 264 /** 265 * Parse parameters' values 266 * @param configuration The root configuration 267 * @return The parameters 268 * @throws ConfigurationException if an error occurred 269 */ 270 protected Map<String, Object> _parseParameters(Configuration configuration) throws ConfigurationException 271 { 272 Map<String, Object> values = new LinkedHashMap<>(); 273 274 Configuration[] params = configuration.getChildren("param"); 275 for (Configuration paramConfig : params) 276 { 277 values.put(paramConfig.getAttribute("name"), paramConfig.getValue("")); 278 } 279 return values; 280 } 281 282 /** 283 * Parse languages configuration 284 * @param configuration the configuration 285 * @return the list of handled languages 286 * @throws ConfigurationException if an error occurred 287 */ 288 protected List<String> _parseLanguages(Configuration configuration) throws ConfigurationException 289 { 290 List<String> languages = new ArrayList<>(); 291 for (Configuration conf : configuration.getChildren("value")) 292 { 293 languages.add(conf.getValue()); 294 } 295 296 return languages; 297 } 298 299 /** 300 * Transform the remote values to take each attribute cardinality into account 301 * @param remoteValues the remote values 302 * @param contentTypeId the content type ID from which attributes come from 303 * @return the transformed values 304 */ 305 protected Map<String, Object> _transformRemoteValuesCardinality(Map<String, List<Object>> remoteValues, String contentTypeId) 306 { 307 ContentType contentType = _contentTypeEP.getExtension(contentTypeId); 308 309 Map<String, Object> transformedContentValues = new HashMap<>(); 310 for (String attributeName : remoteValues.keySet()) 311 { 312 if (contentType.hasModelItem(attributeName)) 313 { 314 List<Object> attributeValues = remoteValues.get(attributeName); 315 Object transformedAttributeValue = attributeValues; 316 317 ModelItem modelItem = contentType.getModelItem(attributeName); 318 if (modelItem instanceof ElementDefinition) 319 { 320 ElementDefinition definition = (ElementDefinition) modelItem; 321 if (!definition.isMultiple()) 322 { 323 transformedAttributeValue = attributeValues.stream() 324 .filter(Objects::nonNull) 325 .findFirst() 326 .orElse(null); 327 } 328 } 329 330 transformedContentValues.put(attributeName, transformedAttributeValue); 331 } 332 } 333 334 return transformedContentValues; 335 } 336}