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
commit d3e17cf2586839bb5f69b3fce0bcc274314594d6 Author: Francesco Chicchiriccò <[email protected]> AuthorDate: Mon Nov 2 10:33:43 2026 +0100 Improving concurrent Push handling --- .../syncope/core/logic/ReconciliationLogic.java | 44 +++++++++++++---- .../apache/syncope/core/logic/ResourceLogic.java | 55 ++++++++++++++++------ .../api/pushpull/ProvisioningProfile.java | 8 ++++ .../java/pushpull/AbstractPushResultHandler.java | 9 ++-- .../pushpull/DefaultUserPushResultHandler.java | 21 ++++----- .../java/pushpull/OutboundMatcher.java | 45 ++++-------------- .../java/pushpull/PushJobDelegate.java | 37 +++++++++++++-- 7 files changed, 143 insertions(+), 76 deletions(-) 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 9c37e4df0f..e248beae34 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 @@ -18,13 +18,17 @@ */ package org.apache.syncope.core.logic; +import static org.apache.syncope.core.logic.AbstractLogic.LOG; + import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.BooleanUtils; import org.apache.syncope.common.lib.Attr; import org.apache.syncope.common.lib.SyncopeClientException; @@ -70,6 +74,7 @@ import org.apache.syncope.core.persistence.api.utils.RealmUtils; import org.apache.syncope.core.provisioning.api.ConnectorManager; import org.apache.syncope.core.provisioning.api.MappingManager; import org.apache.syncope.core.provisioning.api.job.JobExecutionException; +import org.apache.syncope.core.provisioning.api.propagation.PropagationActions; import org.apache.syncope.core.provisioning.api.pushpull.ConstantReconFilterBuilder; import org.apache.syncope.core.provisioning.api.pushpull.KeyValueReconFilterBuilder; import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder; @@ -86,6 +91,7 @@ import org.apache.syncope.core.provisioning.java.pushpull.stream.StreamPullJobDe import org.apache.syncope.core.provisioning.java.pushpull.stream.StreamPushJobDelegate; import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils; import org.apache.syncope.core.provisioning.java.utils.MappingUtils; +import org.apache.syncope.core.spring.implementation.ImplementationManager; import org.apache.syncope.core.spring.security.AuthContextUtils; import org.apache.syncope.core.spring.security.DelegatedAdministrationException; import org.identityconnectors.framework.common.objects.Attribute; @@ -133,6 +139,8 @@ public class ReconciliationLogic extends AbstractLogic<EntityTO> { protected final ConfigurableApplicationContext ctx; + protected final Map<String, PropagationActions> perContextPropagationActions = new ConcurrentHashMap<>(); + public ReconciliationLogic( final AnyUtilsFactory anyUtilsFactory, final AnyTypeDAO anyTypeDAO, @@ -235,7 +243,7 @@ public class ReconciliationLogic extends AbstractLogic<EntityTO> { orElseThrow(() -> new NotFoundException("Resource '" + resourceKey + '\'')); Provision provision = resource.getProvisionByAnyType(anyType.getKey()). orElseThrow(() -> new NotFoundException( - "Provision for " + anyType + " on Resource '" + resourceKey + "'")); + "Provision for " + anyType + " on Resource '" + resourceKey + "'")); if (provision.getMapping() == null) { throw new NotFoundException("Mapping for " + anyType + " on Resource '" + resourceKey + "'"); } @@ -243,6 +251,24 @@ public class ReconciliationLogic extends AbstractLogic<EntityTO> { return new ProvisioningInfo(anyType, resource, provision); } + protected List<PropagationActions> getPropagationActions(final ExternalResource resource) { + List<PropagationActions> result = new ArrayList<>(); + + resource.getPropagationActions().forEach(impl -> { + try { + result.add(ImplementationManager.build( + AuthContextUtils.getDomain(), + impl, + () -> perContextPropagationActions.get(impl.getKey()), + instance -> perContextPropagationActions.put(impl.getKey(), instance))); + } catch (Exception e) { + LOG.error("While building {}", impl, e); + } + }); + + return result; + } + @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')") @Transactional(readOnly = true) public ReconStatus status( @@ -255,8 +281,8 @@ public class ReconciliationLogic extends AbstractLogic<EntityTO> { Item connObjectKeyItem = MappingUtils.getConnObjectKeyItem(info.provision()). orElseThrow(() -> new NotFoundException( - "ConnObjectKey for " + info.anyType().getKey() - + " on resource '" + info.resource().getKey() + "'")); + "ConnObjectKey for " + info.anyType().getKey() + + " on resource '" + info.resource().getKey() + "'")); Any any = getAny(info.provision(), info.anyType().getKind(), anyKey); @@ -267,12 +293,14 @@ public class ReconciliationLogic extends AbstractLogic<EntityTO> { status.setRealm(any.getRealm().getFullPath()); status.setOnSyncope(getOnSyncope(any, connObjectKeyItem, info.resource(), info.provision())); + getPropagationActions(info.resource()). + forEach(action -> moreAttrsToGet.addAll(action.moreAttrsToGet(Optional.empty(), info.provision()))); List<ConnectorObject> connObjs = outboundMatcher.match( connectorManager.getConnector(info.resource()), any, info.resource(), info.provision(), - Optional.of(moreAttrsToGet.toArray(String[]::new))); + moreAttrsToGet.toArray(String[]::new)); if (!connObjs.isEmpty()) { status.setOnResource(ConnObjectUtils.getConnObjectTO( outboundMatcher.getFIQL(connObjs.getFirst(), info.resource(), info.provision()), @@ -335,8 +363,8 @@ public class ReconciliationLogic extends AbstractLogic<EntityTO> { if (syncDeltaBuilder.getObject() != null) { Item connObjectKeyItem = MappingUtils.getConnObjectKeyItem(info.provision()). orElseThrow(() -> new NotFoundException( - "ConnObjectKey for " + info.anyType().getKey() - + " on resource '" + info.resource().getKey() + "'")); + "ConnObjectKey for " + info.anyType().getKey() + + " on resource '" + info.resource().getKey() + "'")); inboundMatcher.match( syncDeltaBuilder.build(), info.resource(), info.provision(), info.anyType().getKind()). @@ -547,8 +575,8 @@ public class ReconciliationLogic extends AbstractLogic<EntityTO> { String connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, info.resource(), info.provision()). orElseThrow(() -> new NotFoundException( - "ConnObjectKey for " + info.anyType().getKey() - + " on resource '" + info.resource().getKey() + "'")); + "ConnObjectKey for " + info.anyType().getKey() + + " on resource '" + info.resource().getKey() + "'")); return pull( info.resource(), 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 4678327172..f02a14208f 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,9 +20,12 @@ package org.apache.syncope.core.logic; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; @@ -50,9 +53,11 @@ import org.apache.syncope.core.provisioning.api.Connector; import org.apache.syncope.core.provisioning.api.ConnectorManager; import org.apache.syncope.core.provisioning.api.MappingManager; import org.apache.syncope.core.provisioning.api.data.ResourceDataBinder; +import org.apache.syncope.core.provisioning.api.propagation.PropagationActions; 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.apache.syncope.core.spring.implementation.ImplementationManager; import org.apache.syncope.core.spring.security.AuthContextUtils; import org.apache.syncope.core.spring.security.DelegatedAdministrationException; import org.identityconnectors.framework.common.objects.ConnectorObject; @@ -83,6 +88,8 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> { protected final AnyUtilsFactory anyUtilsFactory; + protected final Map<String, PropagationActions> perContextPropagationActions = new ConcurrentHashMap<>(); + public ResourceLogic( final ExternalResourceDAO resourceDAO, final AnyTypeDAO anyTypeDAO, @@ -179,7 +186,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> { orElseThrow(() -> new NotFoundException("AnyType " + anyTypeKey)); Provision provision = resource.getProvisionByAnyType(anyType.getKey()). orElseThrow(() -> new NotFoundException( - "Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + '\'')); + "Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + '\'')); provision.setSyncToken(ConnObjectUtils.toString( connector.getLatestSyncToken(new ObjectClass(provision.getObjectClass())))); @@ -208,7 +215,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> { orElseThrow(() -> new NotFoundException("AnyType " + anyTypeKey)); Provision provision = resource.getProvisionByAnyType(anyType.getKey()). orElseThrow(() -> new NotFoundException( - "Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + '\'')); + "Provision for AnyType '" + anyTypeKey + "' in Resource '" + key + '\'')); provision.setSyncToken(null); } @@ -261,7 +268,7 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> { orElseThrow(() -> new NotFoundException("Resource '" + resourceKey + '\'')); Provision provision = resource.getProvisionByAnyType(anyType.getKey()). orElseThrow(() -> new NotFoundException( - "Provision for " + anyType + " on Resource '" + resourceKey + "'")); + "Provision for " + anyType + " on Resource '" + resourceKey + "'")); if (provision.getMapping() == null) { throw new NotFoundException("Mapping for " + anyType + " on Resource '" + resourceKey + "'"); } @@ -285,8 +292,26 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> { // 2.get ConnObjectKey value return mappingManager.getConnObjectKeyValue(any, info.resource(), info.provision()). - orElseThrow(() -> new NotFoundException( - "No ConnObjectKey value found for " + anyTypeKey + " " + anyKey + " on resource '" + key + "'")); + orElseThrow(() -> new NotFoundException("No ConnObjectKey value found for " + + anyTypeKey + " " + anyKey + " on resource '" + key + "'")); + } + + protected List<PropagationActions> getPropagationActions(final ExternalResource resource) { + List<PropagationActions> result = new ArrayList<>(); + + resource.getPropagationActions().forEach(impl -> { + try { + result.add(ImplementationManager.build( + AuthContextUtils.getDomain(), + impl, + () -> perContextPropagationActions.get(impl.getKey()), + instance -> perContextPropagationActions.put(impl.getKey(), instance))); + } catch (Exception e) { + LOG.error("While building {}", impl, e); + } + }); + + return result; } @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_GET_CONNOBJECT + "')") @@ -304,12 +329,15 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> { orElseThrow(() -> new NotFoundException(info.anyType() + " " + anyKey)); // 2. find on resource + Set<String> moreAttrsToGet = new HashSet<>(); + getPropagationActions(info.resource()). + forEach(action -> moreAttrsToGet.addAll(action.moreAttrsToGet(Optional.empty(), info.provision()))); List<ConnectorObject> connObjs = outboundMatcher.match( connectorManager.getConnector(info.resource()), any, info.resource(), info.provision(), - Optional.empty()); + moreAttrsToGet.toArray(String[]::new)); if (connObjs.isEmpty()) { throw new NotFoundException( "Object " + any + " with class " + info.provision().getObjectClass() @@ -336,21 +364,20 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> { Item connObjectKeyItem = MappingUtils.getConnObjectKeyItem(info.provision()). orElseThrow(() -> new NotFoundException( - "ConnObjectKey mapping for " + info.anyType().getKey() - + " on resource '" + info.resource().getKey() + "'")); + "ConnObjectKey mapping for " + info.anyType().getKey() + + " on resource '" + info.resource().getKey() + "'")); return outboundMatcher.matchByConnObjectKeyValue( connectorManager.getConnector(info.resource()), connObjectKeyItem, connObjectKeyValue, - info.provision(), - Optional.empty()). + info.provision()). map(connectorObject -> ConnObjectUtils.getConnObjectTO( - outboundMatcher.getFIQL(connectorObject, info.resource(), info.provision()), - connectorObject.getAttributes())). + outboundMatcher.getFIQL(connectorObject, info.resource(), info.provision()), + connectorObject.getAttributes())). orElseThrow(() -> new NotFoundException( - "Object " + connObjectKeyValue + " with class " + info.provision().getObjectClass() - + " not found on resource " + info.resource().getKey())); + "Object " + connObjectKeyValue + " with class " + info.provision().getObjectClass() + + " not found on resource " + info.resource().getKey())); } @PreAuthorize("hasRole('" + IdMEntitlement.RESOURCE_LIST_CONNOBJECT + "')") diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java index 3cb8e6034a..cc90962e68 100644 --- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java +++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java @@ -18,6 +18,7 @@ */ package org.apache.syncope.core.provisioning.api.pushpull; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.apache.syncope.common.lib.to.ProvisioningReport; @@ -25,6 +26,7 @@ import org.apache.syncope.common.lib.types.ConflictResolutionAction; import org.apache.syncope.common.lib.types.TaskType; import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask; import org.apache.syncope.core.provisioning.api.Connector; +import org.apache.syncope.core.provisioning.api.propagation.PropagationActions; public class ProvisioningProfile<T extends ProvisioningTask<?>, A extends ProvisioningActions> { @@ -42,6 +44,8 @@ public class ProvisioningProfile<T extends ProvisioningTask<?>, A extends Provis private final List<A> actions; + private final List<PropagationActions> propagationActions = new ArrayList<>(); + private final List<ProvisioningReport> results = new CopyOnWriteArrayList<>(); public ProvisioningProfile( @@ -86,6 +90,10 @@ public class ProvisioningProfile<T extends ProvisioningTask<?>, A extends Provis return actions; } + public List<PropagationActions> getPropagationActions() { + return propagationActions; + } + public List<ProvisioningReport> getResults() { return results; } 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 418c70bd2a..06db727110 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 @@ -300,13 +300,16 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan // Try to read remote object BEFORE any actual operation Set<String> moreAttrsToGet = new HashSet<>(); - profile.getActions().forEach(action -> moreAttrsToGet.addAll(action.moreAttrsToGet(profile, any))); + profile.getActions(). + forEach(action -> moreAttrsToGet.addAll(action.moreAttrsToGet(profile, any))); + profile.getPropagationActions(). + forEach(action -> moreAttrsToGet.addAll(action.moreAttrsToGet(Optional.empty(), provision))); List<ConnectorObject> connObjs = outboundMatcher.match( profile.getConnector(), any, profile.getTask().getResource(), provision, - Optional.of(moreAttrsToGet.toArray(String[]::new))); + moreAttrsToGet.toArray(String[]::new)); LOG.debug("Match(es) found for {} as {}: {}", any, provision.getObjectClass(), connObjs); if (connObjs.size() > 1) { @@ -507,7 +510,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan any, profile.getTask().getResource(), provision, - Optional.of(moreAttrsToGet.toArray(String[]::new))); + moreAttrsToGet.toArray(String[]::new)); } } catch (IgnoreProvisionException e) { throw e; 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 b99933fbdf..542b68b3f6 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 @@ -83,8 +83,8 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>(); ((User) any).getLinkedAccounts(profile.getTask().getResource().getKey()). forEach(account -> propByLinkedAccount.add( - ResourceOperation.CREATE, - Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()))); + ResourceOperation.CREATE, + Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()))); PropagationReporter reporter = taskExecutor.execute(propagationManager.getUserCreateTasks( before.getKey(), @@ -118,8 +118,8 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>(); ((User) any).getLinkedAccounts(profile.getTask().getResource().getKey()). forEach(account -> propByLinkedAccount.add( - ResourceOperation.UPDATE, - Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()))); + ResourceOperation.UPDATE, + Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()))); List<PropagationTaskInfo> taskInfos = propagationManager.getUpdateTasks( null, @@ -152,8 +152,8 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl PropagationByResource<Pair<String, String>> propByLinkedAccount = new PropagationByResource<>(); ((User) any).getLinkedAccounts(profile.getTask().getResource().getKey()). forEach(account -> propByLinkedAccount.add( - ResourceOperation.DELETE, - Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()))); + ResourceOperation.DELETE, + Pair.of(account.getResource().getKey(), account.getConnObjectKeyValue()))); List<PropagationTaskInfo> taskInfos = propagationManager.getDeleteTasks( any.getType().getKind(), @@ -222,11 +222,10 @@ public class DefaultUserPushResultHandler extends AbstractPushResultHandler impl // Try to read remote object BEFORE any actual operation Optional<ConnectorObject> connObj = MappingUtils.getConnObjectKeyItem(provision). flatMap(connObjectKeyItem -> outboundMatcher.matchByConnObjectKeyValue( - profile.getConnector(), - connObjectKeyItem, - account.getConnObjectKeyValue(), - provision, - Optional.empty())); + profile.getConnector(), + connObjectKeyItem, + account.getConnObjectKeyValue(), + provision)); LOG.debug("Match found for linked account {} as {}: {}", account, provision.getObjectClass(), connObj); ConnectorObject beforeObj = connObj.orElse(null); 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 index 5fe2d98e3c..f8a422df20 100644 --- 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 @@ -25,7 +25,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Stream; import org.apache.syncope.common.lib.to.Item; import org.apache.syncope.common.lib.to.Provision; import org.apache.syncope.common.lib.types.AnyTypeKind; @@ -64,8 +63,6 @@ public class OutboundMatcher { protected final AnyUtilsFactory anyUtilsFactory; - protected final Map<String, PropagationActions> perContextActions = new ConcurrentHashMap<>(); - protected final Map<String, PushCorrelationRule> perContextPushCorrelationRules = new ConcurrentHashMap<>(); public OutboundMatcher( @@ -137,14 +134,14 @@ public class OutboundMatcher { connector, rule.get().getFilter(any, taskInfo.getResource(), provision), provision, - Optional.of(moreAttrsToGet.toArray(String[]::new)))); + moreAttrsToGet.toArray(String[]::new))); } else { MappingUtils.getConnObjectKeyItem(provision).flatMap(connObjectKeyItem -> matchByConnObjectKeyValue( connector, connObjectKeyItem, connObjectKeyValue, provision, - Optional.of(moreAttrsToGet.toArray(String[]::new)))).ifPresent(result::add); + moreAttrsToGet.toArray(String[]::new))).ifPresent(result::add); } } catch (RuntimeException e) { LOG.error("Could not match {} with any existing {}", any, provision.getObjectClass(), e); @@ -153,37 +150,13 @@ public class OutboundMatcher { return result; } - protected List<PropagationActions> getPropagationActions(final ExternalResource resource) { - List<PropagationActions> result = new ArrayList<>(); - - resource.getPropagationActions().forEach(impl -> { - try { - result.add(ImplementationManager.build( - AuthContextUtils.getDomain(), - impl, - () -> perContextActions.get(impl.getKey()), - instance -> perContextActions.put(impl.getKey(), instance))); - } catch (Exception e) { - LOG.error("While building {}", impl, e); - } - }); - - return result; - } - @Transactional(readOnly = true) public List<ConnectorObject> match( final Connector connector, final Any any, final ExternalResource resource, final Provision provision, - final Optional<String[]> moreAttrsToGet) { - - Stream<String> matgFromPropagationActions = getPropagationActions(resource).stream(). - flatMap(a -> a.moreAttrsToGet(Optional.empty(), provision).stream()); - Optional<String[]> effectiveMATG = Optional.of(Stream.concat( - moreAttrsToGet.stream().flatMap(Stream::of), - matgFromPropagationActions).toArray(String[]::new)); + final String... moreAttrsToGet) { Optional<PushCorrelationRule> rule = rule(resource, provision); @@ -194,7 +167,7 @@ public class OutboundMatcher { connector, rule.get().getFilter(any, resource, provision), provision, - effectiveMATG)); + moreAttrsToGet)); } else { Optional<Item> connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision); Optional<String> connObjectKeyValue = mappingManager.getConnObjectKeyValue(any, resource, provision); @@ -205,7 +178,7 @@ public class OutboundMatcher { connObjectKeyItem.get(), connObjectKeyValue.get(), provision, - effectiveMATG). + moreAttrsToGet). ifPresent(result::add); } } @@ -220,7 +193,7 @@ public class OutboundMatcher { final Connector connector, final Filter filter, final Provision provision, - final Optional<String[]> moreAttrsToGet) { + final String... moreAttrsToGet) { List<ConnectorObject> objs = new ArrayList<>(); try { @@ -237,7 +210,7 @@ public class OutboundMatcher { return true; } }, MappingUtils.buildOperationOptions( - provision.getMapping().getItems().stream(), moreAttrsToGet.orElse(null))); + provision.getMapping().getItems().stream(), moreAttrsToGet)); } catch (TimeoutException toe) { LOG.debug("Request timeout", toe); throw toe; @@ -254,7 +227,7 @@ public class OutboundMatcher { final Item connObjectKeyItem, final String connObjectKeyValue, final Provision provision, - final Optional<String[]> moreAttrsToGet) { + final String... moreAttrsToGet) { ConnectorObject obj = null; try { @@ -263,7 +236,7 @@ public class OutboundMatcher { AttributeBuilder.build(connObjectKeyItem.getExtAttrName(), connObjectKeyValue), provision.isIgnoreCaseMatch(), MappingUtils.buildOperationOptions( - provision.getMapping().getItems().stream(), moreAttrsToGet.orElse(null))); + provision.getMapping().getItems().stream(), moreAttrsToGet)); } 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/pushpull/PushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java index 6f60b26493..e5ad81f7cc 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java @@ -48,6 +48,7 @@ import org.apache.syncope.core.provisioning.api.ProvisionSorter; import org.apache.syncope.core.provisioning.api.job.JobExecutionContext; import org.apache.syncope.core.provisioning.api.job.JobExecutionException; import org.apache.syncope.core.provisioning.api.job.StoppableJobDelegate; +import org.apache.syncope.core.provisioning.api.propagation.PropagationActions; import org.apache.syncope.core.provisioning.api.pushpull.AnyPushResultHandler; import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile; import org.apache.syncope.core.provisioning.api.pushpull.PushActions; @@ -81,7 +82,9 @@ public class PushJobDelegate protected final Map<String, MutablePair<Integer, String>> handled = new ConcurrentHashMap<>(); - protected final Map<String, PushActions> perContextActions = new ConcurrentHashMap<>(); + protected final Map<String, PushActions> perContextOPushActions = new ConcurrentHashMap<>(); + + protected final Map<String, PropagationActions> perContextPropagationActions = new ConcurrentHashMap<>(); protected PushResultHandlerDispatcher dispatcher; @@ -139,7 +142,10 @@ public class PushJobDelegate return ctx.getBeanFactory().createBean(DefaultGroupPushResultHandler.class); } - protected List<PushActions> getPushActions(final String domain, final List<? extends Implementation> impls) { + protected List<PushActions> getPushActions( + final String domain, + final List<? extends Implementation> impls) { + List<PushActions> result = new ArrayList<>(); impls.forEach(impl -> { @@ -147,8 +153,8 @@ public class PushJobDelegate result.add(ImplementationManager.build( domain, impl, - () -> perContextActions.get(impl.getKey()), - instance -> perContextActions.put(impl.getKey(), instance))); + () -> perContextOPushActions.get(impl.getKey()), + instance -> perContextOPushActions.put(impl.getKey(), instance))); } catch (Exception e) { LOG.warn("While building {}", impl, e); } @@ -157,6 +163,27 @@ public class PushJobDelegate return result; } + protected List<PropagationActions> getPropagationActions( + final String domain, + final List<? extends Implementation> impls) { + + List<PropagationActions> result = new ArrayList<>(); + + impls.forEach(impl -> { + try { + result.add(ImplementationManager.build( + domain, + impl, + () -> perContextPropagationActions.get(impl.getKey()), + instance -> perContextPropagationActions.put(impl.getKey(), instance))); + } catch (Exception e) { + LOG.error("While building {}", impl, e); + } + }); + + return result; + } + @Override protected void init( final TaskType taskType, @@ -175,6 +202,8 @@ public class PushJobDelegate getPushActions(context.domain(), task.getActions()), AuthContextUtils.getUsername(), context.dryRun()); + profile.getPropagationActions().addAll( + getPropagationActions(context.domain(), task.getResource().getPropagationActions())); } @Override
