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