You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2019/10/22 09:43:16 UTC
[syncope] branch master updated: [SYNCOPE-1500] Reconciliation now
supports single pull / push + [SYNCOPE-957] Reconciliation now supports
Linked Accounts + [SYNCOPE-1499] Use Push correlation rule wherever it
makes sense
This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new 64495ef [SYNCOPE-1500] Reconciliation now supports single pull / push + [SYNCOPE-957] Reconciliation now supports Linked Accounts + [SYNCOPE-1499] Use Push correlation rule wherever it makes sense
64495ef is described below
commit 64495efbbc906599bf3c7de1c0692a7c3139b024
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Tue Oct 22 09:13:42 2019 +0200
[SYNCOPE-1500] Reconciliation now supports single pull / push + [SYNCOPE-957] Reconciliation now supports Linked Accounts + [SYNCOPE-1499] Use Push correlation rule wherever it makes sense
---
.../client/console/commons/IdMStatusProvider.java | 3 +-
.../console/rest/ReconciliationRestClient.java | 24 +-
.../console/status/AnyStatusDirectoryPanel.java | 8 +-
.../client/console/status/ReconStatusPanel.java | 9 +-
.../client/console/status/ReconStatusUtils.java | 9 +-
.../client/console/status/ReconTaskPanel.java | 28 +-
.../status/ResourceStatusDirectoryPanel.java | 29 +-
.../client/ui/commons/status/StatusUtils.java | 6 +-
.../client/console/wizards/any/StatusPanel.java | 6 +-
.../apache/syncope/common/lib/to/ReconStatus.java | 35 ++
.../syncope/common/rest/api/beans/ReconQuery.java | 96 ++++++
.../rest/api/service/ReconciliationService.java | 43 +--
.../common/lib/collections/IteratorChain.java | 281 ----------------
.../apache/syncope/common/lib/types/MatchType.java | 9 +-
core/idm/logic/pom.xml | 5 +
.../syncope/core/logic/ReconciliationLogic.java | 303 ++++++++++++------
.../apache/syncope/core/logic/ResourceLogic.java | 137 ++++----
.../cxf/service/ReconciliationServiceImpl.java | 49 ++-
.../core/rest/cxf/service/ResourceServiceImpl.java | 2 +-
.../apache/syncope/core/logic/AnyTypeLogic.java | 1 -
.../persistence/api/dao/PullCorrelationRule.java | 5 +-
.../core/persistence/api/dao/PullMatch.java | 69 ++--
.../syncope/core/persistence/api/dao/UserDAO.java | 3 +
.../core/persistence/jpa/dao/JPAUserDAO.java | 15 +
.../core/persistence/jpa/inner/PolicyTest.java | 2 +-
.../src/test/resources/domains/MasterContent.xml | 2 +-
.../core/provisioning/api/VirAttrHandler.java | 9 +
.../api/pushpull/SyncopeSinglePullExecutor.java | 2 -
.../api/pushpull/SyncopeSinglePushExecutor.java | 8 +-
.../api/pushpull/UserPushResultHandler.java | 4 +
.../java/DefaultAnyObjectProvisioningManager.java | 11 +-
.../java/DefaultGroupProvisioningManager.java | 13 +-
.../java/DefaultUserProvisioningManager.java | 18 +-
.../core/provisioning/java/MappingManagerImpl.java | 59 ++--
.../core/provisioning/java/VirAttrHandlerImpl.java | 134 ++++----
.../java/data/AbstractAnyDataBinder.java | 4 +-
.../java/data/AnyObjectDataBinderImpl.java | 1 +
.../java/data/AnyTypeDataBinderImpl.java | 8 +-
.../java/data/ResourceDataBinderImpl.java | 13 +-
.../core/provisioning/java/job/JobManagerImpl.java | 14 +-
.../java/job/report/ReconciliationReportlet.java | 2 +-
.../AbstractPropagationTaskExecutor.java | 67 +---
.../java/propagation/AzurePropagationActions.java | 4 +-
.../propagation/DefaultPropagationReporter.java | 4 +-
.../propagation/GoogleAppsPropagationActions.java | 4 +-
.../java/propagation/PropagationManagerImpl.java | 21 +-
.../java/pushpull/ADMembershipPullActions.java | 14 +-
.../java/pushpull/AbstractPullResultHandler.java | 139 ++++----
.../java/pushpull/AbstractPushResultHandler.java | 23 +-
.../java/pushpull/AbstractRealmResultHandler.java | 4 +
.../pushpull/AbstractSyncopeResultHandler.java | 11 +-
.../DefaultAnyObjectPullResultHandler.java | 8 +-
.../DefaultAnyObjectPushResultHandler.java | 4 +-
.../pushpull/DefaultGroupPullResultHandler.java | 8 +-
.../pushpull/DefaultGroupPushResultHandler.java | 4 +-
.../pushpull/DefaultRealmPullResultHandler.java | 355 +++++++++------------
.../pushpull/DefaultRealmPushResultHandler.java | 21 +-
.../pushpull/DefaultUserPullResultHandler.java | 60 ++--
.../pushpull/DefaultUserPushResultHandler.java | 250 ++++++++++++++-
.../{PullUtils.java => InboundMatcher.java} | 283 ++++++++--------
.../java/pushpull/LDAPMembershipPullActions.java | 33 +-
.../java/pushpull/OutboundMatcher.java | 229 +++++++++++++
.../java/pushpull/PullJobDelegate.java | 113 +++----
.../core/provisioning/java/pushpull/PushUtils.java | 139 --------
.../java/pushpull/SinglePullJobDelegate.java | 36 +--
.../java/pushpull/SinglePushJobDelegate.java | 83 +++--
.../provisioning/java/utils/ConnObjectUtils.java | 50 +--
.../core/provisioning/java/utils/MappingUtils.java | 35 +-
.../LinkedAccountSamplePullCorrelationRule.java | 17 +-
.../org/apache/syncope/fit/AbstractITCase.java | 2 +
.../apache/syncope/fit/core/AnyObjectITCase.java | 4 +-
.../org/apache/syncope/fit/core/AnyTypeITCase.java | 12 +-
.../org/apache/syncope/fit/core/GroupITCase.java | 26 +-
.../org/apache/syncope/fit/core/LoggerITCase.java | 5 +-
.../syncope/fit/core/MultitenancyITCase.java | 4 +-
.../syncope/fit/core/PropagationTaskITCase.java | 2 +-
.../apache/syncope/fit/core/PullTaskITCase.java | 6 +-
.../apache/syncope/fit/core/PushTaskITCase.java | 89 +++---
.../syncope/fit/core/ReconciliationITCase.java | 63 +++-
.../apache/syncope/fit/core/ResourceITCase.java | 10 +-
.../org/apache/syncope/fit/core/SearchITCase.java | 8 +-
81 files changed, 1949 insertions(+), 1780 deletions(-)
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMStatusProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMStatusProvider.java
index 9d60687..4c778dd 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMStatusProvider.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMStatusProvider.java
@@ -29,7 +29,6 @@ import org.apache.syncope.client.console.status.ReconStatusUtils;
import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.to.ConnObjectTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdMEntitlement;
public class IdMStatusProvider implements StatusProvider {
@@ -41,7 +40,7 @@ public class IdMStatusProvider implements StatusProvider {
final AnyTO any, final Collection<String> resources) {
return ReconStatusUtils.getReconStatuses(
- AnyTypeKind.fromTOClass(any.getClass()), any.getKey(), any.getResources()).stream().
+ any.getType(), any.getKey(), any.getResources()).stream().
map(status -> Triple.<ConnObjectTO, ConnObjectWrapper, String>of(
status.getRight().getOnSyncope(),
new ConnObjectWrapper(any, status.getLeft(), status.getRight().getOnResource()),
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
index 7f43da4..4d7f94c 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java
@@ -21,32 +21,22 @@ package org.apache.syncope.client.console.rest;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.to.ReconStatus;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.syncope.common.rest.api.service.ReconciliationService;
public class ReconciliationRestClient extends BaseRestClient {
private static final long serialVersionUID = -3161863874876938094L;
- public static ReconStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
- return getService(ReconciliationService.class).status(anyTypeKind, anyKey, resourceKey);
+ public static ReconStatus status(final ReconQuery reconQuery) {
+ return getService(ReconciliationService.class).status(reconQuery);
}
- public static void push(
- final AnyTypeKind anyTypeKind,
- final String anyKey,
- final String resourceKey,
- final PushTaskTO pushTask) {
-
- getService(ReconciliationService.class).push(anyTypeKind, anyKey, resourceKey, pushTask);
+ public static void push(final ReconQuery reconQuery, final PushTaskTO pushTask) {
+ getService(ReconciliationService.class).push(reconQuery, pushTask);
}
- public static void pull(
- final AnyTypeKind anyTypeKind,
- final String anyKey,
- final String resourceKey,
- final PullTaskTO pullTask) {
-
- getService(ReconciliationService.class).pull(anyTypeKind, anyKey, resourceKey, pullTask);
+ public static void pull(final ReconQuery reconQuery, final PullTaskTO pullTask) {
+ getService(ReconciliationService.class).pull(reconQuery, pullTask);
}
}
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java
index 6fad939..7081671 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java
@@ -192,7 +192,7 @@ public class AnyStatusDirectoryPanel
@Override
public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
multiLevelPanelRef.next(bean.getResource(),
- new ReconStatusPanel(bean.getResource(), anyTypeKind, anyTO.getKey()),
+ new ReconStatusPanel(bean.getResource(), anyTO.getType(), anyTO.getKey()),
target);
target.add(multiLevelPanelRef);
AnyStatusDirectoryPanel.this.getTogglePanel().close(target);
@@ -211,7 +211,7 @@ public class AnyStatusDirectoryPanel
new ReconTaskPanel(
bean.getResource(),
new PushTaskTO(),
- anyTypeKind,
+ anyTO.getType(),
anyTO.getKey(),
multiLevelPanelRef,
pageRef),
@@ -231,7 +231,7 @@ public class AnyStatusDirectoryPanel
new ReconTaskPanel(
bean.getResource(),
new PullTaskTO(),
- anyTypeKind,
+ anyTO.getType(),
anyTO.getKey(),
multiLevelPanelRef,
pageRef),
@@ -288,7 +288,7 @@ public class AnyStatusDirectoryPanel
List<StatusBean> statusBeans = actual.getResources().stream().map(resource -> {
List<Pair<String, ReconStatus>> statuses = List.of();
if (statusOnly) {
- statuses = ReconStatusUtils.getReconStatuses(anyTypeKind, anyTO.getKey(), List.of(resource));
+ statuses = ReconStatusUtils.getReconStatuses(anyTO.getType(), anyTO.getKey(), List.of(resource));
}
return StatusUtils.getStatusBean(actual,
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java
index a19ffbb..a7f2360 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java
@@ -25,7 +25,6 @@ import org.apache.syncope.client.console.panels.RemoteObjectPanel;
import org.apache.syncope.client.console.wizards.any.ConnObjectPanel;
import org.apache.syncope.common.lib.to.ConnObjectTO;
import org.apache.syncope.common.lib.to.ReconStatus;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.ResourceModel;
@@ -36,17 +35,17 @@ public class ReconStatusPanel extends RemoteObjectPanel {
private final String resource;
- private final AnyTypeKind anyTypeKind;
+ private final String anyTypeKey;
private final String anyKey;
public ReconStatusPanel(
final String resource,
- final AnyTypeKind anyTypeKind,
+ final String anyTypeKey,
final String anyKey) {
this.resource = resource;
- this.anyTypeKind = anyTypeKind;
+ this.anyTypeKey = anyTypeKey;
this.anyKey = anyKey;
add(new ConnObjectPanel(
@@ -59,7 +58,7 @@ public class ReconStatusPanel extends RemoteObjectPanel {
@Override
protected Pair<ConnObjectTO, ConnObjectTO> getConnObjectTOs() {
List<Pair<String, ReconStatus>> statuses =
- ReconStatusUtils.getReconStatuses(anyTypeKind, anyKey, List.of(resource));
+ ReconStatusUtils.getReconStatuses(anyTypeKey, anyKey, List.of(resource));
return statuses.isEmpty()
? null
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusUtils.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusUtils.java
index 6f89e06..9da9dcf 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusUtils.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusUtils.java
@@ -26,7 +26,7 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.client.console.rest.ReconciliationRestClient;
import org.apache.syncope.common.lib.to.ReconStatus;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,13 +37,14 @@ public final class ReconStatusUtils implements Serializable {
private static final Logger LOG = LoggerFactory.getLogger(ReconStatusUtils.class);
public static List<Pair<String, ReconStatus>> getReconStatuses(
- final AnyTypeKind anyTypeKind, final String anyKey, final Collection<String> resources) {
+ final String anyTypeKey, final String anyKey, final Collection<String> resources) {
return resources.stream().map(resource -> {
try {
- return Pair.of(resource, ReconciliationRestClient.status(anyTypeKind, anyKey, resource));
+ return Pair.of(resource, ReconciliationRestClient.status(
+ new ReconQuery.Builder(anyTypeKey, resource).anyKey(anyKey).build()));
} catch (Exception e) {
- LOG.warn("Unexpected error for {} {} on {}", anyTypeKind, anyKey, resource, e);
+ LOG.warn("Unexpected error for {} {} on {}", anyTypeKey, anyKey, resource, e);
return null;
}
}).filter(Objects::nonNull).collect(Collectors.toList());
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
index 9d50891..48228f6 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java
@@ -34,10 +34,10 @@ import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.ProvisioningTaskTO;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdMImplementationType;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.wicket.PageReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
@@ -81,7 +81,7 @@ public class ReconTaskPanel extends MultilevelPanel.SecondLevel {
public ReconTaskPanel(
final String resource,
final ProvisioningTaskTO taskTO,
- final AnyTypeKind anyTypeKind,
+ final String anyType,
final String anyKey,
final MultilevelPanel multiLevelPanelRef,
final PageReference pageRef) {
@@ -92,41 +92,41 @@ public class ReconTaskPanel extends MultilevelPanel.SecondLevel {
AjaxPalettePanel<String> actions = new AjaxPalettePanel.Builder<String>().
setAllowMoveAll(true).setAllowOrder(true).
build("actions",
- new PropertyModel<List<String>>(taskTO, "actions"),
+ new PropertyModel<>(taskTO, "actions"),
new ListModel<>(taskTO instanceof PushTaskTO
? pushActions.getObject() : pullActions.getObject()));
actions.setOutputMarkupId(true);
form.add(actions);
AjaxDropDownChoicePanel<MatchingRule> matchingRule = new AjaxDropDownChoicePanel<>(
- "matchingRule", "matchingRule", new PropertyModel<MatchingRule>(taskTO, "matchingRule"), false);
+ "matchingRule", "matchingRule", new PropertyModel<>(taskTO, "matchingRule"), false);
matchingRule.setChoices(List.of(MatchingRule.values()));
form.add(matchingRule);
AjaxDropDownChoicePanel<UnmatchingRule> unmatchingRule = new AjaxDropDownChoicePanel<>(
- "unmatchingRule", "unmatchingRule", new PropertyModel<UnmatchingRule>(taskTO, "unmatchingRule"),
+ "unmatchingRule", "unmatchingRule", new PropertyModel<>(taskTO, "unmatchingRule"),
false);
unmatchingRule.setChoices(List.of(UnmatchingRule.values()));
form.add(unmatchingRule);
taskTO.setPerformCreate(true);
AjaxCheckBoxPanel performCreate = new AjaxCheckBoxPanel(
- "performCreate", "performCreate", new PropertyModel<Boolean>(taskTO, "performCreate"), false);
+ "performCreate", "performCreate", new PropertyModel<>(taskTO, "performCreate"), false);
form.add(performCreate);
taskTO.setPerformUpdate(true);
AjaxCheckBoxPanel performUpdate = new AjaxCheckBoxPanel(
- "performUpdate", "performUpdate", new PropertyModel<Boolean>(taskTO, "performUpdate"), false);
+ "performUpdate", "performUpdate", new PropertyModel<>(taskTO, "performUpdate"), false);
form.add(performUpdate);
taskTO.setPerformDelete(true);
AjaxCheckBoxPanel performDelete = new AjaxCheckBoxPanel(
- "performDelete", "performDelete", new PropertyModel<Boolean>(taskTO, "performDelete"), false);
+ "performDelete", "performDelete", new PropertyModel<>(taskTO, "performDelete"), false);
form.add(performDelete);
taskTO.setSyncStatus(true);
AjaxCheckBoxPanel syncStatus = new AjaxCheckBoxPanel(
- "syncStatus", "syncStatus", new PropertyModel<Boolean>(taskTO, "syncStatus"), false);
+ "syncStatus", "syncStatus", new PropertyModel<>(taskTO, "syncStatus"), false);
form.add(syncStatus);
form.add(new AjaxSubmitLink("reconcile") {
@@ -135,19 +135,17 @@ public class ReconTaskPanel extends MultilevelPanel.SecondLevel {
@Override
protected void onSubmit(final AjaxRequestTarget target) {
+ ReconQuery reconQuery = new ReconQuery.Builder(anyType, resource).anyKey(anyKey).build();
try {
if (taskTO instanceof PushTaskTO) {
- ReconciliationRestClient.push(anyTypeKind, anyKey, resource,
- (PushTaskTO) form.getModelObject());
+ ReconciliationRestClient.push(reconQuery, (PushTaskTO) form.getModelObject());
} else {
- ReconciliationRestClient.pull(anyTypeKind, anyKey, resource,
- (PullTaskTO) form.getModelObject());
+ ReconciliationRestClient.pull(reconQuery, (PullTaskTO) form.getModelObject());
}
SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
} catch (Exception e) {
- LOG.error("While attempting reconciliation on {} {} {} {}",
- anyTypeKind, anyKey, resource, form.getModelObject(), e);
+ LOG.error("While attempting reconciliation on {}", reconQuery, form.getModelObject(), e);
SyncopeConsoleSession.get().error(resource + ": "
+ (StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage()));
}
diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java
index fbaf8b3..7660e30 100644
--- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java
+++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java
@@ -103,23 +103,6 @@ public class ResourceStatusDirectoryPanel
return columns;
}
- private AnyTypeKind getAnyTypeKind() {
- if (StringUtils.isBlank(type)) {
- return null;
- }
-
- switch (type) {
- case "USER":
- return AnyTypeKind.USER;
-
- case "GROUP":
- return AnyTypeKind.GROUP;
-
- default:
- return AnyTypeKind.ANY_OBJECT;
- }
- }
-
@Override
public ActionsPanel<StatusBean> getActions(final IModel<StatusBean> model) {
final ActionsPanel<StatusBean> panel = super.getActions(model);
@@ -130,13 +113,13 @@ public class ResourceStatusDirectoryPanel
@Override
protected boolean statusCondition(final StatusBean bean) {
- return getAnyTypeKind() != null;
+ return StringUtils.isNotBlank(type);
}
@Override
public void onClick(final AjaxRequestTarget target, final StatusBean bean) {
multiLevelPanelRef.next(bean.getResource(),
- new ReconStatusPanel(bean.getResource(), getAnyTypeKind(), bean.getKey()),
+ new ReconStatusPanel(bean.getResource(), type, bean.getKey()),
target);
target.add(multiLevelPanelRef);
getTogglePanel().close(target);
@@ -149,7 +132,7 @@ public class ResourceStatusDirectoryPanel
@Override
protected boolean statusCondition(final StatusBean bean) {
- return getAnyTypeKind() != null;
+ return StringUtils.isNotBlank(type);
}
@Override
@@ -158,7 +141,7 @@ public class ResourceStatusDirectoryPanel
new ReconTaskPanel(
bean.getResource(),
new PushTaskTO(),
- getAnyTypeKind(),
+ type,
bean.getKey(),
multiLevelPanelRef,
pageRef),
@@ -174,7 +157,7 @@ public class ResourceStatusDirectoryPanel
@Override
protected boolean statusCondition(final StatusBean bean) {
- return getAnyTypeKind() != null;
+ return StringUtils.isNotBlank(type);
}
@Override
@@ -183,7 +166,7 @@ public class ResourceStatusDirectoryPanel
new ReconTaskPanel(
bean.getResource(),
new PullTaskTO(),
- getAnyTypeKind(),
+ type,
bean.getKey(),
multiLevelPanelRef,
pageRef),
diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/StatusUtils.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/StatusUtils.java
index d964136..fe33e4e 100644
--- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/StatusUtils.java
+++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/StatusUtils.java
@@ -50,8 +50,8 @@ public final class StatusUtils implements Serializable {
if (connObjectTO != null) {
Boolean enabled = isEnabled(connObjectTO);
statusBean.setStatus(Optional.ofNullable(enabled).map(aBoolean -> aBoolean
- ? Status.ACTIVE
- : Status.SUSPENDED).orElseGet(() -> (notUser ? Status.ACTIVE : Status.UNDEFINED)));
+ ? Status.ACTIVE
+ : Status.SUSPENDED).orElseGet(() -> (notUser ? Status.ACTIVE : Status.UNDEFINED)));
statusBean.setConnObjectLink(getConnObjectLink(connObjectTO));
}
@@ -69,7 +69,7 @@ public final class StatusUtils implements Serializable {
if (connObjectTO != null) {
Boolean enabled = isEnabled(connObjectTO);
statusBean.setStatus(Optional.ofNullable(enabled)
- .filter(aBoolean -> !aBoolean).map(aBoolean -> Status.SUSPENDED).orElse(Status.ACTIVE));
+ .filter(aBoolean -> !aBoolean).map(aBoolean -> Status.SUSPENDED).orElse(Status.ACTIVE));
statusBean.setConnObjectLink(getConnObjectLink(connObjectTO));
}
diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/StatusPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/StatusPanel.java
index 16abbe8..481eaa9 100644
--- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/StatusPanel.java
+++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/any/StatusPanel.java
@@ -201,9 +201,9 @@ public class StatusPanel extends Panel {
}
protected static Pair<ConnObjectTO, ConnObjectTO> getConnObjectTOs(
- final String anyKey,
- final String resource,
- final List<Triple<ConnObjectTO, ConnObjectWrapper, String>> objects) {
+ final String anyKey,
+ final String resource,
+ final List<Triple<ConnObjectTO, ConnObjectWrapper, String>> objects) {
for (Triple<ConnObjectTO, ConnObjectWrapper, String> object : objects) {
if (anyKey.equals(object.getMiddle().getAny().getKey())
diff --git a/common/idm/lib/src/main/java/org/apache/syncope/common/lib/to/ReconStatus.java b/common/idm/lib/src/main/java/org/apache/syncope/common/lib/to/ReconStatus.java
index 04577c8..b7b4474 100644
--- a/common/idm/lib/src/main/java/org/apache/syncope/common/lib/to/ReconStatus.java
+++ b/common/idm/lib/src/main/java/org/apache/syncope/common/lib/to/ReconStatus.java
@@ -22,6 +22,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.MatchType;
/**
* Reconciliation status.
@@ -32,11 +34,44 @@ public class ReconStatus implements Serializable {
private static final long serialVersionUID = -8516345256596521490L;
+ private AnyTypeKind anyTypeKind;
+
+ private String anyKey;
+
+ private MatchType matchType;
+
private ConnObjectTO onSyncope;
private ConnObjectTO onResource;
@Schema(accessMode = Schema.AccessMode.READ_ONLY)
+ public AnyTypeKind getAnyTypeKind() {
+ return anyTypeKind;
+ }
+
+ public void setAnyTypeKind(final AnyTypeKind anyTypeKind) {
+ this.anyTypeKind = anyTypeKind;
+ }
+
+ @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+ public String getAnyKey() {
+ return anyKey;
+ }
+
+ public void setAnyKey(final String anyKey) {
+ this.anyKey = anyKey;
+ }
+
+ @Schema(accessMode = Schema.AccessMode.READ_ONLY)
+ public MatchType getMatchType() {
+ return matchType;
+ }
+
+ public void setMatchType(final MatchType matchType) {
+ this.matchType = matchType;
+ }
+
+ @Schema(accessMode = Schema.AccessMode.READ_ONLY)
public ConnObjectTO getOnSyncope() {
return onSyncope;
}
diff --git a/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ReconQuery.java b/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ReconQuery.java
new file mode 100644
index 0000000..ddd6799
--- /dev/null
+++ b/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/ReconQuery.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.rest.api.beans;
+
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.QueryParam;
+
+public class ReconQuery {
+
+ public static class Builder {
+
+ private final ReconQuery instance;
+
+ public Builder(final String anyTypeKey, final String resourceKey) {
+ instance = new ReconQuery();
+ instance.setAnyTypeKey(anyTypeKey);
+ instance.setResourceKey(resourceKey);
+ }
+
+ public Builder anyKey(final String anyKey) {
+ instance.setAnyKey(anyKey);
+ return this;
+ }
+
+ public Builder connObjectKeyValue(final String connObjectKeyValue) {
+ instance.setConnObjectKeyValue(connObjectKeyValue);
+ return this;
+ }
+
+ public ReconQuery build() {
+ return instance;
+ }
+ }
+
+ private String anyTypeKey;
+
+ private String anyKey;
+
+ private String resourceKey;
+
+ private String connObjectKeyValue;
+
+ public String getAnyTypeKey() {
+ return anyTypeKey;
+ }
+
+ @NotNull
+ @QueryParam("anyTypeKey")
+ public void setAnyTypeKey(final String anyTypeKey) {
+ this.anyTypeKey = anyTypeKey;
+ }
+
+ public String getAnyKey() {
+ return anyKey;
+ }
+
+ @QueryParam("anyKey")
+ public void setAnyKey(final String anyKey) {
+ this.anyKey = anyKey;
+ }
+
+ public String getResourceKey() {
+ return resourceKey;
+ }
+
+ @NotNull
+ @QueryParam("resourceKey")
+ public void setResourceKey(final String resourceKey) {
+ this.resourceKey = resourceKey;
+ }
+
+ public String getConnObjectKeyValue() {
+ return connObjectKeyValue;
+ }
+
+ @QueryParam("connObjectKeyValue")
+ public void setConnObjectKeyValue(final String connObjectKeyValue) {
+ this.connObjectKeyValue = connObjectKeyValue;
+ }
+}
diff --git a/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java b/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
index 11bffe0..cb44ef9 100644
--- a/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
+++ b/common/idm/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ReconciliationService.java
@@ -24,18 +24,18 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.security.SecurityRequirements;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.validation.constraints.NotNull;
+import javax.ws.rs.BeanParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.to.ReconStatus;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
/**
* REST operations for reconciliation.
@@ -48,29 +48,19 @@ import org.apache.syncope.common.rest.api.RESTHeaders;
public interface ReconciliationService extends JAXRSService {
/**
- * Gets current attributes on Syncope and on the given External Resource, related to given user, group or
- * any object.
+ * Gets compared status between attributes in Syncope and on the given External Resource.
*
- * @param anyTypeKind anyTypeKind
- * @param anyKey user, group or any object: if value looks like a UUID then it is interpreted as key, otherwise as
- * a (user)name
- * @param resourceKey resource key
+ * @param query query conditions
* @return reconciliation status
*/
@GET
@Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
- ReconStatus status(
- @NotNull @QueryParam("anyTypeKind") AnyTypeKind anyTypeKind,
- @NotNull @QueryParam("anyKey") String anyKey,
- @NotNull @QueryParam("resourceKey") String resourceKey);
+ ReconStatus status(@BeanParam ReconQuery query);
/**
- * Pushes the given user, group or any object in Syncope onto the External Resource.
+ * Pushes the matching user, group, any object or linked account in Syncope onto the External Resource.
*
- * @param anyTypeKind anyTypeKind
- * @param anyKey user, group or any object: if value looks like a UUID then it is interpreted as key, otherwise as
- * a (user)name
- * @param resourceKey resource key
+ * @param query query conditions
* @param pushTask push specification
*/
@ApiResponses(
@@ -79,19 +69,12 @@ public interface ReconciliationService extends JAXRSService {
@Path("push")
@Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
- void push(
- @NotNull @QueryParam("anyTypeKind") AnyTypeKind anyTypeKind,
- @NotNull @QueryParam("anyKey") String anyKey,
- @NotNull @QueryParam("resourceKey") String resourceKey,
- @NotNull PushTaskTO pushTask);
+ void push(@BeanParam ReconQuery query, @NotNull PushTaskTO pushTask);
/**
- * Pulls the given user, group or any object from the External Resource into Syncope.
+ * Pulls the matching user, group, any object or linked account from the External Resource into Syncope.
*
- * @param anyTypeKind anyTypeKind
- * @param anyKey user, group or any object: if value looks like a UUID then it is interpreted as key, otherwise as
- * a (user)name
- * @param resourceKey resource key
+ * @param query query conditions
* @param pullTask pull specification
*/
@ApiResponses(
@@ -100,9 +83,5 @@ public interface ReconciliationService extends JAXRSService {
@Path("pull")
@Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
- void pull(
- @NotNull @QueryParam("anyTypeKind") AnyTypeKind anyTypeKind,
- @NotNull @QueryParam("anyKey") String anyKey,
- @NotNull @QueryParam("resourceKey") String resourceKey,
- @NotNull PullTaskTO pullTask);
+ void pull(@BeanParam ReconQuery query, @NotNull PullTaskTO pullTask);
}
diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/collections/IteratorChain.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/collections/IteratorChain.java
deleted file mode 100644
index 6d4b822..0000000
--- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/collections/IteratorChain.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.common.lib.collections;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Queue;
-
-/**
- * An IteratorChain is an Iterator that wraps a number of Iterators.
- *
- * This class makes multiple iterators look like one to the caller. When any
- * method from the Iterator interface is called, the IteratorChain will delegate
- * to a single underlying Iterator. The IteratorChain will invoke the Iterators
- * in sequence until all Iterators are exhausted.
- *
- * Under many circumstances, linking Iterators together in this manner is more
- * efficient (and convenient) than reading out the contents of each Iterator
- * into a List and creating a new Iterator.
- *
- * Calling a method that adds new Iterator <i>after a method in the Iterator
- * interface has been called</i> will result in an UnsupportedOperationException.
- *
- * NOTE: As from version 3.0, the IteratorChain may contain no iterators. In
- * this case the class will function as an empty iterator.
- *
- * NOTE: As from version 4.0, the IteratorChain stores the iterators in a queue
- * and removes any reference to them as soon as they are not used anymore. Thus
- * the methods {@code setIterator(Iterator)} and {@code getIterators()} have been
- * removed and {@link #size()} will return the number of remaining iterators in
- * the queue.
- *
- * @param <E> the type of elements held in this collection
- */
-public class IteratorChain<E> implements Iterator<E> {
-
- /** The chain of iterators. */
- private final Queue<Iterator<? extends E>> iteratorChain = new LinkedList<>();
-
- /** The current iterator. */
- private Iterator<? extends E> currentIterator = null;
-
- /**
- * The "last used" Iterator is the Iterator upon which next() or hasNext()
- * was most recently called used for the remove() operation only.
- */
- private Iterator<? extends E> lastUsedIterator = null;
-
- /**
- * ComparatorChain is "locked" after the first time compare(Object,Object)
- * is called.
- */
- private boolean isLocked = false;
-
- //-----------------------------------------------------------------------
- /**
- * Construct an IteratorChain with no Iterators.
- *
- * You will normally use {@link #addIterator(Iterator)} to add some
- * iterators after using this constructor.
- */
- public IteratorChain() {
- super();
- }
-
- /**
- * Construct an IteratorChain with a single Iterator.
- *
- * This method takes one iterator. The newly constructed iterator will
- * iterate through that iterator. Thus calling this constructor on its own
- * will have no effect other than decorating the input iterator.
- *
- * You will normally use {@link #addIterator(Iterator)} to add some more
- * iterators after using this constructor.
- *
- * @param iterator the first child iterator in the IteratorChain, not null
- * @throws NullPointerException if the iterator is null
- */
- public IteratorChain(final Iterator<? extends E> iterator) {
- super();
- addIterator(iterator);
- }
-
- /**
- * Constructs a new {@code IteratorChain} over the two given iterators.
- *
- * This method takes two iterators. The newly constructed iterator will
- * iterate through each one of the input iterators in turn.
- *
- * @param first the first child iterator in the IteratorChain, not null
- * @param second the second child iterator in the IteratorChain, not null
- * @throws NullPointerException if either iterator is null
- */
- public IteratorChain(final Iterator<? extends E> first, final Iterator<? extends E> second) {
- super();
- addIterator(first);
- addIterator(second);
- }
-
- /**
- * Constructs a new {@code IteratorChain} over the array of iterators.
- *
- * This method takes an array of iterators. The newly constructed iterator
- * will iterate through each one of the input iterators in turn.
- *
- * @param iteratorChain the array of iterators, not null
- * @throws NullPointerException if iterators array is or contains null
- */
- @SafeVarargs
- public IteratorChain(final Iterator<? extends E>... iteratorChain) {
- super();
- for (final Iterator<? extends E> element : iteratorChain) {
- addIterator(element);
- }
- }
-
- /**
- * Constructs a new {@code IteratorChain} over the collection of
- * iterators.
- *
- * This method takes a collection of iterators. The newly constructed
- * iterator will iterate through each one of the input iterators in turn.
- *
- * @param iteratorChain the collection of iterators, not null
- * @throws NullPointerException if iterators collection is or contains null
- * @throws ClassCastException if iterators collection doesn't contain an
- * iterator
- */
- public IteratorChain(final Collection<Iterator<? extends E>> iteratorChain) {
- super();
- iteratorChain.forEach(this::addIterator);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Add an Iterator to the end of the chain
- *
- * @param iterator Iterator to add
- * @throws IllegalStateException if I've already started iterating
- * @throws NullPointerException if the iterator is null
- */
- private void addIterator(final Iterator<? extends E> iterator) {
- checkLocked();
- if (iterator == null) {
- throw new NullPointerException("Iterator must not be null");
- }
- iteratorChain.add(iterator);
- }
-
- /**
- * Returns the remaining number of Iterators in the current IteratorChain.
- *
- * @return Iterator count
- */
- public int size() {
- return iteratorChain.size();
- }
-
- /**
- * Determine if modifications can still be made to the IteratorChain.
- * IteratorChains cannot be modified once they have executed a method from
- * the Iterator interface.
- *
- * @return true if IteratorChain cannot be modified, false if it can
- */
- public boolean isLocked() {
- return isLocked;
- }
-
- /**
- * Checks whether the iterator chain is now locked and in use.
- */
- private void checkLocked() {
- if (isLocked) {
- throw new UnsupportedOperationException(
- "IteratorChain cannot be changed after the first use of a method from the Iterator interface");
- }
- }
-
- /**
- * Lock the chain so no more iterators can be added. This must be called
- * from all Iterator interface methods.
- */
- private void lockChain() {
- if (!isLocked) {
- isLocked = true;
- }
- }
-
- /**
- * Updates the current iterator field to ensure that the current Iterator is
- * not exhausted
- */
- protected void updateCurrentIterator() {
- if (currentIterator == null) {
- if (iteratorChain.isEmpty()) {
- currentIterator = Collections.emptyListIterator();
- } else {
- currentIterator = iteratorChain.remove();
- }
- // set last used iterator here, in case the user calls remove
- // before calling hasNext() or next() (although they shouldn't)
- lastUsedIterator = currentIterator;
- }
-
- while (!currentIterator.hasNext() && !iteratorChain.isEmpty()) {
- currentIterator = iteratorChain.remove();
- }
- }
-
- //-----------------------------------------------------------------------
- /**
- * Return true if any Iterator in the IteratorChain has a remaining element.
- *
- * @return true if elements remain
- */
- @Override
- public boolean hasNext() {
- lockChain();
- updateCurrentIterator();
- lastUsedIterator = currentIterator;
-
- return currentIterator.hasNext();
- }
-
- /**
- * Returns the next Object of the current Iterator
- *
- * @return Object from the current Iterator
- * @throws java.util.NoSuchElementException if all the Iterators are
- * exhausted
- */
- @Override
- public E next() {
- lockChain();
- updateCurrentIterator();
- lastUsedIterator = currentIterator;
-
- return currentIterator.next();
- }
-
- /**
- * Removes from the underlying collection the last element returned by the
- * Iterator. As with next() and hasNext(), this method calls remove() on the
- * underlying Iterator. Therefore, this method may throw an
- * UnsupportedOperationException if the underlying Iterator does not support
- * this method.
- *
- * @throws UnsupportedOperationException if the remove operator is not
- * supported by the underlying Iterator
- * @throws IllegalStateException if the next method has not yet been called,
- * or the remove method has already been called after the last call to the
- * next method.
- */
- @Override
- public void remove() {
- lockChain();
- if (currentIterator == null) {
- updateCurrentIterator();
- }
- lastUsedIterator.remove();
- }
-}
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/UserPushResultHandler.java b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/MatchType.java
similarity index 84%
copy from core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/UserPushResultHandler.java
copy to common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/MatchType.java
index f96c0ef..0885aac 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/UserPushResultHandler.java
+++ b/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/types/MatchType.java
@@ -16,8 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.core.provisioning.api.pushpull;
+package org.apache.syncope.common.lib.types;
-public interface UserPushResultHandler extends SyncopePushResultHandler {
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum
+public enum MatchType {
+ ANY,
+ LINKED_ACCOUNT;
}
diff --git a/core/idm/logic/pom.xml b/core/idm/logic/pom.xml
index 78d8001..c34b10c 100644
--- a/core/idm/logic/pom.xml
+++ b/core/idm/logic/pom.xml
@@ -43,6 +43,11 @@ under the License.
<artifactId>syncope-core-idrepo-logic</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.syncope.common.idm</groupId>
+ <artifactId>syncope-common-idm-rest-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<build>
diff --git a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
index 941c2ca..490864f 100644
--- a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
+++ b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ReconciliationLogic.java
@@ -19,14 +19,15 @@
package org.apache.syncope.core.logic;
import java.lang.reflect.Method;
-import java.util.Iterator;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
-import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.collections.IteratorChain;
import org.apache.syncope.common.lib.Attr;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.ConnObjectTO;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.PullTaskTO;
@@ -36,29 +37,32 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.IdMEntitlement;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
+import org.apache.syncope.common.lib.types.MatchType;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
+import org.apache.syncope.core.persistence.api.dao.AnyDAO;
+import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
-import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
-import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
import org.apache.syncope.core.provisioning.api.ConnectorFactory;
import org.apache.syncope.core.provisioning.api.MappingManager;
+import org.apache.syncope.core.provisioning.api.VirAttrHandler;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePullExecutor;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePushExecutor;
+import org.apache.syncope.core.provisioning.java.pushpull.InboundMatcher;
+import org.apache.syncope.core.provisioning.java.pushpull.OutboundMatcher;
import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
import org.identityconnectors.framework.common.objects.Attribute;
-import org.identityconnectors.framework.common.objects.AttributeBuilder;
-import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.Uid;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -72,15 +76,27 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
private AnyUtilsFactory anyUtilsFactory;
@Autowired
+ private AnyTypeDAO anyTypeDAO;
+
+ @Autowired
private ExternalResourceDAO resourceDAO;
@Autowired
- private VirSchemaDAO virSchemaDAO;
+ private RealmDAO realmDAO;
+
+ @Autowired
+ private VirAttrHandler virAttrHandler;
@Autowired
private MappingManager mappingManager;
@Autowired
+ private InboundMatcher inboundMatcher;
+
+ @Autowired
+ private OutboundMatcher outboundMatcher;
+
+ @Autowired
private ConnectorFactory connFactory;
@Autowired
@@ -89,118 +105,190 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
@Autowired
private SyncopeSinglePushExecutor singlePushExecutor;
- @SuppressWarnings("unchecked")
- private Pair<Any<?>, Provision> init(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
- AnyUtils anyUtils = anyUtilsFactory.getInstance(anyTypeKind);
-
- Any<?> any = anyUtils.dao().authFind(anyKey);
- if (any == null) {
- throw new NotFoundException(anyTypeKind + " '" + anyKey + '\'');
+ private Provision getProvision(final String anyTypeKey, final String resourceKey) {
+ AnyType anyType = anyTypeDAO.find(anyTypeKey);
+ if (anyType == null) {
+ throw new NotFoundException("AnyType '" + anyTypeKey + "'");
}
ExternalResource resource = resourceDAO.find(resourceKey);
if (resource == null) {
- throw new NotFoundException("Resource '" + resourceKey + '\'');
+ throw new NotFoundException("Resource '" + resourceKey + "'");
}
- Provision provision = resource.getProvision(any.getType()).orElseThrow(()
- -> new NotFoundException("Provision for " + any.getType() + " on Resource '" + resourceKey + '\''));
+ Provision provision = resource.getProvision(anyType).
+ orElseThrow(() -> new NotFoundException(
+ "Provision for " + anyType + " on Resource '" + resourceKey + "'"));
if (provision.getMapping() == null) {
- throw new NotFoundException("Mapping for " + any.getType() + " on Resource '" + resourceKey + '\'');
+ throw new NotFoundException("Mapping for " + anyType + " on Resource '" + resourceKey + "'");
}
- return (Pair<Any<?>, Provision>) Pair.of(any, provision);
+ return provision;
}
- private ConnObjectTO getOnSyncope(final Any<?> any, final Provision provision, final String resourceKey) {
- Pair<String, Set<Attribute>> attrs = mappingManager.prepareAttrs(any, null, false, true, provision);
+ private ConnObjectTO getOnSyncope(
+ final MappingItem connObjectKeyItem,
+ final String connObjectKeyValue,
+ final Set<Attribute> attrs) {
- MappingItem connObjectKey = provision.getMapping().getConnObjectKeyItem().orElseThrow(()
- -> new NotFoundException("No RemoteKey set for " + resourceKey));
-
- ConnObjectTO connObjectTO = ConnObjectUtils.getConnObjectTO(attrs.getRight());
- if (attrs.getLeft() != null) {
- connObjectTO.getAttrs().add(new Attr.Builder(connObjectKey.getExtAttrName()).
- value(attrs.getLeft()).build());
- connObjectTO.getAttrs().add(new Attr.Builder(Uid.NAME).
- value(attrs.getLeft()).build());
- }
+ ConnObjectTO connObjectTO = ConnObjectUtils.getConnObjectTO(attrs);
+ connObjectTO.getAttrs().add(new Attr.Builder(connObjectKeyItem.getExtAttrName()).
+ value(connObjectKeyValue).build());
+ connObjectTO.getAttrs().add(new Attr.Builder(Uid.NAME).
+ value(connObjectKeyValue).build());
return connObjectTO;
}
- private ConnObjectTO getOnResource(final Any<?> any, final Provision provision) {
- // 1. build connObjectKeyItem
- MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).orElseThrow(()
- -> new NotFoundException("ConnObjectKey for " + any.getType()
- + " on resource '" + provision.getResource().getKey() + '\''));
- String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision).orElse(null);
- if (connObjectKeyValue == null) {
- return null;
- }
+ private ConnObjectTO getOnSyncope(
+ final Any<?> any,
+ final MappingItem connObjectKeyItem,
+ final Provision provision) {
- // 2. determine attributes to query
- Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(provision).stream().
- map(VirSchema::asLinkingMappingItem).collect(Collectors.toSet());
- Iterator<MappingItem> mapItems = new IteratorChain<>(
- provision.getMapping().getItems().iterator(),
- linkinMappingItems.iterator());
-
- // 3. read from the underlying connector
- ConnObjectTO connObjectTO = null;
-
- Connector connector = connFactory.getConnector(provision.getResource());
- ConnectorObject connectorObject = connector.getObject(
- provision.getObjectClass(),
- AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue),
- provision.isIgnoreCaseMatch(),
- MappingUtils.buildOperationOptions(mapItems));
- if (connectorObject != null) {
- Set<Attribute> attributes = connectorObject.getAttributes();
- if (AttributeUtil.find(Uid.NAME, attributes) == null) {
- attributes.add(connectorObject.getUid());
- }
- if (AttributeUtil.find(Name.NAME, attributes) == null) {
- attributes.add(connectorObject.getName());
- }
+ Pair<String, Set<Attribute>> prepared = mappingManager.prepareAttrs(any, null, false, true, provision);
+ return getOnSyncope(connObjectKeyItem, prepared.getLeft(), prepared.getRight());
+ }
- connObjectTO = ConnObjectUtils.getConnObjectTO(attributes);
- }
+ private ConnObjectTO getOnSyncope(
+ final LinkedAccount account,
+ final MappingItem connObjectKeyItem,
+ final Provision provision) {
- return connObjectTO;
+ Set<Attribute> attrs = mappingManager.prepareAttrs(account.getOwner(), account, null, false, provision);
+ return getOnSyncope(connObjectKeyItem, account.getConnObjectKeyValue(), attrs);
+ }
+
+ private Any<?> getAny(final Provision provision, final String anyKey) {
+ AnyDAO<Any<?>> dao = anyUtilsFactory.getInstance(provision.getAnyType().getKind()).dao();
+ Any<?> any = SyncopeConstants.UUID_PATTERN.matcher(anyKey).matches()
+ ? dao.authFind(anyKey)
+ : dao.authFind(dao.findKey(anyKey));
+ if (any == null) {
+ throw new NotFoundException(provision.getAnyType().getKey() + " '" + anyKey + "'");
+ }
+ return any;
}
@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
- public ReconStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
- Pair<Any<?>, Provision> init = init(anyTypeKind, anyKey, resourceKey);
+ public ReconStatus status(final ReconQuery query) {
+ Provision provision = getProvision(query.getAnyTypeKey(), query.getResourceKey());
+
+ MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).
+ orElseThrow(() -> new NotFoundException(
+ "ConnObjectKey for " + provision.getAnyType().getKey()
+ + " on resource '" + provision.getResource().getKey() + "'"));
ReconStatus status = new ReconStatus();
- status.setOnSyncope(getOnSyncope(init.getLeft(), init.getRight(), resourceKey));
- status.setOnResource(getOnResource(init.getLeft(), init.getRight()));
+
+ if (query.getConnObjectKeyValue() != null) {
+ inboundMatcher.matchByConnObjectKeyValue(connObjectKeyItem, query.getConnObjectKeyValue(), provision).
+ stream().findFirst().ifPresent(match -> {
+ if (match.getAny() != null) {
+ status.setMatchType(MatchType.ANY);
+ status.setAnyTypeKind(match.getAny().getType().getKind());
+ status.setAnyKey(match.getAny().getKey());
+ status.setOnSyncope(getOnSyncope(match.getAny(), connObjectKeyItem, provision));
+ } else if (match.getLinkedAccount() != null) {
+ status.setMatchType(MatchType.LINKED_ACCOUNT);
+ status.setAnyTypeKind(AnyTypeKind.USER);
+ status.setAnyKey(match.getLinkedAccount().getOwner().getKey());
+ status.setOnSyncope(getOnSyncope(match.getLinkedAccount(), connObjectKeyItem, provision));
+ }
+ });
+
+ outboundMatcher.matchByConnObjectKeyValue(
+ connFactory.getConnector(provision.getResource()),
+ connObjectKeyItem,
+ query.getConnObjectKeyValue(),
+ provision).
+ ifPresent(connObj -> {
+ status.setOnResource(ConnObjectUtils.getConnObjectTO(connObj.getAttributes()));
+
+ if (status.getMatchType() == MatchType.ANY && StringUtils.isNotBlank(status.getAnyKey())) {
+ virAttrHandler.setValues(getAny(provision, status.getAnyKey()), connObj);
+ }
+ });
+ }
+ if (query.getAnyKey() != null) {
+ Any<?> any = getAny(provision, query.getAnyKey());
+ status.setMatchType(MatchType.ANY);
+ status.setAnyTypeKind(any.getType().getKind());
+ status.setAnyKey(any.getKey());
+ status.setOnSyncope(getOnSyncope(any, connObjectKeyItem, provision));
+
+ List<ConnectorObject> connObjs = outboundMatcher.match(
+ connFactory.getConnector(provision.getResource()), any, provision);
+ if (!connObjs.isEmpty()) {
+ status.setOnResource(ConnObjectUtils.getConnObjectTO(connObjs.get(0).getAttributes()));
+
+ if (connObjs.size() > 1) {
+ LOG.warn("Expected single match, found {}", connObjs);
+ } else {
+ virAttrHandler.setValues(any, connObjs.get(0));
+ }
+ }
+ }
return status;
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
- public void push(
- final AnyTypeKind anyTypeKind,
- final String anyKey,
- final String resourceKey,
- final PushTaskTO pushTask) {
+ public void push(final ReconQuery query, final PushTaskTO pushTask) {
+ Provision provision = getProvision(query.getAnyTypeKey(), query.getResourceKey());
- Pair<Any<?>, Provision> init = init(anyTypeKind, anyKey, resourceKey);
+ MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).
+ orElseThrow(() -> new NotFoundException(
+ "ConnObjectKey for " + provision.getAnyType().getKey()
+ + " on resource '" + provision.getResource().getKey() + "'"));
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
- try {
- List<ProvisioningReport> results = singlePushExecutor.push(
- init.getRight(),
- connFactory.getConnector(init.getRight().getResource()),
- init.getLeft(),
- pushTask);
- if (!results.isEmpty() && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
- sce.getElements().add(results.get(0).getMessage());
+ List<ProvisioningReport> results = new ArrayList<>();
+
+ if (query.getConnObjectKeyValue() != null) {
+ inboundMatcher.matchByConnObjectKeyValue(connObjectKeyItem, query.getConnObjectKeyValue(), provision).
+ stream().findFirst().ifPresent(match -> {
+ try {
+ if (match.getMatchTarget() == MatchType.ANY) {
+ results.addAll(singlePushExecutor.push(
+ provision,
+ connFactory.getConnector(provision.getResource()),
+ match.getAny(),
+ pushTask));
+ if (!results.isEmpty()
+ && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
+
+ sce.getElements().add(results.get(0).getMessage());
+ }
+ } else {
+ ProvisioningReport result = singlePushExecutor.push(
+ provision,
+ connFactory.getConnector(provision.getResource()),
+ match.getLinkedAccount(),
+ pushTask);
+ if (result.getStatus() == ProvisioningReport.Status.FAILURE) {
+ sce.getElements().add(results.get(0).getMessage());
+ } else {
+ results.add(result);
+ }
+ }
+ } catch (JobExecutionException e) {
+ sce.getElements().add(e.getMessage());
+ }
+ });
+ }
+
+ if (sce.isEmpty() && results.isEmpty() && query.getAnyKey() != null) {
+ try {
+ results.addAll(singlePushExecutor.push(
+ provision,
+ connFactory.getConnector(provision.getResource()),
+ getAny(provision, query.getAnyKey()),
+ pushTask));
+ if (!results.isEmpty() && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
+ sce.getElements().add(results.get(0).getMessage());
+ }
+ } catch (JobExecutionException e) {
+ sce.getElements().add(e.getMessage());
}
- } catch (JobExecutionException e) {
- sce.getElements().add(e.getMessage());
}
if (!sce.isEmpty()) {
@@ -209,22 +297,31 @@ public class ReconciliationLogic extends AbstractTransactionalLogic<EntityTO> {
}
@PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_EXECUTE + "')")
- public void pull(
- final AnyTypeKind anyTypeKind,
- final String anyKey,
- final String resourceKey,
- final PullTaskTO pullTask) {
+ public void pull(final ReconQuery query, final PullTaskTO pullTask) {
+ Provision provision = getProvision(query.getAnyTypeKey(), query.getResourceKey());
- Pair<Any<?>, Provision> init = init(anyTypeKind, anyKey, resourceKey);
+ Optional<String> connObjectKeyValue = Optional.ofNullable(query.getConnObjectKeyValue());
+ if (query.getAnyKey() != null) {
+ Any<?> any = getAny(provision, query.getAnyKey());
+ connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision);
+ }
+ if (!connObjectKeyValue.isPresent()) {
+ throw new NotFoundException(
+ "ConnObjectKey for " + provision.getAnyType().getKey()
+ + " on resource '" + provision.getResource().getKey() + "'");
+ }
+
+ if (pullTask.getDestinationRealm() == null || realmDAO.findByFullPath(pullTask.getDestinationRealm()) == null) {
+ throw new NotFoundException("Realm " + pullTask.getDestinationRealm());
+ }
SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Reconciliation);
try {
List<ProvisioningReport> results = singlePullExecutor.pull(
- init.getRight(),
- connFactory.getConnector(init.getRight().getResource()),
- init.getRight().getMapping().getConnObjectKeyItem().get().getExtAttrName(),
- mappingManager.getConnObjectKeyValue(init.getLeft(), init.getRight()).get(),
- init.getLeft().getRealm(),
+ provision,
+ connFactory.getConnector(provision.getResource()),
+ provision.getMapping().getConnObjectKeyItem().get().getExtAttrName(),
+ connObjectKeyValue.get(),
pullTask);
if (!results.isEmpty() && results.get(0).getStatus() == ProvisioningReport.Status.FAILURE) {
sce.getElements().add(results.get(0).getMessage());
diff --git a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 9dd0c93..29befbf 100644
--- a/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/idm/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -20,15 +20,14 @@ package org.apache.syncope.core.logic;
import java.lang.reflect.Method;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.collections.IteratorChain;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.ConnObjectTO;
@@ -54,21 +53,17 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.ConnInstance;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.provisioning.api.MappingManager;
+import org.apache.syncope.core.provisioning.api.VirAttrHandler;
import org.apache.syncope.core.provisioning.api.data.ConnInstanceDataBinder;
import org.apache.syncope.core.provisioning.api.utils.RealmUtils;
+import org.apache.syncope.core.provisioning.java.pushpull.OutboundMatcher;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
import org.apache.syncope.core.spring.security.AuthContextUtils;
import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
-import org.identityconnectors.framework.common.objects.Attribute;
-import org.identityconnectors.framework.common.objects.AttributeBuilder;
-import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.SearchResult;
-import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.common.objects.filter.Filter;
import org.identityconnectors.framework.spi.SearchResultsHandler;
import org.springframework.beans.factory.annotation.Autowired;
@@ -92,13 +87,16 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
private VirSchemaDAO virSchemaDAO;
@Autowired
+ private VirAttrHandler virAttrHandler;
+
+ @Autowired
private ResourceDataBinder binder;
@Autowired
private ConnInstanceDataBinder connInstanceDataBinder;
@Autowired
- private MappingManager mappingManager;
+ private OutboundMatcher outboundMatcher;
@Autowired
private ConnectorFactory connFactory;
@@ -267,9 +265,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
return resourceDAO.findAll().stream().map(binder::getResourceTO).collect(Collectors.toList());
}
- private Pair<AnyType, Provision> connObjectInit(
- final String resourceKey, final String anyTypeKey) {
-
+ private Provision getProvision(final String resourceKey, final String anyTypeKey) {
ExternalResource resource = resourceDAO.authFind(resourceKey);
if (resource == null) {
throw new NotFoundException("Resource '" + resourceKey + '\'');
@@ -280,53 +276,9 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
throw new NotFoundException("AnyType '" + anyTypeKey + '\'');
}
- Provision provision = resource.getProvision(anyType).
+ return resource.getProvision(anyType).
orElseThrow(() -> new NotFoundException(
"Provision on resource '" + resourceKey + "' for type '" + anyTypeKey + "'"));
-
- return Pair.of(anyType, provision);
- }
-
- private ConnObjectTO readConnObject(
- final Provision provision,
- final String connObjectKeyValue) {
-
- // 0. build connObjectKeyItem
- MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).
- orElseThrow(() -> new NotFoundException(
- "ConnObjectKey mapping for " + provision.getAnyType().getKey()
- + " on resource '" + provision.getResource().getKey() + "'"));
-
- // 1. determine attributes to query
- Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(provision).stream().
- map(virSchema -> virSchema.asLinkingMappingItem()).collect(Collectors.toSet());
- Iterator<MappingItem> mapItems = new IteratorChain<>(
- provision.getMapping().getItems().iterator(),
- linkinMappingItems.iterator());
-
- // 2. read from the underlying connector
- Connector connector = connFactory.getConnector(provision.getResource());
- ConnectorObject connectorObject = connector.getObject(
- provision.getObjectClass(),
- AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue),
- provision.isIgnoreCaseMatch(),
- MappingUtils.buildOperationOptions(mapItems));
- if (connectorObject == null) {
- throw new NotFoundException(
- "Object " + connObjectKeyValue + " with class " + provision.getObjectClass()
- + " not found on resource " + provision.getResource().getKey());
- }
-
- // 3. build result
- Set<Attribute> attributes = connectorObject.getAttributes();
- if (AttributeUtil.find(Uid.NAME, attributes) == null) {
- attributes.add(connectorObject.getUid());
- }
- if (AttributeUtil.find(Name.NAME, attributes) == null) {
- attributes.add(connectorObject.getName());
- }
-
- return ConnObjectUtils.getConnObjectTO(connectorObject);
}
@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
@@ -336,31 +288,58 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
final String anyTypeKey,
final String anyKey) {
- Pair<AnyType, Provision> init = connObjectInit(key, anyTypeKey);
+ Provision provision = getProvision(key, anyTypeKey);
// 1. find any
- Any<?> any = anyUtilsFactory.getInstance(init.getLeft().getKind()).dao().authFind(anyKey);
+ Any<?> any = anyUtilsFactory.getInstance(provision.getAnyType().getKind()).dao().authFind(anyKey);
if (any == null) {
- throw new NotFoundException(init.getLeft() + " " + anyKey);
+ throw new NotFoundException(provision.getAnyType() + " " + anyKey);
}
- // 2. find connObjectKeyValue
- String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, init.getRight()).
- orElseThrow(() -> new NotFoundException(
- "ConnObjectKey value for " + init.getLeft() + " " + anyKey + " on resource '" + key + "'"));
+ // 2. find on resource
+ List<ConnectorObject> connObjs = outboundMatcher.match(
+ connFactory.getConnector(provision.getResource()), any, provision);
+ if (connObjs.isEmpty()) {
+ throw new NotFoundException(
+ "Object " + any + " with class " + provision.getObjectClass()
+ + " not found on resource " + provision.getResource().getKey());
+ }
+
+ if (connObjs.size() > 1) {
+ LOG.warn("Expected single match, found {}", connObjs);
+ } else {
+ virAttrHandler.setValues(any, connObjs.get(0));
+ }
- return readConnObject(init.getRight(), connObjectKeyValue);
+ return ConnObjectUtils.getConnObjectTO(connObjs.get(0).getAttributes());
}
@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')")
@Transactional(readOnly = true)
- public ConnObjectTO readConnObjectByConnObjectKey(
+ public ConnObjectTO readConnObjectByConnObjectKeyValue(
final String key,
final String anyTypeKey,
final String connObjectKeyValue) {
- Pair<AnyType, Provision> init = connObjectInit(key, anyTypeKey);
- return readConnObject(init.getRight(), connObjectKeyValue);
+ Provision provision = getProvision(key, anyTypeKey);
+
+ MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision).
+ orElseThrow(() -> new NotFoundException(
+ "ConnObjectKey mapping for " + provision.getAnyType().getKey()
+ + " on resource '" + provision.getResource().getKey() + "'"));
+
+ Optional<ConnectorObject> connObj = outboundMatcher.matchByConnObjectKeyValue(
+ connFactory.getConnector(provision.getResource()),
+ connObjectKeyItem,
+ connObjectKeyValue,
+ provision);
+ if (connObj.isPresent()) {
+ return ConnObjectUtils.getConnObjectTO(connObj.get().getAttributes());
+ }
+
+ throw new NotFoundException(
+ "Object " + connObjectKeyValue + " with class " + provision.getObjectClass()
+ + " not found on resource " + provision.getResource().getKey());
}
@PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_LIST_CONNOBJECT + "')")
@@ -386,19 +365,15 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
}
objectClass = resource.getOrgUnit().getObjectClass();
- options = MappingUtils.buildOperationOptions(
- MappingUtils.getPropagationItems(resource.getOrgUnit().getItems()).iterator());
+ options = MappingUtils.buildOperationOptions(resource.getOrgUnit().getItems().stream());
} else {
- Pair<AnyType, Provision> init = connObjectInit(key, anyTypeKey);
- resource = init.getRight().getResource();
- objectClass = init.getRight().getObjectClass();
- init.getRight().getMapping().getItems();
-
- Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(init.getRight()).stream().
- map(VirSchema::asLinkingMappingItem).collect(Collectors.toSet());
- Iterator<MappingItem> mapItems = new IteratorChain<>(
- init.getRight().getMapping().getItems().iterator(),
- linkinMappingItems.iterator());
+ Provision provision = getProvision(key, anyTypeKey);
+ resource = provision.getResource();
+ objectClass = provision.getObjectClass();
+
+ Stream<MappingItem> mapItems = Stream.concat(
+ provision.getMapping().getItems().stream(),
+ virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem));
options = MappingUtils.buildOperationOptions(mapItems);
}
@@ -410,7 +385,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
@Override
public boolean handle(final ConnectorObject connectorObject) {
- connObjects.add(ConnObjectUtils.getConnObjectTO(connectorObject));
+ connObjects.add(ConnObjectUtils.getConnObjectTO(connectorObject.getAttributes()));
// safety protection against uncontrolled result size
count++;
return count < size;
diff --git a/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java b/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
index ed24be5..7b77c2f 100644
--- a/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
+++ b/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ReconciliationServiceImpl.java
@@ -18,13 +18,13 @@
*/
package org.apache.syncope.core.rest.cxf.service;
+import javax.validation.ValidationException;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.to.ReconStatus;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.syncope.common.rest.api.service.ReconciliationService;
import org.apache.syncope.core.logic.ReconciliationLogic;
-import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -34,42 +34,29 @@ public class ReconciliationServiceImpl extends AbstractServiceImpl implements Re
@Autowired
private ReconciliationLogic logic;
- @Autowired
- private AnyUtilsFactory anyUtilsFactory;
+ private void validate(final ReconQuery reconQuery) {
+ if ((reconQuery.getAnyKey() == null && reconQuery.getConnObjectKeyValue() == null)
+ || (reconQuery.getAnyKey() != null && reconQuery.getConnObjectKeyValue() != null)) {
- @Override
- public ReconStatus status(final AnyTypeKind anyTypeKind, final String anyKey, final String resourceKey) {
- return logic.status(
- anyTypeKind,
- getActualKey(anyUtilsFactory.getInstance(anyTypeKind).dao(), anyKey),
- resourceKey);
+ throw new ValidationException("Either provide anyKey or connObjectKeyValue, not both");
+ }
}
@Override
- public void push(
- final AnyTypeKind anyTypeKind,
- final String anyKey,
- final String resourceKey,
- final PushTaskTO pushTask) {
-
- logic.push(
- anyTypeKind,
- getActualKey(anyUtilsFactory.getInstance(anyTypeKind).dao(), anyKey),
- resourceKey,
- pushTask);
+ public ReconStatus status(final ReconQuery reconQuery) {
+ validate(reconQuery);
+ return logic.status(reconQuery);
}
@Override
- public void pull(
- final AnyTypeKind anyTypeKind,
- final String anyKey,
- final String resourceKey,
- final PullTaskTO pullTask) {
+ public void push(final ReconQuery reconQuery, final PushTaskTO pushTask) {
+ validate(reconQuery);
+ logic.push(reconQuery, pushTask);
+ }
- logic.pull(
- anyTypeKind,
- getActualKey(anyUtilsFactory.getInstance(anyTypeKind).dao(), anyKey),
- resourceKey,
- pullTask);
+ @Override
+ public void pull(final ReconQuery reconQuery, final PullTaskTO pullTask) {
+ validate(reconQuery);
+ logic.pull(reconQuery, pullTask);
}
}
diff --git a/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java b/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
index ea255de..3eb8954 100644
--- a/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
+++ b/core/idm/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
@@ -94,7 +94,7 @@ public class ResourceServiceImpl extends AbstractServiceImpl implements Resource
public ConnObjectTO readConnObject(final String key, final String anyTypeKey, final String value) {
return SyncopeConstants.UUID_PATTERN.matcher(value).matches()
? logic.readConnObjectByAnyKey(key, anyTypeKey, value)
- : logic.readConnObjectByConnObjectKey(key, anyTypeKey, value);
+ : logic.readConnObjectByConnObjectKeyValue(key, anyTypeKey, value);
}
@Override
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
index 49bf59c..1503b42 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/AnyTypeLogic.java
@@ -94,7 +94,6 @@ public class AnyTypeLogic extends AbstractTransactionalLogic<AnyTypeTO> {
}
binder.update(anyType, anyTypeTO);
- anyType = anyTypeDAO.save(anyType);
return binder.getAnyTypeTO(anyTypeDAO.save(anyType));
}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRule.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRule.java
index 332baab..47b2bd7 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRule.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRule.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.api.dao;
import java.util.Optional;
import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
+import org.apache.syncope.common.lib.types.MatchType;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
@@ -31,7 +32,7 @@ import org.identityconnectors.framework.common.objects.SyncDelta;
@FunctionalInterface
public interface PullCorrelationRule {
- PullMatch NO_MATCH = new PullMatch.Builder().build();
+ PullMatch NO_MATCH = new PullMatch(MatchType.ANY, null);
default void setConf(PullCorrelationRuleConf conf) {
}
@@ -57,7 +58,7 @@ public interface PullCorrelationRule {
* @return matching information
*/
default PullMatch matching(Any<?> any, SyncDelta syncDelta, Provision provision) {
- return new PullMatch.Builder().matchingKey(any.getKey()).build();
+ return new PullMatch(MatchType.ANY, any);
}
/**
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullMatch.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullMatch.java
index f66906f..75d292a 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullMatch.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullMatch.java
@@ -21,69 +21,49 @@ package org.apache.syncope.core.persistence.api.dao;
import java.io.Serializable;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.common.lib.types.MatchType;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
public final class PullMatch implements Serializable {
private static final long serialVersionUID = 6515473131174179932L;
- public enum MatchTarget {
- ANY,
- LINKED_ACCOUNT;
+ private final MatchType matchTarget;
- }
-
- public static class Builder {
-
- private final PullMatch instance = new PullMatch();
+ private Any<?> any;
- public Builder matchingKey(final String matchingKey) {
- instance.matchingKey = matchingKey;
- return this;
- }
-
- public Builder matchTarget(final MatchTarget matchTarget) {
- instance.matchTarget = matchTarget;
- return this;
- }
+ private LinkedAccount linkedAccount;
- public Builder linkingUserKey(final String linkingUserKey) {
- instance.linkingUserKey = linkingUserKey;
- return this;
- }
+ public PullMatch(final MatchType matchTarget, final Entity entity) {
+ this.matchTarget = matchTarget;
- public PullMatch build() {
- return instance;
+ if (entity instanceof Any) {
+ any = (Any<?>) entity;
+ } else if (entity instanceof LinkedAccount) {
+ linkedAccount = (LinkedAccount) entity;
}
}
- private MatchTarget matchTarget = MatchTarget.ANY;
-
- private String matchingKey;
-
- private String linkingUserKey;
-
- private PullMatch() {
- // private constructor
- }
-
- public MatchTarget getMatchTarget() {
+ public MatchType getMatchTarget() {
return matchTarget;
}
- public String getMatchingKey() {
- return matchingKey;
+ public Any<?> getAny() {
+ return any;
}
- public String getLinkingUserKey() {
- return linkingUserKey;
+ public LinkedAccount getLinkedAccount() {
+ return linkedAccount;
}
@Override
public int hashCode() {
return new HashCodeBuilder().
append(matchTarget).
- append(matchingKey).
- append(linkingUserKey).
+ append(any).
+ append(linkedAccount).
build();
}
@@ -100,9 +80,9 @@ public final class PullMatch implements Serializable {
}
final PullMatch other = (PullMatch) obj;
return new EqualsBuilder().
- append(matchingKey, other.matchingKey).
append(matchTarget, other.matchTarget).
- append(linkingUserKey, other.linkingUserKey).
+ append(any, other.any).
+ append(linkedAccount, other.linkedAccount).
build();
}
@@ -110,7 +90,8 @@ public final class PullMatch implements Serializable {
public String toString() {
return "PullMatch{"
+ "matchTarget=" + matchTarget
- + ", matchingKey=" + matchingKey
- + ", linkingUserKey=" + linkingUserKey + '}';
+ + ", any=" + any
+ + ", linkedAccount=" + linkedAccount
+ + '}';
}
}
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
index 008791e..dacb88c 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.persistence.api.dao;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.core.persistence.api.entity.Privilege;
@@ -62,6 +63,8 @@ public interface UserDAO extends AnyDAO<User> {
boolean linkedAccountExists(String userKey, String connObjectKeyValue);
+ Optional<? extends LinkedAccount> findLinkedAccount(ExternalResource resource, String connObjectKeyValue);
+
List<LinkedAccount> findLinkedAccounts(String userKey);
List<LinkedAccount> findLinkedAccountsByResource(ExternalResource resource);
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
index a27495b..5698043 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -25,6 +25,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -554,6 +555,20 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
return !query.getResultList().isEmpty();
}
+ @Override
+ public Optional<? extends LinkedAccount> findLinkedAccount(
+ final ExternalResource resource, final String connObjectKeyValue) {
+
+ TypedQuery<LinkedAccount> query = entityManager().createQuery(
+ "SELECT e FROM " + JPALinkedAccount.class.getSimpleName() + " e "
+ + "WHERE e.resource=:resource AND e.connObjectKeyValue=:connObjectKeyValue", LinkedAccount.class);
+ query.setParameter("resource", resource);
+ query.setParameter("connObjectKeyValue", connObjectKeyValue);
+
+ List<LinkedAccount> result = query.getResultList();
+ return query.getResultList().isEmpty() ? Optional.empty() : Optional.of(result.get(0));
+ }
+
@Transactional(readOnly = true)
@Override
public List<LinkedAccount> findLinkedAccounts(final String userKey) {
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
index 0b2ed8f..34ea16e 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
@@ -92,7 +92,7 @@ public class PolicyTest extends AbstractTest {
POJOHelper.deserialize(pushCR.getImplementation().getBody(), DefaultPushCorrelationRuleConf.class);
assertNotNull(pushCRConf);
assertEquals(1, pushCRConf.getSchemas().size());
- assertTrue(pushCRConf.getSchemas().contains("email"));
+ assertTrue(pushCRConf.getSchemas().contains("surname"));
}
@Test
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 0809c01..9043a95 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -511,7 +511,7 @@ under the License.
<!-- push policies -->
<PushPolicy id="fb6530e5-892d-4f47-a46b-180c5b6c5c83" description="a push policy" conflictResolutionAction="IGNORE"/>
<Implementation id="TestPushCorrelationRule" type="PUSH_CORRELATION_RULE" engine="JAVA"
- body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf","name":"org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf","schemas":["email"]}'/>
+ body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf","name":"org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf","schemas":["surname"]}'/>
<PushCorrelationRuleEntity id="24463935-32a0-4272-bc78-04d6d0adc69e" pushPolicy_id="fb6530e5-892d-4f47-a46b-180c5b6c5c83"
anyType_id="USER" implementation_id="TestPushCorrelationRule"/>
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
index 72bb198..886457c 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
@@ -23,10 +23,19 @@ import java.util.Map;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.Membership;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
public interface VirAttrHandler {
/**
+ * Updates cache with values from external resource.
+ *
+ * @param any any object
+ * @param connObj connector object from external resource
+ */
+ void setValues(Any<?> any, ConnectorObject connObj);
+
+ /**
* Query external resource (or cache, if configured) associated to the given any for values associated to the given
* virtual schema, not related to any membership.
*
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
index 5913036..c0ca069 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePullExecutor.java
@@ -20,7 +20,6 @@ package org.apache.syncope.core.provisioning.api.pushpull;
import java.util.List;
import org.apache.syncope.common.lib.to.PullTaskTO;
-import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.provisioning.api.Connector;
import org.quartz.JobExecutionException;
@@ -33,6 +32,5 @@ public interface SyncopeSinglePullExecutor {
Connector connector,
String connObjectKey,
String connObjectValue,
- Realm realm,
PullTaskTO pullTaskTO) throws JobExecutionException;
}
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
index 1f8c344..8053a65 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/SyncopeSinglePushExecutor.java
@@ -22,10 +22,10 @@ import java.util.List;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
import org.apache.syncope.core.provisioning.api.Connector;
import org.quartz.JobExecutionException;
-@FunctionalInterface
public interface SyncopeSinglePushExecutor {
List<ProvisioningReport> push(
@@ -33,4 +33,10 @@ public interface SyncopeSinglePushExecutor {
Connector connector,
Any<?> any,
PushTaskTO pushTaskTO) throws JobExecutionException;
+
+ ProvisioningReport push(
+ Provision provision,
+ Connector connector,
+ LinkedAccount account,
+ PushTaskTO pushTaskTO) throws JobExecutionException;
}
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/UserPushResultHandler.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/UserPushResultHandler.java
index f96c0ef..06adc0b 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/UserPushResultHandler.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/UserPushResultHandler.java
@@ -18,6 +18,10 @@
*/
package org.apache.syncope.core.provisioning.api.pushpull;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
+
public interface UserPushResultHandler extends SyncopePushResultHandler {
+ boolean handle(LinkedAccount account, Provision provision);
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
index 1efe3b6..8a7813a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
@@ -42,7 +42,6 @@ import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
-
import javax.annotation.Resource;
public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisioningManager {
@@ -86,7 +85,7 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin
created.getPropByRes(),
anyObjectCR.getVirAttrs(),
excludedResources);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return Pair.of(created.getResult(), propagationReporter.getStatuses());
}
@@ -114,7 +113,7 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin
null,
anyObjectUR.getVirAttrs(),
excludedResources);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return Pair.of(updated.getResult(), propagationReporter.getStatuses());
}
@@ -143,7 +142,7 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin
propByRes,
null,
excludedResources);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
try {
awfAdapter.delete(key);
@@ -180,7 +179,7 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin
null,
null,
null);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return propagationReporter.getStatuses();
}
@@ -200,7 +199,7 @@ public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisionin
anyObjectDAO.findAllResourceKeys(key).stream().
filter(resource -> !resources.contains(resource)).
collect(Collectors.toList()));
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return propagationReporter.getStatuses();
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
index 08783bb..a0ec90f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
@@ -45,7 +45,6 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
import org.apache.syncope.core.workflow.api.GroupWorkflowAdapter;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
-
import javax.annotation.Resource;
public class DefaultGroupProvisioningManager implements GroupProvisioningManager {
@@ -82,7 +81,7 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
created.getPropByRes(),
groupCR.getVirAttrs(),
Set.of());
- PropagationReporter propagationReporter = taskExecutor.execute(tasks, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(tasks, nullPriorityAsync, adminUser);
return Pair.of(created.getResult(), propagationReporter.getStatuses());
}
@@ -108,7 +107,7 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
created.getPropByRes(),
groupCR.getVirAttrs(),
excludedResources);
- PropagationReporter propagationReporter = taskExecutor.execute(tasks, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(tasks, nullPriorityAsync, adminUser);
return Pair.of(created.getResult(), propagationReporter.getStatuses());
}
@@ -136,7 +135,7 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
null,
groupUR.getVirAttrs(),
excludedResources);
- PropagationReporter propagationReporter = taskExecutor.execute(tasks, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(tasks, nullPriorityAsync, adminUser);
return Pair.of(updated.getResult(), propagationReporter.getStatuses());
}
@@ -180,7 +179,7 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
null,
null));
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
gwfAdapter.delete(key);
@@ -208,7 +207,7 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
null,
null,
null);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return propagationReporter.getStatuses();
}
@@ -228,7 +227,7 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
groupDAO.findAllResourceKeys(key).stream().
filter(resource -> !resources.contains(resource)).
collect(Collectors.toList()));
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return propagationReporter.getStatuses();
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
index 4439bc6..bb86889 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
@@ -101,7 +101,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
created.getPropByLinkedAccount(),
userCR.getVirAttrs(),
excludedResources);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return Pair.of(created.getResult().getLeft(), propagationReporter.getStatuses());
}
@@ -111,7 +111,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
UserWorkflowResult<Pair<UserUR, Boolean>> updated = uwfAdapter.update(userUR);
List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(updated);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return Pair.of(updated.getResult().getLeft(), propagationReporter.getStatuses());
}
@@ -172,7 +172,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(
updated, updated.getResult().getLeft().getPassword() != null, excludedResources);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return Pair.of(updated.getResult().getLeft(), propagationReporter.getStatuses());
}
@@ -205,7 +205,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
propByRes,
propByLinkedAccount,
excludedResources);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
try {
uwfAdapter.delete(key);
@@ -266,7 +266,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
null,
null,
null);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return propagationReporter.getStatuses();
}
@@ -285,7 +285,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
updated.getLeft().getPropByRes(),
updated.getLeft().getPropByLinkedAccount(),
updated.getLeft().getPerformedTasks()));
- taskExecutor.execute(taskInfos, false, this.adminUser);
+ taskExecutor.execute(taskInfos, false, adminUser);
}
}
@@ -318,7 +318,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
Pair.of(userUR, (Boolean) null), propByRes, null, "update");
List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(wfResult, changePwd, null);
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return propagationReporter.getStatuses();
}
@@ -345,7 +345,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
userDAO.findAllResourceKeys(key).stream().
filter(resource -> !resources.contains(resource)).
collect(Collectors.toList()));
- PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, this.adminUser);
+ PropagationReporter propagationReporter = taskExecutor.execute(taskInfos, nullPriorityAsync, adminUser);
return propagationReporter.getStatuses();
}
@@ -360,6 +360,6 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
UserWorkflowResult<Pair<UserUR, Boolean>> updated = uwfAdapter.confirmPasswordReset(key, token, password);
List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(updated);
- taskExecutor.execute(taskInfos, false, this.adminUser);
+ taskExecutor.execute(taskInfos, false, adminUser);
}
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index 6c9118f..63fd67d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -195,13 +195,13 @@ public class MappingManagerImpl implements MappingManager {
any, provision, any.getPlainAttrs());
Set<Attribute> attributes = new HashSet<>();
- String connObjectKey = null;
+ String[] connObjectKeyValue = new String[1];
- for (Item mapItem : MappingUtils.getPropagationItems(provision.getMapping().getItems())) {
+ MappingUtils.getPropagationItems(provision.getMapping().getItems().stream()).forEach(mapItem -> {
LOG.debug("Processing expression '{}'", mapItem.getIntAttrName());
try {
- String processedConnObjectKey = processPreparedAttr(
+ String processedConnObjectKeyValue = processPreparedAttr(
prepareAttr(
provision,
mapItem,
@@ -211,27 +211,28 @@ public class MappingManagerImpl implements MappingManager {
AccountGetter.DEFAULT,
PlainAttrGetter.DEFAULT),
attributes);
- if (processedConnObjectKey != null) {
- connObjectKey = processedConnObjectKey;
+ if (processedConnObjectKeyValue != null) {
+ connObjectKeyValue[0] = processedConnObjectKeyValue;
}
} catch (Exception e) {
LOG.error("Expression '{}' processing failed", mapItem.getIntAttrName(), e);
}
- }
+ });
- Optional<? extends MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
- if (connObjectKeyItem.isPresent()) {
- Attribute connObjectKeyExtAttr = AttributeUtil.find(connObjectKeyItem.get().getExtAttrName(), attributes);
- if (connObjectKeyExtAttr != null) {
- attributes.remove(connObjectKeyExtAttr);
- attributes.add(AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKey));
+ MappingUtils.getConnObjectKeyItem(provision).ifPresent(connObjectKeyItem -> {
+ Attribute connObjectKeyAttr = AttributeUtil.find(connObjectKeyItem.getExtAttrName(), attributes);
+ if (connObjectKeyAttr != null) {
+ attributes.remove(connObjectKeyAttr);
+ attributes.add(AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue[0]));
}
- Name name = MappingUtils.evaluateNAME(any, provision, connObjectKey);
+ Name name = MappingUtils.evaluateNAME(any, provision, connObjectKeyValue[0]);
attributes.add(name);
- if (connObjectKey != null && !connObjectKey.equals(name.getNameValue()) && connObjectKeyExtAttr == null) {
- attributes.add(AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKey));
+ if (connObjectKeyAttr == null
+ && connObjectKeyValue[0] != null && !connObjectKeyValue[0].equals(name.getNameValue())) {
+
+ attributes.add(AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue[0]));
}
- }
+ });
if (enable != null) {
attributes.add(AttributeBuilder.buildEnabled(enable));
@@ -243,7 +244,7 @@ public class MappingManagerImpl implements MappingManager {
}
}
- return Pair.of(connObjectKey, attributes);
+ return Pair.of(connObjectKeyValue[0], attributes);
}
@Transactional(readOnly = true)
@@ -261,7 +262,7 @@ public class MappingManagerImpl implements MappingManager {
Set<Attribute> attributes = new HashSet<>();
- for (Item mapItem : MappingUtils.getPropagationItems(provision.getMapping().getItems())) {
+ MappingUtils.getPropagationItems(provision.getMapping().getItems().stream()).forEach(mapItem -> {
LOG.debug("Processing expression '{}'", mapItem.getIntAttrName());
try {
@@ -290,7 +291,7 @@ public class MappingManagerImpl implements MappingManager {
} catch (Exception e) {
LOG.error("Expression '{}' processing failed", mapItem.getIntAttrName(), e);
}
- }
+ });
String connObjectKey = account.getConnObjectKeyValue();
MappingUtils.getConnObjectKeyItem(provision).ifPresent(connObjectKeyItem -> {
@@ -339,15 +340,15 @@ public class MappingManagerImpl implements MappingManager {
LOG.debug("Preparing resource attributes for {} with orgUnit {}", realm, orgUnit);
Set<Attribute> attributes = new HashSet<>();
- String connObjectKey = null;
+ String[] connObjectKeyValue = new String[1];
- for (Item orgUnitItem : MappingUtils.getPropagationItems(orgUnit.getItems())) {
+ MappingUtils.getPropagationItems(orgUnit.getItems().stream()).forEach(orgUnitItem -> {
LOG.debug("Processing expression '{}'", orgUnitItem.getIntAttrName());
String value = getIntValue(realm, orgUnitItem);
if (orgUnitItem.isConnObjectKey()) {
- connObjectKey = value;
+ connObjectKeyValue[0] = value;
}
Attribute alreadyAdded = AttributeUtil.find(orgUnitItem.getExtAttrName(), attributes);
@@ -368,19 +369,19 @@ public class MappingManagerImpl implements MappingManager {
attributes.add(AttributeBuilder.build(orgUnitItem.getExtAttrName(), values));
}
- }
+ });
Optional<? extends OrgUnitItem> connObjectKeyItem = orgUnit.getConnObjectKeyItem();
if (connObjectKeyItem.isPresent()) {
- Attribute connObjectKeyExtAttr = AttributeUtil.find(connObjectKeyItem.get().getExtAttrName(), attributes);
- if (connObjectKeyExtAttr != null) {
- attributes.remove(connObjectKeyExtAttr);
- attributes.add(AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKey));
+ Attribute connObjectKeyAttr = AttributeUtil.find(connObjectKeyItem.get().getExtAttrName(), attributes);
+ if (connObjectKeyAttr != null) {
+ attributes.remove(connObjectKeyAttr);
+ attributes.add(AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKeyValue[0]));
}
- attributes.add(MappingUtils.evaluateNAME(realm, orgUnit, connObjectKey));
+ attributes.add(MappingUtils.evaluateNAME(realm, orgUnit, connObjectKeyValue[0]));
}
- return Pair.of(connObjectKey, attributes);
+ return Pair.of(connObjectKeyValue[0], attributes);
}
protected String getPasswordAttrValue(final Provision provision, final Account account, final String defaultValue) {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
index e41eeb0..11cdc39 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
@@ -22,25 +22,22 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.LinkingMappingItem;
import org.apache.syncope.core.persistence.api.entity.Membership;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
-import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.provisioning.api.Connector;
import org.apache.syncope.core.provisioning.api.ConnectorFactory;
-import org.apache.syncope.core.provisioning.api.MappingManager;
import org.apache.syncope.core.provisioning.api.VirAttrHandler;
import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
-import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.apache.syncope.core.provisioning.java.pushpull.OutboundMatcher;
import org.identityconnectors.framework.common.objects.Attribute;
-import org.identityconnectors.framework.common.objects.AttributeBuilder;
import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,86 +58,85 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
private VirAttrCache virAttrCache;
@Autowired
- private MappingManager mappingManager;
+ private OutboundMatcher outboundMatcher;
@Autowired
private AnyUtilsFactory anyUtilsFactory;
+ @Override
+ public void setValues(final Any<?> any, final ConnectorObject connObj) {
+ if (any == null) {
+ LOG.warn("Null any passed, ignoring");
+ return;
+ }
+
+ AllowedSchemas<VirSchema> schemas =
+ anyUtilsFactory.getInstance(any).dao().findAllowedSchemas(any, VirSchema.class);
+ Stream.concat(
+ schemas.getForSelf().stream(),
+ schemas.getForMemberships().values().stream().flatMap(Set::stream)).forEach(schema -> {
+ Attribute attr = connObj.getAttributeByName(schema.getExtAttrName());
+ if (attr == null) {
+ virAttrCache.expire(any.getType().getKey(), any.getKey(), schema.getKey());
+ } else {
+ VirAttrCacheValue virAttrCacheValue = new VirAttrCacheValue(attr.getValue());
+ virAttrCache.put(
+ any.getType().getKey(),
+ any.getKey(),
+ schema.getKey(),
+ virAttrCacheValue);
+ LOG.debug("Values for {} set in cache: {}", schema, virAttrCacheValue);
+ }
+ });
+ }
+
private Map<VirSchema, List<String>> getValues(final Any<?> any, final Set<VirSchema> schemas) {
- Set<ExternalResource> ownedResources = anyUtilsFactory.getInstance(any).getAllResources(any);
+ Set<ExternalResource> resources = anyUtilsFactory.getInstance(any).getAllResources(any);
Map<VirSchema, List<String>> result = new HashMap<>();
Map<Provision, Set<VirSchema>> toRead = new HashMap<>();
- schemas.forEach(schema -> {
- if (ownedResources.contains(schema.getProvision().getResource())) {
- VirAttrCacheValue virAttrCacheValue =
- virAttrCache.get(any.getType().getKey(), any.getKey(), schema.getKey());
-
- if (virAttrCache.isValidEntry(virAttrCacheValue)) {
- LOG.debug("Values for {} found in cache: {}", schema, virAttrCacheValue);
- result.put(schema, virAttrCacheValue.getValues());
- } else if (schema.getProvision().getAnyType().equals(any.getType())) {
- Set<VirSchema> schemasToRead = toRead.get(schema.getProvision());
- if (schemasToRead == null) {
- schemasToRead = new HashSet<>();
- toRead.put(schema.getProvision(), schemasToRead);
- }
- schemasToRead.add(schema);
+ schemas.stream().filter(schema -> resources.contains(schema.getProvision().getResource())).forEach(schema -> {
+ VirAttrCacheValue virAttrCacheValue =
+ virAttrCache.get(any.getType().getKey(), any.getKey(), schema.getKey());
+
+ if (virAttrCache.isValidEntry(virAttrCacheValue)) {
+ LOG.debug("Values for {} found in cache: {}", schema, virAttrCacheValue);
+ result.put(schema, virAttrCacheValue.getValues());
+ } else if (schema.getProvision().getAnyType().equals(any.getType())) {
+ Set<VirSchema> schemasToRead = toRead.get(schema.getProvision());
+ if (schemasToRead == null) {
+ schemasToRead = new HashSet<>();
+ toRead.put(schema.getProvision(), schemasToRead);
}
- } else {
- LOG.debug("Not considering {} since {} is not assigned to {}",
- schema, any, schema.getProvision().getResource());
+ schemasToRead.add(schema);
}
});
toRead.forEach((provision, schemasToRead) -> {
LOG.debug("About to read from {}: {}", provision, schemasToRead);
- Optional<? extends MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
- String connObjectKeyValue = connObjectKeyItem.isPresent()
- ? mappingManager.getConnObjectKeyValue(any, provision).orElse(null)
- : null;
- if (connObjectKeyItem.isEmpty() || connObjectKeyValue == null) {
- LOG.error("No ConnObjectKey or value found for {}, ignoring...", provision);
- } else {
- Set<MappingItem> linkingMappingItems = new HashSet<>();
- linkingMappingItems.add(connObjectKeyItem.get());
- linkingMappingItems.addAll(schemasToRead.stream().
- map(VirSchema::asLinkingMappingItem).collect(Collectors.toSet()));
-
- Connector connector = connFactory.getConnector(provision.getResource());
- try {
- ConnectorObject connectorObject = connector.getObject(
- provision.getObjectClass(),
- AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKeyValue),
- provision.isIgnoreCaseMatch(),
- MappingUtils.buildOperationOptions(linkingMappingItems.iterator()));
-
- if (connectorObject == null) {
- LOG.debug("No read from {} with filter '{} == {}'",
- provision, connObjectKeyItem.get().getExtAttrName(), connObjectKeyValue);
- } else {
- schemasToRead.forEach(schema -> {
- Attribute attr = connectorObject.getAttributeByName(schema.getExtAttrName());
- if (attr != null) {
- VirAttrCacheValue virAttrCacheValue = new VirAttrCacheValue(attr.getValue());
- virAttrCache.put(
- any.getType().getKey(),
- any.getKey(),
- schema.getKey(),
- virAttrCacheValue);
- LOG.debug("Values for {} set in cache: {}", schema, virAttrCacheValue);
-
- result.put(schema, virAttrCacheValue.getValues());
- }
- });
- }
- } catch (Exception e) {
- LOG.error("Error reading from {}", provision, e);
+ outboundMatcher.match(
+ connFactory.getConnector(provision.getResource()),
+ any,
+ provision,
+ schemasToRead.stream().map(VirSchema::asLinkingMappingItem).toArray(LinkingMappingItem[]::new)).
+ forEach(connObj -> schemasToRead.forEach(schema -> {
+
+ Attribute attr = connObj.getAttributeByName(schema.getExtAttrName());
+ if (attr != null) {
+ VirAttrCacheValue virAttrCacheValue = new VirAttrCacheValue(attr.getValue());
+ virAttrCache.put(
+ any.getType().getKey(),
+ any.getKey(),
+ schema.getKey(),
+ virAttrCacheValue);
+ LOG.debug("Values for {} set in cache: {}", schema, virAttrCacheValue);
+
+ result.put(schema, virAttrCacheValue.getValues());
}
- }
+ }));
});
return result;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index 406b484..4f9649a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -206,7 +206,7 @@ abstract class AbstractAnyDataBinder {
private List<String> evaluateMandatoryCondition(final Provision provision, final Any<?> any) {
List<String> missingAttrNames = new ArrayList<>();
- MappingUtils.getPropagationItems(provision.getMapping().getItems()).forEach(mapItem -> {
+ MappingUtils.getPropagationItems(provision.getMapping().getItems().stream()).forEach(mapItem -> {
IntAttrName intAttrName = null;
try {
intAttrName = intAttrNameParser.parse(mapItem.getIntAttrName(), provision.getAnyType().getKind());
@@ -344,7 +344,7 @@ abstract class AbstractAnyDataBinder {
filter(resource -> resource.getProvision(any.getType()).isPresent()
&& resource.getProvision(any.getType()).get().getMapping() != null).
forEach(resource -> MappingUtils.getPropagationItems(
- resource.getProvision(any.getType()).get().getMapping().getItems()).stream().
+ resource.getProvision(any.getType()).get().getMapping().getItems().stream()).
filter(item -> (schema.getKey().equals(item.getIntAttrName()))).
forEach(item -> {
propByRes.add(ResourceOperation.UPDATE, resource.getKey());
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index 4cfae47..284abeb 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -72,6 +72,7 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
return getAnyObjectTO(anyObjectDAO.authFind(key), true);
}
+ @Transactional(readOnly = true)
@Override
public AnyObjectTO getAnyObjectTO(final AnyObject anyObject, final boolean details) {
AnyObjectTO anyObjectTO = new AnyObjectTO();
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
index dcdef11..6cf9a19 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
@@ -37,6 +37,7 @@ import org.apache.syncope.core.persistence.api.entity.EntityFactory;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
import org.apache.syncope.common.lib.types.EntitlementsHolder;
+import org.apache.syncope.core.persistence.api.entity.Entity;
import org.apache.syncope.core.provisioning.api.data.AnyTypeDataBinder;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.apache.syncope.core.spring.security.AuthContextUtils;
@@ -85,7 +86,7 @@ public class AnyTypeDataBinderImpl implements AnyTypeDataBinder {
}));
added.forEach(entitlement -> authorities.add(
- new SyncopeGrantedAuthority(entitlement, SyncopeConstants.ROOT_REALM)));
+ new SyncopeGrantedAuthority(entitlement, SyncopeConstants.ROOT_REALM)));
accessToken.setAuthorities(ENCRYPTOR.encode(
POJOHelper.serialize(authorities), CipherAlgorithm.AES).
@@ -160,12 +161,9 @@ public class AnyTypeDataBinderImpl implements AnyTypeDataBinder {
@Override
public AnyTypeTO getAnyTypeTO(final AnyType anyType) {
AnyTypeTO anyTypeTO = new AnyTypeTO();
-
anyTypeTO.setKey(anyType.getKey());
anyTypeTO.setKind(anyType.getKind());
- anyType.getClasses().forEach(anyTypeClass -> anyTypeTO.getClasses().add(anyTypeClass.getKey()));
-
+ anyTypeTO.getClasses().addAll(anyType.getClasses().stream().map(Entity::getKey).collect(Collectors.toList()));
return anyTypeTO;
}
-
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index 480a5ae..133f171 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -26,9 +26,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
-import org.apache.syncope.common.lib.collections.IteratorChain;
import org.apache.syncope.common.lib.SyncopeClientCompositeException;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.to.AnyTypeClassTO;
@@ -230,18 +230,17 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
}
AnyTypeClassTO allowedSchemas = new AnyTypeClassTO();
- for (Iterator<AnyTypeClass> itor = new IteratorChain<>(
- provision.getAnyType().getClasses().iterator(),
- provision.getAuxClasses().iterator()); itor.hasNext();) {
+ Stream.concat(
+ provision.getAnyType().getClasses().stream(),
+ provision.getAuxClasses().stream()).forEach(anyTypeClass -> {
- AnyTypeClass anyTypeClass = itor.next();
allowedSchemas.getPlainSchemas().addAll(anyTypeClass.getPlainSchemas().stream().
map(Entity::getKey).collect(Collectors.toList()));
allowedSchemas.getDerSchemas().addAll(anyTypeClass.getDerSchemas().stream().
map(Entity::getKey).collect(Collectors.toList()));
allowedSchemas.getVirSchemas().addAll(anyTypeClass.getVirSchemas().stream().
map(Entity::getKey).collect(Collectors.toList()));
- }
+ });
populateMapping(
provisionTO.getMapping(),
@@ -627,7 +626,7 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
resourceTO.setConnector(Optional.ofNullable(connector).map(Entity::getKey).orElse(null));
resourceTO.setConnectorDisplayName(Optional.ofNullable(connector)
- .map(ConnInstance::getDisplayName).orElse(null));
+ .map(ConnInstance::getDisplayName).orElse(null));
// set the provision information
resource.getProvisions().forEach(provision -> {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
index b14bf09..257efae 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
@@ -102,7 +102,7 @@ public class JobManagerImpl implements JobManager, SyncopeCoreLoader {
@Resource(name = "adminUser")
private String adminUser;
-
+
private boolean disableQuartzInstance;
public void setDisableQuartzInstance(final boolean disableQuartzInstance) {
@@ -222,7 +222,7 @@ public class JobManagerImpl implements JobManager, SyncopeCoreLoader {
@Override
public Map<String, Object> register(final SchedTask task, final Date startAt, final long interruptMaxRetries,
- final String executor)
+ final String executor)
throws SchedulerException {
TaskJob job = createSpringBean(TaskJob.class);
@@ -258,7 +258,7 @@ public class JobManagerImpl implements JobManager, SyncopeCoreLoader {
@Override
public void register(final Report report, final Date startAt, final long interruptMaxRetries,
- final String executor) throws SchedulerException {
+ final String executor) throws SchedulerException {
ReportJob job = createSpringBean(ReportJob.class);
job.setReportKey(report.getKey());
@@ -347,7 +347,7 @@ public class JobManagerImpl implements JobManager, SyncopeCoreLoader {
for (Iterator<SchedTask> it = tasks.iterator(); it.hasNext() && !loadException;) {
SchedTask task = it.next();
try {
- register(task, task.getStartAt(), conf.getRight(), this.adminUser);
+ register(task, task.getStartAt(), conf.getRight(), adminUser);
} catch (Exception e) {
LOG.error("While loading job instance for task " + task.getKey(), e);
loadException = true;
@@ -361,7 +361,7 @@ public class JobManagerImpl implements JobManager, SyncopeCoreLoader {
for (Iterator<Report> it = reportDAO.findAll().iterator(); it.hasNext() && !loadException;) {
Report report = it.next();
try {
- register(report, null, conf.getRight(), this.adminUser);
+ register(report, null, conf.getRight(), adminUser);
} catch (Exception e) {
LOG.error("While loading job instance for report " + report.getName(), e);
loadException = true;
@@ -387,7 +387,7 @@ public class JobManagerImpl implements JobManager, SyncopeCoreLoader {
try {
NotificationJob job = createSpringBean(NotificationJob.class);
- Map<String, Object> jobData = createJobMapForExecutionContext(this.adminUser);
+ Map<String, Object> jobData = createJobMapForExecutionContext(adminUser);
registerJob(
NOTIFICATION_JOB.getName(),
job,
@@ -403,7 +403,7 @@ public class JobManagerImpl implements JobManager, SyncopeCoreLoader {
LOG.debug("Registering {}", SystemLoadReporterJob.class);
try {
SystemLoadReporterJob job = createSpringBean(SystemLoadReporterJob.class);
- Map<String, Object> jobData = createJobMapForExecutionContext(this.adminUser);
+ Map<String, Object> jobData = createJobMapForExecutionContext(adminUser);
registerJob(
StringUtils.uncapitalize(SystemLoadReporterJob.class.getSimpleName()),
job,
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReconciliationReportlet.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReconciliationReportlet.java
index 8b830ac..70077db 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReconciliationReportlet.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReconciliationReportlet.java
@@ -288,7 +288,7 @@ public class ReconciliationReportlet extends AbstractReportlet {
provision.getObjectClass(),
AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKeyValue),
provision.isIgnoreCaseMatch(),
- MappingUtils.buildOperationOptions(provision.getMapping().getItems().iterator()));
+ MappingUtils.buildOperationOptions(provision.getMapping().getItems().stream()));
if (connectorObject == null) {
// 2. not found on resource?
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index 40e9943..bbfc20d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -30,9 +30,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.collections.IteratorChain;
import org.apache.syncope.common.lib.to.ExecTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.common.lib.types.AuditElements.Result;
import org.apache.syncope.common.lib.types.ExecStatus;
@@ -42,7 +40,6 @@ import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.TaskDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
import org.apache.syncope.core.provisioning.api.Connector;
@@ -55,22 +52,19 @@ import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
import org.apache.syncope.core.provisioning.api.utils.ExceptionUtils2;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
-import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
-import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
import org.apache.syncope.core.persistence.api.entity.resource.OrgUnitItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.task.TaskUtilsFactory;
import org.apache.syncope.core.provisioning.api.AuditManager;
-import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
-import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
import org.apache.syncope.core.provisioning.api.data.TaskDataBinder;
import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.provisioning.java.pushpull.OutboundMatcher;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
import org.apache.syncope.core.spring.ImplementationManager;
import org.apache.syncope.core.spring.security.AuthContextUtils;
@@ -132,9 +126,6 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
@Autowired
protected ExternalResourceDAO resourceDAO;
- @Autowired
- protected VirSchemaDAO virSchemaDAO;
-
/**
* Notification Manager.
*/
@@ -163,7 +154,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
protected EntityFactory entityFactory;
@Autowired
- protected VirAttrCache virAttrCache;
+ protected OutboundMatcher outboundMatcher;
protected List<PropagationActions> getPropagationActions(final ExternalResource resource) {
List<PropagationActions> result = new ArrayList<>();
@@ -348,7 +339,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
@Override
public TaskExec execute(final PropagationTaskInfo taskInfo, final PropagationReporter reporter,
- final String executor) {
+ final String executor) {
PropagationTask task;
if (taskInfo.getKey() == null) {
task = entityFactory.newEntity(PropagationTask.class);
@@ -626,53 +617,14 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
final Provision provision,
final boolean latest) {
- String connObjectKey = latest || task.getOldConnObjectKey() == null
+ String connObjectKeyValue = latest || task.getOldConnObjectKey() == null
? task.getConnObjectKey()
: task.getOldConnObjectKey();
- boolean isLinkedAccount = task.getAnyTypeKind() == AnyTypeKind.USER
- && userDAO.linkedAccountExists(task.getEntityKey(), connObjectKey);
-
- Set<MappingItem> linkingMappingItems = isLinkedAccount
- ? Set.of()
- : virSchemaDAO.findByProvision(provision).stream().
- map(VirSchema::asLinkingMappingItem).collect(Collectors.toSet());
-
- Optional<? extends MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
- String connObjectKeyName = connObjectKeyItem.isPresent()
- ? connObjectKeyItem.get().getExtAttrName()
- : Name.NAME;
-
- ConnectorObject obj = null;
- try {
- obj = connector.getObject(
- new ObjectClass(task.getObjectClassName()),
- AttributeBuilder.build(connObjectKeyName, connObjectKey),
- provision.isIgnoreCaseMatch(),
- MappingUtils.buildOperationOptions(new IteratorChain<>(
- MappingUtils.getPropagationItems(provision.getMapping().getItems()).iterator(),
- linkingMappingItems.iterator())));
-
- for (MappingItem item : linkingMappingItems) {
- Attribute attr = obj.getAttributeByName(item.getExtAttrName());
- if (attr == null) {
- virAttrCache.expire(task.getAnyType(), task.getEntityKey(), item.getIntAttrName());
- } else {
- virAttrCache.put(
- task.getAnyType(),
- task.getEntityKey(),
- item.getIntAttrName(),
- new VirAttrCacheValue(attr.getValue()));
- }
- }
- } catch (TimeoutException toe) {
- LOG.debug("Request timeout", toe);
- throw toe;
- } catch (RuntimeException ignore) {
- LOG.debug("While resolving {}", connObjectKey, ignore);
- }
+ List<ConnectorObject> matches = outboundMatcher.match(task, connector, provision, connObjectKeyValue);
+ LOG.debug("Found for propagation task {}: {}", task, matches);
- return obj;
+ return matches.isEmpty() ? null : matches.get(0);
}
/**
@@ -698,11 +650,12 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
Optional<? extends OrgUnitItem> connObjectKeyItem = orgUnit.getConnObjectKeyItem();
if (connObjectKeyItem.isPresent()) {
try {
- obj = connector.getObject(new ObjectClass(task.getObjectClassName()),
+ obj = connector.getObject(
+ new ObjectClass(task.getObjectClassName()),
AttributeBuilder.build(connObjectKeyItem.get().getExtAttrName(), connObjectKey),
orgUnit.isIgnoreCaseMatch(),
MappingUtils.buildOperationOptions(
- MappingUtils.getPropagationItems(orgUnit.getItems()).iterator()));
+ MappingUtils.getPropagationItems(orgUnit.getItems().stream())));
} catch (TimeoutException toe) {
LOG.debug("Request timeout", toe);
throw toe;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java
index 24a2f50..b96cc3a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AzurePropagationActions.java
@@ -35,7 +35,7 @@ import org.springframework.transaction.annotation.Transactional;
* This class is required during setup of an External Resource based on the ConnId
* <a href="https://github.com/Tirasa/ConnIdAzureBundle">Azure connector</a>.
*
- * It ensures to send the configured e-mail address as <pre>__NAME__</pre>.
+ * It ensures to send the configured e-mail address as {@code __NAME__}.
*/
public class AzurePropagationActions implements PropagationActions {
@@ -70,7 +70,7 @@ public class AzurePropagationActions implements PropagationActions {
Set<Attribute> attrs = new HashSet<>(task.getAttributes());
if (AttributeUtil.find(getEmailAttrName(), attrs) == null) {
- LOG.warn("Can't find {} attribute to set as __NAME__ attribute value, skipping...", getEmailAttrName());
+ LOG.warn("Can't find {} to set as {} attribute value, skipping...", getEmailAttrName(), Name.NAME);
return;
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
index 53b9fe8..5fbb4b0 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
@@ -59,11 +59,11 @@ public class DefaultPropagationReporter implements PropagationReporter {
status.setFailureReason(failureReason);
if (beforeObj != null) {
- status.setBeforeObj(ConnObjectUtils.getConnObjectTO(beforeObj));
+ status.setBeforeObj(ConnObjectUtils.getConnObjectTO(beforeObj.getAttributes()));
}
if (afterObj != null) {
- status.setAfterObj(ConnObjectUtils.getConnObjectTO(afterObj));
+ status.setAfterObj(ConnObjectUtils.getConnObjectTO(afterObj.getAttributes()));
}
add(status);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
index 0f1ff74..a106842 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/GoogleAppsPropagationActions.java
@@ -36,7 +36,7 @@ import org.springframework.transaction.annotation.Transactional;
* This class is required during setup of an External Resource based on the ConnId
* <a href="https://github.com/Tirasa/ConnIdGoogleAppsBundle">GoogleApps connector</a>.
*
- * It ensures to send the configured e-mail address as <pre>__NAME__</pre>.
+ * It ensures to send the configured e-mail address as {@code __NAME__}.
*/
public class GoogleAppsPropagationActions implements PropagationActions {
@@ -59,7 +59,7 @@ public class GoogleAppsPropagationActions implements PropagationActions {
Set<Attribute> attrs = new HashSet<>(task.getAttributes());
if (AttributeUtil.find(getEmailAttrName(), attrs) == null) {
- LOG.warn("Can't find {} attribute to set as __NAME__ attribute value, skipping...", getEmailAttrName());
+ LOG.warn("Can't find {} to set as {} attribute value, skipping...", getEmailAttrName(), Name.NAME);
return;
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
index 47957d6..1c38712 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.provisioning.java.propagation;
+import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.Attr;
@@ -393,7 +394,7 @@ public class PropagationManagerImpl implements PropagationManager {
final ResourceOperation operation,
final Provision provision,
final boolean deleteOnResource,
- final List<? extends Item> mappingItems,
+ final Stream<? extends Item> mappingItems,
final Pair<String, Set<Attribute>> preparedAttrs) {
PropagationTaskInfo task = new PropagationTaskInfo();
@@ -411,7 +412,7 @@ public class PropagationManagerImpl implements PropagationManager {
// if so, add special attributes that will be evaluated by PropagationTaskExecutor
List<String> mandatoryMissing = new ArrayList<>();
List<String> mandatoryNullOrEmpty = new ArrayList<>();
- mappingItems.stream().filter(item -> (!item.isConnObjectKey()
+ mappingItems.filter(item -> (!item.isConnObjectKey()
&& JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any))).forEach(item -> {
Attribute attr = AttributeUtil.find(item.getExtAttrName(), preparedAttrs.getRight());
@@ -507,16 +508,16 @@ public class PropagationManagerImpl implements PropagationManager {
Provision provision = Optional.ofNullable(resource).
map(externalResource -> externalResource.getProvision(any.getType()).
orElse(null)).orElse(null);
- List<? extends Item> mappingItems = provision == null
- ? List.of()
- : MappingUtils.getPropagationItems(provision.getMapping().getItems());
+ Stream<? extends Item> mappingItems = provision == null
+ ? Stream.empty()
+ : MappingUtils.getPropagationItems(provision.getMapping().getItems().stream());
if (resource == null) {
LOG.error("Invalid resource name specified: {}, ignoring...", resourceKey);
} else if (provision == null) {
LOG.error("No provision specified on resource {} for type {}, ignoring...",
resource, any.getType());
- } else if (mappingItems.isEmpty()) {
+ } else if (provision.getMapping() == null || provision.getMapping().getItems().isEmpty()) {
LOG.warn("Requesting propagation for {} but no propagation mapping provided for {}",
any.getType(), resource);
} else {
@@ -553,9 +554,9 @@ public class PropagationManagerImpl implements PropagationManager {
Provision provision = account == null || account.getResource() == null
? null
: account.getResource().getProvision(AnyTypeKind.USER.name()).orElse(null);
- List<? extends Item> mappingItems = provision == null
- ? List.of()
- : MappingUtils.getPropagationItems(provision.getMapping().getItems());
+ Stream<? extends Item> mappingItems = provision == null
+ ? Stream.empty()
+ : MappingUtils.getPropagationItems(provision.getMapping().getItems().stream());
if (account == null) {
LOG.error("Invalid operation {} on deleted account {} on resource {}, ignoring...",
@@ -565,7 +566,7 @@ public class PropagationManagerImpl implements PropagationManager {
} else if (provision == null) {
LOG.error("No provision specified on resource {} for type {}, ignoring...",
account.getResource(), AnyTypeKind.USER.name());
- } else if (mappingItems.isEmpty()) {
+ } else if (provision.getMapping() == null || provision.getMapping().getItems().isEmpty()) {
LOG.warn("Requesting propagation for {} but no propagation mapping provided for {}",
AnyTypeKind.USER.name(), account.getResource());
} else {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/ADMembershipPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/ADMembershipPullActions.java
index db1b6ac..7229f07 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/ADMembershipPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/ADMembershipPullActions.java
@@ -18,8 +18,6 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull;
-import java.util.Optional;
-import org.apache.syncope.common.lib.types.ConnConfProperty;
import org.apache.syncope.core.provisioning.api.Connector;
/**
@@ -38,14 +36,10 @@ public class ADMembershipPullActions extends LDAPMembershipPullActions {
*/
@Override
protected String getGroupMembershipAttrName(final Connector connector) {
- Optional<ConnConfProperty> groupMembership = connector.getConnInstance().getConf().stream().
+ return connector.getConnInstance().getConf().stream().
filter(property -> "groupMemberReferenceAttribute".equals(property.getSchema().getName())
- && !property.getValues().isEmpty()).
- findFirst();
-
- return groupMembership.isPresent()
- ? (String) groupMembership.get().getValues().get(0)
- : "member";
+ && !property.getValues().isEmpty()).findFirst().
+ map(groupMembership -> (String) groupMembership.getValues().get(0)).
+ orElse("member");
}
-
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
index 5097e9e..7afe3a5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
@@ -30,8 +30,10 @@ import org.apache.syncope.common.lib.request.AnyCR;
import org.apache.syncope.common.lib.request.AnyUR;
import org.apache.syncope.common.lib.request.StringPatchItem;
import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.common.lib.types.AuditElements.Result;
+import org.apache.syncope.common.lib.types.MatchType;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.core.provisioning.api.PropagationByResource;
@@ -44,7 +46,6 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
-import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
import org.apache.syncope.core.persistence.api.entity.Remediation;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
@@ -69,17 +70,12 @@ import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
-import javax.annotation.Resource;
-
@Transactional(rollbackFor = Throwable.class)
public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHandler<PullTask, PullActions>
implements SyncopePullResultHandler {
- @Resource(name = "adminUser")
- protected String adminUser;
-
@Autowired
- protected PullUtils pullUtils;
+ protected InboundMatcher inboundMatcher;
@Autowired
protected NotificationManager notificationManager;
@@ -130,8 +126,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
try {
provision = profile.getTask().getResource().getProvision(delta.getObject().getObjectClass()).
orElseThrow(() -> new JobExecutionException(
- "No provision found on " + profile.getTask().getResource() + " for "
- + delta.getObject().getObjectClass()));
+ "No provision found on " + profile.getTask().getResource()
+ + " for " + delta.getObject().getObjectClass()));
doHandle(delta, provision);
executor.reportHandled(delta.getObjectClass(), delta.getObject().getName());
@@ -188,16 +184,15 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
protected List<ProvisioningReport> provision(
final UnmatchingRule rule,
final SyncDelta delta,
- final Provision provision,
- final AnyUtils anyUtils) throws JobExecutionException {
+ final Provision provision) throws JobExecutionException {
if (!profile.getTask().isPerformCreate()) {
LOG.debug("PullTask not configured for create");
- finalize(UnmatchingRule.toEventName(rule), Result.SUCCESS, null, null, delta);
- return List.of();
+ end(provision.getAnyType().getKind(), UnmatchingRule.toEventName(rule), Result.SUCCESS, null, null, delta);
+ return Collections.<ProvisioningReport>emptyList();
}
- AnyCR anyCR = connObjectUtils.getAnyCR(delta.getObject(), profile.getTask(), provision, anyUtils, true);
+ AnyCR anyCR = connObjectUtils.getAnyCR(delta.getObject(), profile.getTask(), provision, true);
if (rule == UnmatchingRule.ASSIGN) {
anyCR.getResources().add(profile.getTask().getResource().getKey());
}
@@ -211,7 +206,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
if (profile.isDryRun()) {
result.setKey(null);
- finalize(UnmatchingRule.toEventName(rule), Result.SUCCESS, null, null, delta);
+ end(provision.getAnyType().getKind(), UnmatchingRule.toEventName(rule), Result.SUCCESS, null, null, delta);
} else {
for (PullActions action : profile.getActions()) {
if (rule == UnmatchingRule.ASSIGN) {
@@ -266,7 +261,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
}
}
- finalize(UnmatchingRule.toEventName(rule), resultStatus, null, output, delta);
+ end(provision.getAnyType().getKind(), UnmatchingRule.toEventName(rule), resultStatus, null, output, delta);
}
return Collections.singletonList(result);
@@ -297,7 +292,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
if (!profile.getTask().isPerformUpdate()) {
LOG.debug("PullTask not configured for update");
- finalize(MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta);
+ end(provision.getAnyType().getKind(),
+ MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta);
return Collections.<ProvisioningReport>emptyList();
}
@@ -312,9 +308,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
result.setOperation(ResourceOperation.UPDATE);
result.setAnyType(provision.getAnyType().getKey());
result.setStatus(ProvisioningReport.Status.SUCCESS);
- result.setKey(match.getMatchingKey());
+ result.setKey(match.getAny().getKey());
- AnyTO before = getAnyTO(match.getMatchingKey());
+ AnyTO before = getAnyTO(match.getAny());
if (before == null) {
result.setStatus(ProvisioningReport.Status.FAILURE);
result.setMessage(String.format("Any '%s(%s)' not found", provision.getAnyType().getKey(), match));
@@ -338,8 +334,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
delta.getObject(),
before,
profile.getTask(),
- provision,
- getAnyUtils());
+ provision);
for (PullActions action : profile.getActions()) {
action.beforeUpdate(profile, delta, before, anyUR);
@@ -388,7 +383,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
}
}
}
- finalize(MatchingRule.toEventName(MatchingRule.UPDATE),
+ end(provision.getAnyType().getKind(),
+ MatchingRule.toEventName(MatchingRule.UPDATE),
resultStatus, before, output, delta, effectiveReq);
}
results.add(result);
@@ -405,7 +401,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
if (!profile.getTask().isPerformUpdate()) {
LOG.debug("PullTask not configured for update");
- finalize(MatchingRule.toEventName(matchingRule), Result.SUCCESS, null, null, delta);
+ end(provision.getAnyType().getKind(),
+ MatchingRule.toEventName(matchingRule), Result.SUCCESS, null, null, delta);
return Collections.<ProvisioningReport>emptyList();
}
@@ -420,9 +417,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
result.setOperation(ResourceOperation.DELETE);
result.setAnyType(provision.getAnyType().getKey());
result.setStatus(ProvisioningReport.Status.SUCCESS);
- result.setKey(match.getMatchingKey());
+ result.setKey(match.getAny().getKey());
- AnyTO before = getAnyTO(match.getMatchingKey());
+ AnyTO before = getAnyTO(match.getAny());
if (before == null) {
result.setStatus(ProvisioningReport.Status.FAILURE);
@@ -455,22 +452,22 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
taskExecutor.execute(propagationManager.getDeleteTasks(
provision.getAnyType().getKind(),
- match.getMatchingKey(),
+ match.getAny().getKey(),
propByRes,
null,
null),
false,
- this.adminUser);
+ adminUser);
AnyUR anyUR = null;
if (matchingRule == MatchingRule.UNASSIGN) {
- anyUR = getAnyUtils().newAnyUR(match.getMatchingKey());
+ anyUR = getAnyUtils().newAnyUR(match.getAny().getKey());
anyUR.getResources().add(new StringPatchItem.Builder().
operation(PatchOperation.DELETE).
value(profile.getTask().getResource().getKey()).build());
}
if (anyUR == null) {
- output = getAnyTO(match.getMatchingKey());
+ output = getAnyTO(match.getAny());
} else {
output = doUpdate(before, anyUR, delta, result);
}
@@ -500,7 +497,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
resultStatus = Result.FAILURE;
}
}
- finalize(MatchingRule.toEventName(matchingRule), resultStatus, before, output, delta);
+ end(provision.getAnyType().getKind(),
+ MatchingRule.toEventName(matchingRule), resultStatus, before, output, delta);
}
results.add(result);
}
@@ -517,9 +515,11 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
if (!profile.getTask().isPerformUpdate()) {
LOG.debug("PullTask not configured for update");
- finalize(unlink
- ? MatchingRule.toEventName(MatchingRule.UNLINK)
- : MatchingRule.toEventName(MatchingRule.LINK), Result.SUCCESS, null, null, delta);
+ end(provision.getAnyType().getKind(),
+ unlink
+ ? MatchingRule.toEventName(MatchingRule.UNLINK)
+ : MatchingRule.toEventName(MatchingRule.LINK),
+ Result.SUCCESS, null, null, delta);
return Collections.<ProvisioningReport>emptyList();
}
@@ -534,9 +534,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
result.setOperation(ResourceOperation.NONE);
result.setAnyType(provision.getAnyType().getKey());
result.setStatus(ProvisioningReport.Status.SUCCESS);
- result.setKey(match.getMatchingKey());
+ result.setKey(match.getAny().getKey());
- AnyTO before = getAnyTO(match.getMatchingKey());
+ AnyTO before = getAnyTO(match.getAny());
if (before == null) {
result.setStatus(ProvisioningReport.Status.FAILURE);
@@ -598,9 +598,10 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
resultStatus = Result.FAILURE;
}
}
- finalize(unlink
- ? MatchingRule.toEventName(MatchingRule.UNLINK)
- : MatchingRule.toEventName(MatchingRule.LINK),
+ end(provision.getAnyType().getKind(),
+ unlink
+ ? MatchingRule.toEventName(MatchingRule.UNLINK)
+ : MatchingRule.toEventName(MatchingRule.LINK),
resultStatus, before, output, delta, effectiveReq);
}
results.add(result);
@@ -617,7 +618,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
if (!profile.getTask().isPerformDelete()) {
LOG.debug("PullTask not configured for delete");
- finalize(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta);
+ end(provision.getAnyType().getKind(),
+ ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta);
return Collections.<ProvisioningReport>emptyList();
}
@@ -632,9 +634,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
ProvisioningReport result = new ProvisioningReport();
try {
- AnyTO before = getAnyTO(match.getMatchingKey());
+ AnyTO before = getAnyTO(match.getAny());
- result.setKey(match.getMatchingKey());
+ result.setKey(match.getAny().getKey());
result.setName(getName(before));
result.setOperation(ResourceOperation.DELETE);
result.setAnyType(provision.getAnyType().getKey());
@@ -647,7 +649,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
try {
getProvisioningManager().delete(
- match.getMatchingKey(),
+ match.getAny().getKey(),
Collections.singleton(profile.getTask().getResource().getKey()),
true);
output = null;
@@ -668,7 +670,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
Remediation entity = entityFactory.newEntity(Remediation.class);
entity.setAnyType(provision.getAnyType());
entity.setOperation(ResourceOperation.DELETE);
- entity.setPayload(match.getMatchingKey());
+ entity.setPayload(match.getAny().getKey());
entity.setError(result.getMessage());
entity.setInstant(new Date());
entity.setRemoteName(delta.getObject().getName().getNameValue());
@@ -678,7 +680,8 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
}
}
- finalize(ResourceOperation.DELETE.name().toLowerCase(), resultStatus, before, output, delta);
+ end(provision.getAnyType().getKind(),
+ ResourceOperation.DELETE.name().toLowerCase(), resultStatus, before, output, delta);
}
results.add(result);
@@ -721,7 +724,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
} else {
matches.forEach(match -> {
ProvisioningReport report = new ProvisioningReport();
- report.setKey(match.getMatchingKey());
+ report.setKey(match.getAny().getKey());
report.setName(delta.getObject().getUid().getUidValue());
report.setOperation(ResourceOperation.NONE);
report.setAnyType(provision.getAnyType().getKey());
@@ -734,9 +737,10 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
});
}
- finalize(matching
- ? MatchingRule.toEventName(MatchingRule.IGNORE)
- : UnmatchingRule.toEventName(UnmatchingRule.IGNORE), Result.SUCCESS, null, null, delta);
+ end(provision.getAnyType().getKind(),
+ matching
+ ? MatchingRule.toEventName(MatchingRule.IGNORE)
+ : UnmatchingRule.toEventName(UnmatchingRule.IGNORE), Result.SUCCESS, null, null, delta);
return results;
}
@@ -744,8 +748,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
protected void handleAnys(
final SyncDelta delta,
final List<PullMatch> matches,
- final Provision provision,
- final AnyUtils anyUtils) throws JobExecutionException {
+ final Provision provision) throws JobExecutionException {
if (matches.isEmpty()) {
LOG.debug("Nothing to do");
@@ -753,12 +756,12 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
}
if (SyncDeltaType.CREATE_OR_UPDATE == delta.getDeltaType()) {
- if (matches.get(0).getMatchingKey() == null) {
+ if (matches.get(0).getAny() == null) {
switch (profile.getTask().getUnmatchingRule()) {
case ASSIGN:
case PROVISION:
profile.getResults().addAll(
- provision(profile.getTask().getUnmatchingRule(), delta, provision, anyUtils));
+ provision(profile.getTask().getUnmatchingRule(), delta, provision));
break;
case IGNORE:
@@ -776,12 +779,12 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
if (attr == null) {
virAttrCache.expire(
provision.getAnyType().getKey(),
- match.getMatchingKey(),
+ match.getAny().getKey(),
virSchema.getKey());
} else {
virAttrCache.put(
provision.getAnyType().getKey(),
- match.getMatchingKey(),
+ match.getAny().getKey(),
virSchema.getKey(),
new VirAttrCacheValue(attr.getValue()));
}
@@ -823,8 +826,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
protected void handleLinkedAccounts(
final SyncDelta delta,
final List<PullMatch> matches,
- final Provision provision,
- final AnyUtils anyUtils) throws JobExecutionException {
+ final Provision provision) throws JobExecutionException {
if (matches.isEmpty()) {
LOG.debug("Nothing to do");
@@ -832,7 +834,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
}
// nothing to do in the general case
- LOG.warn("Unexpected linked accounts found for {}: {}", anyUtils.anyTypeKind(), matches);
+ LOG.warn("Unexpected linked accounts found for {}: {}", provision.getAnyType().getKind(), matches);
}
/**
@@ -843,8 +845,6 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
* @throws JobExecutionException in case of pull failure.
*/
protected void doHandle(final SyncDelta delta, final Provision provision) throws JobExecutionException {
- AnyUtils anyUtils = getAnyUtils();
-
LOG.debug("Process {} for {} as {}",
delta.getDeltaType(), delta.getUid().getUidValue(), delta.getObject().getObjectClass());
@@ -857,7 +857,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
finalDelta.getDeltaType(), finalDelta.getUid().getUidValue(), finalDelta.getObject().getObjectClass());
try {
- List<PullMatch> matches = pullUtils.match(finalDelta, provision, anyUtils);
+ List<PullMatch> matches = inboundMatcher.match(finalDelta, provision);
LOG.debug("Match(es) found for {} as {}: {}",
finalDelta.getUid().getUidValue(), finalDelta.getObject().getObjectClass(), matches);
@@ -884,23 +884,22 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
handleAnys(
finalDelta,
matches.stream().
- filter(match -> match.getMatchTarget() == PullMatch.MatchTarget.ANY).
- collect(Collectors.toList()), provision,
- anyUtils);
+ filter(match -> match.getMatchTarget() == MatchType.ANY).
+ collect(Collectors.toList()), provision);
// linked accounts
handleLinkedAccounts(
finalDelta,
matches.stream().
- filter(match -> match.getMatchTarget() == PullMatch.MatchTarget.LINKED_ACCOUNT).
- collect(Collectors.toList()), provision,
- anyUtils);
+ filter(match -> match.getMatchTarget() == MatchType.LINKED_ACCOUNT).
+ collect(Collectors.toList()), provision);
} catch (IllegalStateException | IllegalArgumentException e) {
LOG.warn(e.getMessage());
}
}
- protected void finalize(
+ protected void end(
+ final AnyTypeKind anyTypeKind,
final String event,
final Result result,
final Object before,
@@ -912,12 +911,10 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
this.latestResult = result;
}
- AnyUtils anyUtils = getAnyUtils();
-
notificationManager.createTasks(
AuthContextUtils.getUsername(),
AuditElements.EventCategoryType.PULL,
- anyUtils.anyTypeKind().name().toLowerCase(),
+ anyTypeKind.name().toLowerCase(),
profile.getTask().getResource().getKey(),
event,
result,
@@ -929,7 +926,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
auditManager.audit(
AuthContextUtils.getUsername(),
AuditElements.EventCategoryType.PULL,
- anyUtils.anyTypeKind().name().toLowerCase(),
+ anyTypeKind.name().toLowerCase(),
profile.getTask().getResource().getKey(),
event,
result,
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
index 73ced5d..f8a4e1b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
@@ -62,16 +62,11 @@ import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
-import javax.annotation.Resource;
-
public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHandler<PushTask, PushActions>
implements SyncopePushResultHandler {
@Autowired
- protected PushUtils pushUtils;
-
- @Resource(name = "adminUser")
- protected String adminUser;
+ protected OutboundMatcher outboundMatcher;
/**
* Notification Manager.
@@ -129,13 +124,13 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
if (!taskInfos.isEmpty()) {
taskInfos.get(0).setBeforeObj(Optional.of(beforeObj));
PropagationReporter reporter = new DefaultPropagationReporter();
- taskExecutor.execute(taskInfos.get(0), reporter, this.adminUser);
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
reportPropagation(result, reporter);
}
}
protected void deprovision(final Any<?> any, final ConnectorObject beforeObj, final ProvisioningReport result) {
- AnyTO before = getAnyTO(any.getKey());
+ AnyTO before = getAnyTO(any);
List<String> noPropResources = new ArrayList<>(before.getResources());
noPropResources.remove(profile.getTask().getResource().getKey());
@@ -153,13 +148,13 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
if (!taskInfos.isEmpty()) {
taskInfos.get(0).setBeforeObj(Optional.of(beforeObj));
PropagationReporter reporter = new DefaultPropagationReporter();
- taskExecutor.execute(taskInfos.get(0), reporter, this.adminUser);
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
reportPropagation(result, reporter);
}
}
protected void provision(final Any<?> any, final Boolean enable, final ProvisioningReport result) {
- AnyTO before = getAnyTO(any.getKey());
+ AnyTO before = getAnyTO(any);
List<String> noPropResources = new ArrayList<>(before.getResources());
noPropResources.remove(profile.getTask().getResource().getKey());
@@ -177,7 +172,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
if (!taskInfos.isEmpty()) {
taskInfos.get(0).setBeforeObj(Optional.ofNullable(null));
PropagationReporter reporter = new DefaultPropagationReporter();
- taskExecutor.execute(taskInfos.get(0), reporter, this.adminUser);
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
reportPropagation(result, reporter);
}
}
@@ -263,11 +258,11 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
result.setAnyType(any.getType().getKey());
result.setName(getName(any));
- LOG.debug("Propagating {} with key {} towards {}",
+ LOG.debug("Pushing {} with key {} towards {}",
any.getType().getKind(), any.getKey(), profile.getTask().getResource());
// Try to read remote object BEFORE any actual operation
- List<ConnectorObject> connObjs = pushUtils.match(profile.getConnector(), any, provision);
+ List<ConnectorObject> connObjs = outboundMatcher.match(profile.getConnector(), any, provision);
LOG.debug("Match(es) found for {} as {}: {}", any, provision.getObjectClass(), connObjs);
if (connObjs.size() > 1) {
@@ -460,7 +455,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
if (notificationsAvailable || auditRequested) {
resultStatus = AuditElements.Result.SUCCESS;
- output = pushUtils.findByConnObjectKey(profile.getConnector(), any, provision);
+ output = outboundMatcher.match(profile.getConnector(), any, provision);
}
} catch (IgnoreProvisionException e) {
throw e;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractRealmResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractRealmResultHandler.java
index e914ce3..35a1180 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractRealmResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractRealmResultHandler.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull;
+import javax.annotation.Resource;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
import org.apache.syncope.core.provisioning.api.AuditManager;
@@ -69,6 +70,9 @@ public abstract class AbstractRealmResultHandler<T extends ProvisioningTask, A e
@Autowired
protected PropagationTaskExecutor taskExecutor;
+ @Resource(name = "adminUser")
+ protected String adminUser;
+
/**
* Provisioning profile.
*/
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java
index b8b0df9..3b5e8f2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java
@@ -18,8 +18,12 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull;
+import javax.annotation.Resource;
import org.apache.syncope.common.lib.request.AnyUR;
import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
@@ -27,8 +31,6 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopeResultHandler;
-import org.apache.syncope.core.persistence.api.entity.AnyUtils;
-import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.provisioning.api.WorkflowResult;
import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningActions;
@@ -83,6 +85,9 @@ public abstract class AbstractSyncopeResultHandler<T extends ProvisioningTask, A
@Autowired
protected AnyUtilsFactory anyUtilsFactory;
+ @Resource(name = "adminUser")
+ protected String adminUser;
+
/**
* Provisioning profile.
*/
@@ -90,7 +95,7 @@ public abstract class AbstractSyncopeResultHandler<T extends ProvisioningTask, A
protected abstract AnyUtils getAnyUtils();
- protected abstract AnyTO getAnyTO(String key);
+ protected abstract AnyTO getAnyTO(Any<?> any);
protected abstract WorkflowResult<? extends AnyUR> update(AnyUR req);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java
index 6e728ae..a87fff4 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java
@@ -31,7 +31,9 @@ import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.to.PropagationStatus;
import org.apache.syncope.common.lib.to.AnyObjectTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
import org.apache.syncope.core.provisioning.api.ProvisioningManager;
import org.apache.syncope.core.provisioning.api.WorkflowResult;
@@ -66,8 +68,8 @@ public class DefaultAnyObjectPullResultHandler extends AbstractPullResultHandler
}
@Override
- protected AnyTO getAnyTO(final String key) {
- return anyObjectDataBinder.getAnyObjectTO(key);
+ protected AnyTO getAnyTO(final Any<?> any) {
+ return anyObjectDataBinder.getAnyObjectTO((AnyObject) any, true);
}
@Override
@@ -82,7 +84,7 @@ public class DefaultAnyObjectPullResultHandler extends AbstractPullResultHandler
Map.Entry<String, List<PropagationStatus>> created = anyObjectProvisioningManager.create(
anyObjectCR, Set.of(profile.getTask().getResource().getKey()), true);
- return getAnyTO(created.getKey());
+ return anyObjectDataBinder.getAnyObjectTO(created.getKey());
}
@Override
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java
index 98e4d6c..dc7ab63 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java
@@ -41,8 +41,8 @@ public class DefaultAnyObjectPushResultHandler extends AbstractPushResultHandler
}
@Override
- protected AnyTO getAnyTO(final String key) {
- return anyObjectDataBinder.getAnyObjectTO(key);
+ protected AnyTO getAnyTO(final Any<?> any) {
+ return anyObjectDataBinder.getAnyObjectTO((AnyObject) any, true);
}
@Override
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java
index 77a2363..96c765a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java
@@ -34,7 +34,9 @@ import org.apache.syncope.common.lib.to.PropagationStatus;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.PatchOperation;
+import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.provisioning.api.GroupProvisioningManager;
import org.apache.syncope.core.provisioning.api.ProvisioningManager;
import org.apache.syncope.core.provisioning.api.WorkflowResult;
@@ -76,8 +78,8 @@ public class DefaultGroupPullResultHandler extends AbstractPullResultHandler imp
}
@Override
- protected AnyTO getAnyTO(final String key) {
- return groupDataBinder.getGroupTO(key);
+ protected AnyTO getAnyTO(final Any<?> any) {
+ return groupDataBinder.getGroupTO((Group) any, true);
}
@Override
@@ -95,7 +97,7 @@ public class DefaultGroupPullResultHandler extends AbstractPullResultHandler imp
Set.of(profile.getTask().getResource().getKey()),
true);
- return getAnyTO(created.getKey());
+ return groupDataBinder.getGroupTO(created.getKey());
}
@Override
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java
index 39da94a..714711c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java
@@ -41,8 +41,8 @@ public class DefaultGroupPushResultHandler extends AbstractPushResultHandler imp
}
@Override
- protected AnyTO getAnyTO(final String key) {
- return groupDataBinder.getGroupTO(key);
+ protected AnyTO getAnyTO(final Any<?> any) {
+ return groupDataBinder.getGroupTO((Group) any, true);
}
@Override
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
index af39823..d275ea2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPullResultHandler.java
@@ -57,18 +57,13 @@ import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
-import javax.annotation.Resource;
-
@Transactional(rollbackFor = Throwable.class)
public class DefaultRealmPullResultHandler
extends AbstractRealmResultHandler<PullTask, PullActions>
implements RealmPullResultHandler {
- @Resource(name = "adminUser")
- protected String adminUser;
-
@Autowired
- private PullUtils pullUtils;
+ private InboundMatcher inboundMatcher;
@Autowired
private ConnObjectUtils connObjectUtils;
@@ -244,7 +239,7 @@ public class DefaultRealmPullResultHandler
propByRes.addAll(ResourceOperation.CREATE, realm.getResourceKeys());
if (unmatchingRule == UnmatchingRule.ASSIGN) {
List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
- taskExecutor.execute(taskInfos, false, this.adminUser);
+ taskExecutor.execute(taskInfos, false, adminUser);
}
RealmTO actual = binder.getRealmTO(realm, true);
@@ -279,7 +274,7 @@ public class DefaultRealmPullResultHandler
finalize(UnmatchingRule.toEventName(unmatchingRule), resultStatus, null, output, delta);
}
- private List<ProvisioningReport> update(final SyncDelta delta, final List<String> keys, final boolean inLink)
+ private List<ProvisioningReport> update(final SyncDelta delta, final List<Realm> realms, final boolean inLink)
throws JobExecutionException {
if (!profile.getTask().isPerformUpdate()) {
@@ -288,84 +283,74 @@ public class DefaultRealmPullResultHandler
return List.of();
}
- LOG.debug("About to update {}", keys);
+ LOG.debug("About to update {}", realms);
List<ProvisioningReport> results = new ArrayList<>();
- for (String key : keys) {
- LOG.debug("About to update {}", key);
+ for (Realm realm : realms) {
+ LOG.debug("About to update {}", realm);
ProvisioningReport result = new ProvisioningReport();
result.setOperation(ResourceOperation.UPDATE);
result.setAnyType(REALM_TYPE);
result.setStatus(ProvisioningReport.Status.SUCCESS);
- result.setKey(key);
-
- Realm realm = realmDAO.find(key);
- RealmTO before = binder.getRealmTO(realm, true);
- if (before == null) {
- result.setStatus(ProvisioningReport.Status.FAILURE);
- result.setMessage(String.format("Realm '%s' not found", key));
- } else {
- result.setName(before.getFullPath());
- }
+ result.setKey(realm.getKey());
+ result.setName(realm.getFullPath());
if (!profile.isDryRun()) {
Result resultStatus;
Object output;
- if (before == null) {
- resultStatus = Result.FAILURE;
- output = null;
- } else {
- try {
- if (!inLink) {
- for (PullActions action : profile.getActions()) {
- action.beforeUpdate(profile, delta, before, null);
- }
+ RealmTO before = binder.getRealmTO(realm, true);
+ try {
+ if (!inLink) {
+ for (PullActions action : profile.getActions()) {
+ action.beforeUpdate(profile, delta, before, null);
}
+ }
- PropagationByResource<String> propByRes = binder.update(realm, before);
- realm = realmDAO.save(realm);
- RealmTO updated = binder.getRealmTO(realm, true);
+ PropagationByResource<String> propByRes = binder.update(realm, before);
+ realm = realmDAO.save(realm);
+ RealmTO updated = binder.getRealmTO(realm, true);
- List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
- taskExecutor.execute(taskInfos, false, this.adminUser);
+ List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
+ taskExecutor.execute(taskInfos, false, adminUser);
- for (PullActions action : profile.getActions()) {
- action.after(profile, delta, updated, result);
- }
+ for (PullActions action : profile.getActions()) {
+ action.after(profile, delta, updated, result);
+ }
- output = updated;
- resultStatus = Result.SUCCESS;
- result.setName(updated.getFullPath());
+ output = updated;
+ resultStatus = Result.SUCCESS;
+ result.setName(updated.getFullPath());
- LOG.debug("{} successfully updated", updated);
- } catch (PropagationException e) {
- // A propagation failure doesn't imply a pull failure.
- // The propagation exception status will be reported into the propagation task execution.
- LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
- output = e;
- resultStatus = Result.FAILURE;
- } catch (Exception e) {
- throwIgnoreProvisionException(delta, e);
+ LOG.debug("{} successfully updated", updated);
+ } catch (PropagationException e) {
+ // A propagation failure doesn't imply a pull failure.
+ // The propagation exception status will be reported into the propagation task execution.
+ LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
+ output = e;
+ resultStatus = Result.FAILURE;
+ } catch (Exception e) {
+ throwIgnoreProvisionException(delta, e);
- result.setStatus(ProvisioningReport.Status.FAILURE);
- result.setMessage(ExceptionUtils.getRootCauseMessage(e));
- LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
- output = e;
- resultStatus = Result.FAILURE;
- }
+ result.setStatus(ProvisioningReport.Status.FAILURE);
+ result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+ LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
+ output = e;
+ resultStatus = Result.FAILURE;
}
+
finalize(MatchingRule.toEventName(MatchingRule.UPDATE), resultStatus, before, output, delta);
}
+
results.add(result);
}
return results;
}
- private List<ProvisioningReport> deprovision(final SyncDelta delta, final List<String> keys, final boolean unlink)
+ private List<ProvisioningReport> deprovision(final SyncDelta delta, final List<Realm> realms, final boolean unlink)
throws JobExecutionException {
if (!profile.getTask().isPerformUpdate()) {
@@ -376,95 +361,84 @@ public class DefaultRealmPullResultHandler
return List.of();
}
- LOG.debug("About to deprovision {}", keys);
+ LOG.debug("About to deprovision {}", realms);
final List<ProvisioningReport> results = new ArrayList<>();
- for (String key : keys) {
- LOG.debug("About to unassign resource {}", key);
+ for (Realm realm : realms) {
+ LOG.debug("About to unassign resource {}", realm);
ProvisioningReport result = new ProvisioningReport();
result.setOperation(ResourceOperation.DELETE);
result.setAnyType(REALM_TYPE);
result.setStatus(ProvisioningReport.Status.SUCCESS);
- result.setKey(key);
-
- Realm realm = realmDAO.find(key);
- RealmTO before = binder.getRealmTO(realm, true);
- if (before == null) {
- result.setStatus(ProvisioningReport.Status.FAILURE);
- result.setMessage(String.format("Realm '%s' not found", key));
- } else {
- result.setName(before.getFullPath());
- }
+ result.setKey(realm.getKey());
+ result.setName(realm.getFullPath());
if (!profile.isDryRun()) {
Object output;
Result resultStatus;
- if (before == null) {
- resultStatus = Result.FAILURE;
- output = null;
- } else {
- try {
- if (unlink) {
- for (PullActions action : profile.getActions()) {
- action.beforeUnassign(profile, delta, before);
- }
- } else {
- for (PullActions action : profile.getActions()) {
- action.beforeDeprovision(profile, delta, before);
- }
- }
-
- PropagationByResource<String> propByRes = new PropagationByResource<>();
- propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey());
- taskExecutor.execute(propagationManager.createTasks(realm, propByRes, null),
- false, this.adminUser);
-
- RealmTO realmTO;
- if (unlink) {
- realm.getResources().remove(profile.getTask().getResource());
- realmTO = binder.getRealmTO(realmDAO.save(realm), true);
- } else {
- realmTO = binder.getRealmTO(realm, true);
+ RealmTO before = binder.getRealmTO(realm, true);
+ try {
+ if (unlink) {
+ for (PullActions action : profile.getActions()) {
+ action.beforeUnassign(profile, delta, before);
}
- output = realmTO;
-
+ } else {
for (PullActions action : profile.getActions()) {
- action.after(profile, delta, realmTO, result);
+ action.beforeDeprovision(profile, delta, before);
}
+ }
- resultStatus = Result.SUCCESS;
+ PropagationByResource<String> propByRes = new PropagationByResource<>();
+ propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey());
+ taskExecutor.execute(propagationManager.createTasks(realm, propByRes, null), false, adminUser);
- LOG.debug("{} successfully updated", realm);
- } catch (PropagationException e) {
- // A propagation failure doesn't imply a pull failure.
- // The propagation exception status will be reported into the propagation task execution.
- LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
- output = e;
- resultStatus = Result.FAILURE;
- } catch (Exception e) {
- throwIgnoreProvisionException(delta, e);
+ RealmTO realmTO;
+ if (unlink) {
+ realm.getResources().remove(profile.getTask().getResource());
+ realmTO = binder.getRealmTO(realmDAO.save(realm), true);
+ } else {
+ realmTO = binder.getRealmTO(realm, true);
+ }
+ output = realmTO;
- result.setStatus(ProvisioningReport.Status.FAILURE);
- result.setMessage(ExceptionUtils.getRootCauseMessage(e));
- LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
- output = e;
- resultStatus = Result.FAILURE;
+ for (PullActions action : profile.getActions()) {
+ action.after(profile, delta, realmTO, result);
}
+
+ resultStatus = Result.SUCCESS;
+
+ LOG.debug("{} successfully updated", realm);
+ } catch (PropagationException e) {
+ // A propagation failure doesn't imply a pull failure.
+ // The propagation exception status will be reported into the propagation task execution.
+ LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
+ output = e;
+ resultStatus = Result.FAILURE;
+ } catch (Exception e) {
+ throwIgnoreProvisionException(delta, e);
+
+ result.setStatus(ProvisioningReport.Status.FAILURE);
+ result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+ LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
+ output = e;
+ resultStatus = Result.FAILURE;
}
+
finalize(unlink
? MatchingRule.toEventName(MatchingRule.UNASSIGN)
: MatchingRule.toEventName(MatchingRule.DEPROVISION), resultStatus, before, output, delta);
}
+
results.add(result);
}
return results;
}
- private List<ProvisioningReport> link(final SyncDelta delta, final List<String> keys, final boolean unlink)
+ private List<ProvisioningReport> link(final SyncDelta delta, final List<Realm> realms, final boolean unlink)
throws JobExecutionException {
if (!profile.getTask().isPerformUpdate()) {
@@ -475,72 +449,62 @@ public class DefaultRealmPullResultHandler
return List.of();
}
- LOG.debug("About to link {}", keys);
+ LOG.debug("About to link {}", realms);
final List<ProvisioningReport> results = new ArrayList<>();
- for (String key : keys) {
- LOG.debug("About to unassign resource {}", key);
+ for (Realm realm : realms) {
+ LOG.debug("About to unassign resource {}", realm);
ProvisioningReport result = new ProvisioningReport();
result.setOperation(ResourceOperation.NONE);
result.setAnyType(REALM_TYPE);
result.setStatus(ProvisioningReport.Status.SUCCESS);
- result.setKey(key);
-
- Realm realm = realmDAO.find(key);
- RealmTO before = binder.getRealmTO(realm, true);
- if (before == null) {
- result.setStatus(ProvisioningReport.Status.FAILURE);
- result.setMessage(String.format("Realm '%s' not found", key));
- } else {
- result.setName(before.getFullPath());
- }
+ result.setKey(realm.getKey());
+ result.setName(realm.getFullPath());
- Object output;
- Result resultStatus;
if (!profile.isDryRun()) {
- if (before == null) {
- resultStatus = Result.FAILURE;
- output = null;
- } else {
- try {
- if (unlink) {
- for (PullActions action : profile.getActions()) {
- action.beforeUnlink(profile, delta, before);
- }
- } else {
- for (PullActions action : profile.getActions()) {
- action.beforeLink(profile, delta, before);
- }
- }
+ Object output;
+ Result resultStatus;
- if (unlink) {
- realm.getResources().remove(profile.getTask().getResource());
- } else {
- realm.add(profile.getTask().getResource());
+ RealmTO before = binder.getRealmTO(realm, true);
+ try {
+ if (unlink) {
+ for (PullActions action : profile.getActions()) {
+ action.beforeUnlink(profile, delta, before);
}
- output = update(delta, List.of(key), true);
+ } else {
+ for (PullActions action : profile.getActions()) {
+ action.beforeLink(profile, delta, before);
+ }
+ }
- resultStatus = Result.SUCCESS;
+ if (unlink) {
+ realm.getResources().remove(profile.getTask().getResource());
+ } else {
+ realm.add(profile.getTask().getResource());
+ }
+ output = update(delta, List.of(realm), true);
- LOG.debug("{} successfully updated", realm);
- } catch (PropagationException e) {
- // A propagation failure doesn't imply a pull failure.
- // The propagation exception status will be reported into the propagation task execution.
- LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
- output = e;
- resultStatus = Result.FAILURE;
- } catch (Exception e) {
- throwIgnoreProvisionException(delta, e);
+ resultStatus = Result.SUCCESS;
- result.setStatus(ProvisioningReport.Status.FAILURE);
- result.setMessage(ExceptionUtils.getRootCauseMessage(e));
- LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
- output = e;
- resultStatus = Result.FAILURE;
- }
+ LOG.debug("{} successfully updated", realm);
+ } catch (PropagationException e) {
+ // A propagation failure doesn't imply a pull failure.
+ // The propagation exception status will be reported into the propagation task execution.
+ LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
+ output = e;
+ resultStatus = Result.FAILURE;
+ } catch (Exception e) {
+ throwIgnoreProvisionException(delta, e);
+
+ result.setStatus(ProvisioningReport.Status.FAILURE);
+ result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+ LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
+ output = e;
+ resultStatus = Result.FAILURE;
}
+
finalize(unlink
? MatchingRule.toEventName(MatchingRule.UNLINK)
: MatchingRule.toEventName(MatchingRule.LINK), resultStatus, before, output, delta);
@@ -551,7 +515,7 @@ public class DefaultRealmPullResultHandler
return results;
}
- private List<ProvisioningReport> delete(final SyncDelta delta, final List<String> keys)
+ private List<ProvisioningReport> delete(final SyncDelta delta, final List<Realm> realms)
throws JobExecutionException {
if (!profile.getTask().isPerformDelete()) {
@@ -560,31 +524,24 @@ public class DefaultRealmPullResultHandler
return List.of();
}
- LOG.debug("About to delete {}", keys);
+ LOG.debug("About to delete {}", realms);
List<ProvisioningReport> results = new ArrayList<>();
- for (String key : keys) {
+ realms.forEach(realm -> {
Object output;
Result resultStatus = Result.FAILURE;
ProvisioningReport result = new ProvisioningReport();
+ RealmTO before = binder.getRealmTO(realm, true);
try {
- result.setKey(key);
+ result.setKey(realm.getKey());
+ result.setName(realm.getFullPath());
result.setOperation(ResourceOperation.DELETE);
result.setAnyType(REALM_TYPE);
result.setStatus(ProvisioningReport.Status.SUCCESS);
- Realm realm = realmDAO.find(key);
- RealmTO before = binder.getRealmTO(realm, true);
- if (before == null) {
- result.setStatus(ProvisioningReport.Status.FAILURE);
- result.setMessage(String.format("Realm '%s' not found", key));
- } else {
- result.setName(before.getFullPath());
- }
-
if (!profile.isDryRun()) {
for (PullActions action : profile.getActions()) {
action.beforeDelete(profile, delta, before);
@@ -615,7 +572,7 @@ public class DefaultRealmPullResultHandler
PropagationByResource<String> propByRes = new PropagationByResource<>();
propByRes.addAll(ResourceOperation.DELETE, realm.getResourceKeys());
List<PropagationTaskInfo> taskInfos = propagationManager.createTasks(realm, propByRes, null);
- taskExecutor.execute(taskInfos, false, this.adminUser);
+ taskExecutor.execute(taskInfos, false, adminUser);
realmDAO.delete(realm);
@@ -639,20 +596,16 @@ public class DefaultRealmPullResultHandler
results.add(result);
} catch (DelegatedAdministrationException e) {
- LOG.error("Not allowed to read Realm {}", key, e);
+ LOG.error("Not allowed to read Realm {}", realm, e);
} catch (Exception e) {
- LOG.error("Could not delete Realm {}", key, e);
+ LOG.error("Could not delete Realm {}", realm, e);
}
- }
+ });
return results;
}
- private ProvisioningReport ignore(
- final SyncDelta delta,
- final boolean matching)
- throws JobExecutionException {
-
+ private ProvisioningReport ignore(final SyncDelta delta, final boolean matching) throws JobExecutionException {
LOG.debug("Any to ignore {}", delta.getObject().getUid().getUidValue());
ProvisioningReport result = new ProvisioningReport();
@@ -684,22 +637,22 @@ public class DefaultRealmPullResultHandler
LOG.debug("Transformed {} for {} as {}",
finalDelta.getDeltaType(), finalDelta.getUid().getUidValue(), finalDelta.getObject().getObjectClass());
- List<String> keys = pullUtils.match(finalDelta, orgUnit);
+ List<Realm> realms = inboundMatcher.match(finalDelta, orgUnit);
LOG.debug("Match found for {} as {}: {}",
- finalDelta.getUid().getUidValue(), finalDelta.getObject().getObjectClass(), keys);
+ finalDelta.getUid().getUidValue(), finalDelta.getObject().getObjectClass(), realms);
- if (keys.size() > 1) {
+ if (realms.size() > 1) {
switch (profile.getConflictResolutionAction()) {
case IGNORE:
throw new IgnoreProvisionException("More than one match found for "
- + finalDelta.getObject().getUid().getUidValue() + ": " + keys);
+ + finalDelta.getObject().getUid().getUidValue() + ": " + realms);
case FIRSTMATCH:
- keys = keys.subList(0, 1);
+ realms = realms.subList(0, 1);
break;
case LASTMATCH:
- keys = keys.subList(keys.size() - 1, keys.size());
+ realms = realms.subList(realms.size() - 1, realms.size());
break;
default:
@@ -709,7 +662,7 @@ public class DefaultRealmPullResultHandler
try {
if (SyncDeltaType.CREATE_OR_UPDATE == finalDelta.getDeltaType()) {
- if (keys.isEmpty()) {
+ if (realms.isEmpty()) {
switch (profile.getTask().getUnmatchingRule()) {
case ASSIGN:
profile.getResults().addAll(assign(finalDelta, orgUnit));
@@ -729,23 +682,23 @@ public class DefaultRealmPullResultHandler
} else {
switch (profile.getTask().getMatchingRule()) {
case UPDATE:
- profile.getResults().addAll(update(finalDelta, keys, false));
+ profile.getResults().addAll(update(finalDelta, realms, false));
break;
case DEPROVISION:
- profile.getResults().addAll(deprovision(finalDelta, keys, false));
+ profile.getResults().addAll(deprovision(finalDelta, realms, false));
break;
case UNASSIGN:
- profile.getResults().addAll(deprovision(finalDelta, keys, true));
+ profile.getResults().addAll(deprovision(finalDelta, realms, true));
break;
case LINK:
- profile.getResults().addAll(link(finalDelta, keys, false));
+ profile.getResults().addAll(link(finalDelta, realms, false));
break;
case UNLINK:
- profile.getResults().addAll(link(finalDelta, keys, true));
+ profile.getResults().addAll(link(finalDelta, realms, true));
break;
case IGNORE:
@@ -757,11 +710,11 @@ public class DefaultRealmPullResultHandler
}
}
} else if (SyncDeltaType.DELETE == finalDelta.getDeltaType()) {
- if (keys.isEmpty()) {
+ if (realms.isEmpty()) {
finalize(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, finalDelta);
LOG.debug("No match found for deletion");
} else {
- profile.getResults().addAll(delete(finalDelta, keys));
+ profile.getResults().addAll(delete(finalDelta, realms));
}
}
} catch (IllegalStateException | IllegalArgumentException e) {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java
index 1460e6a..3576c8c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultRealmPushResultHandler.java
@@ -20,10 +20,10 @@ package org.apache.syncope.core.provisioning.java.pushpull;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.stream.Stream;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.syncope.common.lib.to.RealmTO;
import org.apache.syncope.common.lib.types.AuditElements;
@@ -60,15 +60,10 @@ import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
-import javax.annotation.Resource;
-
public class DefaultRealmPushResultHandler
extends AbstractRealmResultHandler<PushTask, PushActions>
implements RealmPushResultHandler {
- @Resource(name = "adminUser")
- protected String adminUser;
-
@Autowired
private MappingManager mappingManager;
@@ -115,7 +110,7 @@ public class DefaultRealmPushResultHandler
if (!taskInfos.isEmpty()) {
taskInfos.get(0).setBeforeObj(Optional.ofNullable(beforeObj));
PropagationReporter reporter = new DefaultPropagationReporter();
- taskExecutor.execute(taskInfos.get(0), reporter, this.adminUser);
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
reportPropagation(result, reporter);
}
@@ -133,7 +128,7 @@ public class DefaultRealmPushResultHandler
if (!taskInfos.isEmpty()) {
taskInfos.get(0).setBeforeObj(Optional.ofNullable(beforeObj));
PropagationReporter reporter = new DefaultPropagationReporter();
- taskExecutor.execute(taskInfos.get(0), reporter, this.adminUser);
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
reportPropagation(result, reporter);
}
}
@@ -146,7 +141,7 @@ public class DefaultRealmPushResultHandler
propByRes.add(ResourceOperation.CREATE, profile.getTask().getResource().getKey());
PropagationReporter reporter = taskExecutor.execute(
- propagationManager.createTasks(realm, propByRes, noPropResources), false, this.adminUser);
+ propagationManager.createTasks(realm, propByRes, noPropResources), false, adminUser);
reportPropagation(result, reporter);
}
@@ -180,7 +175,7 @@ public class DefaultRealmPushResultHandler
final String connObjectKey,
final String connObjectKeyValue,
final boolean ignoreCaseMatch,
- final Iterator<? extends Item> iterator) {
+ final Stream<? extends Item> mapItems) {
ConnectorObject obj = null;
try {
@@ -188,7 +183,7 @@ public class DefaultRealmPushResultHandler
objectClass,
AttributeBuilder.build(connObjectKey, connObjectKeyValue),
ignoreCaseMatch,
- MappingUtils.buildOperationOptions(iterator));
+ MappingUtils.buildOperationOptions(mapItems));
} catch (TimeoutException toe) {
LOG.debug("Request timeout", toe);
throw toe;
@@ -224,7 +219,7 @@ public class DefaultRealmPushResultHandler
connObjectKey.get().getExtAttrName(),
connObjecKeyValue.get(),
orgUnit.isIgnoreCaseMatch(),
- orgUnit.getItems().iterator());
+ orgUnit.getItems().stream());
} else {
LOG.debug("OrgUnitItem {} or its value {} are null", connObjectKey, connObjecKeyValue);
}
@@ -406,7 +401,7 @@ public class DefaultRealmPushResultHandler
connObjectKey.get().getExtAttrName(),
connObjecKeyValue.get(),
orgUnit.isIgnoreCaseMatch(),
- orgUnit.getItems().iterator());
+ orgUnit.getItems().stream());
}
}
} catch (IgnoreProvisionException e) {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPullResultHandler.java
index 20ec326..3ddd89e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPullResultHandler.java
@@ -40,11 +40,13 @@ import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.common.lib.types.AuditElements.Result;
+import org.apache.syncope.common.lib.types.MatchType;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.core.persistence.api.dao.PullMatch;
+import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
@@ -90,8 +92,8 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
}
@Override
- protected AnyTO getAnyTO(final String key) {
- return userDataBinder.getUserTO(key);
+ protected AnyTO getAnyTO(final Any<?> any) {
+ return userDataBinder.getUserTO((User) any, true);
}
@Override
@@ -113,7 +115,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
Set.of(profile.getTask().getResource().getKey()),
true);
- return getAnyTO(created.getKey());
+ return userDataBinder.getUserTO(created.getKey());
}
@Override
@@ -137,11 +139,10 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
protected void handleLinkedAccounts(
final SyncDelta delta,
final List<PullMatch> matches,
- final Provision provision,
- final AnyUtils anyUtils) throws JobExecutionException {
+ final Provision provision) throws JobExecutionException {
for (PullMatch match : matches) {
- User user = userDAO.find(match.getLinkingUserKey());
+ User user = (User) match.getAny();
if (user == null) {
LOG.error("Could not find linking user, cannot process match {}", match);
return;
@@ -201,7 +202,8 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
// do nothing
}
} else if (SyncDeltaType.DELETE == delta.getDeltaType()) {
- finalize(
+ end(
+ AnyTypeKind.USER,
ResourceOperation.DELETE.name().toLowerCase(),
AuditElements.Result.SUCCESS,
null,
@@ -220,7 +222,8 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
if (!profile.getTask().isPerformUpdate()) {
LOG.debug("PullTask not configured for update");
- finalize(MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta);
+ end(AnyTypeKind.USER,
+ MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta);
return Optional.empty();
}
@@ -228,7 +231,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
ProvisioningReport report = new ProvisioningReport();
report.setOperation(ResourceOperation.DELETE);
- report.setAnyType(PullMatch.MatchTarget.LINKED_ACCOUNT.name());
+ report.setAnyType(MatchType.LINKED_ACCOUNT.name());
report.setStatus(ProvisioningReport.Status.SUCCESS);
report.setKey(account.getKey());
@@ -285,7 +288,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
resultStatus = Result.FAILURE;
}
- finalize(MatchingRule.toEventName(matchingRule), resultStatus, before, output, delta);
+ end(AnyTypeKind.USER, MatchingRule.toEventName(matchingRule), resultStatus, before, output, delta);
}
return Optional.of(report);
@@ -301,7 +304,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
if (!profile.getTask().isPerformCreate()) {
LOG.debug("PullTask not configured for create");
- finalize(UnmatchingRule.toEventName(rule), Result.SUCCESS, null, null, delta);
+ end(AnyTypeKind.USER, UnmatchingRule.toEventName(rule), Result.SUCCESS, null, null, delta);
return Optional.empty();
}
@@ -310,16 +313,16 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
ProvisioningReport report = new ProvisioningReport();
report.setOperation(ResourceOperation.CREATE);
report.setName(accountTO.getConnObjectKeyValue());
- report.setAnyType(PullMatch.MatchTarget.LINKED_ACCOUNT.name());
+ report.setAnyType(MatchType.LINKED_ACCOUNT.name());
report.setStatus(ProvisioningReport.Status.SUCCESS);
if (profile.isDryRun()) {
report.setKey(null);
- finalize(UnmatchingRule.toEventName(rule), Result.SUCCESS, null, null, delta);
+ end(AnyTypeKind.USER, UnmatchingRule.toEventName(rule), Result.SUCCESS, null, null, delta);
} else {
UserTO owner = userDataBinder.getUserTO(user, false);
UserCR connObject = connObjectUtils.getAnyCR(
- delta.getObject(), profile.getTask(), provision, getAnyUtils(), false);
+ delta.getObject(), profile.getTask(), provision, false);
if (connObject.getUsername().equals(owner.getUsername())) {
accountTO.setUsername(null);
@@ -395,7 +398,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
resultStatus = Result.FAILURE;
}
- finalize(UnmatchingRule.toEventName(rule), resultStatus, null, output, delta);
+ end(AnyTypeKind.USER, UnmatchingRule.toEventName(rule), resultStatus, null, output, delta);
}
return Optional.of(report);
@@ -409,7 +412,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
if (!profile.getTask().isPerformUpdate()) {
LOG.debug("PullTask not configured for update");
- finalize(MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta);
+ end(AnyTypeKind.USER, MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta);
return Optional.empty();
}
@@ -419,7 +422,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
report.setOperation(ResourceOperation.UPDATE);
report.setKey(account.getKey());
report.setName(account.getConnObjectKeyValue());
- report.setAnyType(PullMatch.MatchTarget.LINKED_ACCOUNT.name());
+ report.setAnyType(MatchType.LINKED_ACCOUNT.name());
report.setStatus(ProvisioningReport.Status.SUCCESS);
if (!profile.isDryRun()) {
@@ -427,7 +430,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
UserTO owner = userDataBinder.getUserTO(account.getOwner(), false);
UserCR connObject = connObjectUtils.getAnyCR(
- delta.getObject(), profile.getTask(), provision, getAnyUtils(), false);
+ delta.getObject(), profile.getTask(), provision, false);
LinkedAccountTO update = userDataBinder.getLinkedAccountTO(account);
@@ -507,7 +510,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
resultStatus = Result.FAILURE;
}
- finalize(MatchingRule.toEventName(MatchingRule.UPDATE), resultStatus, before, output, delta);
+ end(AnyTypeKind.USER, MatchingRule.toEventName(MatchingRule.UPDATE), resultStatus, before, output, delta);
}
return Optional.of(report);
@@ -520,7 +523,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
if (!profile.getTask().isPerformDelete()) {
LOG.debug("PullTask not configured for delete");
- finalize(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta);
+ end(AnyTypeKind.USER, ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta);
return Optional.empty();
}
@@ -535,7 +538,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
report.setKey(account.getKey());
report.setName(account.getConnObjectKeyValue());
report.setOperation(ResourceOperation.DELETE);
- report.setAnyType(PullMatch.MatchTarget.LINKED_ACCOUNT.name());
+ report.setAnyType(MatchType.LINKED_ACCOUNT.name());
report.setStatus(ProvisioningReport.Status.SUCCESS);
if (!profile.isDryRun()) {
@@ -573,7 +576,8 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
output = e;
}
- finalize(ResourceOperation.DELETE.name().toLowerCase(), resultStatus, before, output, delta);
+ end(AnyTypeKind.USER,
+ ResourceOperation.DELETE.name().toLowerCase(), resultStatus, before, output, delta);
}
} catch (Exception e) {
LOG.error("Could not delete linked account {}", account, e);
@@ -596,7 +600,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
report.setKey(null);
report.setName(delta.getObject().getUid().getUidValue());
report.setOperation(ResourceOperation.NONE);
- report.setAnyType(PullMatch.MatchTarget.LINKED_ACCOUNT.name());
+ report.setAnyType(MatchType.LINKED_ACCOUNT.name());
report.setStatus(ProvisioningReport.Status.SUCCESS);
if (message != null && message.length >= 1) {
report.setMessage(message[0]);
@@ -605,16 +609,18 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
report.setKey(account.getKey());
report.setName(delta.getObject().getUid().getUidValue());
report.setOperation(ResourceOperation.NONE);
- report.setAnyType(PullMatch.MatchTarget.LINKED_ACCOUNT.name());
+ report.setAnyType(MatchType.LINKED_ACCOUNT.name());
report.setStatus(ProvisioningReport.Status.SUCCESS);
if (message != null && message.length >= 1) {
report.setMessage(message[0]);
}
}
- finalize(matching
- ? MatchingRule.toEventName(MatchingRule.IGNORE)
- : UnmatchingRule.toEventName(UnmatchingRule.IGNORE), AuditElements.Result.SUCCESS, null, null, delta);
+ end(AnyTypeKind.USER,
+ matching
+ ? MatchingRule.toEventName(MatchingRule.IGNORE)
+ : UnmatchingRule.toEventName(UnmatchingRule.IGNORE),
+ AuditElements.Result.SUCCESS, null, null, delta);
return report;
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPushResultHandler.java
index 535d705..d7060c3 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultUserPushResultHandler.java
@@ -22,24 +22,38 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.syncope.common.lib.request.AnyUR;
import org.apache.syncope.common.lib.request.UserUR;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.MatchType;
+import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.core.provisioning.api.PropagationByResource;
import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.provisioning.api.UserWorkflowResult;
import org.apache.syncope.core.provisioning.api.WorkflowResult;
import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskInfo;
+import org.apache.syncope.core.provisioning.api.pushpull.IgnoreProvisionException;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
+import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
import org.apache.syncope.core.provisioning.api.pushpull.UserPushResultHandler;
import org.apache.syncope.core.provisioning.java.propagation.DefaultPropagationReporter;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.quartz.JobExecutionException;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
public class DefaultUserPushResultHandler extends AbstractPushResultHandler implements UserPushResultHandler {
@@ -54,13 +68,13 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl
}
@Override
- protected AnyTO getAnyTO(final String key) {
- return userDataBinder.getUserTO(key);
+ protected AnyTO getAnyTO(final Any<?> any) {
+ return userDataBinder.getUserTO((User) any, true);
}
@Override
protected void provision(final Any<?> any, final Boolean enabled, final ProvisioningReport result) {
- AnyTO before = getAnyTO(any.getKey());
+ AnyTO before = getAnyTO(any);
List<String> noPropResources = new ArrayList<>(before.getResources());
noPropResources.remove(profile.getTask().getResource().getKey());
@@ -83,7 +97,7 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl
before.getVirAttrs(),
noPropResources),
false,
- this.adminUser);
+ adminUser);
reportPropagation(result, reporter);
}
@@ -122,14 +136,14 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl
if (!taskInfos.isEmpty()) {
taskInfos.get(0).setBeforeObj(Optional.of(beforeObj));
PropagationReporter reporter = new DefaultPropagationReporter();
- taskExecutor.execute(taskInfos.get(0), reporter, this.adminUser);
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
reportPropagation(result, reporter);
}
}
@Override
protected void deprovision(final Any<?> any, final ConnectorObject beforeObj, final ProvisioningReport result) {
- AnyTO before = getAnyTO(any.getKey());
+ AnyTO before = getAnyTO(any);
List<String> noPropResources = new ArrayList<>(before.getResources());
noPropResources.remove(profile.getTask().getResource().getKey());
@@ -153,7 +167,7 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl
if (!taskInfos.isEmpty()) {
taskInfos.get(0).setBeforeObj(Optional.of(beforeObj));
PropagationReporter reporter = new DefaultPropagationReporter();
- taskExecutor.execute(taskInfos.get(0), reporter, this.adminUser);
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
reportPropagation(result, reporter);
}
}
@@ -163,4 +177,226 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl
WorkflowResult<Pair<UserUR, Boolean>> update = uwfAdapter.update((UserUR) req);
return new WorkflowResult<>(update.getResult().getLeft(), update.getPropByRes(), update.getPerformedTasks());
}
+
+ @Transactional(propagation = Propagation.REQUIRES_NEW)
+ @Override
+ public boolean handle(final LinkedAccount account, final Provision provision) {
+ try {
+ doHandle(account, provision);
+ return true;
+ } catch (IgnoreProvisionException e) {
+ ProvisioningReport ignoreResult = profile.getResults().stream().
+ filter(report -> account.getKey().equalsIgnoreCase(report.getKey())).
+ findFirst().
+ orElse(null);
+ if (ignoreResult == null) {
+ ignoreResult = new ProvisioningReport();
+ ignoreResult.setKey(account.getKey());
+ ignoreResult.setAnyType(MatchType.LINKED_ACCOUNT.name());
+
+ profile.getResults().add(ignoreResult);
+ }
+
+ ignoreResult.setOperation(ResourceOperation.NONE);
+ ignoreResult.setStatus(ProvisioningReport.Status.IGNORE);
+ ignoreResult.setMessage(e.getMessage());
+
+ LOG.warn("Ignoring during push", e);
+ return true;
+ } catch (JobExecutionException e) {
+ LOG.error("Push failed", e);
+ return false;
+ }
+ }
+
+ protected void doHandle(final LinkedAccount account, final Provision provision) throws JobExecutionException {
+ ProvisioningReport result = new ProvisioningReport();
+ profile.getResults().add(result);
+
+ result.setKey(account.getKey());
+ result.setAnyType(MatchType.LINKED_ACCOUNT.name());
+ result.setName(account.getConnObjectKeyValue());
+
+ LOG.debug("Pushing linked account {} towards {}", account.getKey(), profile.getTask().getResource());
+
+ // Try to read remote object BEFORE any actual operation
+ Optional<ConnectorObject> connObj = MappingUtils.getConnObjectKeyItem(provision).
+ map(connObjectKeyItem -> outboundMatcher.matchByConnObjectKeyValue(
+ profile.getConnector(), connObjectKeyItem, account.getConnObjectKeyValue(), provision)).
+ orElse(Optional.empty());
+ LOG.debug("Match found for linked account {} as {}: {}", account, provision.getObjectClass(), connObj);
+
+ ConnectorObject beforeObj = connObj.isPresent() ? connObj.get() : null;
+
+ if (profile.isDryRun()) {
+ if (beforeObj == null) {
+ result.setOperation(toResourceOperation(profile.getTask().getUnmatchingRule()));
+ } else {
+ result.setOperation(toResourceOperation(profile.getTask().getMatchingRule()));
+ }
+ result.setStatus(ProvisioningReport.Status.SUCCESS);
+ } else {
+ Boolean enable = profile.getTask().isSyncStatus()
+ ? BooleanUtils.negate(account.isSuspended())
+ : null;
+ try {
+ if (beforeObj == null) {
+ result.setOperation(toResourceOperation(profile.getTask().getUnmatchingRule()));
+
+ switch (profile.getTask().getUnmatchingRule()) {
+ case ASSIGN:
+ case PROVISION:
+ for (PushActions action : profile.getActions()) {
+ if (profile.getTask().getUnmatchingRule() == UnmatchingRule.ASSIGN) {
+ action.beforeAssign(profile, account);
+ } else {
+ action.beforeProvision(profile, account);
+ }
+ }
+
+ if (!profile.getTask().isPerformCreate()) {
+ LOG.debug("PushTask not configured for create");
+ result.setStatus(ProvisioningReport.Status.IGNORE);
+ } else {
+ provision(account, enable, result);
+ }
+ break;
+
+ case UNLINK:
+ LOG.warn("{} not applicable to linked accounts, ignoring",
+ profile.getTask().getUnmatchingRule());
+ break;
+
+ case IGNORE:
+ result.setStatus(ProvisioningReport.Status.IGNORE);
+ break;
+
+ default:
+ // do nothing
+ }
+ } else {
+ result.setOperation(toResourceOperation(profile.getTask().getMatchingRule()));
+
+ switch (profile.getTask().getMatchingRule()) {
+ case UPDATE:
+ for (PushActions action : profile.getActions()) {
+ action.beforeUpdate(profile, account);
+ }
+ if (!profile.getTask().isPerformUpdate()) {
+ LOG.debug("PushTask not configured for update");
+ result.setStatus(ProvisioningReport.Status.IGNORE);
+ } else {
+ update(account, enable, beforeObj, ResourceOperation.UPDATE, result);
+ }
+ break;
+
+ case UNASSIGN:
+ case DEPROVISION:
+ for (PushActions action : profile.getActions()) {
+ if (profile.getTask().getMatchingRule() == MatchingRule.UNASSIGN) {
+ action.beforeUnassign(profile, account);
+ } else {
+ action.beforeDeprovision(profile, account);
+ }
+ }
+
+ if (!profile.getTask().isPerformDelete()) {
+ LOG.debug("PushTask not configured for delete");
+ result.setStatus(ProvisioningReport.Status.IGNORE);
+ } else {
+ update(account, enable, beforeObj, ResourceOperation.DELETE, result);
+ }
+ break;
+
+ case LINK:
+ case UNLINK:
+ LOG.warn("{} not applicable to linked accounts, ignoring",
+ profile.getTask().getMatchingRule());
+ break;
+
+ case IGNORE:
+ result.setStatus(ProvisioningReport.Status.IGNORE);
+ break;
+
+ default:
+ // do nothing
+ }
+ }
+
+ for (PushActions action : profile.getActions()) {
+ action.after(profile, account, result);
+ }
+
+ if (result.getStatus() == null) {
+ result.setStatus(ProvisioningReport.Status.SUCCESS);
+ }
+ } catch (IgnoreProvisionException e) {
+ throw e;
+ } catch (Exception e) {
+ result.setStatus(ProvisioningReport.Status.FAILURE);
+ result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+
+ LOG.warn("Error pushing linked account {} towards {}", account, profile.getTask().getResource(), e);
+
+ for (PushActions action : profile.getActions()) {
+ action.onError(profile, account, result, e);
+ }
+
+ throw new JobExecutionException(e);
+ }
+ }
+ }
+
+ protected void provision(
+ final LinkedAccount account,
+ final Boolean enable,
+ final ProvisioningReport result) {
+
+ PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>();
+ propByLinkedAccount.add(
+ ResourceOperation.CREATE,
+ Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()));
+
+ List<PropagationTaskInfo> taskInfos = propagationManager.getUserCreateTasks(
+ account.getOwner().getKey(),
+ null,
+ enable,
+ new PropagationByResource<>(),
+ propByLinkedAccount,
+ null,
+ null);
+ if (!taskInfos.isEmpty()) {
+ taskInfos.get(0).setBeforeObj(Optional.ofNullable(null));
+ PropagationReporter reporter = new DefaultPropagationReporter();
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
+ reportPropagation(result, reporter);
+ }
+ }
+
+ protected void update(
+ final LinkedAccount account,
+ final Boolean enable,
+ final ConnectorObject beforeObj,
+ final ResourceOperation operation,
+ final ProvisioningReport result) {
+
+ UserUR req = new UserUR();
+ req.setKey(account.getOwner().getKey());
+
+ PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>();
+ propByLinkedAccount.add(operation, Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()));
+
+ List<PropagationTaskInfo> taskInfos = propagationManager.getUserUpdateTasks(
+ new UserWorkflowResult<>(
+ Pair.of(req, enable),
+ new PropagationByResource<>(),
+ propByLinkedAccount,
+ ""));
+ if (!taskInfos.isEmpty()) {
+ taskInfos.get(0).setBeforeObj(Optional.ofNullable(null));
+ PropagationReporter reporter = new DefaultPropagationReporter();
+ taskExecutor.execute(taskInfos.get(0), reporter, adminUser);
+ reportPropagation(result, reporter);
+ }
+ }
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
similarity index 65%
rename from core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
rename to core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
index 5dab005..33a9764 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/InboundMatcher.java
@@ -20,43 +20,45 @@ package org.apache.syncope.core.provisioning.java.pushpull;
import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.MatchType;
import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
-import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
-import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
-import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.AnyUtils;
-import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
-import org.apache.syncope.core.persistence.api.entity.Entity;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.api.entity.Realm;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
-import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.policy.PullCorrelationRuleEntity;
import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
import org.apache.syncope.core.persistence.api.entity.resource.OrgUnitItem;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.provisioning.api.Connector;
import org.apache.syncope.core.provisioning.api.IntAttrName;
import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
import org.apache.syncope.core.persistence.api.dao.PullMatch;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
+import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.provisioning.api.VirAttrHandler;
import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
import org.apache.syncope.core.spring.ImplementationManager;
@@ -70,40 +72,30 @@ import org.identityconnectors.framework.common.objects.SyncDelta;
import org.identityconnectors.framework.common.objects.SyncDeltaBuilder;
import org.identityconnectors.framework.common.objects.SyncDeltaType;
import org.identityconnectors.framework.common.objects.SyncToken;
+import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.spi.SearchResultsHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
@Transactional(readOnly = true)
@Component
-public class PullUtils {
+public class InboundMatcher {
- private static final Logger LOG = LoggerFactory.getLogger(PullUtils.class);
+ private static final Logger LOG = LoggerFactory.getLogger(InboundMatcher.class);
- /**
- * Any Object DAO.
- */
@Autowired
- private AnyObjectDAO anyObjectDAO;
+ private UserDAO userDAO;
- /**
- * User DAO.
- */
@Autowired
- private UserDAO userDAO;
+ private AnyObjectDAO anyObjectDAO;
- /**
- * Group DAO.
- */
@Autowired
private GroupDAO groupDAO;
- /**
- * Search DAO.
- */
@Autowired
private AnySearchDAO searchDAO;
@@ -111,31 +103,39 @@ public class PullUtils {
private RealmDAO realmDAO;
@Autowired
- private AnyUtilsFactory anyUtilsFactory;
+ private VirSchemaDAO virSchemaDAO;
+
+ @Autowired
+ private VirAttrHandler virAttrHandler;
@Autowired
private IntAttrNameParser intAttrNameParser;
- public Optional<String> match(
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
+ public Optional<PullMatch> match(
final AnyType anyType,
- final String name,
+ final String nameValue,
final ExternalResource resource,
- final Connector connector,
- final boolean ignoreCaseMatch) {
+ final Connector connector) {
Optional<? extends Provision> provision = resource.getProvision(anyType);
- if (provision.isEmpty()) {
+ if (!provision.isPresent()) {
return Optional.empty();
}
- Optional<String> result = Optional.empty();
-
- AnyUtils anyUtils = anyUtilsFactory.getInstance(anyType.getKind());
+ Stream<MappingItem> mapItems = Stream.concat(
+ provision.get().getMapping().getItems().stream(),
+ virSchemaDAO.findByProvision(provision.get()).stream().map(VirSchema::asLinkingMappingItem));
List<ConnectorObject> found = new ArrayList<>();
- Name nameAttr = new Name(name);
+
+ Name nameAttr = new Name(nameValue);
connector.search(provision.get().getObjectClass(),
- ignoreCaseMatch ? FilterBuilder.equalsIgnoreCase(nameAttr) : FilterBuilder.equalTo(nameAttr),
+ provision.get().isIgnoreCaseMatch()
+ ? FilterBuilder.equalsIgnoreCase(nameAttr)
+ : FilterBuilder.equalTo(nameAttr),
new SearchResultsHandler() {
@Override
@@ -147,15 +147,16 @@ public class PullUtils {
public boolean handle(final ConnectorObject connectorObject) {
return found.add(connectorObject);
}
- }, MappingUtils.buildOperationOptions(
- MappingUtils.getPullItems(provision.get().getMapping().getItems()).iterator()));
+ }, MappingUtils.buildOperationOptions(mapItems));
+
+ Optional<PullMatch> result = Optional.empty();
if (found.isEmpty()) {
- LOG.debug("No {} found on {} with __NAME__ {}", provision.get().getObjectClass(), resource, name);
+ LOG.debug("No {} found on {} with {} {}", provision.get().getObjectClass(), resource, Name.NAME, nameValue);
} else {
if (found.size() > 1) {
- LOG.warn("More than one {} found on {} with __NAME__ {} - taking first only",
- provision.get().getObjectClass(), resource, name);
+ LOG.warn("More than one {} found on {} with {} {} - taking first only",
+ provision.get().getObjectClass(), resource, Name.NAME, nameValue);
}
ConnectorObject connObj = found.iterator().next();
@@ -166,15 +167,18 @@ public class PullUtils {
setDeltaType(SyncDeltaType.CREATE_OR_UPDATE).
setObject(connObj).
build(),
- provision.get(), anyUtils);
+ provision.get());
if (matches.isEmpty()) {
- LOG.debug("No matching {} found for {}, aborting", anyUtils.anyTypeKind(), connObj);
+ LOG.debug("No matching {} found for {}, aborting", anyType.getKind(), connObj);
} else {
if (matches.size() > 1) {
- LOG.warn("More than one {} found {} - taking first only", anyUtils.anyTypeKind(), matches);
+ LOG.warn("More than one {} found {} - taking first only", anyType.getKind(), matches);
}
- result = Optional.ofNullable(matches.iterator().next().getMatchingKey());
+ result = matches.stream().filter(match -> match.getAny() != null).findFirst();
+ if (result.isPresent()) {
+ virAttrHandler.setValues(result.get().getAny(), connObj);
+ }
}
} catch (IllegalArgumentException e) {
LOG.warn(e.getMessage());
@@ -184,69 +188,51 @@ public class PullUtils {
return result;
}
- private List<PullMatch> findByConnObjectKey(
- final SyncDelta syncDelta, final Provision provision, final AnyUtils anyUtils) {
-
- List<PullMatch> noMatchResult = List.of(PullCorrelationRule.NO_MATCH);
-
- String connObjectKey = null;
+ public List<PullMatch> matchByConnObjectKeyValue(
+ final MappingItem connObjectKeyItem,
+ final String connObjectKeyValue,
+ final Provision provision) {
- Optional<? extends MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
- if (connObjectKeyItem.isPresent()) {
- Attribute connObjectKeyAttr = syncDelta.getObject().
- getAttributeByName(connObjectKeyItem.get().getExtAttrName());
- if (connObjectKeyAttr != null) {
- connObjectKey = AttributeUtil.getStringValue(connObjectKeyAttr);
- }
- }
- if (connObjectKey == null) {
- return noMatchResult;
- }
-
- for (ItemTransformer transformer : MappingUtils.getItemTransformers(connObjectKeyItem.get())) {
+ String finalConnObjectKeyValue = connObjectKeyValue;
+ for (ItemTransformer transformer : MappingUtils.getItemTransformers(connObjectKeyItem)) {
List<Object> output = transformer.beforePull(
- connObjectKeyItem.get(),
+ connObjectKeyItem,
null,
- List.of(connObjectKey));
- if (output != null && !output.isEmpty()) {
- connObjectKey = output.get(0).toString();
+ Collections.<Object>singletonList(finalConnObjectKeyValue));
+ if (!CollectionUtils.isEmpty(output)) {
+ finalConnObjectKeyValue = output.get(0).toString();
}
}
+ List<PullMatch> noMatchResult = Collections.singletonList(PullCorrelationRule.NO_MATCH);
+
IntAttrName intAttrName;
try {
intAttrName = intAttrNameParser.parse(
- connObjectKeyItem.get().getIntAttrName(),
- provision.getAnyType().getKind());
+ connObjectKeyItem.getIntAttrName(), provision.getAnyType().getKind());
} catch (ParseException e) {
- LOG.error("Invalid intAttrName '{}' specified, ignoring", connObjectKeyItem.get().getIntAttrName(), e);
+ LOG.error("Invalid intAttrName '{}' specified, ignoring", connObjectKeyItem.getIntAttrName(), e);
return noMatchResult;
}
- List<PullMatch> result = new ArrayList<>();
+ AnyUtils anyUtils = anyUtilsFactory.getInstance(provision.getAnyType().getKind());
+
+ List<Any<?>> anys = new ArrayList<>();
if (intAttrName.getField() != null) {
switch (intAttrName.getField()) {
case "key":
- Any<?> any = anyUtils.dao().find(connObjectKey);
- if (any != null) {
- result.add(new PullMatch.Builder().matchingKey(any.getKey()).build());
- }
+ Optional.ofNullable(anyUtils.dao().find(connObjectKeyValue)).ifPresent(anys::add);
break;
case "username":
if (provision.getAnyType().getKind() == AnyTypeKind.USER && provision.isIgnoreCaseMatch()) {
AnyCond cond = new AnyCond(AttributeCond.Type.IEQ);
cond.setSchema("username");
- cond.setExpression(connObjectKey);
- result.addAll(searchDAO.search(SearchCond.getLeafCond(cond), AnyTypeKind.USER).stream().
- map(user -> new PullMatch.Builder().matchingKey(user.getKey()).build()).
- collect(Collectors.toList()));
+ cond.setExpression(connObjectKeyValue);
+ anys.addAll(searchDAO.search(SearchCond.getLeafCond(cond), AnyTypeKind.USER));
} else {
- User user = userDAO.findByUsername(connObjectKey);
- if (user != null) {
- result.add(new PullMatch.Builder().matchingKey(user.getKey()).build());
- }
+ Optional.ofNullable(userDAO.findByUsername(connObjectKeyValue)).ifPresent(anys::add);
}
break;
@@ -254,29 +240,19 @@ public class PullUtils {
if (provision.getAnyType().getKind() == AnyTypeKind.GROUP && provision.isIgnoreCaseMatch()) {
AnyCond cond = new AnyCond(AttributeCond.Type.IEQ);
cond.setSchema("name");
- cond.setExpression(connObjectKey);
- result.addAll(searchDAO.search(SearchCond.getLeafCond(cond), AnyTypeKind.GROUP).stream().
- map(group -> new PullMatch.Builder().matchingKey(group.getKey()).build()).
- collect(Collectors.toList()));
+ cond.setExpression(connObjectKeyValue);
+ anys.addAll(searchDAO.search(SearchCond.getLeafCond(cond), AnyTypeKind.GROUP));
} else {
- Group group = groupDAO.findByName(connObjectKey);
- if (group != null) {
- result.add(new PullMatch.Builder().matchingKey(group.getKey()).build());
- }
+ Optional.ofNullable(groupDAO.findByName(connObjectKeyValue)).ifPresent(anys::add);
}
if (provision.getAnyType().getKind() == AnyTypeKind.ANY_OBJECT && provision.isIgnoreCaseMatch()) {
AnyCond cond = new AnyCond(AttributeCond.Type.IEQ);
cond.setSchema("name");
- cond.setExpression(connObjectKey);
- result.addAll(searchDAO.search(SearchCond.getLeafCond(cond), AnyTypeKind.ANY_OBJECT).stream().
- map(anyObject -> new PullMatch.Builder().matchingKey(anyObject.getKey()).build()).
- collect(Collectors.toList()));
+ cond.setExpression(connObjectKeyValue);
+ anys.addAll(searchDAO.search(SearchCond.getLeafCond(cond), AnyTypeKind.ANY_OBJECT));
} else {
- AnyObject anyObject = anyObjectDAO.findByName(connObjectKey);
- if (anyObject != null) {
- result.add(new PullMatch.Builder().matchingKey(anyObject.getKey()).build());
- }
+ Optional.ofNullable(anyObjectDAO.findByName(connObjectKeyValue)).ifPresent(anys::add);
}
break;
@@ -289,39 +265,43 @@ public class PullUtils {
? anyUtils.newPlainAttrUniqueValue()
: anyUtils.newPlainAttrValue();
try {
- value.parseValue((PlainSchema) intAttrName.getSchema(), connObjectKey);
+ value.parseValue((PlainSchema) intAttrName.getSchema(), connObjectKeyValue);
} catch (ParsingValidationException e) {
- LOG.error("While parsing provided __UID__ {}", value, e);
- value.setStringValue(connObjectKey);
+ LOG.error("While parsing provided {} {}", Uid.NAME, value, e);
+ value.setStringValue(connObjectKeyValue);
}
if (intAttrName.getSchema().isUniqueConstraint()) {
anyUtils.dao().findByPlainAttrUniqueValue((PlainSchema) intAttrName.getSchema(),
(PlainAttrUniqueValue) value, provision.isIgnoreCaseMatch()).
- ifPresent(any -> result.add(new PullMatch.Builder().matchingKey(any.getKey()).build()));
+ ifPresent(anys::add);
} else {
- result.addAll(anyUtils.dao().findByPlainAttrValue((PlainSchema) intAttrName.getSchema(),
- value, provision.isIgnoreCaseMatch()).stream().
- map(any -> new PullMatch.Builder().matchingKey(any.getKey()).build()).
- collect(Collectors.toList()));
+ anys.addAll(anyUtils.dao().findByPlainAttrValue((PlainSchema) intAttrName.getSchema(),
+ value, provision.isIgnoreCaseMatch()));
}
break;
case DERIVED:
- result.addAll(anyUtils.dao().findByDerAttrValue((DerSchema) intAttrName.getSchema(),
- connObjectKey, provision.isIgnoreCaseMatch()).stream().
- map(any -> new PullMatch.Builder().matchingKey(any.getKey()).build()).
- collect(Collectors.toList()));
+ anys.addAll(anyUtils.dao().findByDerAttrValue((DerSchema) intAttrName.getSchema(),
+ connObjectKeyValue, provision.isIgnoreCaseMatch()));
break;
default:
}
}
+ List<PullMatch> result = anys.stream().
+ map(any -> new PullMatch(MatchType.ANY, any)).
+ collect(Collectors.toList());
+
+ userDAO.findLinkedAccount(provision.getResource(), finalConnObjectKeyValue).
+ map(account -> new PullMatch(MatchType.LINKED_ACCOUNT, account)).
+ ifPresent(result::add);
+
return result.isEmpty() ? noMatchResult : result;
}
- private List<PullMatch> findByCorrelationRule(
+ private List<PullMatch> matchByCorrelationRule(
final SyncDelta syncDelta,
final Provision provision,
final PullCorrelationRule rule,
@@ -345,14 +325,9 @@ public class PullUtils {
*
* @param syncDelta change operation, including external attributes
* @param provision mapping
- * @param anyUtils any utils
* @return list of matching users' / groups' / any objects' keys
*/
- public List<PullMatch> match(
- final SyncDelta syncDelta,
- final Provision provision,
- final AnyUtils anyUtils) {
-
+ public List<PullMatch> match(final SyncDelta syncDelta, final Provision provision) {
Optional<? extends PullCorrelationRuleEntity> correlationRule = provision.getResource().getPullPolicy() == null
? Optional.empty()
: provision.getResource().getPullPolicy().getCorrelationRule(provision.getAnyType());
@@ -366,14 +341,40 @@ public class PullUtils {
}
}
+ List<PullMatch> result = Collections.emptyList();
try {
- return rule.isPresent()
- ? findByCorrelationRule(syncDelta, provision, rule.get(), anyUtils.anyTypeKind())
- : findByConnObjectKey(syncDelta, provision, anyUtils);
+ if (rule.isPresent()) {
+ result = matchByCorrelationRule(syncDelta, provision, rule.get(), provision.getAnyType().getKind());
+ } else {
+ String connObjectKeyValue = null;
+
+ Optional<? extends MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
+ if (connObjectKeyItem.isPresent()) {
+ Attribute connObjectKeyAttr = syncDelta.getObject().
+ getAttributeByName(connObjectKeyItem.get().getExtAttrName());
+ if (connObjectKeyAttr != null) {
+ connObjectKeyValue = AttributeUtil.getStringValue(connObjectKeyAttr);
+ }
+ // fallback to __UID__
+ if (connObjectKeyValue == null) {
+ connObjectKeyValue = syncDelta.getUid().getUidValue();
+ }
+ }
+ if (connObjectKeyValue == null) {
+ result = Collections.singletonList(PullCorrelationRule.NO_MATCH);
+ } else {
+ result = matchByConnObjectKeyValue(connObjectKeyItem.get(), connObjectKeyValue, provision);
+ }
+ }
} catch (RuntimeException e) {
LOG.error("Could not match {} with any existing {}", syncDelta, provision.getAnyType(), e);
- return List.of();
}
+
+ if (result.size() == 1 && result.get(0).getMatchTarget() == MatchType.ANY) {
+ virAttrHandler.setValues(result.get(0).getAny(), syncDelta.getObject());
+ }
+
+ return result;
}
/**
@@ -383,10 +384,8 @@ public class PullUtils {
* @param orgUnit mapping
* @return list of matching realms' keys.
*/
- public List<String> match(
- final SyncDelta syncDelta,
- final OrgUnit orgUnit) {
-
+ @Transactional(readOnly = true)
+ public List<Realm> match(final SyncDelta syncDelta, final OrgUnit orgUnit) {
String connObjectKey = null;
Optional<? extends OrgUnitItem> connObjectKeyItem = orgUnit.getConnObjectKeyItem();
@@ -398,27 +397,27 @@ public class PullUtils {
}
}
if (connObjectKey == null) {
- return List.of();
+ return Collections.emptyList();
}
for (ItemTransformer transformer : MappingUtils.getItemTransformers(connObjectKeyItem.get())) {
List<Object> output = transformer.beforePull(
connObjectKeyItem.get(),
null,
- List.of(connObjectKey));
- if (output != null && !output.isEmpty()) {
+ Collections.<Object>singletonList(connObjectKey));
+ if (!CollectionUtils.isEmpty(output)) {
connObjectKey = output.get(0).toString();
}
}
- List<String> result = new ArrayList<>();
+ List<Realm> result = new ArrayList<>();
Realm realm;
switch (connObjectKeyItem.get().getIntAttrName()) {
case "key":
realm = realmDAO.find(connObjectKey);
if (realm != null) {
- result.add(realm.getKey());
+ result.add(realm);
}
break;
@@ -426,18 +425,16 @@ public class PullUtils {
if (orgUnit.isIgnoreCaseMatch()) {
final String realmName = connObjectKey;
result.addAll(realmDAO.findAll().stream().
- filter(r -> r.getName().equalsIgnoreCase(realmName)).
- map(Entity::getKey).collect(Collectors.toList()));
+ filter(r -> r.getName().equalsIgnoreCase(realmName)).collect(Collectors.toList()));
} else {
- result.addAll(realmDAO.findByName(connObjectKey).stream().
- map(Entity::getKey).collect(Collectors.toList()));
+ result.addAll(realmDAO.findByName(connObjectKey).stream().collect(Collectors.toList()));
}
break;
case "fullpath":
realm = realmDAO.findByFullPath(connObjectKey);
if (realm != null) {
- result.add(realm.getKey());
+ result.add(realm);
}
break;
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
index 62c9972..7b09175 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
@@ -27,12 +27,12 @@ import java.util.Set;
import org.apache.syncope.common.lib.request.AnyUR;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.GroupTO;
-import org.apache.syncope.common.lib.types.ConnConfProperty;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.provisioning.api.Connector;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
+import org.apache.syncope.core.persistence.api.dao.PullMatch;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.ConnectorObject;
@@ -63,7 +63,7 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
protected GroupDAO groupDAO;
@Autowired
- private PullUtils pullUtils;
+ private InboundMatcher inboundMatcher;
protected final Map<String, Set<String>> membershipsBefore = new HashMap<>();
@@ -76,14 +76,11 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
* @return the name of the attribute used to keep track of group memberships
*/
protected String getGroupMembershipAttrName(final Connector connector) {
- Optional<ConnConfProperty> groupMembership = connector.getConnInstance().getConf().stream().
+ return connector.getConnInstance().getConf().stream().
filter(property -> "groupMemberAttribute".equals(property.getSchema().getName())
- && !property.getValues().isEmpty()).
- findFirst();
-
- return groupMembership.isPresent()
- ? (String) groupMembership.get().getValues().get(0)
- : "uniquemember";
+ && !property.getValues().isEmpty()).findFirst().
+ map(groupMembership -> (String) groupMembership.getValues().get(0)).
+ orElse("uniquemember");
}
/**
@@ -102,8 +99,11 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
Attribute membAttr = delta.getObject().getAttributeByName(groupMemberName);
// if not found, perform an additional read on the underlying connector for the same connector object
if (membAttr == null) {
- OperationOptionsBuilder oob = new OperationOptionsBuilder().setAttributesToGet(groupMemberName);
- ConnectorObject remoteObj = connector.getObject(ObjectClass.GROUP, delta.getUid(), false, oob.build());
+ ConnectorObject remoteObj = connector.getObject(
+ ObjectClass.GROUP,
+ delta.getUid(),
+ false,
+ new OperationOptionsBuilder().setAttributesToGet(groupMemberName).build());
if (remoteObj == null) {
LOG.debug("Object for '{}' not found", delta.getUid().getUidValue());
} else {
@@ -170,17 +170,16 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
}
getMembAttrValues(delta, profile.getConnector()).forEach(membValue -> {
- Optional<String> userKey = pullUtils.match(
+ Optional<PullMatch> match = inboundMatcher.match(
anyTypeDAO.findUser(),
membValue.toString(),
profile.getTask().getResource(),
- profile.getConnector(),
- false);
- if (userKey.isPresent()) {
- Set<String> memb = membershipsAfter.get(userKey.get());
+ profile.getConnector());
+ if (match.isPresent()) {
+ Set<String> memb = membershipsAfter.get(match.get().getAny().getKey());
if (memb == null) {
memb = new HashSet<>();
- membershipsAfter.put(userKey.get(), memb);
+ membershipsAfter.put(match.get().getAny().getKey(), memb);
}
memb.add(entity.getKey());
} else {
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java
new file mode 100644
index 0000000..e206ca8
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/OutboundMatcher.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java.pushpull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.dao.PushCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.LinkingMappingItem;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.MappingManager;
+import org.apache.syncope.core.provisioning.api.TimeoutException;
+import org.apache.syncope.core.provisioning.api.VirAttrHandler;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.apache.syncope.core.spring.ImplementationManager;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.SearchResult;
+import org.identityconnectors.framework.common.objects.filter.Filter;
+import org.identityconnectors.framework.spi.SearchResultsHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class OutboundMatcher {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OutboundMatcher.class);
+
+ @Autowired
+ private MappingManager mappingManager;
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
+ @Autowired
+ private VirSchemaDAO virSchemaDAO;
+
+ @Autowired
+ private VirAttrHandler virAttrHandler;
+
+ private Optional<PushCorrelationRule> rule(final Provision provision) {
+ Optional<? extends PushCorrelationRuleEntity> correlationRule = provision.getResource().getPushPolicy() == null
+ ? Optional.empty()
+ : provision.getResource().getPushPolicy().getCorrelationRule(provision.getAnyType());
+
+ Optional<PushCorrelationRule> rule = Optional.empty();
+ if (correlationRule.isPresent()) {
+ try {
+ rule = ImplementationManager.buildPushCorrelationRule(correlationRule.get().getImplementation());
+ } catch (Exception e) {
+ LOG.error("While building {}", correlationRule.get().getImplementation(), e);
+ }
+ }
+
+ return rule;
+ }
+
+ public List<ConnectorObject> match(
+ final PropagationTask task,
+ final Connector connector,
+ final Provision provision,
+ final String connObjectKeyValue) {
+
+ Optional<PushCorrelationRule> rule = rule(provision);
+
+ boolean isLinkedAccount = task.getAnyTypeKind() == AnyTypeKind.USER
+ && userDAO.linkedAccountExists(task.getEntityKey(), connObjectKeyValue);
+ Any<?> any = null;
+ if (!isLinkedAccount) {
+ any = anyUtilsFactory.getInstance(task.getAnyTypeKind()).dao().find(task.getEntityKey());
+ }
+
+ List<ConnectorObject> result = new ArrayList<>();
+ try {
+ if (any != null && rule.isPresent()) {
+ result.addAll(matchByCorrelationRule(connector, rule.get().getFilter(any, provision), provision));
+ } else {
+ MappingUtils.getConnObjectKeyItem(provision).ifPresent(connObjectKeyItem
+ -> matchByConnObjectKeyValue(connector, connObjectKeyItem, connObjectKeyValue, provision).
+ ifPresent(result::add));
+ }
+ } catch (RuntimeException e) {
+ LOG.error("Could not match {} with any existing {}", any, provision.getObjectClass(), e);
+ }
+
+ if (any != null && result.size() == 1) {
+ virAttrHandler.setValues(any, result.get(0));
+ }
+
+ return result;
+ }
+
+ @Transactional(readOnly = true)
+ public List<ConnectorObject> match(
+ final Connector connector,
+ final Any<?> any,
+ final Provision provision,
+ final LinkingMappingItem... linkingItems) {
+
+ Optional<PushCorrelationRule> rule = rule(provision);
+
+ List<ConnectorObject> result = new ArrayList<>();
+ try {
+ if (rule.isPresent()) {
+ result.addAll(matchByCorrelationRule(
+ connector, rule.get().getFilter(any, provision), provision, linkingItems));
+ } else {
+ Optional<? extends MappingItem> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
+ Optional<String> connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision);
+
+ if (connObjectKeyItem.isPresent() && connObjectKeyValue.isPresent()) {
+ matchByConnObjectKeyValue(
+ connector, connObjectKeyItem.get(), connObjectKeyValue.get(), provision, linkingItems).
+ ifPresent(result::add);
+ }
+ }
+ } catch (RuntimeException e) {
+ LOG.error("Could not match {} with any existing {}", any, provision.getObjectClass(), e);
+ }
+
+ if (result.size() == 1) {
+ virAttrHandler.setValues(any, result.get(0));
+ }
+
+ return result;
+ }
+
+ private List<ConnectorObject> matchByCorrelationRule(
+ final Connector connector,
+ final Filter filter,
+ final Provision provision,
+ final LinkingMappingItem... linkingItems) {
+
+ Stream<MappingItem> items = Stream.concat(
+ provision.getMapping().getItems().stream(),
+ ArrayUtils.isEmpty(linkingItems)
+ ? virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem)
+ : Stream.of(linkingItems));
+
+ List<ConnectorObject> objs = new ArrayList<>();
+ try {
+ connector.search(provision.getObjectClass(), filter, new SearchResultsHandler() {
+
+ @Override
+ public void handleResult(final SearchResult result) {
+ // nothing to do
+ }
+
+ @Override
+ public boolean handle(final ConnectorObject connectorObject) {
+ objs.add(connectorObject);
+ return true;
+ }
+ }, MappingUtils.buildOperationOptions(items));
+ } catch (TimeoutException toe) {
+ LOG.debug("Request timeout", toe);
+ throw toe;
+ } catch (RuntimeException ignore) {
+ LOG.debug("Unexpected exception", ignore);
+ }
+
+ return objs;
+ }
+
+ @Transactional(readOnly = true)
+ public Optional<ConnectorObject> matchByConnObjectKeyValue(
+ final Connector connector,
+ final MappingItem connObjectKeyItem,
+ final String connObjectKeyValue,
+ final Provision provision,
+ final LinkingMappingItem... linkingItems) {
+
+ Stream<MappingItem> items = Stream.concat(
+ provision.getMapping().getItems().stream(),
+ ArrayUtils.isEmpty(linkingItems)
+ ? virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem)
+ : Stream.of(linkingItems));
+
+ ConnectorObject obj = null;
+ try {
+ obj = connector.getObject(
+ provision.getObjectClass(),
+ AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue),
+ provision.isIgnoreCaseMatch(),
+ MappingUtils.buildOperationOptions(items));
+ } catch (TimeoutException toe) {
+ LOG.debug("Request timeout", toe);
+ throw toe;
+ } catch (RuntimeException ignore) {
+ LOG.debug("While resolving {}", connObjectKeyValue, ignore);
+ }
+
+ return Optional.ofNullable(obj);
+ }
+}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
index 14de90b..3f87d55 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
@@ -20,60 +20,50 @@ package org.apache.syncope.core.provisioning.java.pushpull;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.MutablePair;
-import org.apache.syncope.common.lib.collections.IteratorChain;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
+import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.PullMatch;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
import org.apache.syncope.core.persistence.api.entity.group.Group;
-import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.persistence.api.entity.task.PullTask;
import org.apache.syncope.core.provisioning.api.Connector;
-import org.apache.syncope.core.provisioning.api.pushpull.AnyObjectPullResultHandler;
-import org.apache.syncope.core.provisioning.api.pushpull.GroupPullResultHandler;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.apache.syncope.core.persistence.api.entity.task.PullTask;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.provisioning.api.pushpull.AnyObjectPullResultHandler;
import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
+import org.apache.syncope.core.provisioning.api.pushpull.GroupPullResultHandler;
import org.apache.syncope.core.provisioning.api.pushpull.RealmPullResultHandler;
-import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullExecutor;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandler;
import org.apache.syncope.core.provisioning.api.pushpull.UserPullResultHandler;
import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
-import org.apache.syncope.core.spring.ImplementationManager;
import org.identityconnectors.framework.common.objects.Name;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.SyncToken;
-import org.quartz.JobExecutionException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
+import org.apache.syncope.core.spring.ImplementationManager;
public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> implements SyncopePullExecutor {
- protected final Map<ObjectClass, SyncToken> latestSyncTokens = new HashMap<>();
-
- protected final Map<ObjectClass, MutablePair<Integer, String>> handled = new HashMap<>();
-
- @Autowired
- protected UserDAO userDAO;
-
@Autowired
protected GroupDAO groupDAO;
@@ -81,11 +71,15 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
protected VirSchemaDAO virSchemaDAO;
@Autowired
- protected PullUtils pullUtils;
+ protected InboundMatcher inboundMatcher;
@Autowired
protected AnyUtilsFactory anyUtilsFactory;
+ protected final Map<ObjectClass, SyncToken> latestSyncTokens = new HashMap<>();
+
+ protected final Map<ObjectClass, MutablePair<Integer, String>> handled = new HashMap<>();
+
protected ProvisioningProfile<PullTask, PullActions> profile;
@Override
@@ -129,40 +123,35 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
return status.get();
}
- protected void setGroupOwners(
- final GroupPullResultHandler ghandler,
- final boolean userIgnoreCaseMatch,
- final boolean groupIgnoreCaseMatch) {
-
- ghandler.getGroupOwnerMap().entrySet().stream().map(entry -> {
- Group group = groupDAO.find(entry.getKey());
+ protected void setGroupOwners(final GroupPullResultHandler ghandler) {
+ ghandler.getGroupOwnerMap().forEach((groupKey, ownerKey) -> {
+ Group group = groupDAO.find(groupKey);
if (group == null) {
- throw new NotFoundException("Group " + entry.getKey());
+ throw new NotFoundException("Group " + groupKey);
}
- if (StringUtils.isBlank(entry.getValue())) {
+ if (StringUtils.isBlank(ownerKey)) {
group.setGroupOwner(null);
group.setUserOwner(null);
} else {
- Optional<String> userKey = pullUtils.match(
+ Optional<PullMatch> match = inboundMatcher.match(
anyTypeDAO.findUser(),
- entry.getValue(),
+ ownerKey,
ghandler.getProfile().getTask().getResource(),
- ghandler.getProfile().getConnector(),
- userIgnoreCaseMatch);
- if (userKey.isPresent()) {
- group.setUserOwner(userDAO.find(userKey.get()));
+ ghandler.getProfile().getConnector());
+ if (match.isPresent()) {
+ group.setUserOwner((User) match.get().getAny());
} else {
- pullUtils.match(
+ inboundMatcher.match(
anyTypeDAO.findGroup(),
- entry.getValue(),
+ ownerKey,
ghandler.getProfile().getTask().getResource(),
- ghandler.getProfile().getConnector(),
- groupIgnoreCaseMatch).
- ifPresent(groupKey -> group.setGroupOwner(groupDAO.find(groupKey)));
+ ghandler.getProfile().getConnector()).
+ ifPresent(groupMatch -> group.setGroupOwner((Group) groupMatch.getAny()));
}
}
- return group;
- }).forEachOrdered(group -> groupDAO.save(group));
+
+ groupDAO.save(group);
+ });
}
protected static RealmPullResultHandler buildRealmHandler() {
@@ -229,7 +218,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
OrgUnit orgUnit = pullTask.getResource().getOrgUnit();
OperationOptions options = MappingUtils.buildOperationOptions(
- MappingUtils.getPullItems(orgUnit.getItems()).iterator());
+ MappingUtils.getPullItems(orgUnit.getItems().stream()));
RealmPullResultHandler handler = buildRealmHandler();
handler.setProfile(profile);
@@ -278,16 +267,8 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
// ...then provisions for any types
SyncopePullResultHandler handler;
GroupPullResultHandler ghandler = buildGroupHandler();
- boolean userIgnoreCaseMatch = false;
- boolean groupIgnoreCaseMatch = false;
for (Provision provision : pullTask.getResource().getProvisions()) {
if (provision.getMapping() != null) {
- if (provision.getAnyType().getKind() == AnyTypeKind.USER) {
- userIgnoreCaseMatch = provision.isIgnoreCaseMatch();
- } else if (provision.getAnyType().getKind() == AnyTypeKind.GROUP) {
- groupIgnoreCaseMatch = provision.isIgnoreCaseMatch();
- }
-
status.set("Pulling " + provision.getObjectClass().getObjectClassValue());
switch (provision.getAnyType().getKind()) {
@@ -307,11 +288,9 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
handler.setPullExecutor(this);
try {
- Set<MappingItem> linkingMappingItems = virSchemaDAO.findByProvision(provision).stream().
- map(VirSchema::asLinkingMappingItem).collect(Collectors.toSet());
- Iterator<MappingItem> mapItems = new IteratorChain<>(
- provision.getMapping().getItems().iterator(),
- linkingMappingItems.iterator());
+ Stream<? extends Item> mapItems = Stream.concat(
+ MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
+ virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem));
OperationOptions options = MappingUtils.buildOperationOptions(mapItems);
switch (pullTask.getPullMode()) {
@@ -333,17 +312,17 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
break;
case FILTERED_RECONCILIATION:
- ReconFilterBuilder filterBuilder =
- ImplementationManager.build(pullTask.getReconFilterBuilder());
- connector.filteredReconciliation(provision.getObjectClass(),
- filterBuilder,
+ connector.filteredReconciliation(
+ provision.getObjectClass(),
+ ImplementationManager.build(pullTask.getReconFilterBuilder()),
handler,
options);
break;
case FULL_RECONCILIATION:
default:
- connector.fullReconciliation(provision.getObjectClass(),
+ connector.fullReconciliation(
+ provision.getObjectClass(),
handler,
options);
break;
@@ -365,7 +344,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
}
}
try {
- setGroupOwners(ghandler, userIgnoreCaseMatch, groupIgnoreCaseMatch);
+ setGroupOwners(ghandler);
} catch (Exception e) {
LOG.error("While setting group owners", e);
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushUtils.java
deleted file mode 100644
index 6db67f1..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushUtils.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.provisioning.java.pushpull;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import org.apache.syncope.core.persistence.api.dao.PushCorrelationRule;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
-import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
-import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.provisioning.api.Connector;
-import org.apache.syncope.core.provisioning.api.MappingManager;
-import org.apache.syncope.core.provisioning.api.TimeoutException;
-import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.apache.syncope.core.spring.ImplementationManager;
-import org.identityconnectors.framework.common.objects.AttributeBuilder;
-import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.identityconnectors.framework.common.objects.SearchResult;
-import org.identityconnectors.framework.spi.SearchResultsHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.springframework.transaction.annotation.Transactional;
-
-@Transactional(readOnly = true)
-@Component
-public class PushUtils {
-
- private static final Logger LOG = LoggerFactory.getLogger(PushUtils.class);
-
- @Autowired
- private MappingManager mappingManager;
-
- public List<ConnectorObject> match(
- final Connector connector,
- final Any<?> any,
- final Provision provision) {
-
- Optional<? extends PushCorrelationRuleEntity> correlationRule = provision.getResource().getPushPolicy() == null
- ? Optional.empty()
- : provision.getResource().getPushPolicy().getCorrelationRule(provision.getAnyType());
-
- Optional<PushCorrelationRule> rule = Optional.empty();
- if (correlationRule.isPresent()) {
- try {
- rule = ImplementationManager.buildPushCorrelationRule(correlationRule.get().getImplementation());
- } catch (Exception e) {
- LOG.error("While building {}", correlationRule.get().getImplementation(), e);
- }
- }
-
- try {
- return rule
- .map(pushCorrelationRule -> findByCorrelationRule(connector, any, provision, pushCorrelationRule))
- .orElseGet(() -> findByConnObjectKey(connector, any, provision));
- } catch (RuntimeException e) {
- LOG.error("Could not match {} with any existing {}", any, provision.getObjectClass(), e);
- return List.of();
- }
- }
-
- private static List<ConnectorObject> findByCorrelationRule(
- final Connector connector,
- final Any<?> any,
- final Provision provision,
- final PushCorrelationRule rule) {
-
- List<ConnectorObject> objs = new ArrayList<>();
-
- try {
- connector.search(provision.getObjectClass(), rule.getFilter(any, provision), new SearchResultsHandler() {
-
- @Override
- public void handleResult(final SearchResult result) {
- // nothing to do
- }
-
- @Override
- public boolean handle(final ConnectorObject connectorObject) {
- objs.add(connectorObject);
- return true;
- }
- }, MappingUtils.buildOperationOptions(provision.getMapping().getItems().iterator()));
- } catch (TimeoutException toe) {
- LOG.debug("Request timeout", toe);
- throw toe;
- } catch (RuntimeException ignore) {
- LOG.debug("Unexpected exception", ignore);
- }
-
- return objs;
- }
-
- public List<ConnectorObject> findByConnObjectKey(
- final Connector connector,
- final Any<?> any,
- final Provision provision) {
-
- Optional<? extends MappingItem> connObjectKey = MappingUtils.getConnObjectKeyItem(provision);
- Optional<String> connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, provision);
-
- ConnectorObject obj = null;
- if (connObjectKey.isPresent() && connObjectKeyValue.isPresent()) {
- try {
- obj = connector.getObject(
- provision.getObjectClass(),
- AttributeBuilder.build(connObjectKey.get().getExtAttrName(), connObjectKeyValue.get()),
- provision.isIgnoreCaseMatch(),
- MappingUtils.buildOperationOptions(provision.getMapping().getItems().iterator()));
- } catch (TimeoutException toe) {
- LOG.debug("Request timeout", toe);
- throw toe;
- } catch (RuntimeException ignore) {
- LOG.debug("While resolving {}", connObjectKeyValue.get(), ignore);
- }
- }
-
- return obj == null ? List.of() : List.of(obj);
- }
-}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
index 02919c8..154fe5f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePullJobDelegate.java
@@ -19,12 +19,8 @@
package org.apache.syncope.core.provisioning.java.pushpull;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-import org.apache.syncope.common.lib.collections.IteratorChain;
+import java.util.stream.Stream;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.ConflictResolutionAction;
@@ -33,11 +29,11 @@ import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.PullMode;
import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.VirSchema;
-import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask;
import org.apache.syncope.core.persistence.api.entity.task.PullTask;
@@ -53,7 +49,6 @@ import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
import org.apache.syncope.core.spring.ImplementationManager;
import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
import org.identityconnectors.framework.common.objects.AttributeBuilder;
-import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.filter.Filter;
import org.identityconnectors.framework.common.objects.filter.FilterBuilder;
import org.quartz.JobExecutionException;
@@ -67,7 +62,7 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
private ImplementationDAO implementationDAO;
@Autowired
- private TemplateUtils templateUtils;
+ private RealmDAO realmDAO;
@Override
public List<ProvisioningReport> pull(
@@ -75,7 +70,6 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
final Connector connector,
final String connObjectKey,
final String connObjectValue,
- final Realm realm,
final PullTaskTO pullTaskTO) throws JobExecutionException {
LOG.debug("Executing pull on {}", provision.getResource());
@@ -95,13 +89,6 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
});
try {
- Set<MappingItem> linkinMappingItems = virSchemaDAO.findByProvision(provision).stream().
- map(VirSchema::asLinkingMappingItem).collect(Collectors.toSet());
- Iterator<MappingItem> mapItems = new IteratorChain<>(
- provision.getMapping().getItems().iterator(),
- linkinMappingItems.iterator());
- OperationOptions options = MappingUtils.buildOperationOptions(mapItems);
-
PullTask pullTask = entityFactory.newEntity(PullTask.class);
pullTask.setResource(provision.getResource());
pullTask.setMatchingRule(pullTaskTO.getMatchingRule() == null
@@ -113,7 +100,7 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
pullTask.setPerformUpdate(pullTaskTO.isPerformUpdate());
pullTask.setPerformDelete(pullTaskTO.isPerformDelete());
pullTask.setSyncStatus(pullTaskTO.isSyncStatus());
- pullTask.setDestinationRealm(realm);
+ pullTask.setDestinationRealm(realmDAO.findByFullPath(pullTaskTO.getDestinationRealm()));
pullTask.setRemediation(pullTaskTO.isRemediation());
// validate JEXL expressions from templates and proceed if fine
TemplateUtils.check(pullTaskTO.getTemplates(), ClientExceptionType.InvalidPullTask);
@@ -162,18 +149,17 @@ public class SinglePullJobDelegate extends PullJobDelegate implements SyncopeSin
handler.setPullExecutor(this);
// execute filtered pull
+ Stream<? extends Item> mapItems = Stream.concat(
+ MappingUtils.getPullItems(provision.getMapping().getItems().stream()),
+ virSchemaDAO.findByProvision(provision).stream().map(VirSchema::asLinkingMappingItem));
connector.filteredReconciliation(
provision.getObjectClass(),
- new AccountReconciliationFilterBuilder(connObjectKey, connObjectValue),
+ new AccountReconciliationFilterBuilder(connObjectKey, connObjectValue),
handler,
- options);
+ MappingUtils.buildOperationOptions(mapItems));
- Optional<? extends Provision> userProvision = provision.getResource().getProvision(anyTypeDAO.findUser());
- boolean userIgnoreCaseMatch = userProvision.map(Provision::isIgnoreCaseMatch).orElse(false);
- Optional<? extends Provision> groupProvision = provision.getResource().getProvision(anyTypeDAO.findGroup());
- boolean groupIgnoreCaseMatch = groupProvision.map(Provision::isIgnoreCaseMatch).orElse(false);
try {
- setGroupOwners(ghandler, userIgnoreCaseMatch, groupIgnoreCaseMatch);
+ setGroupOwners(ghandler);
} catch (Exception e) {
LOG.error("While setting group owners", e);
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
index 8bfbc0d..4889311 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SinglePushJobDelegate.java
@@ -30,12 +30,14 @@ import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.Implementation;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.apache.syncope.core.persistence.api.entity.task.PushTask;
+import org.apache.syncope.core.persistence.api.entity.user.LinkedAccount;
import org.apache.syncope.core.provisioning.api.Connector;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopePushResultHandler;
import org.apache.syncope.core.provisioning.api.pushpull.SyncopeSinglePushExecutor;
+import org.apache.syncope.core.provisioning.api.pushpull.UserPushResultHandler;
import org.apache.syncope.core.spring.ImplementationManager;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -47,11 +49,9 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
@Autowired
private ImplementationDAO implementationDAO;
- @Override
- public List<ProvisioningReport> push(
+ private List<PushActions> before(
final Provision provision,
final Connector connector,
- final Any<?> any,
final PushTaskTO pushTaskTO) throws JobExecutionException {
LOG.debug("Executing push on {}", provision.getResource());
@@ -70,25 +70,37 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
}
});
- try {
- PushTask pushTask = entityFactory.newEntity(PushTask.class);
- pushTask.setResource(provision.getResource());
- pushTask.setMatchingRule(pushTaskTO.getMatchingRule() == null
- ? MatchingRule.LINK : pushTaskTO.getMatchingRule());
- pushTask.setUnmatchingRule(pushTaskTO.getUnmatchingRule() == null
- ? UnmatchingRule.ASSIGN : pushTaskTO.getUnmatchingRule());
- pushTask.setPerformCreate(pushTaskTO.isPerformCreate());
- pushTask.setPerformUpdate(pushTaskTO.isPerformUpdate());
- pushTask.setPerformDelete(pushTaskTO.isPerformDelete());
- pushTask.setSyncStatus(pushTaskTO.isSyncStatus());
-
- profile = new ProvisioningProfile<>(connector, pushTask);
- profile.getActions().addAll(actions);
- profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
+ PushTask pushTask = entityFactory.newEntity(PushTask.class);
+ pushTask.setResource(provision.getResource());
+ pushTask.setMatchingRule(pushTaskTO.getMatchingRule() == null
+ ? MatchingRule.LINK : pushTaskTO.getMatchingRule());
+ pushTask.setUnmatchingRule(pushTaskTO.getUnmatchingRule() == null
+ ? UnmatchingRule.ASSIGN : pushTaskTO.getUnmatchingRule());
+ pushTask.setPerformCreate(pushTaskTO.isPerformCreate());
+ pushTask.setPerformUpdate(pushTaskTO.isPerformUpdate());
+ pushTask.setPerformDelete(pushTaskTO.isPerformDelete());
+ pushTask.setSyncStatus(pushTaskTO.isSyncStatus());
- for (PushActions action : actions) {
- action.beforeAll(profile);
- }
+ profile = new ProvisioningProfile<>(connector, pushTask);
+ profile.getActions().addAll(actions);
+ profile.setConflictResolutionAction(ConflictResolutionAction.FIRSTMATCH);
+
+ for (PushActions action : actions) {
+ action.beforeAll(profile);
+ }
+
+ return actions;
+ }
+
+ @Override
+ public List<ProvisioningReport> push(
+ final Provision provision,
+ final Connector connector,
+ final Any<?> any,
+ final PushTaskTO pushTaskTO) throws JobExecutionException {
+
+ try {
+ List<PushActions> actions = before(provision, connector, pushTaskTO);
SyncopePushResultHandler handler;
switch (provision.getAnyType().getKind()) {
@@ -106,7 +118,7 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
}
handler.setProfile(profile);
- doHandle(List.of(any), handler, pushTask.getResource());
+ doHandle(List.of(any), handler, provision.getResource());
for (PushActions action : actions) {
action.afterAll(profile);
@@ -119,4 +131,31 @@ public class SinglePushJobDelegate extends PushJobDelegate implements SyncopeSin
: new JobExecutionException("While pushing to connector", e);
}
}
+
+ @Override
+ public ProvisioningReport push(
+ final Provision provision,
+ final Connector connector,
+ final LinkedAccount account,
+ final PushTaskTO pushTaskTO) throws JobExecutionException {
+
+ try {
+ List<PushActions> actions = before(provision, connector, pushTaskTO);
+
+ UserPushResultHandler handler = buildUserHandler();
+ handler.setProfile(profile);
+
+ handler.handle(account, provision);
+
+ for (PushActions action : actions) {
+ action.afterAll(profile);
+ }
+
+ return profile.getResults().get(0);
+ } catch (Exception e) {
+ throw e instanceof JobExecutionException
+ ? (JobExecutionException) e
+ : new JobExecutionException("While pushing to connector", e);
+ }
+ }
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index fda08a0..3162765 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -41,9 +41,9 @@ import org.apache.syncope.common.lib.to.RealmTO;
import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.entity.AnyUtils;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
import org.apache.syncope.core.persistence.api.entity.Realm;
import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
@@ -90,6 +90,9 @@ public class ConnObjectUtils {
@Autowired
private MappingManager mappingManager;
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
/**
* Extract password value from passed value (if instance of GuardedString or GuardedByteArray).
*
@@ -113,6 +116,7 @@ public class ConnObjectUtils {
}
/**
+ * <<<<<<< HEAD
* Builds {@link ConnObjectTO} out of {@link ConnectorObject}.
*
* @param connObject connector object.
@@ -124,6 +128,9 @@ public class ConnObjectUtils {
}
/**
+ * =======
+ * >>>>>>> 1b918568e... [SYNCOPE-1500] Reconciliation now supports single pull / push + [SYNCOPE-957] Reconciliation
+ * now supports Linked Accounts + [SYNCOPE-1499] Use Push correlation rule wherever it makes sense
* Builds {@link ConnObjectTO} out of a collection of {@link Attribute} instances.
*
* @param attrs attributes
@@ -160,7 +167,6 @@ public class ConnObjectUtils {
* @param obj connector object
* @param pullTask pull task
* @param provision provision information
- * @param anyUtils utils
* @param generatePasswordIfPossible whether password value shall be generated, in case not found from
* connector object and allowed by resource configuration
* @param <C> create request type
@@ -171,11 +177,10 @@ public class ConnObjectUtils {
final ConnectorObject obj,
final PullTask pullTask,
final Provision provision,
- final AnyUtils anyUtils,
final boolean generatePasswordIfPossible) {
- AnyTO anyTO = getAnyTOFromConnObject(obj, pullTask, provision, anyUtils);
- C anyCR = anyUtils.newAnyCR();
+ AnyTO anyTO = getAnyTOFromConnObject(obj, pullTask, provision);
+ C anyCR = anyUtilsFactory.getInstance(provision.getAnyType().getKind()).newAnyCR();
EntityTOUtils.toAnyCR(anyTO, anyCR);
// (for users) if password was not set above, generate if resource is configured for that
@@ -212,6 +217,15 @@ public class ConnObjectUtils {
return anyCR;
}
+ public RealmTO getRealmTO(final ConnectorObject obj, final PullTask task, final OrgUnit orgUnit) {
+ RealmTO realmTO = new RealmTO();
+
+ MappingUtils.getPullItems(orgUnit.getItems().stream()).forEach(item
+ -> mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), realmTO));
+
+ return realmTO;
+ }
+
/**
* Build {@link AnyUR} out of connector object attributes and schema mapping.
*
@@ -220,7 +234,6 @@ public class ConnObjectUtils {
* @param original any object to get diff from
* @param pullTask pull task
* @param provision provision information
- * @param anyUtils utils
* @param <U> any object
* @return modifications for the any object to be updated
*/
@@ -231,14 +244,13 @@ public class ConnObjectUtils {
final ConnectorObject obj,
final AnyTO original,
final PullTask pullTask,
- final Provision provision,
- final AnyUtils anyUtils) {
+ final Provision provision) {
- AnyTO updated = getAnyTOFromConnObject(obj, pullTask, provision, anyUtils);
+ AnyTO updated = getAnyTOFromConnObject(obj, pullTask, provision);
updated.setKey(key);
U anyUR = null;
- switch (anyUtils.anyTypeKind()) {
+ switch (provision.getAnyType().getKind()) {
case USER:
UserTO originalUser = (UserTO) original;
UserTO updatedUser = (UserTO) updated;
@@ -303,17 +315,14 @@ public class ConnObjectUtils {
}
private <T extends AnyTO> T getAnyTOFromConnObject(
- final ConnectorObject obj,
- final PullTask pullTask,
- final Provision provision,
- final AnyUtils anyUtils) {
+ final ConnectorObject obj, final PullTask pullTask, final Provision provision) {
- T anyTO = anyUtils.newAnyTO();
+ T anyTO = anyUtilsFactory.getInstance(provision.getAnyType().getKind()).newAnyTO();
anyTO.setType(provision.getAnyType().getKey());
// 1. fill with data from connector object
anyTO.setRealm(pullTask.getDestinationRealm().getFullPath());
- MappingUtils.getPullItems(provision.getMapping().getItems()).forEach(
+ MappingUtils.getPullItems(provision.getMapping().getItems().stream()).forEach(
item -> mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), anyTO));
// 2. add data from defined template (if any)
@@ -321,13 +330,4 @@ public class ConnObjectUtils {
return anyTO;
}
-
- public RealmTO getRealmTO(final ConnectorObject obj, final PullTask task, final OrgUnit orgUnit) {
- RealmTO realmTO = new RealmTO();
-
- MappingUtils.getPullItems(orgUnit.getItems()).forEach(
- item -> mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), realmTO));
-
- return realmTO;
- }
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
index 0c3f7d8..c425d6e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
@@ -20,11 +20,10 @@ package org.apache.syncope.core.provisioning.java.utils;
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.MapContext;
import org.apache.commons.lang3.StringUtils;
@@ -66,16 +65,14 @@ public final class MappingUtils {
: mapping.getConnObjectKeyItem();
}
- public static List<? extends Item> getPropagationItems(final List<? extends Item> items) {
- return items.stream().
- filter(item -> item.getPurpose() == MappingPurpose.PROPAGATION
- || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
+ public static Stream<? extends Item> getPropagationItems(final Stream<? extends Item> items) {
+ return items.filter(
+ item -> item.getPurpose() == MappingPurpose.PROPAGATION || item.getPurpose() == MappingPurpose.BOTH);
}
- public static List<? extends Item> getPullItems(final List<? extends Item> items) {
- return items.stream().
- filter(item -> item.getPurpose() == MappingPurpose.PULL
- || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
+ public static Stream<? extends Item> getPullItems(final Stream<? extends Item> items) {
+ return items.filter(
+ item -> item.getPurpose() == MappingPurpose.PULL || item.getPurpose() == MappingPurpose.BOTH);
}
private static Name getName(final String evalConnObjectLink, final String connObjectKey) {
@@ -84,14 +81,14 @@ public final class MappingUtils {
Name name;
if (StringUtils.isBlank(evalConnObjectLink)) {
// add connObjectKey as __NAME__ attribute ...
- LOG.debug("Add connObjectKey [{}] as __NAME__", connObjectKey);
+ LOG.debug("Add connObjectKey [{}] as {}", connObjectKey, Name.NAME);
name = new Name(connObjectKey);
} else {
- LOG.debug("Add connObjectLink [{}] as __NAME__", evalConnObjectLink);
+ LOG.debug("Add connObjectLink [{}] as {}", evalConnObjectLink, Name.NAME);
name = new Name(evalConnObjectLink);
// connObjectKey not propagated: it will be used to set the value for __UID__ attribute
- LOG.debug("connObjectKey will be used just as __UID__ attribute");
+ LOG.debug("connObjectKey will be used just as {} attribute", Uid.NAME);
}
return name;
@@ -187,11 +184,11 @@ public final class MappingUtils {
/**
* Build options for requesting all mapped connector attributes.
*
- * @param iterator items
+ * @param items items
* @return options for requesting all mapped connector attributes
* @see OperationOptions
*/
- public static OperationOptions buildOperationOptions(final Iterator<? extends Item> iterator) {
+ public static OperationOptions buildOperationOptions(final Stream<? extends Item> items) {
OperationOptionsBuilder builder = new OperationOptionsBuilder();
Set<String> attrsToGet = new HashSet<>();
@@ -199,12 +196,8 @@ public final class MappingUtils {
attrsToGet.add(Uid.NAME);
attrsToGet.add(OperationalAttributes.ENABLE_NAME);
- while (iterator.hasNext()) {
- Item item = iterator.next();
- if (item.getPurpose() != MappingPurpose.NONE) {
- attrsToGet.add(item.getExtAttrName());
- }
- }
+ items.filter(item -> item.getPurpose() != MappingPurpose.NONE).
+ forEach(item -> attrsToGet.add(item.getExtAttrName()));
builder.setAttributesToGet(attrsToGet);
// -------------------------------------
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/LinkedAccountSamplePullCorrelationRule.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/LinkedAccountSamplePullCorrelationRule.java
index fed103d..0e628e9 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/LinkedAccountSamplePullCorrelationRule.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/LinkedAccountSamplePullCorrelationRule.java
@@ -19,15 +19,19 @@
package org.apache.syncope.fit.core.reference;
import java.util.Optional;
+import org.apache.syncope.common.lib.types.MatchType;
import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
import org.apache.syncope.core.persistence.api.dao.PullCorrelationRuleConfClass;
import org.apache.syncope.core.persistence.api.dao.PullMatch;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.Any;
import org.apache.syncope.core.persistence.api.entity.resource.Provision;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.SyncDelta;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@PullCorrelationRuleConfClass(LinkedAccountSamplePullCorrelationRuleConf.class)
@@ -35,6 +39,9 @@ public class LinkedAccountSamplePullCorrelationRule implements PullCorrelationRu
public static final String VIVALDI_KEY = "b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee";
+ @Autowired
+ private UserDAO userDAO;
+
@Override
public SearchCond getSearchCond(final SyncDelta syncDelta, final Provision provision) {
AttributeCond cond = new AttributeCond();
@@ -51,6 +58,7 @@ public class LinkedAccountSamplePullCorrelationRule implements PullCorrelationRu
return SearchCond.getLeafCond(cond);
}
+ @Transactional(readOnly = true)
@Override
public PullMatch matching(final Any<?> any, final SyncDelta syncDelta, final Provision provision) {
// if match with internal user vivaldi was found but firstName is different, update linked account
@@ -60,19 +68,16 @@ public class LinkedAccountSamplePullCorrelationRule implements PullCorrelationRu
&& firstName != null && !CollectionUtils.isEmpty(firstName.getValue())
&& !"Antonio".equals(firstName.getValue().get(0).toString())) {
- return new PullMatch.Builder().
- linkingUserKey(VIVALDI_KEY).
- matchTarget(PullMatch.MatchTarget.LINKED_ACCOUNT).build();
+ return new PullMatch(MatchType.LINKED_ACCOUNT, any);
}
return PullCorrelationRule.super.matching(any, syncDelta, provision);
}
+ @Transactional(readOnly = true)
@Override
public Optional<PullMatch> unmatching(final SyncDelta syncDelta, final Provision provision) {
// if no match with internal user was found, link account to vivaldi instead of creating new user
- return Optional.of(new PullMatch.Builder().
- linkingUserKey(VIVALDI_KEY).
- matchTarget(PullMatch.MatchTarget.LINKED_ACCOUNT).build());
+ return Optional.of(new PullMatch(MatchType.LINKED_ACCOUNT, userDAO.find(VIVALDI_KEY)));
}
}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
index 9d3e9bd..be5f0cb 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/AbstractITCase.java
@@ -198,6 +198,8 @@ public abstract class AbstractITCase {
protected static final String RESOURCE_LDAP_ADMIN_PWD = "secret";
+ protected static final String PRINTER = "PRINTER";
+
protected static String ANONYMOUS_UNAME;
protected static String ANONYMOUS_KEY;
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
index 68427f3..7eb3d5d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
@@ -51,7 +51,7 @@ import org.junit.jupiter.api.Test;
public class AnyObjectITCase extends AbstractITCase {
public static AnyObjectCR getSample(final String location) {
- return new AnyObjectCR.Builder(SyncopeConstants.ROOT_REALM, "PRINTER", location + getUUIDString()).
+ return new AnyObjectCR.Builder(SyncopeConstants.ROOT_REALM, PRINTER, location + getUUIDString()).
plainAttr(attr("location", location + getUUIDString())).
resource(RESOURCE_NAME_DBSCRIPTED).
build();
@@ -122,7 +122,7 @@ public class AnyObjectITCase extends AbstractITCase {
public void list() {
PagedResult<AnyObjectTO> anyObjectTOs = anyObjectService.search(
new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").query()).
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).query()).
build());
assertNotNull(anyObjectTOs);
assertTrue(anyObjectTOs.getResult().size() >= 2);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyTypeITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyTypeITCase.java
index e5eb88d..33162df 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyTypeITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyTypeITCase.java
@@ -52,10 +52,10 @@ public class AnyTypeITCase extends AbstractITCase {
assertEquals(AnyTypeKind.GROUP.name(), groupType.getKey());
assertFalse(groupType.getClasses().isEmpty());
- AnyTypeTO otherType = anyTypeService.read("PRINTER");
+ AnyTypeTO otherType = anyTypeService.read(PRINTER);
assertNotNull(otherType);
assertEquals(AnyTypeKind.ANY_OBJECT, otherType.getKind());
- assertEquals("PRINTER", otherType.getKey());
+ assertEquals(PRINTER, otherType.getKey());
}
@Test
@@ -137,7 +137,7 @@ public class AnyTypeITCase extends AbstractITCase {
newClass = getObject(response.getLocation(), AnyTypeClassService.class, AnyTypeClassTO.class);
assertNotNull(newClass);
- AnyTypeTO other = anyTypeService.read("PRINTER");
+ AnyTypeTO other = anyTypeService.read(PRINTER);
assertNotNull(other);
other.getClasses().add(newClass.getKey());
@@ -182,7 +182,7 @@ public class AnyTypeITCase extends AbstractITCase {
@Test
public void issueSYNCOPE1472() {
// 1. add any type class csv twice to PRINTER any type
- AnyTypeTO anyTypeTO = anyTypeService.read("PRINTER");
+ AnyTypeTO anyTypeTO = anyTypeService.read(PRINTER);
anyTypeTO.getClasses().clear();
anyTypeTO.getClasses().add("minimal printer");
anyTypeTO.getClasses().add("csv");
@@ -190,11 +190,11 @@ public class AnyTypeITCase extends AbstractITCase {
anyTypeService.update(anyTypeTO);
// 2. read again and remove any type class
- anyTypeTO = anyTypeService.read("PRINTER");
+ anyTypeTO = anyTypeService.read(PRINTER);
anyTypeTO.getClasses().remove("csv");
anyTypeService.update(anyTypeTO);
- assertFalse(anyTypeService.read("PRINTER").getClasses().contains("csv"),
+ assertFalse(anyTypeService.read(PRINTER).getClasses().contains("csv"),
"Should not contain removed any type classes");
}
}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
index 0e60efe..fbebb21 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GroupITCase.java
@@ -249,7 +249,7 @@ public class GroupITCase extends AbstractITCase {
GroupCR createReq = getBasicSample("patch");
createReq.setUDynMembershipCond("(($groups==3;$resources!=ws-target-resource-1);aLong==1)");
createReq.getADynMembershipConds().put(
- "PRINTER",
+ PRINTER,
"(($groups==7;cool==ss);$resources==ws-target-resource-2);$type==PRINTER");
GroupTO created = createGroup(createReq).getEntity();
@@ -649,17 +649,17 @@ public class GroupITCase extends AbstractITCase {
@Test
public void aDynMembership() {
- String fiql = SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").is("location").notNullValue().query();
+ String fiql = SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).is("location").notNullValue().query();
// 1. create group with a given aDynMembership condition
GroupCR groupCR = getBasicSample("aDynMembership");
- groupCR.getADynMembershipConds().put("PRINTER", fiql);
+ groupCR.getADynMembershipConds().put(PRINTER, fiql);
GroupTO group = createGroup(groupCR).getEntity();
- assertEquals(fiql, group.getADynMembershipConds().get("PRINTER"));
+ assertEquals(fiql, group.getADynMembershipConds().get(PRINTER));
group = groupService.read(group.getKey());
final String groupKey = group.getKey();
- assertEquals(fiql, group.getADynMembershipConds().get("PRINTER"));
+ assertEquals(fiql, group.getADynMembershipConds().get(PRINTER));
// verify that the condition is dynamically applied
AnyObjectCR newAnyCR = AnyObjectITCase.getSample("aDynMembership");
@@ -678,17 +678,17 @@ public class GroupITCase extends AbstractITCase {
assertTrue(memberships.stream().anyMatch(m -> m.getGroupKey().equals(groupKey)));
// 2. update group and change aDynMembership condition
- fiql = SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").is("location").nullValue().query();
+ fiql = SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).is("location").nullValue().query();
GroupUR groupUR = new GroupUR();
groupUR.setKey(group.getKey());
- groupUR.getADynMembershipConds().put("PRINTER", fiql);
+ groupUR.getADynMembershipConds().put(PRINTER, fiql);
group = updateGroup(groupUR).getEntity();
- assertEquals(fiql, group.getADynMembershipConds().get("PRINTER"));
+ assertEquals(fiql, group.getADynMembershipConds().get(PRINTER));
group = groupService.read(group.getKey());
- assertEquals(fiql, group.getADynMembershipConds().get("PRINTER"));
+ assertEquals(fiql, group.getADynMembershipConds().get(PRINTER));
// verify that the condition is dynamically applied
AnyObjectUR anyObjectUR = new AnyObjectUR();
@@ -713,14 +713,14 @@ public class GroupITCase extends AbstractITCase {
public void aDynMembershipCount() {
// Create a new printer as a dynamic member of a new group
GroupCR groupCR = getBasicSample("aDynamicMembership");
- String fiql = SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").is("location").equalTo("home").query();
- groupCR.getADynMembershipConds().put("PRINTER", fiql);
+ String fiql = SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).is("location").equalTo("home").query();
+ groupCR.getADynMembershipConds().put(PRINTER, fiql);
GroupTO group = createGroup(groupCR).getEntity();
AnyObjectCR printerCR = new AnyObjectCR();
printerCR.setRealm(SyncopeConstants.ROOT_REALM);
printerCR.setName("Printer_" + getUUIDString());
- printerCR.setType("PRINTER");
+ printerCR.setType(PRINTER);
printerCR.getPlainAttrs().add(new Attr.Builder("location").value("home").build());
AnyObjectTO printer = createAnyObject(printerCR).getEntity();
@@ -741,7 +741,7 @@ public class GroupITCase extends AbstractITCase {
AnyObjectCR printerCR = new AnyObjectCR();
printerCR.setRealm(SyncopeConstants.ROOT_REALM);
printerCR.setName("Printer_" + getUUIDString());
- printerCR.setType("PRINTER");
+ printerCR.setType(PRINTER);
printerCR.getMemberships().add(new MembershipTO.Builder(group.getKey()).build());
AnyObjectTO printer = createAnyObject(printerCR).getEntity();
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LoggerITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LoggerITCase.java
index 36613bd..4d18370 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LoggerITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/LoggerITCase.java
@@ -57,6 +57,7 @@ import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.ResourceOperation;
import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.common.rest.api.LoggerWrapper;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.syncope.core.logic.ConnectorLogic;
import org.apache.syncope.core.logic.ReportLogic;
import org.apache.syncope.core.logic.ResourceLogic;
@@ -421,8 +422,8 @@ public class LoggerITCase extends AbstractITCase {
pushTask.setPerformUpdate(true);
pushTask.setUnmatchingRule(UnmatchingRule.PROVISION);
pushTask.setMatchingRule(MatchingRule.UPDATE);
- reconciliationService.push(
- AnyTypeKind.ANY_OBJECT, "fc6dbc3a-6c07-4965-8781-921e7401a4a5", RESOURCE_NAME_DBSCRIPTED, pushTask);
+ reconciliationService.push(new ReconQuery.Builder(PRINTER, RESOURCE_NAME_DBSCRIPTED).
+ anyKey("fc6dbc3a-6c07-4965-8781-921e7401a4a5").build(), pushTask);
} catch (Exception e) {
LOG.error("Unexpected exception", e);
fail(e::getMessage);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
index 3a8566b..022247d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
@@ -58,6 +58,7 @@ import org.apache.syncope.common.lib.types.PullMode;
import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.syncope.common.lib.types.TaskType;
import org.apache.syncope.common.rest.api.beans.AnyQuery;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.syncope.common.rest.api.beans.SchemaQuery;
import org.apache.syncope.common.rest.api.beans.TaskQuery;
import org.apache.syncope.common.rest.api.service.ConnectorService;
@@ -240,7 +241,8 @@ public class MultitenancyITCase extends AbstractITCase {
pushTask.setPerformUpdate(true);
pushTask.setMatchingRule(MatchingRule.UPDATE);
adminClient.getService(ReconciliationService.class).
- push(AnyTypeKind.USER, pullFromLDAPKey, resource.getKey(), pushTask);
+ push(new ReconQuery.Builder(AnyTypeKind.USER.name(), resource.getKey()).
+ anyKey(pullFromLDAPKey).build(), pushTask);
assertEquals(1, adminClient.getService(TaskService.class).
search(new TaskQuery.Builder(TaskType.PROPAGATION).
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
index 0dd9dfb..95475fd 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
@@ -187,7 +187,7 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
// 0. Set propagation JEXL MappingItemTransformer
ResourceTO resource = resourceService.read(RESOURCE_NAME_DBSCRIPTED);
ResourceTO originalResource = SerializationUtils.clone(resource);
- ProvisionTO provision = resource.getProvision("PRINTER").get();
+ ProvisionTO provision = resource.getProvision(PRINTER).get();
assertNotNull(provision);
Optional<ItemTO> mappingItem = provision.getMapping().getItems().stream().
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
index 85bd8f3..bfa5636 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
@@ -479,7 +479,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
// 0. reset sync token and set MappingItemTransformer
ResourceTO resource = resourceService.read(RESOURCE_NAME_DBSCRIPTED);
ResourceTO originalResource = SerializationUtils.clone(resource);
- ProvisionTO provision = resource.getProvision("PRINTER").get();
+ ProvisionTO provision = resource.getProvision(PRINTER).get();
assertNotNull(provision);
ImplementationTO transformer = null;
@@ -537,7 +537,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
// 3. unlink any existing printer and delete from Syncope (printer is now only on external resource)
PagedResult<AnyObjectTO> matchingPrinters = anyObjectService.search(
new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).
is("location").equalTo("pull*").query()).build());
assertTrue(matchingPrinters.getSize() > 0);
for (AnyObjectTO printer : matchingPrinters.getResult()) {
@@ -557,7 +557,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
// 5. verify that printer was re-created in Syncope (implies that location does not start with given prefix,
// hence PrefixItemTransformer was applied during pull)
matchingPrinters = anyObjectService.search(new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).
is("location").equalTo("pull*").query()).build());
assertTrue(matchingPrinters.getSize() > 0);
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PushTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PushTaskITCase.java
index 5c1f83e..96347d5 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PushTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PushTaskITCase.java
@@ -56,6 +56,7 @@ import org.apache.syncope.common.lib.types.SchemaType;
import org.apache.syncope.common.lib.types.TaskType;
import org.apache.syncope.common.lib.types.TraceLevel;
import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.syncope.common.rest.api.beans.TaskQuery;
import org.apache.syncope.common.rest.api.service.NotificationService;
import org.apache.syncope.common.rest.api.service.ResourceService;
@@ -271,46 +272,54 @@ public class PushTaskITCase extends AbstractTaskITCase {
ResourceTO ldap = resourceService.read(RESOURCE_NAME_LDAP);
assertNull(ldap.getPushPolicy());
- ldap.setPushPolicy("fb6530e5-892d-4f47-a46b-180c5b6c5c83");
- resourceService.update(ldap);
-
- // 2. create push task with sole scope as the user 'vivaldi'
- PushTaskTO sendVivaldi = new PushTaskTO();
- sendVivaldi.setName("Send Vivaldi");
- sendVivaldi.setResource(RESOURCE_NAME_LDAP);
- sendVivaldi.setUnmatchingRule(UnmatchingRule.PROVISION);
- sendVivaldi.setMatchingRule(MatchingRule.UPDATE);
- sendVivaldi.setSourceRealm(SyncopeConstants.ROOT_REALM);
- sendVivaldi.getFilters().put(AnyTypeKind.GROUP.name(), "name==$null");
- sendVivaldi.getFilters().put(AnyTypeKind.USER.name(), "username==vivaldi");
- sendVivaldi.setPerformCreate(true);
- sendVivaldi.setPerformUpdate(true);
-
- Response response = taskService.create(TaskType.PUSH, sendVivaldi);
- sendVivaldi = getObject(response.getLocation(), TaskService.class, PushTaskTO.class);
- assertNotNull(sendVivaldi);
-
- // 3. execute push: vivaldi is found on ldap
- execProvisioningTask(taskService, TaskType.PUSH, sendVivaldi.getKey(), 50, false);
-
- ReconStatus status = reconciliationService.status(AnyTypeKind.USER, "vivaldi", RESOURCE_NAME_LDAP);
- assertNotNull(status.getOnResource());
-
- // 4. update vivaldi on ldap: reconciliation status does not find it anymore, as remote key was changed
- Map<String, String> attrs = new HashMap<>();
- attrs.put("cn", "vivaldiZZ");
- attrs.put("mail", "vivaldi@syncope.org");
- updateLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "uid=vivaldi,ou=People,o=isp", attrs);
-
- status = reconciliationService.status(AnyTypeKind.USER, "vivaldi", RESOURCE_NAME_LDAP);
- assertNull(status.getOnResource());
-
- // 5. execute push again: the push policy will find anyway vivaldi because of the email attribute
- execProvisioningTask(taskService, TaskType.PUSH, sendVivaldi.getKey(), 50, false);
-
- // 6. now the reconciliation status is fine again, as the push above did overwrite the entry on ldap
- status = reconciliationService.status(AnyTypeKind.USER, "vivaldi", RESOURCE_NAME_LDAP);
- assertNotNull(status.getOnResource());
+ try {
+ ldap.setPushPolicy("fb6530e5-892d-4f47-a46b-180c5b6c5c83");
+ resourceService.update(ldap);
+
+ // 2. create push task with sole scope as the user 'vivaldi'
+ PushTaskTO sendVivaldi = new PushTaskTO();
+ sendVivaldi.setName("Send Vivaldi");
+ sendVivaldi.setResource(RESOURCE_NAME_LDAP);
+ sendVivaldi.setUnmatchingRule(UnmatchingRule.PROVISION);
+ sendVivaldi.setMatchingRule(MatchingRule.UPDATE);
+ sendVivaldi.setSourceRealm(SyncopeConstants.ROOT_REALM);
+ sendVivaldi.getFilters().put(AnyTypeKind.GROUP.name(), "name==$null");
+ sendVivaldi.getFilters().put(AnyTypeKind.USER.name(), "username==vivaldi");
+ sendVivaldi.setPerformCreate(true);
+ sendVivaldi.setPerformUpdate(true);
+
+ Response response = taskService.create(TaskType.PUSH, sendVivaldi);
+ sendVivaldi = getObject(response.getLocation(), TaskService.class, PushTaskTO.class);
+ assertNotNull(sendVivaldi);
+
+ // 3. execute push: vivaldi is found on ldap
+ execProvisioningTask(taskService, TaskType.PUSH, sendVivaldi.getKey(), 50, false);
+
+ ReconStatus status = reconciliationService.status(
+ new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).anyKey("vivaldi").build());
+ assertNotNull(status.getOnResource());
+
+ // 4. update vivaldi on ldap: reconciliation status does not find it anymore, as remote key was changed
+ Map<String, String> attrs = new HashMap<>();
+ attrs.put("sn", "VivaldiZ");
+ updateLdapRemoteObject(
+ RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "uid=vivaldi,ou=People,o=isp", attrs);
+
+ status = reconciliationService.status(
+ new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).anyKey("vivaldi").build());
+ assertNull(status.getOnResource());
+
+ // 5. execute push again: propagation task for CREATE will be generated, but that will fail
+ // as task executor is not able any more to identify the entry to UPDATE
+ execProvisioningTask(taskService, TaskType.PUSH, sendVivaldi.getKey(), 50, false);
+
+ status = reconciliationService.status(
+ new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).anyKey("vivaldi").build());
+ assertNull(status.getOnResource());
+ } finally {
+ ldap.setPushPolicy(null);
+ resourceService.update(ldap);
+ }
}
@Test
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
index 720255e..1635f02 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ReconciliationITCase.java
@@ -26,15 +26,20 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Date;
import org.apache.syncope.common.lib.request.AnyObjectCR;
+import java.util.UUID;
+import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.AnyObjectTO;
import org.apache.syncope.common.lib.Attr;
import org.apache.syncope.common.lib.to.PullTaskTO;
import org.apache.syncope.common.lib.to.PushTaskTO;
import org.apache.syncope.common.lib.to.ReconStatus;
import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.MatchType;
import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.syncope.fit.AbstractITCase;
import org.identityconnectors.framework.common.objects.OperationalAttributes;
+import org.identityconnectors.framework.common.objects.Uid;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -54,9 +59,12 @@ public class ReconciliationITCase extends AbstractITCase {
"SELECT id FROM testPRINTER WHERE printername=?", printer.getName()).size());
// 3. verify reconciliation status
- ReconStatus status =
- reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ ReconStatus status = reconciliationService.status(
+ new ReconQuery.Builder(PRINTER, RESOURCE_NAME_DBSCRIPTED).anyKey(printer.getName()).build());
assertNotNull(status);
+ assertEquals(AnyTypeKind.ANY_OBJECT, status.getAnyTypeKind());
+ assertEquals(printer.getKey(), status.getAnyKey());
+ assertEquals(MatchType.ANY, status.getMatchType());
assertNotNull(status.getOnSyncope());
assertNull(status.getOnResource());
@@ -64,7 +72,8 @@ public class ReconciliationITCase extends AbstractITCase {
PushTaskTO pushTask = new PushTaskTO();
pushTask.setPerformCreate(true);
pushTask.setUnmatchingRule(UnmatchingRule.PROVISION);
- reconciliationService.push(AnyTypeKind.ANY_OBJECT, printer.getKey(), "resource-db-scripted", pushTask);
+ reconciliationService.push(new ReconQuery.Builder(PRINTER, RESOURCE_NAME_DBSCRIPTED).
+ anyKey(printer.getKey()).build(), pushTask);
// 5. verify that printer is now propagated
assertEquals(1, jdbcTemplate.queryForList(
@@ -75,7 +84,8 @@ public class ReconciliationITCase extends AbstractITCase {
assertTrue(printer.getResources().isEmpty());
// 7. verify reconciliation status
- status = reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ status = reconciliationService.status(
+ new ReconQuery.Builder(PRINTER, RESOURCE_NAME_DBSCRIPTED).anyKey(printer.getName()).build());
assertNotNull(status);
assertNotNull(status.getOnSyncope());
assertNotNull(status.getOnResource());
@@ -97,15 +107,15 @@ public class ReconciliationITCase extends AbstractITCase {
assertNotNull(printer.getKey());
assertNotEquals("Nowhere", printer.getPlainAttr("location").get().getValues().get(0));
- // 2. create table into the external resource's db, with same name
+ // 2. add row into the external resource's table, with same name
JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
jdbcTemplate.update(
"INSERT INTO TESTPRINTER (id, printername, location, deleted, lastmodification) VALUES (?,?,?,?,?)",
printer.getKey(), printer.getName(), "Nowhere", false, new Date());
// 3. verify reconciliation status
- ReconStatus status =
- reconciliationService.status(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted");
+ ReconStatus status = reconciliationService.status(
+ new ReconQuery.Builder(PRINTER, RESOURCE_NAME_DBSCRIPTED).anyKey(printer.getName()).build());
assertNotNull(status);
assertNotNull(status.getOnSyncope());
assertNotNull(status.getOnResource());
@@ -113,12 +123,49 @@ public class ReconciliationITCase extends AbstractITCase {
// 4. pull
PullTaskTO pullTask = new PullTaskTO();
+ pullTask.setDestinationRealm(SyncopeConstants.ROOT_REALM);
pullTask.setPerformUpdate(true);
- reconciliationService.pull(AnyTypeKind.ANY_OBJECT, printer.getName(), "resource-db-scripted", pullTask);
+ reconciliationService.pull(new ReconQuery.Builder(PRINTER, RESOURCE_NAME_DBSCRIPTED).
+ anyKey(printer.getName()).build(), pullTask);
// 5. verify reconciliation result (and resource is still not assigned)
printer = anyObjectService.read(printer.getKey());
assertEquals("Nowhere", printer.getPlainAttr("location").get().getValues().get(0));
assertTrue(printer.getResources().isEmpty());
}
+
+ @Test
+ public void importSingle() {
+ // 1. add row into the external resource's table
+ String externalKey = UUID.randomUUID().toString();
+ String externalName = "printer" + getUUIDString();
+
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
+ jdbcTemplate.update(
+ "INSERT INTO TESTPRINTER (id, printername, location, deleted, lastmodification) VALUES (?,?,?,?,?)",
+ externalKey, externalName, "Nowhere", false, new Date());
+
+ // 2. verify reconciliation status
+ ReconStatus status = reconciliationService.status(
+ new ReconQuery.Builder(PRINTER, RESOURCE_NAME_DBSCRIPTED).connObjectKeyValue(externalKey).build());
+ assertNotNull(status);
+ assertNull(status.getAnyTypeKind());
+ assertNull(status.getAnyKey());
+ assertNull(status.getMatchType());
+ assertNull(status.getOnSyncope());
+ assertNotNull(status.getOnResource());
+ assertEquals(externalKey, status.getOnResource().getAttr(Uid.NAME).get().getValues().get(0));
+ assertEquals(externalName, status.getOnResource().getAttr("PRINTERNAME").get().getValues().get(0));
+
+ // 3. pull
+ PullTaskTO pullTask = new PullTaskTO();
+ pullTask.setDestinationRealm(SyncopeConstants.ROOT_REALM);
+ pullTask.setPerformCreate(true);
+ reconciliationService.pull(new ReconQuery.Builder(PRINTER, RESOURCE_NAME_DBSCRIPTED).
+ connObjectKeyValue(externalKey).build(), pullTask);
+
+ // 4. verify reconciliation result
+ AnyObjectTO printer = anyObjectService.read(externalName);
+ assertNotNull(printer);
+ }
}
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
index d1d8826..7cdc784 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/ResourceITCase.java
@@ -408,22 +408,22 @@ public class ResourceITCase extends AbstractITCase {
try {
// create a new resource
resource = createResource(resource);
- assertNull(resource.getProvision("PRINTER").get().getSyncToken());
+ assertNull(resource.getProvision(PRINTER).get().getSyncToken());
// create some object on the new resource
anyObject = createAnyObject(anyObjectCR).getEntity();
// update sync token
- resourceService.setLatestSyncToken(resource.getKey(), "PRINTER");
+ resourceService.setLatestSyncToken(resource.getKey(), PRINTER);
resource = resourceService.read(resource.getKey());
- assertNotNull(resource.getProvision("PRINTER").get().getSyncToken());
+ assertNotNull(resource.getProvision(PRINTER).get().getSyncToken());
// remove sync token
- resourceService.removeSyncToken(resource.getKey(), "PRINTER");
+ resourceService.removeSyncToken(resource.getKey(), PRINTER);
resource = resourceService.read(resource.getKey());
- assertNull(resource.getProvision("PRINTER").get().getSyncToken());
+ assertNull(resource.getProvision(PRINTER).get().getSyncToken());
} finally {
if (anyObject != null) {
anyObjectService.delete(anyObject.getKey());
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
index 347e0b7..2a5d64f 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SearchITCase.java
@@ -337,7 +337,7 @@ public class SearchITCase extends AbstractITCase {
public void searchByType() {
PagedResult<AnyObjectTO> matching = anyObjectService.search(new AnyQuery.Builder().realm(
SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").query()).build());
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).query()).build());
assertNotNull(matching);
assertFalse(matching.getResult().isEmpty());
@@ -356,7 +356,7 @@ public class SearchITCase extends AbstractITCase {
public void searchByRelationship() {
PagedResult<AnyObjectTO> anyObjects = anyObjectService.search(new AnyQuery.Builder().realm(
SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).
inRelationships("Canon MF 8030cn").query()).
build());
assertNotNull(anyObjects);
@@ -375,7 +375,7 @@ public class SearchITCase extends AbstractITCase {
public void searchByRelationshipType() {
PagedResult<AnyObjectTO> anyObjects = anyObjectService.search(new AnyQuery.Builder().realm(
SyncopeConstants.ROOT_REALM).
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).
inRelationshipTypes("neighborhood").query()).
build());
assertNotNull(anyObjects);
@@ -423,7 +423,7 @@ public class SearchITCase extends AbstractITCase {
anyMatch(group -> "e7ff94e8-19c9-4f0a-b8b7-28327edbf6ed".equals(group.getKey())));
PagedResult<AnyObjectTO> anyObjects = anyObjectService.search(new AnyQuery.Builder().realm("/odd").
- fiql(SyncopeClient.getAnyObjectSearchConditionBuilder("PRINTER").isAssignable().
+ fiql(SyncopeClient.getAnyObjectSearchConditionBuilder(PRINTER).isAssignable().
and("name").equalTo("*").query()).
build());
assertNotNull(anyObjects);