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 2015/03/06 12:13:52 UTC

[1/4] syncope git commit: Reduing the thread number to avoid OutOfMemory errors on some platforms

Repository: syncope
Updated Branches:
  refs/heads/1_2_X c6640c99c -> 28783291d
  refs/heads/master 350b3bd24 -> 246457cd5


Reduing the thread number to avoid OutOfMemory errors on some platforms


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/c6640c99
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/c6640c99
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/c6640c99

Branch: refs/heads/master
Commit: c6640c99c2cc7d242ba5b7f279de2c967c8cce40
Parents: 312897e
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Wed Mar 4 08:31:05 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Wed Mar 4 08:31:05 2015 +0100

----------------------------------------------------------------------
 .../test/java/org/apache/syncope/client/ConcurrencyTest.java | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/c6640c99/client/src/test/java/org/apache/syncope/client/ConcurrencyTest.java
----------------------------------------------------------------------
diff --git a/client/src/test/java/org/apache/syncope/client/ConcurrencyTest.java b/client/src/test/java/org/apache/syncope/client/ConcurrencyTest.java
index c7228c3..8c599db 100644
--- a/client/src/test/java/org/apache/syncope/client/ConcurrencyTest.java
+++ b/client/src/test/java/org/apache/syncope/client/ConcurrencyTest.java
@@ -30,6 +30,8 @@ public class ConcurrencyTest {
 
     private static final Logger LOG = LoggerFactory.getLogger(ConcurrencyTest.class);
 
+    private static final int THREAD_NUMBER = 1000;
+
     private static final SyncopeClient client =
             new SyncopeClientFactoryBean().setAddress("http://url").create("username", "password");
 
@@ -37,7 +39,7 @@ public class ConcurrencyTest {
     public void multiThreadTest()
             throws InterruptedException {
 
-        for (int i = 0; i < 10000; i++) {
+        for (int i = 0; i < THREAD_NUMBER; i++) {
             Thread execution = new Thread("Th-" + StringUtils.leftPad(String.valueOf(i), 5, '0')) {
 
                 @Override
@@ -55,13 +57,13 @@ public class ConcurrencyTest {
             execution.start();
         }
 
-        Thread.sleep(10000);
+        Thread.sleep(THREAD_NUMBER);
     }
 
     @Test
     public void multiCallTest() {
         try {
-            for (int i = 0; i < 10000; i++) {
+            for (int i = 0; i < THREAD_NUMBER; i++) {
                 client.getService(ResourceService.class);
             }
         } catch (Exception e) {


[3/4] syncope git commit: Cleanup: removing useless public static method

Posted by il...@apache.org.
Cleanup: removing useless public static method


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/28783291
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/28783291
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/28783291

Branch: refs/heads/1_2_X
Commit: 28783291da64c4d4cfd3fe7760cc3ef2826614bf
Parents: c6640c9
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Mar 6 11:46:07 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Mar 6 11:46:07 2015 +0100

----------------------------------------------------------------------
 .../impl/AbstractPropagationTaskExecutor.java   | 48 ++++++--------------
 1 file changed, 15 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/28783291/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java b/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
index 3cd44c2..ac31ec4 100644
--- a/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
+++ b/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
@@ -130,23 +130,18 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         return result;
     }
 
-    public static void createOrUpdate(
-            final ObjectClass oclass,
-            final String accountId,
-            final Set<Attribute> attrs,
-            final String resource,
-            final PropagationMode propagationMode,
+    protected void createOrUpdate(
+            final PropagationTask task,
             final ConnectorObject beforeObj,
             final Connector connector,
-            final Set<String> propagationAttempted,
-            final ConnObjectUtil connObjectUtil) {
+            final Set<String> propagationAttempted) {
 
         // set of attributes to be propagated
-        final Set<Attribute> attributes = new HashSet<Attribute>(attrs);
+        final Set<Attribute> attributes = new HashSet<Attribute>(task.getAttributes());
 
         // check if there is any missing or null / empty mandatory attribute
         List<Object> mandatoryAttrNames = new ArrayList<Object>();
-        Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, attrs);
+        Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, task.getAttributes());
         if (mandatoryMissing != null) {
             attributes.remove(mandatoryMissing);
 
@@ -154,7 +149,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                 mandatoryAttrNames.addAll(mandatoryMissing.getValue());
             }
         }
-        Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, attrs);
+        Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, task.getAttributes());
         if (mandatoryNullOrEmpty != null) {
             attributes.remove(mandatoryNullOrEmpty);
 
@@ -166,8 +161,13 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         }
 
         if (beforeObj == null) {
-            LOG.debug("Create {} on {}", attributes, resource);
-            connector.create(propagationMode, oclass, attributes, null, propagationAttempted);
+            LOG.debug("Create {} on {}", attributes, task.getResource().getName());
+            connector.create(
+                    task.getResource().getPropagationMode(),
+                    new ObjectClass(task.getObjectClassName()),
+                    attributes,
+                    null,
+                    propagationAttempted);
         } else {
             // 1. check if rename is really required
             final Name newName = (Name) AttributeUtil.find(Name.NAME, attributes);
@@ -208,32 +208,14 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                 }
 
                 // 3. provision entry
-                LOG.debug("Update {} on {}", strictlyModified, resource);
+                LOG.debug("Update {} on {}", strictlyModified, task.getResource().getName());
 
-                connector.update(propagationMode, beforeObj.getObjectClass(),
+                connector.update(task.getResource().getPropagationMode(), beforeObj.getObjectClass(),
                         beforeObj.getUid(), strictlyModified, null, propagationAttempted);
             }
         }
     }
 
-    protected void createOrUpdate(
-            final PropagationTask task,
-            final ConnectorObject beforeObj,
-            final Connector connector,
-            final Set<String> propagationAttempted) {
-
-        createOrUpdate(
-                new ObjectClass(task.getObjectClassName()),
-                task.getAccountId(),
-                task.getAttributes(),
-                task.getResource().getName(),
-                task.getResource().getPropagationMode(),
-                beforeObj,
-                connector,
-                propagationAttempted,
-                connObjectUtil);
-    }
-
     protected AbstractSubject getSubject(final PropagationTask task) {
         AbstractSubject subject = null;
 


[2/4] syncope git commit: Cleanup: removing useless public static method

Posted by il...@apache.org.
Cleanup: removing useless public static method


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/28783291
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/28783291
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/28783291

Branch: refs/heads/master
Commit: 28783291da64c4d4cfd3fe7760cc3ef2826614bf
Parents: c6640c9
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Mar 6 11:46:07 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Mar 6 11:46:07 2015 +0100

----------------------------------------------------------------------
 .../impl/AbstractPropagationTaskExecutor.java   | 48 ++++++--------------
 1 file changed, 15 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/28783291/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java b/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
index 3cd44c2..ac31ec4 100644
--- a/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
+++ b/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
@@ -130,23 +130,18 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         return result;
     }
 
-    public static void createOrUpdate(
-            final ObjectClass oclass,
-            final String accountId,
-            final Set<Attribute> attrs,
-            final String resource,
-            final PropagationMode propagationMode,
+    protected void createOrUpdate(
+            final PropagationTask task,
             final ConnectorObject beforeObj,
             final Connector connector,
-            final Set<String> propagationAttempted,
-            final ConnObjectUtil connObjectUtil) {
+            final Set<String> propagationAttempted) {
 
         // set of attributes to be propagated
-        final Set<Attribute> attributes = new HashSet<Attribute>(attrs);
+        final Set<Attribute> attributes = new HashSet<Attribute>(task.getAttributes());
 
         // check if there is any missing or null / empty mandatory attribute
         List<Object> mandatoryAttrNames = new ArrayList<Object>();
-        Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, attrs);
+        Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, task.getAttributes());
         if (mandatoryMissing != null) {
             attributes.remove(mandatoryMissing);
 
@@ -154,7 +149,7 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                 mandatoryAttrNames.addAll(mandatoryMissing.getValue());
             }
         }
-        Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, attrs);
+        Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, task.getAttributes());
         if (mandatoryNullOrEmpty != null) {
             attributes.remove(mandatoryNullOrEmpty);
 
@@ -166,8 +161,13 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         }
 
         if (beforeObj == null) {
-            LOG.debug("Create {} on {}", attributes, resource);
-            connector.create(propagationMode, oclass, attributes, null, propagationAttempted);
+            LOG.debug("Create {} on {}", attributes, task.getResource().getName());
+            connector.create(
+                    task.getResource().getPropagationMode(),
+                    new ObjectClass(task.getObjectClassName()),
+                    attributes,
+                    null,
+                    propagationAttempted);
         } else {
             // 1. check if rename is really required
             final Name newName = (Name) AttributeUtil.find(Name.NAME, attributes);
@@ -208,32 +208,14 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
                 }
 
                 // 3. provision entry
-                LOG.debug("Update {} on {}", strictlyModified, resource);
+                LOG.debug("Update {} on {}", strictlyModified, task.getResource().getName());
 
-                connector.update(propagationMode, beforeObj.getObjectClass(),
+                connector.update(task.getResource().getPropagationMode(), beforeObj.getObjectClass(),
                         beforeObj.getUid(), strictlyModified, null, propagationAttempted);
             }
         }
     }
 
-    protected void createOrUpdate(
-            final PropagationTask task,
-            final ConnectorObject beforeObj,
-            final Connector connector,
-            final Set<String> propagationAttempted) {
-
-        createOrUpdate(
-                new ObjectClass(task.getObjectClassName()),
-                task.getAccountId(),
-                task.getAttributes(),
-                task.getResource().getName(),
-                task.getResource().getPropagationMode(),
-                beforeObj,
-                connector,
-                propagationAttempted,
-                connObjectUtil);
-    }
-
     protected AbstractSubject getSubject(final PropagationTask task) {
         AbstractSubject subject = null;
 


[4/4] syncope git commit: Cleanup: removing useless public static method

Posted by il...@apache.org.
Cleanup: removing useless public static method


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/246457cd
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/246457cd
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/246457cd

Branch: refs/heads/master
Commit: 246457cd59723f769076b213964f77da3e5db232
Parents: 350b3bd 2878329
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Fri Mar 6 12:13:42 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Mar 6 12:13:42 2015 +0100

----------------------------------------------------------------------
 .../AbstractPropagationTaskExecutor.java        | 48 ++++++--------------
 1 file changed, 15 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/246457cd/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --cc core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index 83e14fa,0000000..7114f44
mode 100644,000000..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
@@@ -1,540 -1,0 +1,522 @@@
 +/*
 + * 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.propagation;
 +
 +import java.util.ArrayList;
 +import java.util.Collection;
 +import java.util.Date;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import org.apache.syncope.common.lib.types.AuditElements;
 +import org.apache.syncope.common.lib.types.AuditElements.Result;
 +import org.apache.syncope.common.lib.types.MappingPurpose;
 +import org.apache.syncope.common.lib.types.PropagationMode;
 +import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
 +import org.apache.syncope.common.lib.types.TraceLevel;
 +import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 +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.AttributableUtilFactory;
 +import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 +import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 +import org.apache.syncope.core.persistence.api.entity.Subject;
 +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;
 +import org.apache.syncope.core.provisioning.api.ConnectorFactory;
 +import org.apache.syncope.core.provisioning.api.TimeoutException;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 +import org.apache.syncope.core.misc.AuditManager;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.misc.ConnObjectUtil;
 +import org.apache.syncope.core.misc.ExceptionUtil;
 +import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
 +import org.identityconnectors.framework.common.exceptions.ConnectorException;
 +import org.identityconnectors.framework.common.objects.Attribute;
 +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.Uid;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.beans.factory.support.AbstractBeanDefinition;
 +import org.springframework.transaction.annotation.Transactional;
 +
 +@Transactional(rollbackFor = { Throwable.class })
 +public abstract class AbstractPropagationTaskExecutor implements PropagationTaskExecutor {
 +
 +    /**
 +     * Logger.
 +     */
 +    protected static final Logger LOG = LoggerFactory.getLogger(PropagationTaskExecutor.class);
 +
 +    /**
 +     * Connector factory.
 +     */
 +    @Autowired
 +    protected ConnectorFactory connFactory;
 +
 +    /**
 +     * ConnObjectUtil.
 +     */
 +    @Autowired
 +    protected ConnObjectUtil connObjectUtil;
 +
 +    /**
 +     * User DAO.
 +     */
 +    @Autowired
 +    protected UserDAO userDAO;
 +
 +    /**
 +     * User DAO.
 +     */
 +    @Autowired
 +    protected RoleDAO roleDAO;
 +
 +    /**
 +     * Task DAO.
 +     */
 +    @Autowired
 +    protected TaskDAO taskDAO;
 +
 +    /**
 +     * Notification Manager.
 +     */
 +    @Autowired
 +    protected NotificationManager notificationManager;
 +
 +    /**
 +     * Audit Manager.
 +     */
 +    @Autowired
 +    protected AuditManager auditManager;
 +
 +    @Autowired
 +    protected AttributableUtilFactory attrUtilFactory;
 +
 +    @Autowired
 +    protected EntityFactory entityFactory;
 +
 +    @Override
 +    public TaskExec execute(final PropagationTask task) {
 +        return execute(task, null);
 +    }
 +
 +    protected List<PropagationActions> getPropagationActions(final ExternalResource resource) {
 +        List<PropagationActions> result = new ArrayList<>();
 +
 +        if (!resource.getPropagationActionsClassNames().isEmpty()) {
 +            for (String className : resource.getPropagationActionsClassNames()) {
 +                try {
 +                    Class<?> actionsClass = Class.forName(className);
 +                    result.add((PropagationActions) ApplicationContextProvider.getBeanFactory().
 +                            createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true));
 +                } catch (ClassNotFoundException e) {
 +                    LOG.error("Invalid PropagationAction class name '{}' for resource {}", resource, className, e);
 +                }
 +            }
 +        }
 +
 +        return result;
 +    }
 +
-     public static void createOrUpdate(
-             final ObjectClass oclass,
-             final String accountId,
-             final Set<Attribute> attrs,
-             final String resource,
-             final PropagationMode propagationMode,
++    protected void createOrUpdate(
++            final PropagationTask task,
 +            final ConnectorObject beforeObj,
 +            final Connector connector,
-             final Set<String> propagationAttempted,
-             final ConnObjectUtil connObjectUtil) {
++            final Set<String> propagationAttempted) {
 +
 +        // set of attributes to be propagated
-         final Set<Attribute> attributes = new HashSet<>(attrs);
++        final Set<Attribute> attributes = new HashSet<>(task.getAttributes());
 +
 +        // check if there is any missing or null / empty mandatory attribute
 +        List<Object> mandatoryAttrNames = new ArrayList<>();
-         Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, attrs);
++        Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, task.getAttributes());
 +        if (mandatoryMissing != null) {
 +            attributes.remove(mandatoryMissing);
 +
 +            if (beforeObj == null) {
 +                mandatoryAttrNames.addAll(mandatoryMissing.getValue());
 +            }
 +        }
-         Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, attrs);
++        Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, task.getAttributes());
 +        if (mandatoryNullOrEmpty != null) {
 +            attributes.remove(mandatoryNullOrEmpty);
 +
 +            mandatoryAttrNames.addAll(mandatoryNullOrEmpty.getValue());
 +        }
 +        if (!mandatoryAttrNames.isEmpty()) {
 +            throw new IllegalArgumentException(
 +                    "Not attempted because there are mandatory attributes without value(s): " + mandatoryAttrNames);
 +        }
 +
 +        if (beforeObj == null) {
-             LOG.debug("Create {} on {}", attributes, resource);
-             connector.create(propagationMode, oclass, attributes, null, propagationAttempted);
++            LOG.debug("Create {} on {}", attributes, task.getResource().getKey());
++            connector.create(
++                    task.getResource().getPropagationMode(),
++                    new ObjectClass(task.getObjectClassName()),
++                    attributes,
++                    null,
++                    propagationAttempted);
 +        } else {
 +            // 1. check if rename is really required
 +            final Name newName = (Name) AttributeUtil.find(Name.NAME, attributes);
 +
 +            LOG.debug("Rename required with value {}", newName);
 +
 +            if (newName != null && newName.equals(beforeObj.getName())
 +                    && !newName.getNameValue().equals(beforeObj.getUid().getUidValue())) {
 +
 +                LOG.debug("Remote object name unchanged");
 +                attributes.remove(newName);
 +            }
 +
 +            // 2. check wether anything is actually needing to be propagated, i.e. if there is attribute
 +            // difference between beforeObj - just read above from the connector - and the values to be propagated
 +            Map<String, Attribute> originalAttrMap = connObjectUtil.toMap(beforeObj.getAttributes());
 +            Map<String, Attribute> updateAttrMap = connObjectUtil.toMap(attributes);
 +
 +            // Only compare attribute from beforeObj that are also being updated
 +            Set<String> skipAttrNames = originalAttrMap.keySet();
 +            skipAttrNames.removeAll(updateAttrMap.keySet());
 +            for (String attrName : new HashSet<>(skipAttrNames)) {
 +                originalAttrMap.remove(attrName);
 +            }
 +
 +            Set<Attribute> originalAttrs = new HashSet<>(originalAttrMap.values());
 +
 +            if (originalAttrs.equals(attributes)) {
 +                LOG.debug("Don't need to propagate anything: {} is equal to {}", originalAttrs, attributes);
 +            } else {
 +                LOG.debug("Attributes that would be updated {}", attributes);
 +
 +                Set<Attribute> strictlyModified = new HashSet<>();
 +                for (Attribute attr : attributes) {
 +                    if (!originalAttrs.contains(attr)) {
 +                        strictlyModified.add(attr);
 +                    }
 +                }
 +
 +                // 3. provision entry
-                 LOG.debug("Update {} on {}", strictlyModified, resource);
++                LOG.debug("Update {} on {}", strictlyModified, task.getResource().getKey());
 +
-                 connector.update(propagationMode, beforeObj.getObjectClass(),
++                connector.update(task.getResource().getPropagationMode(), beforeObj.getObjectClass(),
 +                        beforeObj.getUid(), strictlyModified, null, propagationAttempted);
 +            }
 +        }
 +    }
 +
-     protected void createOrUpdate(
-             final PropagationTask task,
-             final ConnectorObject beforeObj,
-             final Connector connector,
-             final Set<String> propagationAttempted) {
- 
-         createOrUpdate(
-                 new ObjectClass(task.getObjectClassName()),
-                 task.getAccountId(),
-                 task.getAttributes(),
-                 task.getResource().getKey(),
-                 task.getResource().getPropagationMode(),
-                 beforeObj,
-                 connector,
-                 propagationAttempted,
-                 connObjectUtil);
-     }
- 
 +    protected Subject<?, ?, ?> getSubject(final PropagationTask task) {
 +        Subject<?, ?, ?> subject = null;
 +
 +        if (task.getSubjectKey() != null) {
 +            switch (task.getSubjectType()) {
 +                case USER:
 +                    try {
 +                        subject = userDAO.authFetch(task.getSubjectKey());
 +                    } catch (Exception e) {
 +                        LOG.error("Could not read user {}", task.getSubjectKey(), e);
 +                    }
 +                    break;
 +
 +                case ROLE:
 +                    try {
 +                        subject = roleDAO.authFetch(task.getSubjectKey());
 +                    } catch (Exception e) {
 +                        LOG.error("Could not read role {}", task.getSubjectKey(), e);
 +                    }
 +                    break;
 +
 +                case MEMBERSHIP:
 +                default:
 +            }
 +        }
 +
 +        return subject;
 +    }
 +
 +    protected void delete(final PropagationTask task, final ConnectorObject beforeObj,
 +            final Connector connector, final Set<String> propagationAttempted) {
 +
 +        if (beforeObj == null) {
 +            LOG.debug("{} not found on external resource: ignoring delete", task.getAccountId());
 +        } else {
 +            /*
 +             * We must choose here whether to
 +             * a. actually delete the provided user / role from the external resource
 +             * b. just update the provided user / role data onto the external resource
 +             *
 +             * (a) happens when either there is no user / role associated with the PropagationTask (this takes place
 +             * when the task is generated via UserController.delete() / RoleController.delete()) or the provided updated
 +             * user / role hasn't the current resource assigned (when the task is generated via
 +             * UserController.update() / RoleController.update()).
 +             *
 +             * (b) happens when the provided updated user / role does have the current resource assigned (when the task
 +             * is generated via UserController.update() / RoleController.updae()): this basically means that before such
 +             * update, this user / role used to have the current resource assigned by more than one mean (for example,
 +             * two different memberships with the same resource).
 +             */
 +            Subject<?, ?, ?> subject = getSubject(task);
 +            if (subject == null || !subject.getResourceNames().contains(task.getResource().getKey())) {
 +                LOG.debug("Delete {} on {}", beforeObj.getUid(), task.getResource().getKey());
 +
 +                connector.delete(
 +                        task.getPropagationMode(),
 +                        beforeObj.getObjectClass(),
 +                        beforeObj.getUid(),
 +                        null,
 +                        propagationAttempted);
 +            } else {
 +                createOrUpdate(task, beforeObj, connector, propagationAttempted);
 +            }
 +        }
 +    }
 +
 +    @Override
 +    public TaskExec execute(final PropagationTask task, final PropagationReporter reporter) {
 +        final List<PropagationActions> actions = getPropagationActions(task.getResource());
 +
 +        final Date startDate = new Date();
 +
 +        final TaskExec execution = entityFactory.newEntity(TaskExec.class);
 +        execution.setStatus(PropagationTaskExecStatus.CREATED.name());
 +
 +        String taskExecutionMessage = null;
 +        String failureReason = null;
 +
 +        // Flag to state whether any propagation has been attempted
 +        Set<String> propagationAttempted = new HashSet<>();
 +
 +        ConnectorObject beforeObj = null;
 +        ConnectorObject afterObj = null;
 +
 +        Connector connector = null;
 +        Result result;
 +        try {
 +            connector = connFactory.getConnector(task.getResource());
 +
 +            // Try to read remote object (user / group) BEFORE any actual operation
 +            beforeObj = getRemoteObject(task, connector, false);
 +
 +            for (PropagationActions action : actions) {
 +                action.before(task, beforeObj);
 +            }
 +
 +            switch (task.getPropagationOperation()) {
 +                case CREATE:
 +                case UPDATE:
 +                    createOrUpdate(task, beforeObj, connector, propagationAttempted);
 +                    break;
 +
 +                case DELETE:
 +                    delete(task, beforeObj, connector, propagationAttempted);
 +                    break;
 +
 +                default:
 +            }
 +
 +            execution.setStatus(task.getPropagationMode() == PropagationMode.ONE_PHASE
 +                    ? PropagationTaskExecStatus.SUCCESS.name()
 +                    : PropagationTaskExecStatus.SUBMITTED.name());
 +
 +            LOG.debug("Successfully propagated to {}", task.getResource());
 +            result = Result.SUCCESS;
 +        } catch (Exception e) {
 +            result = Result.FAILURE;
 +            LOG.error("Exception during provision on resource " + task.getResource().getKey(), e);
 +
 +            if (e instanceof ConnectorException && e.getCause() != null) {
 +                taskExecutionMessage = e.getCause().getMessage();
 +                if (e.getCause().getMessage() == null) {
 +                    failureReason = e.getMessage();
 +                } else {
 +                    failureReason = e.getMessage() + "\n\n Cause: " + e.getCause().getMessage().split("\n")[0];
 +                }
 +            } else {
 +                taskExecutionMessage = ExceptionUtil.getFullStackTrace(e);
 +                if (e.getCause() == null) {
 +                    failureReason = e.getMessage();
 +                } else {
 +                    failureReason = e.getMessage() + "\n\n Cause: " + e.getCause().getMessage().split("\n")[0];
 +                }
 +            }
 +
 +            try {
 +                execution.setStatus(task.getPropagationMode() == PropagationMode.ONE_PHASE
 +                        ? PropagationTaskExecStatus.FAILURE.name()
 +                        : PropagationTaskExecStatus.UNSUBMITTED.name());
 +            } catch (Exception wft) {
 +                LOG.error("While executing KO action on {}", execution, wft);
 +            }
 +
 +            propagationAttempted.add(task.getPropagationOperation().name().toLowerCase());
 +        } finally {
 +            // Try to read remote object (user / group) AFTER any actual operation
 +            if (connector != null) {
 +                try {
 +                    afterObj = getRemoteObject(task, connector, true);
 +                } catch (Exception ignore) {
 +                    // ignore exception
 +                    LOG.error("Error retrieving after object", ignore);
 +                }
 +            }
 +
 +            LOG.debug("Update execution for {}", task);
 +
 +            execution.setStartDate(startDate);
 +            execution.setMessage(taskExecutionMessage);
 +            execution.setEndDate(new Date());
 +
 +            if (hasToBeregistered(task, execution)) {
 +                if (propagationAttempted.isEmpty()) {
 +                    LOG.debug("No propagation attempted for {}", execution);
 +                } else {
 +                    execution.setTask(task);
 +                    task.addExec(execution);
 +
 +                    LOG.debug("Execution finished: {}", execution);
 +                }
 +
 +                taskDAO.save(task);
 +
 +                // this flush call is needed to generate a value for the execution id
 +                taskDAO.flush();
 +            }
 +
 +            if (reporter != null) {
 +                reporter.onSuccessOrSecondaryResourceFailures(
 +                        task.getResource().getKey(),
 +                        PropagationTaskExecStatus.valueOf(execution.getStatus()),
 +                        failureReason,
 +                        beforeObj,
 +                        afterObj);
 +            }
 +        }
 +
 +        for (PropagationActions action : actions) {
 +            action.after(task, execution, afterObj);
 +        }
 +
 +        notificationManager.createTasks(
 +                AuditElements.EventCategoryType.PROPAGATION,
 +                task.getSubjectType().name().toLowerCase(),
 +                task.getResource().getKey(),
 +                task.getPropagationOperation().name().toLowerCase(),
 +                result,
 +                beforeObj, // searching for before object is too much expensive ... 
 +                new Object[] { execution, afterObj },
 +                task);
 +
 +        auditManager.audit(
 +                AuditElements.EventCategoryType.PROPAGATION,
 +                task.getSubjectType().name().toLowerCase(),
 +                task.getResource().getKey(),
 +                task.getPropagationOperation().name().toLowerCase(),
 +                result,
 +                beforeObj, // searching for before object is too much expensive ... 
 +                new Object[] { execution, afterObj },
 +                task);
 +
 +        return execution;
 +    }
 +
 +    @Override
 +    public void execute(final Collection<PropagationTask> tasks) {
 +        execute(tasks, null);
 +    }
 +
 +    @Override
 +    public abstract void execute(Collection<PropagationTask> tasks, final PropagationReporter reporter);
 +
 +    /**
 +     * Check whether an execution has to be stored, for a given task.
 +     *
 +     * @param task execution's task
 +     * @param execution to be decide whether to store or not
 +     * @return true if execution has to be store, false otherwise
 +     */
 +    protected boolean hasToBeregistered(final PropagationTask task, final TaskExec execution) {
 +        boolean result;
 +
 +        final boolean failed = !PropagationTaskExecStatus.valueOf(execution.getStatus()).isSuccessful();
 +
 +        switch (task.getPropagationOperation()) {
 +
 +            case CREATE:
 +                result = (failed && task.getResource().getCreateTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal())
 +                        || task.getResource().getCreateTraceLevel() == TraceLevel.ALL;
 +                break;
 +
 +            case UPDATE:
 +                result = (failed && task.getResource().getUpdateTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal())
 +                        || task.getResource().getUpdateTraceLevel() == TraceLevel.ALL;
 +                break;
 +
 +            case DELETE:
 +                result = (failed && task.getResource().getDeleteTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal())
 +                        || task.getResource().getDeleteTraceLevel() == TraceLevel.ALL;
 +                break;
 +
 +            default:
 +                result = false;
 +        }
 +
 +        return result;
 +    }
 +
 +    /**
 +     * Get remote object for given task.
 +     *
 +     * @param connector connector facade proxy.
 +     * @param task current propagation task.
 +     * @param latest 'FALSE' to retrieve object using old accountId if not null.
 +     * @return remote connector object.
 +     */
 +    protected ConnectorObject getRemoteObject(final PropagationTask task, final Connector connector,
 +            final boolean latest) {
 +
 +        String accountId = latest || task.getOldAccountId() == null
 +                ? task.getAccountId()
 +                : task.getOldAccountId();
 +
 +        ConnectorObject obj = null;
 +        try {
 +            obj = connector.getObject(task.getPropagationMode(),
 +                    task.getPropagationOperation(),
 +                    new ObjectClass(task.getObjectClassName()),
 +                    new Uid(accountId),
 +                    connector.getOperationOptions(attrUtilFactory.getInstance(task.getSubjectType()).
 +                            getMappingItems(task.getResource(), MappingPurpose.PROPAGATION)));
 +        } catch (TimeoutException toe) {
 +            LOG.debug("Request timeout", toe);
 +            throw toe;
 +        } catch (RuntimeException ignore) {
 +            LOG.debug("While resolving {}", accountId, ignore);
 +        }
 +
 +        return obj;
 +    }
 +}