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 2022/10/27 10:51:54 UTC
[syncope] branch master updated: [SYNCOPE-1705] Encapsulating each object processing into an inner transaction (#383)
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 49e013436f [SYNCOPE-1705] Encapsulating each object processing into an inner transaction (#383)
49e013436f is described below
commit 49e013436f13856093548672105d79e5d6edb9a7
Author: Francesco Chicchiriccò <il...@users.noreply.github.com>
AuthorDate: Thu Oct 27 12:51:49 2022 +0200
[SYNCOPE-1705] Encapsulating each object processing into an inner transaction (#383)
---
.../persistence/api/dao/ExternalResourceDAO.java | 4 +-
.../core/persistence/api/dao/RemediationDAO.java | 1 -
.../api/pushpull/ProvisioningActions.java | 4 +-
.../provisioning/java/job/SetUMembershipsJob.java | 129 ---------------------
.../propagation/DefaultPropagationReporter.java | 4 +-
.../java/pushpull/AbstractPullResultHandler.java | 64 ++--------
.../pushpull/DefaultUserPullResultHandler.java | 6 +-
.../java/pushpull/LDAPMembershipPullActions.java | 81 ++++++++++---
.../java/pushpull/SchedulingPullActions.java | 2 +
.../pushpull/LDAPMembershipPullActionsTest.java | 46 ++------
.../apache/syncope/fit/core/PullTaskITCase.java | 4 +-
11 files changed, 99 insertions(+), 246 deletions(-)
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
index 8fc338e8c3..bc3ec6e880 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/ExternalResourceDAO.java
@@ -37,9 +37,9 @@ public interface ExternalResourceDAO extends DAO<ExternalResource> {
boolean anyItemHaving(Implementation transformer);
- List<ExternalResource> findByProvisionSorter(Implementation propagationActions);
+ List<ExternalResource> findByProvisionSorter(Implementation provisionSorter);
- List<ExternalResource> findByPropagationActions(Implementation provisionSorter);
+ List<ExternalResource> findByPropagationActions(Implementation propagationActions);
List<ExternalResource> findByPolicy(Policy policy);
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RemediationDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RemediationDAO.java
index 73216b30cf..5fd3d49737 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RemediationDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/RemediationDAO.java
@@ -41,5 +41,4 @@ public interface RemediationDAO extends DAO<Remediation> {
void delete(Remediation remediation);
void delete(String key);
-
}
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningActions.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningActions.java
index ff3a3e4df1..afbf49aac2 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningActions.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningActions.java
@@ -28,7 +28,7 @@ public interface ProvisioningActions {
* @param profile provisioning profile
* @throws JobExecutionException in case of generic failure
*/
- default void beforeAll(final ProvisioningProfile<?, ?> profile) throws JobExecutionException {
+ default void beforeAll(ProvisioningProfile<?, ?> profile) throws JobExecutionException {
// do nothing
}
@@ -38,7 +38,7 @@ public interface ProvisioningActions {
* @param profile provisioning profile
* @throws JobExecutionException in case of generic failure
*/
- default void afterAll(final ProvisioningProfile<?, ?> profile) throws JobExecutionException {
+ default void afterAll(ProvisioningProfile<?, ?> profile) throws JobExecutionException {
// do nothing
}
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
deleted file mode 100644
index a9d9a52538..0000000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
+++ /dev/null
@@ -1,129 +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.job;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import org.apache.syncope.common.lib.request.MembershipUR;
-import org.apache.syncope.common.lib.request.UserUR;
-import org.apache.syncope.common.lib.types.PatchOperation;
-import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
-import org.apache.syncope.core.provisioning.api.job.JobManager;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
-import org.apache.syncope.core.spring.security.AuthContextUtils;
-import org.apache.syncope.core.spring.security.SecurityProperties;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * Quartz Job used for setting user memberships asynchronously, after the completion of
- * {@link org.apache.syncope.core.provisioning.api.pushpull.PullActions}.
- */
-public class SetUMembershipsJob extends AbstractInterruptableJob {
-
- private static final Logger LOG = LoggerFactory.getLogger(SetUMembershipsJob.class);
-
- public static final String MEMBERSHIPS_BEFORE_KEY = "membershipsBefore";
-
- public static final String MEMBERSHIPS_AFTER_KEY = "membershipsAfter";
-
- public static final String CONTEXT = "context";
-
- @Autowired
- private SecurityProperties securityProperties;
-
- @Autowired
- private UserProvisioningManager userProvisioningManager;
-
- @Override
- public void execute(final JobExecutionContext context) throws JobExecutionException {
- String executor = Optional.ofNullable(context.getMergedJobDataMap().getString(JobManager.EXECUTOR_KEY)).
- orElse(securityProperties.getAdminUser());
-
- try {
- AuthContextUtils.callAsAdmin(context.getMergedJobDataMap().getString(JobManager.DOMAIN_KEY), () -> {
-
- @SuppressWarnings("unchecked")
- Map<String, Set<String>> membershipsBefore =
- (Map<String, Set<String>>) context.getMergedJobDataMap().get(MEMBERSHIPS_BEFORE_KEY);
- LOG.debug("Memberships before pull (User -> Groups) {}", membershipsBefore);
-
- @SuppressWarnings("unchecked")
- Map<String, Set<String>> membershipsAfter =
- (Map<String, Set<String>>) context.getMergedJobDataMap().get(MEMBERSHIPS_AFTER_KEY);
- LOG.debug("Memberships after pull (User -> Groups) {}", membershipsAfter);
-
- List<UserUR> updateReqs = new ArrayList<>();
-
- membershipsAfter.forEach((user, groups) -> {
- UserUR userUR = new UserUR();
- userUR.setKey(user);
- updateReqs.add(userUR);
-
- groups.forEach(group -> {
- Set<String> before = membershipsBefore.get(user);
- if (before == null || !before.contains(group)) {
- userUR.getMemberships().add(new MembershipUR.Builder(group).
- operation(PatchOperation.ADD_REPLACE).
- build());
- }
- });
- });
-
- membershipsBefore.forEach((user, groups) -> {
- UserUR userUR = updateReqs.stream().
- filter(req -> user.equals(req.getKey())).findFirst().
- orElseGet(() -> {
- UserUR req = new UserUR.Builder(user).build();
- updateReqs.add(req);
- return req;
- });
-
- groups.forEach(group -> {
- Set<String> after = membershipsAfter.get(user);
- if (after == null || !after.contains(group)) {
- userUR.getMemberships().add(new MembershipUR.Builder(group).
- operation(PatchOperation.DELETE).
- build());
- }
- });
- });
-
- updateReqs.stream().filter(req -> !req.isEmpty()).forEach(req -> {
- LOG.debug("About to update User {}", req);
- userProvisioningManager.update(
- req, true, executor, context.getMergedJobDataMap().getString(CONTEXT));
- });
-
- return null;
- });
- } catch (RuntimeException e) {
- LOG.error("While setting memberships", e);
- throw new JobExecutionException("While executing memberships", e);
- } finally {
- ApplicationContextProvider.getBeanFactory().destroySingleton(context.getJobDetail().getKey().getName());
- }
- }
-}
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 13037ca4e6..12225b472f 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
@@ -18,10 +18,10 @@
*/
package org.apache.syncope.core.provisioning.java.propagation;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.syncope.common.lib.to.PropagationStatus;
import org.apache.syncope.common.lib.types.ExecStatus;
import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
@@ -36,7 +36,7 @@ public class DefaultPropagationReporter implements PropagationReporter {
protected static final Logger LOG = LoggerFactory.getLogger(DefaultPropagationReporter.class);
- protected final List<PropagationStatus> statuses = new ArrayList<>();
+ protected final List<PropagationStatus> statuses = new CopyOnWriteArrayList<>();
protected boolean add(final PropagationStatus status) {
return statuses.stream().anyMatch(item -> item.getResource().equals(status.getResource()))
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 440d0cfb18..29c7dc094a 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
@@ -70,9 +70,9 @@ import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.SyncDelta;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
-@Transactional(rollbackFor = Throwable.class)
public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHandler<PullTask, PullActions>
implements SyncopePullResultHandler {
@@ -128,6 +128,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
this.executor = executor;
}
+ @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW)
@Override
public boolean handle(final SyncDelta delta) {
Provision provision = null;
@@ -265,15 +266,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
if (profile.getTask().isRemediation()) {
// set to SUCCESS to let the incremental flow go on in case of errors
resultStatus = Result.SUCCESS;
- createRemediation(
- provision.getAnyType(),
- null,
- anyCR,
- null,
- taskDAO.exists(TaskType.PULL, profile.getTask().getKey())
- ? profile.getTask() : null,
- result,
- delta);
+ createRemediation(provision.getAnyType(), null, anyCR, null, result, delta);
} else {
resultStatus = Result.FAILURE;
}
@@ -391,13 +384,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
if (profile.getTask().isRemediation()) {
// set to SUCCESS to let the incremental flow go on in case of errors
resultStatus = Result.SUCCESS;
- createRemediation(
- provision.getAnyType(),
- anyUR,
- taskDAO.exists(TaskType.PULL, profile.getTask().getKey())
- ? profile.getTask() : null,
- result,
- delta);
+ createRemediation(provision.getAnyType(), null, null, anyUR, result, delta);
} else {
resultStatus = Result.FAILURE;
}
@@ -695,14 +682,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
// set to SUCCESS to let the incremental flow go on in case of errors
resultStatus = Result.SUCCESS;
createRemediation(
- provision.getAnyType(),
- match.getAny().getKey(),
- null,
- null,
- taskDAO.exists(TaskType.PULL, profile.getTask().getKey())
- ? profile.getTask() : null,
- result,
- delta);
+ provision.getAnyType(), match.getAny().getKey(), null, null, result, delta);
}
}
@@ -989,43 +969,15 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
final ProvisioningReport result) {
if (ProvisioningReport.Status.FAILURE == result.getStatus() && profile.getTask().isRemediation()) {
- createRemediation(
- result.getAnyType(),
- null,
- null,
- anyUR,
- taskDAO.exists(TaskType.PULL, profile.getTask().getKey()) ? profile.getTask() : null,
- result,
- delta);
+ createRemediation(result.getAnyType(), null, null, anyUR, result, delta);
}
}
- protected void createRemediation(
- final String anyType,
- final AnyCR anyCR,
- final PullTask pullTask,
- final ProvisioningReport result,
- final SyncDelta delta) {
-
- createRemediation(anyType, null, anyCR, null, pullTask, result, delta);
- }
-
- protected void createRemediation(
- final String anyType,
- final AnyUR anyUR,
- final PullTask pullTask,
- final ProvisioningReport result,
- final SyncDelta delta) {
-
- createRemediation(anyType, null, null, anyUR, pullTask, result, delta);
- }
-
protected void createRemediation(
final String anyType,
final String anyKey,
final AnyCR anyCR,
final AnyUR anyUR,
- final PullTask pullTask,
final ProvisioningReport result,
final SyncDelta delta) {
@@ -1043,7 +995,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
remediation.setError(result.getMessage());
remediation.setInstant(OffsetDateTime.now());
remediation.setRemoteName(delta.getObject().getName().getNameValue());
- remediation.setPullTask(pullTask);
+ if (taskDAO.exists(TaskType.PULL, profile.getTask().getKey())) {
+ remediation.setPullTask((PullTask) taskDAO.find(TaskType.PULL, profile.getTask().getKey()));
+ }
remediation = remediationDAO.save(remediation);
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 9232e4b011..08164b5d91 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
@@ -422,7 +422,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
resultStatus = Result.FAILURE;
if (profile.getTask().isRemediation()) {
- createRemediation(provision.getAnyType(), req, profile.getTask(), report, delta);
+ createRemediation(provision.getAnyType(), null, null, req, report, delta);
}
}
@@ -541,7 +541,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
resultStatus = Result.FAILURE;
if (profile.getTask().isRemediation()) {
- createRemediation(provision.getAnyType(), userUR, profile.getTask(), report, delta);
+ createRemediation(provision.getAnyType(), null, null, userUR, report, delta);
}
}
@@ -617,7 +617,7 @@ public class DefaultUserPullResultHandler extends AbstractPullResultHandler impl
output = e;
if (profile.getTask().isRemediation()) {
- createRemediation(provision.getAnyType(), req, profile.getTask(), report, delta);
+ createRemediation(provision.getAnyType(), null, null, req, report, delta);
}
}
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 3bb5a9cc86..0dad00af24 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
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.core.provisioning.java.pushpull;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -25,18 +26,23 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.apache.syncope.common.lib.request.AnyUR;
+import org.apache.syncope.common.lib.request.MembershipUR;
+import org.apache.syncope.common.lib.request.UserUR;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.GroupTO;
import org.apache.syncope.common.lib.to.Provision;
import org.apache.syncope.common.lib.to.ProvisioningReport;
import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.PatchOperation;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.PullMatch;
import org.apache.syncope.core.provisioning.api.Connector;
-import org.apache.syncope.core.provisioning.api.job.JobManager;
+import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
-import org.apache.syncope.core.provisioning.java.job.SetUMembershipsJob;
+import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
+import org.apache.syncope.core.spring.implementation.InstanceScope;
+import org.apache.syncope.core.spring.implementation.SyncopeImplementation;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.identityconnectors.framework.common.objects.ObjectClass;
@@ -46,6 +52,7 @@ import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
@@ -54,7 +61,8 @@ import org.springframework.transaction.annotation.Transactional;
*
* @see org.apache.syncope.core.provisioning.java.propagation.LDAPMembershipPropagationActions
*/
-public class LDAPMembershipPullActions extends SchedulingPullActions {
+@SyncopeImplementation(scope = InstanceScope.PER_CONTEXT)
+public class LDAPMembershipPullActions implements PullActions {
protected static final Logger LOG = LoggerFactory.getLogger(LDAPMembershipPullActions.class);
@@ -65,7 +73,10 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
protected GroupDAO groupDAO;
@Autowired
- private InboundMatcher inboundMatcher;
+ protected InboundMatcher inboundMatcher;
+
+ @Autowired
+ protected UserProvisioningManager userProvisioningManager;
protected final Map<String, Set<String>> membershipsBefore = new HashMap<>();
@@ -137,7 +148,8 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
final AnyUR anyUR) throws JobExecutionException {
if (!(entity instanceof GroupTO)) {
- super.beforeUpdate(profile, delta, entity, anyUR);
+ PullActions.super.beforeUpdate(profile, delta, entity, anyUR);
+ return;
}
groupDAO.findUMemberships(groupDAO.find(entity.getKey())).forEach(uMembership -> {
@@ -162,13 +174,15 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
final ProvisioningReport result) throws JobExecutionException {
if (!(entity instanceof GroupTO)) {
- super.after(profile, delta, entity, result);
+ PullActions.super.after(profile, delta, entity, result);
+ return;
}
Optional<Provision> provision = profile.getTask().getResource().
getProvisionByAnyType(AnyTypeKind.USER.name()).filter(p -> p.getMapping() != null);
if (provision.isEmpty()) {
- super.after(profile, delta, entity, result);
+ PullActions.super.after(profile, delta, entity, result);
+ return;
}
getMembAttrValues(delta, profile.getConnector()).forEach(membValue -> {
@@ -190,15 +204,52 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
});
}
+ @Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void afterAll(final ProvisioningProfile<?, ?> profile) throws JobExecutionException {
- Map<String, Object> jobMap = new HashMap<>();
- jobMap.put(SetUMembershipsJob.MEMBERSHIPS_BEFORE_KEY, membershipsBefore);
- jobMap.put(SetUMembershipsJob.MEMBERSHIPS_AFTER_KEY, membershipsAfter);
- jobMap.put(JobManager.EXECUTOR_KEY, profile.getExecutor());
- jobMap.put(
- SetUMembershipsJob.CONTEXT,
- "PullTask " + profile.getTask().getKey() + " '" + profile.getTask().getName() + "'");
- schedule(SetUMembershipsJob.class, jobMap);
+ List<UserUR> updateReqs = new ArrayList<>();
+
+ membershipsAfter.forEach((user, groups) -> {
+ UserUR userUR = new UserUR();
+ userUR.setKey(user);
+ updateReqs.add(userUR);
+
+ groups.stream().forEach(group -> {
+ Set<String> before = membershipsBefore.get(user);
+ if (before == null || !before.contains(group)) {
+ userUR.getMemberships().add(new MembershipUR.Builder(group).
+ operation(PatchOperation.ADD_REPLACE).
+ build());
+ }
+ });
+ });
+
+ membershipsBefore.forEach((user, groups) -> {
+ UserUR userUR = updateReqs.stream().
+ filter(req -> user.equals(req.getKey())).findFirst().
+ orElseGet(() -> {
+ UserUR req = new UserUR.Builder(user).build();
+ updateReqs.add(req);
+ return req;
+ });
+
+ groups.forEach(group -> {
+ Set<String> after = membershipsAfter.get(user);
+ if (after == null || !after.contains(group)) {
+ userUR.getMemberships().add(new MembershipUR.Builder(group).
+ operation(PatchOperation.DELETE).
+ build());
+ }
+ });
+ });
+
+ membershipsAfter.clear();
+ membershipsBefore.clear();
+
+ String context = "PullTask " + profile.getTask().getKey() + " '" + profile.getTask().getName() + "'";
+ updateReqs.stream().filter(req -> !req.isEmpty()).forEach(req -> {
+ LOG.debug("About to update memberships for User {}", req.getKey());
+ userProvisioningManager.update(req, true, profile.getExecutor(), context);
+ });
}
}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SchedulingPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SchedulingPullActions.java
index cdf4483c45..c4fdbb0863 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SchedulingPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/SchedulingPullActions.java
@@ -41,6 +41,8 @@ import org.springframework.scheduling.quartz.SchedulerFactoryBean;
* Superclass for pull actions that need to schedule actions to run after their completion.
*
* @see LDAPMembershipPullActions for a concrete example
+ * @deprecated From 3.0.0-M2 this class is not needed anymore and will be removed from 3.0.0 onwards.
+ * After SYNCOPE-1705 there is no need anymore to schedule a job to run after the current pull task execution
*/
public abstract class SchedulingPullActions implements PullActions {
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
index a4d6ce0030..0d3a976d6a 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActionsTest.java
@@ -39,6 +39,7 @@ import org.apache.syncope.common.lib.request.AnyUR;
import org.apache.syncope.common.lib.request.UserUR;
import org.apache.syncope.common.lib.to.EntityTO;
import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.Mapping;
import org.apache.syncope.common.lib.to.Provision;
import org.apache.syncope.common.lib.to.ProvisioningReport;
import org.apache.syncope.common.lib.to.UserTO;
@@ -68,10 +69,7 @@ import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.quartz.JobExecutionException;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.test.util.ReflectionTestUtils;
public class LDAPMembershipPullActionsTest extends AbstractTest {
@@ -104,10 +102,13 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
private Map<String, Set<String>> membershipsAfter;
@Mock
- private ProvisioningTask<?> provisioningTask;
+ private ProvisioningTask<?> pullTask;
@Mock
- private ExternalResource externalResource;
+ private ExternalResource resource;
+
+ @Mock
+ private Provision provision;
@Mock
private Connector connector;
@@ -150,8 +151,10 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
connConfProperties = new HashSet<>();
connConfProperties.add(connConfProperty);
- lenient().when(profile.getTask()).thenAnswer(ic -> provisioningTask);
- lenient().when(provisioningTask.getResource()).thenReturn(externalResource);
+ lenient().when(profile.getTask()).thenAnswer(ic -> pullTask);
+ lenient().when(pullTask.getResource()).thenReturn(resource);
+ lenient().when(resource.getProvisionByAnyType(anyString())).thenReturn(Optional.of(provision));
+ lenient().when(provision.getMapping()).thenReturn(new Mapping());
lenient().when(anyTypeDAO.findUser()).thenAnswer(ic -> {
AnyType userAnyType = mock(AnyType.class);
lenient().when(userAnyType.getKey()).thenReturn(AnyTypeKind.USER.name());
@@ -192,27 +195,14 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
assertEquals(1, membershipsBefore.get(user.getKey()).size());
}
- @Test
- public void afterWithEmptyAttributes(final @Mock Attribute attribute) throws JobExecutionException {
- entity = new GroupTO();
-
- when(connectorObj.getAttributeByName(anyString())).thenReturn(attribute);
- when(externalResource.getProvisionByAnyType(anyString())).thenAnswer(ic -> Optional.of(mock(Provision.class)));
-
- ldapMembershipPullActions.after(profile, syncDelta, entity, result);
-
- assertEquals(List.of(), attribute.getValue());
- }
-
@Test
public void after() throws JobExecutionException {
- entity = new UserTO();
+ entity = new GroupTO();
String expectedUid = UUID.randomUUID().toString();
Attribute attribute = new Uid(expectedUid);
List<String> expected = List.of(expectedUid);
when(connectorObj.getAttributeByName(anyString())).thenReturn(attribute);
- when(externalResource.getProvisionByAnyType(anyString())).thenAnswer(ic -> Optional.empty());
when(inboundMatcher.match(any(AnyType.class), anyString(), any(ExternalResource.class), any(Connector.class))).
thenReturn(Optional.of(new PullMatch(MatchType.ANY, user)));
@@ -222,18 +212,4 @@ public class LDAPMembershipPullActionsTest extends AbstractTest {
verify(membershipsAfter).put(anyString(), any());
assertEquals(expected, attribute.getValue());
}
-
- @Test
- public void afterAll(
- final @Mock Map<String, Object> jobMap,
- final @Mock SchedulerFactoryBean schedulerFactoryBean,
- final @Mock Scheduler scheduler) throws JobExecutionException, SchedulerException {
-
- ReflectionTestUtils.setField(ldapMembershipPullActions, "scheduler", schedulerFactoryBean);
- when(schedulerFactoryBean.getScheduler()).thenReturn(scheduler);
-
- ldapMembershipPullActions.afterAll(profile);
-
- verify(scheduler).scheduleJob(any(), any());
- }
}
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 1301d14e25..b6c1571008 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
@@ -436,7 +436,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
assertEquals("odd", userConnObject.getAttr("title").get().getValues().get(0));
Attr userDn = userConnObject.getAttr(Name.NAME).get();
updateLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD,
- userDn.getValues().get(0), Collections.singletonMap("title", (String) null));
+ userDn.getValues().get(0), Collections.singletonMap("title", null));
// SYNCOPE-317
execProvisioningTask(
@@ -1083,7 +1083,7 @@ public class PullTaskITCase extends AbstractTaskITCase {
@Test
public void issueSYNCOPE307() {
assumeFalse(ElasticsearchDetector.isElasticSearchEnabled(ADMIN_CLIENT.platform()));
-
+
UserCR userCR = UserITCase.getUniqueSample("s307@apache.org");
userCR.setUsername("test0");
userCR.getPlainAttrs().removeIf(attr -> "firstname".equals(attr.getSchema()));