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.plugins.userdirectory.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.Optional; 024import java.util.Set; 025 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.commons.lang3.StringUtils; 029import org.apache.commons.lang3.tuple.Triple; 030import org.slf4j.Logger; 031 032import org.ametys.cms.content.references.OutgoingReferencesExtractor; 033import org.ametys.cms.data.ContentSynchronizationResult; 034import org.ametys.cms.repository.Content; 035import org.ametys.cms.repository.ContentQueryHelper; 036import org.ametys.cms.repository.ContentTypeExpression; 037import org.ametys.cms.repository.LanguageExpression; 038import org.ametys.cms.repository.ModifiableContent; 039import org.ametys.cms.repository.WorkflowAwareContent; 040import org.ametys.cms.workflow.AbstractContentWorkflowComponent; 041import org.ametys.cms.workflow.EditContentFunction; 042import org.ametys.core.user.CurrentUserProvider; 043import org.ametys.plugins.contentio.synchronize.SynchronizableContentsCollectionDataProvider; 044import org.ametys.plugins.contentio.synchronize.impl.SQLSynchronizableContentsCollection; 045import org.ametys.plugins.contentio.synchronize.workflow.EditSynchronizedContentFunction; 046import org.ametys.plugins.repository.AmetysObjectIterable; 047import org.ametys.plugins.repository.AmetysObjectIterator; 048import org.ametys.plugins.repository.data.external.ExternalizableDataProvider.ExternalizableDataStatus; 049import org.ametys.plugins.repository.data.holder.ModifiableModelLessDataHolder; 050import org.ametys.plugins.repository.data.holder.values.SynchronizationContext; 051import org.ametys.plugins.repository.data.holder.values.SynchronizationResult; 052import org.ametys.plugins.repository.query.expression.AndExpression; 053import org.ametys.plugins.repository.query.expression.Expression; 054import org.ametys.plugins.repository.query.expression.Expression.Operator; 055import org.ametys.plugins.repository.query.expression.ExpressionContext; 056import org.ametys.plugins.repository.query.expression.StringExpression; 057import org.ametys.plugins.userdirectory.DeleteOrgUnitComponent; 058import org.ametys.plugins.userdirectory.OrganisationChartPageHandler; 059import org.ametys.plugins.userdirectory.UserDirectoryPageHandler; 060import org.ametys.plugins.workflow.AbstractWorkflowComponent; 061import org.ametys.runtime.i18n.I18nizableText; 062import org.ametys.runtime.model.View; 063import org.ametys.runtime.model.type.ModelItemTypeConstants; 064 065import com.opensymphony.workflow.InvalidActionException; 066import com.opensymphony.workflow.WorkflowException; 067 068/** 069 * Synchronizable collection for UD Orgunits 070 */ 071public class SQLSynchronizableUDOrgunitCollection extends SQLSynchronizableContentsCollection 072{ 073 /** The internal data name for orgUnit remote sql id */ 074 public static final String ORGUNIT_REMOTE_ID_INTERNAL_DATA = "orgunit-remote-id"; 075 076 /** The result map key for number of deleted contents */ 077 public static final String RESULT_NB_SYNCHRONIZED_ORGUNITS_RELATIONS = "nbSynchronizedOrgUnitsRelations"; 078 079 private static final String __PARAM_SQL_TABLE_USER = "tableNameUser"; 080 private static final String __PARAM_SQL_ORGUNIT_JOIN_COLUMN_NAME = "orgUnitJoinColumnName"; 081 private static final String __PARAM_LOGIN_USER_ATTRIBUTE_NAME = "loginUser"; 082 private static final String __PARAM_SQL_LOGIN_USER_COLUMN_NAME = "loginColumnName"; 083 private static final String __PARAM_SQL_ROLE_USER_COLUMN_NAME = "roleColumnName"; 084 private static final String __PARAM_SQL_ORGUNIT_REMOTE_ID_COLUMN_NAME = "orgunitRemoteIdColumnName"; 085 private static final String __PARAM_SQL_USER_SORT_COLUMN_NAME = "sortColumnName"; 086 private static final String __PARAM_SQL_USER_SORT_PREVAIL_NAME = "sortPrevail"; 087 088 /** The map which link orgunit with this parent */ 089 protected Map<String, String> _orgUnitParents; 090 091 /** The map which link users (userId and role) to their orgunits */ 092 protected Map<String, Map<String, String>> _usersByOrgUnitId; 093 094 /** The map which link orgunit with sql remote ids */ 095 protected Map<String, String> _orgUnitRemoteIds; 096 097 098 /** Number of updated contents for parent-child org unit relation */ 099 protected Integer _nbSynchronizedOrgUnit; 100 101 /** The sql user search DAO */ 102 protected SQLUserSearchDAO _sqlUserDAO; 103 104 /** The organisation chart page handler */ 105 protected OrganisationChartPageHandler _orgChartPageHandler; 106 107 /** The current user provider */ 108 protected CurrentUserProvider _userProvider; 109 110 /** The OutgoingReferences extractor */ 111 protected OutgoingReferencesExtractor _outgoingReferencesExtractor; 112 113 /** The delete orgUnit component */ 114 protected DeleteOrgUnitComponent _deleteOrgUnitComponent; 115 116 @Override 117 public void service(ServiceManager smanager) throws ServiceException 118 { 119 super.service(smanager); 120 _sqlUserDAO = (SQLUserSearchDAO) smanager.lookup(SQLUserSearchDAO.ROLE); 121 _orgChartPageHandler = (OrganisationChartPageHandler) smanager.lookup(OrganisationChartPageHandler.ROLE); 122 _userProvider = (CurrentUserProvider) smanager.lookup(CurrentUserProvider.ROLE); 123 _outgoingReferencesExtractor = (OutgoingReferencesExtractor) smanager.lookup(OutgoingReferencesExtractor.ROLE); 124 _deleteOrgUnitComponent = (DeleteOrgUnitComponent) smanager.lookup(DeleteOrgUnitComponent.ROLE); 125 } 126 127 public boolean handleRightAssignmentContext() 128 { 129 return false; 130 } 131 132 /** 133 * Get the name of user SQL table 134 * @return The user SQL table name 135 */ 136 public String getUserTableName() 137 { 138 return (String) getParameterValues().get(__PARAM_SQL_TABLE_USER); 139 } 140 141 /** 142 * Get the name of the orgunit join column name of the user table 143 * @return The name of the orgunit join column name 144 */ 145 public String getOrgunitJoinColumnNameForUser() 146 { 147 return (String) getParameterValues().get(__PARAM_SQL_ORGUNIT_JOIN_COLUMN_NAME); 148 } 149 150 /** 151 * Get the login user attribute name 152 * @return The login user attribute name 153 */ 154 public String getLoginUserAttributeName() 155 { 156 return (String) getParameterValues().get(__PARAM_LOGIN_USER_ATTRIBUTE_NAME); 157 } 158 159 /** 160 * Get the login user column name 161 * @return The login user column name 162 */ 163 public String getLoginUserColumnName() 164 { 165 return (String) getParameterValues().get(__PARAM_SQL_LOGIN_USER_COLUMN_NAME); 166 } 167 168 /** 169 * Get the role user column name 170 * @return The role user column name 171 */ 172 public String getRoleUserColumnName() 173 { 174 return (String) getParameterValues().get(__PARAM_SQL_ROLE_USER_COLUMN_NAME); 175 } 176 177 /** 178 * Get the user sort column name 179 * @return The user sort column name 180 */ 181 public String getUserSortColumnName() 182 { 183 return (String) getParameterValues().get(__PARAM_SQL_USER_SORT_COLUMN_NAME); 184 } 185 186 /** 187 * Get the orgunit remote id column name 188 * @return The orgunit remote id column name 189 */ 190 public String getOrgUnitRemoteIdColumnName() 191 { 192 return (String) getParameterValues().get(__PARAM_SQL_ORGUNIT_REMOTE_ID_COLUMN_NAME); 193 } 194 195 /** 196 * True if the SQL sort for users prevail 197 * @return true if the SQL sort for users prevail 198 */ 199 public boolean isUserSortPrevail() 200 { 201 return Boolean.valueOf((String) getParameterValues().get(__PARAM_SQL_USER_SORT_PREVAIL_NAME)); 202 } 203 204 @Override 205 protected Map<String, Object> _getSearchParameters(Map<String, Object> parameters, int offset, int limit, List<Object> sort, List<String> columns) 206 { 207 // Add the sql column name for the orgunit id. 208 // It's for setting the ametys-internal:orgunit-remote-id and retrieve easily the orgUnit content with this Id 209 String orgUnitIdColumnName = getOrgUnitRemoteIdColumnName(); 210 if (!columns.contains(orgUnitIdColumnName)) 211 { 212 columns.add(orgUnitIdColumnName); 213 } 214 215 return super._getSearchParameters(parameters, offset, limit, sort, columns); 216 } 217 218 @Override 219 protected Map<String, Map<String, Object>> internalSearch(Map<String, Object> searchParameters, int offset, int limit, List<Object> sort, Logger logger) 220 { 221 Map<String, Map<String, Object>> internalSearch = super.internalSearch(searchParameters, offset, limit, sort, logger); 222 223 // Fill _orgUnitRemoteIds and _orgUnitParents maps with search results 224 String orgUnitRemoteIdColumnName = getOrgUnitRemoteIdColumnName(); 225 for (String orgUnitIdValue : internalSearch.keySet()) 226 { 227 Map<String, Object> orgUnitValues = internalSearch.get(orgUnitIdValue); 228 _orgUnitRemoteIds.put(orgUnitIdValue, orgUnitValues.get(orgUnitRemoteIdColumnName).toString()); 229 230 Map<String, List<String>> mapping = getMapping(); 231 if (mapping.containsKey(OrganisationChartPageHandler.PARENT_ORGUNIT_ATTRIBUTE_NAME)) 232 { 233 // We take the first because it's no sense to defined two sql columns to define orgunit parents 234 String parentColumn = mapping.get(OrganisationChartPageHandler.PARENT_ORGUNIT_ATTRIBUTE_NAME).get(0); 235 if (orgUnitValues.containsKey(parentColumn)) 236 { 237 String parentId = Optional.of(orgUnitValues) 238 .map(v -> v.get(parentColumn)) 239 .map(Object::toString) 240 .orElse(null); 241 _orgUnitParents.put(orgUnitIdValue, parentId); 242 } 243 } 244 } 245 246 return internalSearch; 247 } 248 249 @Override 250 protected void _logSynchronizationResult(Logger logger) 251 { 252 super._logSynchronizationResult(logger); 253 logger.info("{} contents have been modified to update the parent-child relations.", _nbSynchronizedOrgUnit); 254 } 255 256 @Override 257 protected boolean _hasSomethingChanged() 258 { 259 return super._hasSomethingChanged() || _nbSynchronizedOrgUnit > 0; 260 } 261 262 @Override 263 protected List<ModifiableContent> _internalPopulate(Logger logger) 264 { 265 _orgUnitParents = new HashMap<>(); 266 _orgUnitRemoteIds = new HashMap<>(); 267 _usersByOrgUnitId = _getUsersByOrgUnit(logger); 268 _nbSynchronizedOrgUnit = 0; 269 270 List<ModifiableContent> contents = super._internalPopulate(logger); 271 272 // All orgunits are imported, now we can set relation with parent orgunit 273 _setContentsRelationWithParentOrgunit(contents, logger); 274 275 return contents; 276 } 277 278 /** 279 * Retrieves the user attributes for all org units 280 * @param logger The logger 281 * @return the org units' users 282 */ 283 protected Map<String, Map<String, String>> _getUsersByOrgUnit(Logger logger) 284 { 285 Map<String, Map<String, String>> orgUnitsUsers = new HashMap<>(); 286 287 Map<String, List<String>> mapping = getMapping(); 288 String idField = getIdField(); 289 List<String> orgUnitKeys = mapping.get(idField); 290 if (orgUnitKeys != null && orgUnitKeys.size() > 0) 291 { 292 String orgUnitKey = orgUnitKeys.get(0); 293 Map<String, Object> userParameters = _getSearchUserParameters(orgUnitKey, logger); 294 List<Map<String, Object>> searchUserList = _sqlUserDAO.searchUser(userParameters, getDataSourceId()); 295 296 String loginColumnName = getLoginUserColumnName(); 297 String roleColumnName = getRoleUserColumnName(); 298 299 List<String> userColumns = new ArrayList<>(); 300 userColumns.add(loginColumnName); 301 userColumns.add(orgUnitKey); 302 if (StringUtils.isNotBlank(roleColumnName)) 303 { 304 userColumns.add(roleColumnName); 305 } 306 307 for (Map<String, Object> userMap : searchUserList) 308 { 309 Map<String, Object> normalizedUserMap = _getNormalizedSearchResult(userColumns, userMap); 310 Optional<Triple<String, String, String>> orgUnitUser = _getUserByOrgUnit(orgUnitKey, loginColumnName, roleColumnName, normalizedUserMap, logger); 311 if (orgUnitUser.isPresent()) 312 { 313 Triple<String, String, String> triple = orgUnitUser.get(); 314 String orgUnitId = triple.getLeft(); 315 Map<String, String> orgUnitUsers = orgUnitsUsers.computeIfAbsent(orgUnitId, __ -> new LinkedHashMap<>()); 316 orgUnitUsers.put(triple.getMiddle(), triple.getRight()); 317 } 318 } 319 } 320 321 return orgUnitsUsers; 322 } 323 324 /** 325 * Retrieves a {@link Triple} containing the orgunit id, and the user's login and role for the given normalized user 326 * @param orgUnitKey the orgUnit key 327 * @param loginColumnName the login column name 328 * @param roleColumnName the role column name 329 * @param normalizedUser the normalized user 330 * @param logger the logger 331 * @return the user info as a {@link Triple} 332 */ 333 protected Optional<Triple<String, String, String>> _getUserByOrgUnit(String orgUnitKey, String loginColumnName, String roleColumnName, Map<String, Object> normalizedUser, Logger logger) 334 { 335 String loginValue = (normalizedUser.get(loginColumnName) == null) ? null : String.valueOf(normalizedUser.get(loginColumnName)); 336 String orgUnitIdValue = normalizedUser.get(orgUnitKey).toString(); 337 338 if (StringUtils.isNotBlank(loginValue)) 339 { 340 String roleValue = null; 341 if (StringUtils.isNotBlank(roleColumnName)) 342 { 343 roleValue = (normalizedUser.get(roleColumnName) == null) ? null : String.valueOf(normalizedUser.get(roleColumnName)); 344 } 345 346 return Optional.of(Triple.of(orgUnitIdValue, loginValue, roleValue)); 347 } 348 else 349 { 350 logger.warn("Can't add user to orgunit '" + orgUnitIdValue + "' because the login value is blank ..."); 351 return Optional.empty(); 352 } 353 } 354 355 @Override 356 protected Optional<ModifiableContent> _importOrSynchronizeContent(String idValue, String lang, Map<String, List<Object>> remoteValues, boolean forceImport, Logger logger) 357 { 358 // Do not set relation with parent orgunit now, while they might miss some that are not yet created 359 remoteValues.remove(OrganisationChartPageHandler.PARENT_ORGUNIT_ATTRIBUTE_NAME); 360 361 return super._importOrSynchronizeContent(idValue, lang, remoteValues, forceImport, logger); 362 } 363 364 @Override 365 public ContentSynchronizationResult additionalCommonOperations(ModifiableContent content, Map<String, Object> additionalParameters, Logger logger) 366 { 367 ContentSynchronizationResult result = super.additionalCommonOperations(content, additionalParameters, logger); 368 369 try 370 { 371 SynchronizationResult additionalResult = new SynchronizationResult(); 372 String orgUnitIdValue = content.getValue(getIdField()); 373 ModifiableModelLessDataHolder internalDataHolder = content.getInternalDataHolder(); 374 375 String oldValue = internalDataHolder.getValueOfType(ORGUNIT_REMOTE_ID_INTERNAL_DATA, ModelItemTypeConstants.STRING_TYPE_ID); 376 String value = _orgUnitRemoteIds.get(orgUnitIdValue); 377 378 if (!value.equals(oldValue)) 379 { 380 internalDataHolder.setValue(ORGUNIT_REMOTE_ID_INTERNAL_DATA, value); 381 additionalResult.setHasChanged(true); 382 } 383 384 result.aggregateResult(additionalResult); 385 } 386 catch (Exception e) 387 { 388 _nbError++; 389 logger.error("An error occurred while importing or synchronizing orgunit '{}' and setting its remote id.", content, e); 390 } 391 392 return result; 393 } 394 395 @Override 396 protected Map<String, Object> getAdditionalAttributeValues(String idValue, Content content, Map<String, Object> additionalParameters, boolean create, Logger logger) 397 { 398 Map<String, Object> additionalRemoteValues = super.getAdditionalAttributeValues(idValue, content, additionalParameters, create, logger); 399 400 List<Map<String, Object>> orgUnitUsers = _getOrgUnitUsers(idValue, content.getLanguage()); 401 if (!orgUnitUsers.isEmpty()) 402 { 403 additionalRemoteValues.put(OrganisationChartPageHandler.ORGUNIT_USERS_ATTRIBUTE_NAME, orgUnitUsers); 404 } 405 406 return additionalRemoteValues; 407 } 408 409 /** 410 * Retrieves the users of the given orgunit 411 * @param orgUnitId the orgunit identifier 412 * @param lang the language of the orgunit 413 * @return the users linked to the given orgunit 414 */ 415 protected List<Map<String, Object>> _getOrgUnitUsers(String orgUnitId, String lang) 416 { 417 if (_usersByOrgUnitId.containsKey(orgUnitId)) 418 { 419 List<Map<String, Object>> users = new ArrayList<>(); 420 for (Map.Entry<String, String> user : _usersByOrgUnitId.get(orgUnitId).entrySet()) 421 { 422 Map<String, Object> orgUnitUser = new HashMap<>(); 423 424 String loginValue = user.getKey(); 425 Content userContent = _getUserContent(loginValue, lang); 426 427 if (userContent != null) 428 { 429 String roleValue = user.getValue(); 430 orgUnitUser.put(OrganisationChartPageHandler.ORGUNIT_USER_ROLE_ATTRIBUTE_NAME, roleValue); 431 orgUnitUser.put(OrganisationChartPageHandler.ORGUNIT_USER_ATTRIBUTE_NAME, userContent); 432 433 users.add(orgUnitUser); 434 } 435 } 436 437 return users; 438 } 439 else 440 { 441 return List.of(); 442 } 443 } 444 445 /** 446 * Set all orgunit parents relation for each synchronized content 447 * @param orgUnitContents the synchronized content 448 * @param logger the logger 449 */ 450 protected void _setContentsRelationWithParentOrgunit(List<ModifiableContent> orgUnitContents, Logger logger) 451 { 452 for (ModifiableContent orgUnitContent : orgUnitContents) 453 { 454 try 455 { 456 if (orgUnitContent instanceof WorkflowAwareContent) 457 { 458 I18nizableText commentText = new I18nizableText("plugin.user-directory", "PLUGINS_USER_DIRECTORY_WORKFLOW_ACTION_EDIT_ORGUNIT_REFERENCE_MSG"); 459 String comment = _i18nUtils.translate(commentText, orgUnitContent.getLanguage()); 460 461 View view = View.of(orgUnitContent.getModel(), OrganisationChartPageHandler.PARENT_ORGUNIT_ATTRIBUTE_NAME); 462 463 Map<String, Object> values = new HashMap<>(); 464 String orgUnitIdValue = orgUnitContent.getValue(getIdField()); 465 String newParentSynchroId = _orgUnitParents.get(orgUnitIdValue); 466 Content newParentContent = newParentSynchroId != null ? _getOrgUnitContentFromRemoteId(newParentSynchroId, orgUnitContent.getLanguage(), logger) : null; 467 values.put(OrganisationChartPageHandler.PARENT_ORGUNIT_ATTRIBUTE_NAME, newParentContent); 468 469 SynchronizationContext synchronizationContext = SynchronizationContext.newInstance() 470 .withStatus(ExternalizableDataStatus.EXTERNAL) 471 .withExternalizableDataContextEntry(SynchronizableContentsCollectionDataProvider.SCC_ID_CONTEXT_KEY, getId()); 472 473 if (orgUnitContent.hasDifferences(view, values, synchronizationContext)) 474 { 475 Map<String, Object> inputs = new HashMap<>(); 476 if (StringUtils.isNotEmpty(comment)) 477 { 478 inputs.put("comment", comment); 479 } 480 481 Map<String, Object> parameters = new HashMap<>(); 482 483 parameters.put(EditContentFunction.VIEW, view); 484 parameters.put(EditContentFunction.VALUES_KEY, values); 485 parameters.put(EditContentFunction.QUIT, true); 486 inputs.put(AbstractWorkflowComponent.CONTEXT_PARAMETERS_KEY, parameters); 487 488 inputs.put(EditSynchronizedContentFunction.SYNCHRO_INVERT_EDIT_ACTION_ID_KEY, getSynchronizeActionId()); 489 490 Map<String, Object> actionResult = _contentWorkflowHelper.doAction((WorkflowAwareContent) orgUnitContent, getSynchronizeActionId(), inputs); 491 if ((boolean) actionResult.getOrDefault(AbstractContentWorkflowComponent.HAS_CHANGED_KEY, false)) 492 { 493 _nbSynchronizedOrgUnit++; 494 } 495 } 496 } 497 } 498 catch (WorkflowException | InvalidActionException e) 499 { 500 logger.error("An error occurred while updating parent-child relations of org unit {} ", orgUnitContent, e); 501 } 502 } 503 } 504 505 /** 506 * Get user content from login value 507 * @param loginValue the login value 508 * @param lang the language 509 * @return the user content 510 */ 511 protected Content _getUserContent(String loginValue, String lang) 512 { 513 String loginAttribute = getLoginUserAttributeName(); 514 Set<String> contentTypes = _contentTypeEP.getSubTypes(UserDirectoryPageHandler.ABSTRACT_USER_CONTENT_TYPE); 515 516 Expression ctypeExpression = new ContentTypeExpression(Operator.EQ, contentTypes.toArray(new String[contentTypes.size()])); 517 LanguageExpression languageExpression = new LanguageExpression(Operator.EQ, lang); 518 StringExpression loginExp = new StringExpression(loginAttribute, Operator.EQ, loginValue); 519 520 Expression userExp = new AndExpression(loginExp, ctypeExpression, languageExpression); 521 String xPathQuery = ContentQueryHelper.getContentXPathQuery(userExp); 522 523 AmetysObjectIterable<Content> contentQuery = _resolver.query(xPathQuery); 524 AmetysObjectIterator<Content> contentIterator = contentQuery.iterator(); 525 if (contentIterator.hasNext()) 526 { 527 return contentIterator.next(); 528 } 529 530 return null; 531 } 532 533 /** 534 * Get orgunit content from the remote Id 535 * @param remoteId the remote Id 536 * @param lang the language 537 * @param logger the logger 538 * @return the orgunit content 539 */ 540 protected Content _getOrgUnitContentFromRemoteId(String remoteId, String lang, Logger logger) 541 { 542 Expression ctypeExpression = new ContentTypeExpression(Operator.EQ, OrganisationChartPageHandler.ORGUNIT_CONTENT_TYPE); 543 StringExpression remoteIdOrgunitExpression = new StringExpression(ORGUNIT_REMOTE_ID_INTERNAL_DATA, Operator.EQ, remoteId, ExpressionContext.newInstance().withInternal(true)); 544 LanguageExpression languageExpression = new LanguageExpression(Operator.EQ, lang); 545 546 Expression collectionExpression = _sccHelper.getCollectionExpression(getId()); 547 548 Expression userExp = new AndExpression(remoteIdOrgunitExpression, ctypeExpression, languageExpression, collectionExpression); 549 String xPathQuery = ContentQueryHelper.getContentXPathQuery(userExp); 550 551 AmetysObjectIterable<Content> contentQuery = _resolver.query(xPathQuery); 552 AmetysObjectIterator<Content> contentIterator = contentQuery.iterator(); 553 if (contentIterator.hasNext()) 554 { 555 return contentIterator.next(); 556 } 557 558 return null; 559 } 560 561 /** 562 * Get the parameters map for user mybatis search 563 * @param orgUnitColumnKey the column name of the orgunit key 564 * @param logger the logger 565 * @return the parameter map 566 */ 567 protected Map<String, Object> _getSearchUserParameters(String orgUnitColumnKey, Logger logger) 568 { 569 Map<String, Object> params = new HashMap<>(); 570 params.put("loginColumnName", getLoginUserColumnName()); 571 params.put("tableUser", getUserTableName()); 572 params.put("tableOrgUnit", getTableName()); 573 params.put("joinColumnName", getOrgunitJoinColumnNameForUser()); 574 params.put("orgUnitColumnKey", orgUnitColumnKey); 575 params.put("orgUnitIdColumnName", getOrgUnitRemoteIdColumnName()); 576 577 String roleUserColumnName = getRoleUserColumnName(); 578 if (StringUtils.isNotBlank(roleUserColumnName)) 579 { 580 params.put("roleColumnName", roleUserColumnName); 581 } 582 583 String sortColumnName = getUserSortColumnName(); 584 if (StringUtils.isNotBlank(sortColumnName)) 585 { 586 params.put("sortColumnName", sortColumnName); 587 } 588 589 return params; 590 } 591 592 @Override 593 protected int _deleteContents(List<Content> contentsToRemove, Logger logger) 594 { 595 return _deleteOrgUnitComponent.deleteContentsWithLog(contentsToRemove, Map.of(DeleteOrgUnitComponent.SCC_ID_PARAMETERS_KEY, getId()), Map.of(), logger); 596 } 597 598 @Override 599 public Map<String, Integer> getSynchronizationResult() 600 { 601 Map<String, Integer> result = super.getSynchronizationResult(); 602 603 result.put(RESULT_NB_SYNCHRONIZED_ORGUNITS_RELATIONS, _nbSynchronizedOrgUnit); 604 605 return result; 606 } 607}