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/05/27 15:06:13 UTC

[2/2] syncope git commit: [SYNCOPE-666] All but integration tests work

[SYNCOPE-666] All but integration tests work


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

Branch: refs/heads/SYNCOPE-666
Commit: 705bfb86c37a06a538e8973cee8c4948d160bac4
Parents: c608b58
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Wed May 27 15:06:04 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Wed May 27 15:06:04 2015 +0200

----------------------------------------------------------------------
 .../client/console/rest/SchemaRestClient.java   |   1 -
 .../common/lib/types/ClientExceptionType.java   |   4 +-
 .../syncope/core/logic/AnyObjectLogic.java      |  27 +--
 .../syncope/core/logic/NotificationTest.java    |   3 -
 .../core/persistence/api/entity/Any.java        |   6 +
 .../persistence/jpa/entity/AbstractAny.java     |  92 ++++++++
 .../persistence/jpa/entity/AbstractAttr.java    |  81 +------
 .../persistence/jpa/entity/conf/JPAConf.java    |  18 ++
 .../api/AnyObjectProvisioningManager.java       |   9 -
 .../api/GroupProvisioningManager.java           |   4 -
 .../provisioning/api/ProvisioningManager.java   |   7 +
 .../api/UserProvisioningManager.java            |   2 -
 .../provisioning/api/data/UserDataBinder.java   |   8 +
 .../api/propagation/PropagationManager.java     |  23 +-
 .../DefaultAnyObjectProvisioningManager.java    | 173 +++++++++++++++
 .../java/DefaultGroupProvisioningManager.java   |  60 +++---
 .../java/DefaultUserProvisioningManager.java    | 122 ++++++-----
 .../java/data/AbstractAnyDataBinder.java        |  51 ++---
 .../java/data/AnyObjectDataBinderImpl.java      | 209 +++++++++++++++++++
 .../java/data/GroupDataBinderImpl.java          |   7 +-
 .../java/data/ResourceDataBinderImpl.java       |  49 +++--
 .../java/data/UserDataBinderImpl.java           |  21 +-
 .../propagation/PropagationManagerImpl.java     |  77 ++++---
 .../java/sync/AbstractProvisioningJob.java      |  10 +-
 .../src/main/resources/provisioning.properties  |   1 +
 .../src/main/resources/provisioningContext.xml  |   1 +
 .../java/data/ResourceDataBinderTest.java       |   5 +-
 .../java/AbstractAnyObjectWorkflowAdapter.java  |  61 ++++++
 .../java/DefaultAnyObjectWorkflowAdapter.java   | 112 ++++++++++
 .../src/main/resources/workflow.properties      |   1 +
 .../src/main/resources/workflowContext.xml      |   1 +
 .../camel/CamelGroupProvisioningManager.java    |  12 +-
 .../camel/CamelUserProvisioningManager.java     |  11 +
 .../camel/processor/GroupDeleteProcessor.java   |  16 +-
 34 files changed, 953 insertions(+), 332 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
index 9f7a6d2..8a145dc 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
@@ -31,7 +31,6 @@ import org.apache.syncope.common.lib.to.AbstractSchemaTO;
 import org.apache.syncope.common.lib.to.DerSchemaTO;
 import org.apache.syncope.common.lib.to.PlainSchemaTO;
 import org.apache.syncope.common.lib.to.VirSchemaTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.common.rest.api.service.SchemaService;
 import org.springframework.stereotype.Component;

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
index 6875279..498f603 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
@@ -37,9 +37,11 @@ public enum ClientExceptionType {
     InvalidPolicy(Response.Status.BAD_REQUEST),
     InvalidConf(Response.Status.BAD_REQUEST),
     InvalidPath(Response.Status.BAD_REQUEST),
+    InvalidProvision(Response.Status.BAD_REQUEST),
     InvalidReport(Response.Status.BAD_REQUEST),
     InvalidReportExec(Response.Status.BAD_REQUEST),
-    InvalidGroups(Response.Status.BAD_REQUEST),
+    InvalidAnyObject(Response.Status.BAD_REQUEST),
+    InvalidGroup(Response.Status.BAD_REQUEST),
     InvalidSchemaDefinition(Response.Status.BAD_REQUEST),
     InvalidSearchExpression(Response.Status.BAD_REQUEST),
     InvalidPageOrSize(Response.Status.BAD_REQUEST),

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
index 31fda37..4919097 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
@@ -37,9 +37,7 @@ import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.Entitlement;
-import org.apache.syncope.core.misc.RealmUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
@@ -136,7 +134,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
     public List<AnyObjectTO> search(final SearchCond searchCondition, final int page, final int size,
             final List<OrderByClause> orderBy, final List<String> realms) {
 
-        final List<AnyObject> matchingAnyObjects = searchDAO.search(
+        List<AnyObject> matchingAnyObjects = searchDAO.search(
                 getEffectiveRealms(AuthContextUtils.getAuthorizations().get(Entitlement.ANY_OBJECT_SEARCH), realms),
                 searchCondition, page, size, orderBy, AnyTypeKind.ANY_OBJECT);
         return CollectionUtils.collect(matchingAnyObjects, new Transformer<AnyObject, AnyObjectTO>() {
@@ -227,7 +225,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
     @Transactional(rollbackFor = { Throwable.class })
     @Override
     public AnyObjectTO unlink(final Long anyObjectKey, final Collection<String> resources) {
-        final AnyObjectMod anyObjectMod = new AnyObjectMod();
+        AnyObjectMod anyObjectMod = new AnyObjectMod();
         anyObjectMod.setKey(anyObjectKey);
         anyObjectMod.getResourcesToRemove().addAll(resources);
         final Long updatedResult = provisioningManager.unlink(anyObjectMod);
@@ -239,7 +237,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
     @Transactional(rollbackFor = { Throwable.class })
     @Override
     public AnyObjectTO link(final Long anyObjectKey, final Collection<String> resources) {
-        final AnyObjectMod anyObjectMod = new AnyObjectMod();
+        AnyObjectMod anyObjectMod = new AnyObjectMod();
         anyObjectMod.setKey(anyObjectKey);
         anyObjectMod.getResourcesToAdd().addAll(resources);
         return binder.getAnyObjectTO(provisioningManager.link(anyObjectMod));
@@ -249,7 +247,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
     @Transactional(rollbackFor = { Throwable.class })
     @Override
     public AnyObjectTO unassign(final Long anyObjectKey, final Collection<String> resources) {
-        final AnyObjectMod anyObjectMod = new AnyObjectMod();
+        AnyObjectMod anyObjectMod = new AnyObjectMod();
         anyObjectMod.setKey(anyObjectKey);
         anyObjectMod.getResourcesToRemove().addAll(resources);
         return update(anyObjectMod);
@@ -258,10 +256,10 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
     @PreAuthorize("hasRole('" + Entitlement.ANY_OBJECT_UPDATE + "')")
     @Transactional(rollbackFor = { Throwable.class })
     @Override
-    public AnyObjectTO assign(
-            final Long anyObjectKey, final Collection<String> resources, final boolean changePwd, final String password) {
+    public AnyObjectTO assign(final Long anyObjectKey, final Collection<String> resources,
+            final boolean changePwd, final String password) {
 
-        final AnyObjectMod userMod = new AnyObjectMod();
+        AnyObjectMod userMod = new AnyObjectMod();
         userMod.setKey(anyObjectKey);
         userMod.getResourcesToAdd().addAll(resources);
         return update(userMod);
@@ -271,7 +269,7 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
     @Transactional(rollbackFor = { Throwable.class })
     @Override
     public AnyObjectTO deprovision(final Long anyObjectKey, final Collection<String> resources) {
-        final AnyObject anyObject = anyObjectDAO.authFind(anyObjectKey);
+        AnyObject anyObject = anyObjectDAO.authFind(anyObjectKey);
 
         List<PropagationStatus> statuses = provisioningManager.deprovision(anyObjectKey, resources);
 
@@ -283,8 +281,9 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
     @PreAuthorize("hasRole('" + Entitlement.ANY_OBJECT_UPDATE + "')")
     @Transactional(rollbackFor = { Throwable.class })
     @Override
-    public AnyObjectTO provision(
-            final Long anyObjectKey, final Collection<String> resources, final boolean changePwd, final String password) {
+    public AnyObjectTO provision(final Long anyObjectKey, final Collection<String> resources,
+            final boolean changePwd, final String password) {
+
         AnyObjectTO original = binder.getAnyObjectTO(anyObjectKey);
 
         //trick: assign and retrieve propagation statuses ...
@@ -297,7 +296,9 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
     }
 
     @Override
-    protected AnyObjectTO resolveReference(final Method method, final Object... args) throws UnresolvedReferenceException {
+    protected AnyObjectTO resolveReference(final Method method, final Object... args)
+            throws UnresolvedReferenceException {
+
         Long key = null;
 
         if (ArrayUtils.isNotEmpty(args)) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/logic/src/test/java/org/apache/syncope/core/logic/NotificationTest.java
----------------------------------------------------------------------
diff --git a/core/logic/src/test/java/org/apache/syncope/core/logic/NotificationTest.java b/core/logic/src/test/java/org/apache/syncope/core/logic/NotificationTest.java
index 64aaa09..4401a6b 100644
--- a/core/logic/src/test/java/org/apache/syncope/core/logic/NotificationTest.java
+++ b/core/logic/src/test/java/org/apache/syncope/core/logic/NotificationTest.java
@@ -97,9 +97,6 @@ import org.springframework.transaction.annotation.Transactional;
 @Transactional
 public class NotificationTest {
 
-    /**
-     * Logger.
-     */
     private static final Logger LOG = LoggerFactory.getLogger(NotificationTest.class);
 
     private static final String SMTP_HOST = "localhost";

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
index 12bf9b6..0384db7 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.api.entity;
 
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import java.util.List;
+import java.util.Set;
 
 public interface Any<P extends PlainAttr<?>, D extends DerAttr<?>, V extends VirAttr<?>> extends AnnotatedEntity<Long> {
 
@@ -77,4 +78,9 @@ public interface Any<P extends PlainAttr<?>, D extends DerAttr<?>, V extends Vir
 
     List<? extends AnyTypeClass> getAuxClasses();
 
+    Set<PlainSchema> getAllowedPlainSchemas();
+
+    Set<DerSchema> getAllowedDerSchemas();
+
+    Set<VirSchema> getAllowedVirSchemas();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
index 161927c..2e344b0 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
@@ -20,20 +20,33 @@ package org.apache.syncope.core.persistence.jpa.entity;
 
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import javax.persistence.Column;
 import javax.persistence.FetchType;
 import javax.persistence.ManyToOne;
 import javax.persistence.MappedSuperclass;
+import javax.persistence.Transient;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.DerAttr;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
+import org.apache.syncope.core.persistence.api.entity.user.User;
 
 @MappedSuperclass
 public abstract class AbstractAny<P extends PlainAttr<?>, D extends DerAttr<?>, V extends VirAttr<?>>
@@ -50,6 +63,15 @@ public abstract class AbstractAny<P extends PlainAttr<?>, D extends DerAttr<?>,
     @Column(nullable = true)
     private String status;
 
+    @Transient
+    private Set<PlainSchema> allowedPlainSchemas;
+
+    @Transient
+    private Set<DerSchema> allowedDerSchemas;
+
+    @Transient
+    private Set<VirSchema> allowedVirSchemas;
+
     @Override
     public Realm getRealm() {
         return realm;
@@ -146,4 +168,74 @@ public abstract class AbstractAny<P extends PlainAttr<?>, D extends DerAttr<?>,
     public List<? extends ExternalResource> getResources() {
         return internalGetResources();
     }
+
+    private void populateAllowedSchemas(final Collection<? extends AnyTypeClass> anyTypeClasses) {
+        for (AnyTypeClass anyTypeClass : anyTypeClasses) {
+            allowedPlainSchemas.addAll(anyTypeClass.getPlainSchemas());
+        }
+
+        for (AnyTypeClass anyTypeClass : anyTypeClasses) {
+            allowedDerSchemas.addAll(anyTypeClass.getDerSchemas());
+        }
+
+        for (AnyTypeClass anyTypeClass : anyTypeClasses) {
+            allowedVirSchemas.addAll(anyTypeClass.getVirSchemas());
+        }
+    }
+
+    private void populateAllowedSchemas() {
+        synchronized (this) {
+            if (allowedPlainSchemas == null) {
+                allowedPlainSchemas = new HashSet<>();
+            } else {
+                allowedPlainSchemas.clear();
+            }
+            if (allowedDerSchemas == null) {
+                allowedDerSchemas = new HashSet<>();
+            } else {
+                allowedDerSchemas.clear();
+            }
+            if (allowedVirSchemas == null) {
+                allowedVirSchemas = new HashSet<>();
+            } else {
+                allowedVirSchemas.clear();
+            }
+
+            populateAllowedSchemas(getType().getClasses());
+            populateAllowedSchemas(getAuxClasses());
+            if (this instanceof User) {
+                for (UMembership memb : ((User) this).getMemberships()) {
+                    for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
+                        populateAllowedSchemas(typeExtension.getAuxClasses());
+                    }
+                }
+            }
+            if (this instanceof AnyObject) {
+                for (AMembership memb : ((AnyObject) this).getMemberships()) {
+                    for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
+                        populateAllowedSchemas(typeExtension.getAuxClasses());
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public Set<PlainSchema> getAllowedPlainSchemas() {
+        populateAllowedSchemas();
+        return allowedPlainSchemas;
+    }
+
+    @Override
+    public Set<DerSchema> getAllowedDerSchemas() {
+        populateAllowedSchemas();
+        return allowedDerSchemas;
+    }
+
+    @Override
+    public Set<VirSchema> getAllowedVirSchemas() {
+        populateAllowedSchemas();
+        return allowedVirSchemas;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java
index 4f4a3ec..914bd02 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttr.java
@@ -18,84 +18,30 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity;
 
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Set;
-import javax.persistence.Transient;
 import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.Attr;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
-import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
-import org.apache.syncope.core.persistence.api.entity.user.UMembership;
-import org.apache.syncope.core.persistence.api.entity.user.User;
 
 public abstract class AbstractAttr<S extends Schema, O extends Any<?, ?, ?>>
         extends AbstractEntity<Long> implements Attr<S, O> {
 
     private static final long serialVersionUID = -7722134717360731874L;
 
-    @Transient
-    private Set<PlainSchema> allowedPlainSchemas;
-
-    @Transient
-    private Set<DerSchema> allowedDerSchemas;
-
-    @Transient
-    private Set<VirSchema> allowedVirSchemas;
-
-    private void populateClasses(final Collection<? extends AnyTypeClass> anyTypeClasses) {
-        synchronized (this) {
-            if (getSchema() instanceof PlainSchema) {
-                if (allowedPlainSchemas == null) {
-                    allowedPlainSchemas = new HashSet<>();
-                }
-                for (AnyTypeClass anyTypeClass : anyTypeClasses) {
-                    allowedPlainSchemas.addAll(anyTypeClass.getPlainSchemas());
-                }
-            } else if (getSchema() instanceof DerSchema) {
-                if (allowedDerSchemas == null) {
-                    allowedDerSchemas = new HashSet<>();
-                }
-                for (AnyTypeClass anyTypeClass : anyTypeClasses) {
-                    allowedDerSchemas.addAll(anyTypeClass.getDerSchemas());
-                }
-            } else if (getSchema() instanceof VirSchema) {
-                if (allowedVirSchemas == null) {
-                    allowedVirSchemas = new HashSet<>();
-                }
-                for (AnyTypeClass anyTypeClass : anyTypeClasses) {
-                    allowedVirSchemas.addAll(anyTypeClass.getVirSchemas());
-                }
-            }
-        }
-    }
-
     @SuppressWarnings("unchecked")
-    private Set<S> getAllowedSchemas() {
+    private Set<S> getAllowedSchemas(final O any) {
         Set<S> result = Collections.emptySet();
 
         if (getSchema() instanceof PlainSchema) {
-            if (allowedPlainSchemas == null) {
-                allowedPlainSchemas = new HashSet<>();
-            }
-            result = (Set<S>) allowedPlainSchemas;
+            result = (Set<S>) any.getAllowedPlainSchemas();
         } else if (getSchema() instanceof DerSchema) {
-            if (allowedDerSchemas == null) {
-                allowedDerSchemas = new HashSet<>();
-            }
-            result = (Set<S>) allowedDerSchemas;
+            result = (Set<S>) any.getAllowedDerSchemas();
         } else if (getSchema() instanceof VirSchema) {
-            if (allowedVirSchemas == null) {
-                allowedVirSchemas = new HashSet<>();
-            }
-            result = (Set<S>) allowedVirSchemas;
+            result = (Set<S>) any.getAllowedVirSchemas();
         }
 
         return result;
@@ -106,24 +52,7 @@ public abstract class AbstractAttr<S extends Schema, O extends Any<?, ?, ?>>
             throw new IllegalStateException("First set owner then schema and finally add values");
         }
 
-        populateClasses(getOwner().getType().getClasses());
-        populateClasses(getOwner().getAuxClasses());
-        if (getOwner() instanceof User) {
-            for (UMembership memb : ((User) getOwner()).getMemberships()) {
-                for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
-                    populateClasses(typeExtension.getAuxClasses());
-                }
-            }
-        }
-        if (getOwner() instanceof AnyObject) {
-            for (AMembership memb : ((AnyObject) getOwner()).getMemberships()) {
-                for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
-                    populateClasses(typeExtension.getAuxClasses());
-                }
-            }
-        }
-
-        if (!getAllowedSchemas().contains(schema)) {
+        if (!getAllowedSchemas(getOwner()).contains(schema)) {
             throw new IllegalArgumentException(schema + " not allowed for this instance");
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
index 3253f66..2b44253 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.persistence.jpa.entity.conf;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import javax.persistence.Cacheable;
 import javax.persistence.CascadeType;
 import javax.persistence.Entity;
@@ -33,8 +34,11 @@ import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.DerAttr;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
@@ -210,4 +214,18 @@ public class JPAConf extends AbstractAnnotatedEntity<Long> implements Conf {
         // nothing to do
     }
 
+    @Override
+    public Set<PlainSchema> getAllowedPlainSchemas() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<DerSchema> getAllowedDerSchemas() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<VirSchema> getAllowedVirSchemas() {
+        return Collections.emptySet();
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AnyObjectProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AnyObjectProvisioningManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AnyObjectProvisioningManager.java
index 6b423d5..6928ffd 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AnyObjectProvisioningManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/AnyObjectProvisioningManager.java
@@ -18,17 +18,8 @@
  */
 package org.apache.syncope.core.provisioning.api;
 
-import java.util.List;
-import java.util.Set;
-import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.mod.AnyObjectMod;
-import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 
 public interface AnyObjectProvisioningManager extends ProvisioningManager<AnyObjectTO, AnyObjectMod> {
-
-    Pair<Long, List<PropagationStatus>> create(AnyObjectTO anyObjectTO, Set<String> excludedResources);
-
-    Pair<Long, List<PropagationStatus>> update(AnyObjectMod anyObjectMod, Set<String> excludedResources);
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/GroupProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/GroupProvisioningManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/GroupProvisioningManager.java
index 0913405..1dce013 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/GroupProvisioningManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/GroupProvisioningManager.java
@@ -28,11 +28,7 @@ import org.apache.syncope.common.lib.to.GroupTO;
 
 public interface GroupProvisioningManager extends ProvisioningManager<GroupTO, GroupMod> {
 
-    Pair<Long, List<PropagationStatus>> create(GroupTO groupTO, Set<String> excludedResources);
-
     Pair<Long, List<PropagationStatus>> create(
             GroupTO groupTO, Map<Long, String> groupOwnerMap, Set<String> excludedResources);
 
-    Pair<Long, List<PropagationStatus>> update(GroupMod groupMod, Set<String> excludedResources);
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/ProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/ProvisioningManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/ProvisioningManager.java
index 28b2663..e517270 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/ProvisioningManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/ProvisioningManager.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.api;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.mod.AnyMod;
 import org.apache.syncope.common.lib.to.AnyTO;
@@ -29,10 +30,16 @@ public interface ProvisioningManager<T extends AnyTO, M extends AnyMod> {
 
     Pair<Long, List<PropagationStatus>> create(T anyTO);
 
+    Pair<Long, List<PropagationStatus>> create(T anyTO, Set<String> excludedResources);
+
     Pair<Long, List<PropagationStatus>> update(M anyMod);
 
+    Pair<Long, List<PropagationStatus>> update(M anyMod, Set<String> excludedResources);
+
     List<PropagationStatus> delete(Long anyKey);
 
+    List<PropagationStatus> delete(Long anyKey, Set<String> excludedResources);
+
     Long unlink(M anyMod);
 
     Long link(M anyMod);

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java
index ad7a01e..810a788 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java
@@ -46,8 +46,6 @@ public interface UserProvisioningManager extends ProvisioningManager<UserTO, Use
     Pair<Long, List<PropagationStatus>> update(UserMod userMod, Long key,
             ProvisioningResult result, Boolean enabled, Set<String> excludedResources);
 
-    List<PropagationStatus> delete(Long key, Set<String> excludedResources);
-
     void requestPasswordReset(Long key);
 
     void confirmPasswordReset(User user, String token, String password);

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java
index e5fbb00..942c212 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/UserDataBinder.java
@@ -35,6 +35,14 @@ public interface UserDataBinder {
 
     void create(User user, UserTO userTO, boolean storePassword);
 
+    /**
+     * Update user, given UserMod.
+     *
+     * @param toBeUpdated user to be updated
+     * @param userMod bean containing update request
+     * @return updated user + propagation by resource
+     * @see PropagationByResource
+     */
     PropagationByResource update(User toBeUpdated, UserMod userMod);
 
     boolean verifyPassword(String username, String password);

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java
index 36821c3..cf8cde4 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/propagation/PropagationManager.java
@@ -113,13 +113,24 @@ public interface PropagationManager {
     List<PropagationTask> getGroupDeleteTasks(
             Long groupKey, Set<String> resourceNames, Collection<String> noPropResourceNames);
 
+    List<PropagationTask> getAnyObjectCreateTasks(
+            WorkflowResult<Long> wfResult, Collection<AttrTO> vAttrs, Collection<String> noPropResourceNames);
+
     List<PropagationTask> getAnyObjectCreateTasks(Long anyObjectKey, Collection<AttrTO> vAttrs,
-            PropagationByResource propByRes, List<String> noPropResourceNames);
+            PropagationByResource propByRes, Collection<String> noPropResourceNames);
+
+    List<PropagationTask> getAnyObjectUpdateTasks(WorkflowResult<Long> wfResult, Set<String> vAttrsToBeRemoved,
+            Set<AttrMod> vAttrsToBeUpdated, Set<String> noPropResourceNames);
+
+    List<PropagationTask> getAnyObjectDeleteTasks(Long anyObjectKey);
 
     List<PropagationTask> getAnyObjectDeleteTasks(Long anyObjectKey, String noPropResourceName);
 
     List<PropagationTask> getAnyObjectDeleteTasks(Long anyObjectKey, Collection<String> noPropResourceNames);
 
+    List<PropagationTask> getAnyObjectDeleteTasks(
+            Long groupKey, Set<String> resourceNames, Collection<String> noPropResourceNames);
+
     /**
      * Create the user on every associated resource.
      *
@@ -186,14 +197,4 @@ public interface PropagationManager {
     List<PropagationTask> getUserDeleteTasks(
             Long userKey, Set<String> resourceNames, Collection<String> noPropResourceNames);
 
-    /**
-     * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
-     * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
-     * the creation fails onto a mandatory resource.
-     *
-     * @param wfResult user to be propagated (and info associated), as per result from workflow
-     * @return list of propagation tasks
-     */
-    List<PropagationTask> getUserDeleteTasks(WorkflowResult<Long> wfResult);
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
new file mode 100644
index 0000000..1bd2638
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultAnyObjectProvisioningManager.java
@@ -0,0 +1,173 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.mod.AnyObjectMod;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
+import org.apache.syncope.core.provisioning.api.WorkflowResult;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultAnyObjectProvisioningManager implements AnyObjectProvisioningManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AnyObjectProvisioningManager.class);
+
+    @Autowired
+    protected AnyObjectWorkflowAdapter awfAdapter;
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    protected VirAttrHandler virtAttrHandler;
+
+    @Autowired
+    protected AnyObjectDAO anyObjectDAO;
+
+    @Override
+    public Pair<Long, List<PropagationStatus>> create(final AnyObjectTO anyObjectTO) {
+        return create(anyObjectTO, Collections.<String>emptySet());
+    }
+
+    @Override
+    public Pair<Long, List<PropagationStatus>> create(
+            final AnyObjectTO anyObjectTO, final Set<String> excludedResources) {
+
+        WorkflowResult<Long> created = awfAdapter.create(anyObjectTO);
+
+        List<PropagationTask> tasks = propagationManager.getAnyObjectCreateTasks(
+                created, anyObjectTO.getVirAttrs(), excludedResources);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        return new ImmutablePair<>(created.getResult(), propagationReporter.getStatuses());
+    }
+
+    @Override
+    public Pair<Long, List<PropagationStatus>> update(final AnyObjectMod anyObjectMod) {
+        return update(anyObjectMod, Collections.<String>emptySet());
+    }
+
+    @Override
+    public Pair<Long, List<PropagationStatus>> update(
+            final AnyObjectMod anyObjectMod, final Set<String> excludedResources) {
+
+        WorkflowResult<Long> updated = awfAdapter.update(anyObjectMod);
+
+        List<PropagationTask> tasks = propagationManager.getAnyObjectUpdateTasks(updated,
+                anyObjectMod.getVirAttrsToRemove(), anyObjectMod.getVirAttrsToUpdate(), null);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        return new ImmutablePair<>(updated.getResult(), propagationReporter.getStatuses());
+    }
+
+    @Override
+    public List<PropagationStatus> delete(final Long anyObjectKey) {
+        return delete(anyObjectKey, Collections.<String>emptySet());
+    }
+
+    @Override
+    public List<PropagationStatus> delete(final Long anyObjectKey, final Set<String> excludedResources) {
+        List<PropagationTask> tasks = new ArrayList<>();
+
+        AnyObject anyObject = anyObjectDAO.authFind(anyObjectKey);
+        if (anyObject != null) {
+            tasks.addAll(propagationManager.getAnyObjectDeleteTasks(anyObject.getKey()));
+        }
+
+        PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().
+                getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        awfAdapter.delete(anyObjectKey);
+
+        return propagationReporter.getStatuses();
+    }
+
+    @Override
+    public Long unlink(final AnyObjectMod anyObjectMod) {
+        return awfAdapter.update(anyObjectMod).getResult();
+    }
+
+    @Override
+    public Long link(final AnyObjectMod anyObjectMod) {
+        return awfAdapter.update(anyObjectMod).getResult();
+    }
+
+    @Override
+    public List<PropagationStatus> deprovision(final Long anyObjectKey, final Collection<String> resources) {
+        AnyObject anyObject = anyObjectDAO.authFind(anyObjectKey);
+
+        Collection<String> noPropResourceName = CollectionUtils.removeAll(anyObject.getResourceNames(), resources);
+
+        List<PropagationTask> tasks = propagationManager.getAnyObjectDeleteTasks(
+                anyObjectKey, new HashSet<>(resources), noPropResourceName);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+        return propagationReporter.getStatuses();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
index 8535dc2..c7bc1c4 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultGroupProvisioningManager.java
@@ -66,16 +66,16 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
     protected GroupDAO groupDAO;
 
     @Override
-    public Pair<Long, List<PropagationStatus>> create(final GroupTO any) {
-        return create(any, Collections.<String>emptySet());
+    public Pair<Long, List<PropagationStatus>> create(final GroupTO group) {
+        return create(group, Collections.<String>emptySet());
     }
 
     @Override
-    public Pair<Long, List<PropagationStatus>> create(final GroupTO any, final Set<String> excludedResources) {
-        WorkflowResult<Long> created = gwfAdapter.create(any);
+    public Pair<Long, List<PropagationStatus>> create(final GroupTO groupTO, final Set<String> excludedResources) {
+        WorkflowResult<Long> created = gwfAdapter.create(groupTO);
 
-        List<PropagationTask> tasks =
-                propagationManager.getGroupCreateTasks(created, any.getVirAttrs(), excludedResources);
+        List<PropagationTask> tasks = propagationManager.getGroupCreateTasks(
+                created, groupTO.getVirAttrs(), excludedResources);
         PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().getBean(
                 PropagationReporter.class);
         try {
@@ -107,18 +107,18 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
     }
 
     @Override
-    public Pair<Long, List<PropagationStatus>> update(final GroupMod anyMod) {
-        return update(anyMod, Collections.<String>emptySet());
+    public Pair<Long, List<PropagationStatus>> update(final GroupMod groupObjectMod) {
+        return update(groupObjectMod, Collections.<String>emptySet());
     }
 
     @Override
     public Pair<Long, List<PropagationStatus>> update(
-            final GroupMod anyMod, final Set<String> excludedResources) {
+            final GroupMod groupMod, final Set<String> excludedResources) {
 
-        WorkflowResult<Long> updated = gwfAdapter.update(anyMod);
+        WorkflowResult<Long> updated = gwfAdapter.update(groupMod);
 
         List<PropagationTask> tasks = propagationManager.getGroupUpdateTasks(updated,
-                anyMod.getVirAttrsToRemove(), anyMod.getVirAttrsToUpdate(), null);
+                groupMod.getVirAttrsToRemove(), groupMod.getVirAttrsToUpdate(), excludedResources);
         PropagationReporter propagationReporter =
                 ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
         try {
@@ -128,25 +128,35 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
             propagationReporter.onPrimaryResourceFailure(tasks);
         }
 
-        Pair<Long, List<PropagationStatus>> result = new ImmutablePair<>(
-                updated.getResult(), propagationReporter.getStatuses());
-        return result;
+        return new ImmutablePair<>(updated.getResult(), propagationReporter.getStatuses());
     }
 
     @Override
-    public List<PropagationStatus> delete(final Long anyKey) {
-        final List<PropagationTask> tasks = new ArrayList<>();
+    public List<PropagationStatus> delete(final Long groupObjectKey) {
+        return delete(groupObjectKey, Collections.<String>emptySet());
+    }
 
-        Group group = groupDAO.authFind(anyKey);
+    @Override
+    public List<PropagationStatus> delete(final Long groupKey, final Set<String> excludedResources) {
+        List<PropagationTask> tasks = new ArrayList<>();
+
+        Group group = groupDAO.authFind(groupKey);
         if (group != null) {
             // Generate propagation tasks for deleting users from group resources, if they are on those resources only
             // because of the reason being deleted (see SYNCOPE-357)
             for (Map.Entry<Long, PropagationByResource> entry
+                    : groupDAO.findUsersWithTransitiveResources(group.getKey()).entrySet()) {
+
+                WorkflowResult<Long> wfResult =
+                        new WorkflowResult<>(entry.getKey(), entry.getValue(), Collections.<String>emptySet());
+                tasks.addAll(propagationManager.getUserDeleteTasks(wfResult.getResult(), excludedResources));
+            }
+            for (Map.Entry<Long, PropagationByResource> entry
                     : groupDAO.findAnyObjectsWithTransitiveResources(group.getKey()).entrySet()) {
 
                 WorkflowResult<Long> wfResult =
                         new WorkflowResult<>(entry.getKey(), entry.getValue(), Collections.<String>emptySet());
-                tasks.addAll(propagationManager.getUserDeleteTasks(wfResult));
+                tasks.addAll(propagationManager.getAnyObjectDeleteTasks(wfResult.getResult(), excludedResources));
             }
 
             // Generate propagation tasks for deleting this group from resources
@@ -162,18 +172,14 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
             propagationReporter.onPrimaryResourceFailure(tasks);
         }
 
-        try {
-            gwfAdapter.delete(anyKey);
-        } catch (RuntimeException e) {
-            throw e;
-        }
+        gwfAdapter.delete(groupKey);
 
         return propagationReporter.getStatuses();
     }
 
     @Override
-    public Long unlink(final GroupMod anyMod) {
-        WorkflowResult<Long> updated = gwfAdapter.update(anyMod);
+    public Long unlink(final GroupMod groupMod) {
+        WorkflowResult<Long> updated = gwfAdapter.update(groupMod);
         return updated.getResult();
     }
 
@@ -197,8 +203,8 @@ public class DefaultGroupProvisioningManager implements GroupProvisioningManager
     }
 
     @Override
-    public Long link(final GroupMod anyMod) {
-        return gwfAdapter.update(anyMod).getResult();
+    public Long link(final GroupMod groupMod) {
+        return gwfAdapter.update(groupMod).getResult();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
index 58ecb4a..88d3094 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java
@@ -77,6 +77,11 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
     }
 
     @Override
+    public Pair<Long, List<PropagationStatus>> create(final UserTO userTO, final Set<String> excludedResources) {
+        return create(userTO, false, false, null, excludedResources);
+    }
+
+    @Override
     public Pair<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword,
             final boolean disablePwdPolicyCheck, final Boolean enabled, final Set<String> excludedResources) {
 
@@ -138,6 +143,64 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
     }
 
     @Override
+    public Pair<Long, List<PropagationStatus>> update(final UserMod userMod, final Set<String> excludedResources) {
+        return update(userMod, userMod.getKey(), new ProvisioningResult(), null, excludedResources);
+    }
+
+    @Override
+    public Pair<Long, List<PropagationStatus>> update(final UserMod userMod, final Long key,
+            final ProvisioningResult result, final Boolean enabled, final Set<String> excludedResources) {
+
+        WorkflowResult<Pair<UserMod, Boolean>> updated;
+        try {
+            updated = uwfAdapter.update(userMod);
+        } catch (Exception e) {
+            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", key, e);
+
+            result.setStatus(ProvisioningResult.Status.FAILURE);
+            result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
+
+            updated = new WorkflowResult<Pair<UserMod, Boolean>>(
+                    new ImmutablePair<>(userMod, false), new PropagationByResource(),
+                    new HashSet<String>());
+        }
+
+        if (enabled != null) {
+            User user = userDAO.find(key);
+
+            WorkflowResult<Long> enableUpdate = null;
+            if (user.isSuspended() == null) {
+                enableUpdate = uwfAdapter.activate(key, null);
+            } else if (enabled && user.isSuspended()) {
+                enableUpdate = uwfAdapter.reactivate(key);
+            } else if (!enabled && !user.isSuspended()) {
+                enableUpdate = uwfAdapter.suspend(key);
+            }
+
+            if (enableUpdate != null) {
+                if (enableUpdate.getPropByRes() != null) {
+                    updated.getPropByRes().merge(enableUpdate.getPropByRes());
+                    updated.getPropByRes().purge();
+                }
+                updated.getPerformedTasks().addAll(enableUpdate.getPerformedTasks());
+            }
+        }
+
+        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
+                updated, updated.getResult().getKey().getPassword() != null, excludedResources);
+        PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().
+                getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        return new ImmutablePair<>(updated.getResult().getKey().getKey(), propagationReporter.getStatuses());
+    }
+
+    @Override
     public List<PropagationStatus> delete(final Long userKey) {
         return delete(userKey, Collections.<String>emptySet());
     }
@@ -176,8 +239,8 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
     }
 
     @Override
-    public Long link(final UserMod anyMod) {
-        return uwfAdapter.update(anyMod).getResult().getKey().getKey();
+    public Long link(final UserMod userMod) {
+        return uwfAdapter.update(userMod).getResult().getKey().getKey();
     }
 
     @Override
@@ -265,61 +328,6 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
     }
 
     @Override
-    public Pair<Long, List<PropagationStatus>> update(final UserMod userMod, final Long key,
-            final ProvisioningResult result, final Boolean enabled, final Set<String> excludedResources) {
-
-        WorkflowResult<Pair<UserMod, Boolean>> updated;
-        try {
-            updated = uwfAdapter.update(userMod);
-        } catch (Exception e) {
-            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", key, e);
-
-            result.setStatus(ProvisioningResult.Status.FAILURE);
-            result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
-
-            updated = new WorkflowResult<Pair<UserMod, Boolean>>(
-                    new ImmutablePair<>(userMod, false), new PropagationByResource(),
-                    new HashSet<String>());
-        }
-
-        if (enabled != null) {
-            User user = userDAO.find(key);
-
-            WorkflowResult<Long> enableUpdate = null;
-            if (user.isSuspended() == null) {
-                enableUpdate = uwfAdapter.activate(key, null);
-            } else if (enabled && user.isSuspended()) {
-                enableUpdate = uwfAdapter.reactivate(key);
-            } else if (!enabled && !user.isSuspended()) {
-                enableUpdate = uwfAdapter.suspend(key);
-            }
-
-            if (enableUpdate != null) {
-                if (enableUpdate.getPropByRes() != null) {
-                    updated.getPropByRes().merge(enableUpdate.getPropByRes());
-                    updated.getPropByRes().purge();
-                }
-                updated.getPerformedTasks().addAll(enableUpdate.getPerformedTasks());
-            }
-        }
-
-        List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
-                updated, updated.getResult().getKey().getPassword() != null, excludedResources);
-        PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().
-                getBean(PropagationReporter.class);
-        try {
-            taskExecutor.execute(tasks, propagationReporter);
-        } catch (PropagationException e) {
-            LOG.error("Error propagation primary resource", e);
-            propagationReporter.onPrimaryResourceFailure(tasks);
-        }
-
-        return new ImmutablePair<>(updated.getResult().getKey().getKey(),
-                propagationReporter.getStatuses());
-
-    }
-
-    @Override
     public void requestPasswordReset(final Long id) {
         uwfAdapter.requestPasswordReset(id);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index f63a9b4..fb01aa4 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -59,6 +59,7 @@ import org.apache.syncope.core.persistence.api.entity.VirAttr;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.core.misc.ConnObjectUtils;
 import org.apache.syncope.core.provisioning.java.VirAttrHandler;
 import org.apache.syncope.core.misc.MappingUtils;
 import org.apache.syncope.core.misc.jexl.JexlUtils;
@@ -130,6 +131,9 @@ abstract class AbstractAnyDataBinder {
     @Autowired
     protected VirAttrHandler virtAttrHander;
 
+    @Autowired
+    protected ConnObjectUtils connObjectUtils;
+
     protected void setRealm(final Any<?, ?, ?> any, final AnyMod anyMod) {
         if (StringUtils.isNotBlank(anyMod.getRealm())) {
             Realm newRealm = realmDAO.find(anyMod.getRealm());
@@ -239,8 +243,7 @@ abstract class AbstractAnyDataBinder {
         SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
 
         // Check if there is some mandatory schema defined for which no value has been provided
-        List<PlainSchema> plainSchemas = plainSchemaDAO.findAll();
-        for (PlainSchema schema : plainSchemas) {
+        for (PlainSchema schema : any.getAllowedPlainSchemas()) {
             if (any.getPlainAttr(schema.getKey()) == null
                     && !schema.isReadonly()
                     && (JexlUtils.evaluateMandatoryCondition(schema.getMandatoryCondition(), any)
@@ -253,8 +256,7 @@ abstract class AbstractAnyDataBinder {
             }
         }
 
-        List<DerSchema> derSchemas = derSchemaDAO.findAll();
-        for (DerSchema derSchema : derSchemas) {
+        for (DerSchema derSchema : any.getAllowedDerSchemas()) {
             if (any.getDerAttr(derSchema.getKey()) == null
                     && evaluateMandatoryCondition(anyUtils, any, derSchema.getKey(),
                             anyUtils.derIntMappingType())) {
@@ -265,8 +267,7 @@ abstract class AbstractAnyDataBinder {
             }
         }
 
-        List<VirSchema> virSchemas = virSchemaDAO.findAll();
-        for (VirSchema virSchema : virSchemas) {
+        for (VirSchema virSchema : any.getAllowedVirSchemas()) {
             if (any.getVirAttr(virSchema.getKey()) == null
                     && !virSchema.isReadonly()
                     && evaluateMandatoryCondition(anyUtils, any, virSchema.getKey(),
@@ -294,7 +295,7 @@ abstract class AbstractAnyDataBinder {
             ExternalResource resource = resourceDAO.find(resourceToBeRemoved);
             if (resource != null) {
                 propByRes.add(ResourceOperation.DELETE, resource.getKey());
-                ((Any<?, ?, ?>) any).remove(resource);
+                any.remove(resource);
             }
         }
 
@@ -305,7 +306,7 @@ abstract class AbstractAnyDataBinder {
             ExternalResource resource = resourceDAO.find(resourceToBeAdded);
             if (resource != null) {
                 propByRes.add(ResourceOperation.CREATE, resource.getKey());
-                ((Any<?, ?, ?>) any).add(resource);
+                any.add(resource);
             }
         }
 
@@ -512,17 +513,15 @@ abstract class AbstractAnyDataBinder {
                     PlainAttr attr = any.getPlainAttr(schema.getKey());
                     if (attr == null) {
                         attr = anyUtils.newPlainAttr();
+                        attr.setOwner(any);
                         attr.setSchema(schema);
                     }
-                    if (attr.getSchema() == null) {
-                        LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
-                    } else {
-                        fillAttribute(attributeTO.getValues(), anyUtils, schema, attr, invalidValues);
+                    fillAttribute(attributeTO.getValues(), anyUtils, schema, attr, invalidValues);
 
-                        if (!attr.getValuesAsStrings().isEmpty()) {
-                            any.add(attr);
-                            attr.setOwner(any);
-                        }
+                    if (attr.getValuesAsStrings().isEmpty()) {
+                        attr.setOwner(null);
+                    } else {
+                        any.add(attr);
                     }
                 }
             }
@@ -538,13 +537,9 @@ abstract class AbstractAnyDataBinder {
 
             if (derSchema != null) {
                 DerAttr derAttr = anyUtils.newDerAttr();
+                derAttr.setOwner(any);
                 derAttr.setSchema(derSchema);
-                if (derAttr.getSchema() == null) {
-                    LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
-                } else {
-                    derAttr.setOwner(any);
-                    any.add(derAttr);
-                }
+                any.add(derAttr);
             }
         }
 
@@ -554,13 +549,9 @@ abstract class AbstractAnyDataBinder {
 
             if (virSchema != null) {
                 VirAttr virAttr = anyUtils.newVirAttr();
+                virAttr.setOwner(any);
                 virAttr.setSchema(virSchema);
-                if (virAttr.getSchema() == null) {
-                    LOG.debug("Ignoring {} because no valid schema or template was found", vattrTO);
-                } else {
-                    virAttr.setOwner(any);
-                    any.add(virAttr);
-                }
+                any.add(virAttr);
             }
         }
 
@@ -574,13 +565,13 @@ abstract class AbstractAnyDataBinder {
                     "Invalid or null realm specified: " + anyTO.getRealm());
             scce.addException(noRealm);
         }
-        ((Any<?, ?, ?>) any).setRealm(realm);
+        any.setRealm(realm);
 
         for (String resourceName : anyTO.getResources()) {
             ExternalResource resource = resourceDAO.find(resourceName);
 
             if (resource != null) {
-                ((Any<?, ?, ?>) any).add(resource);
+                any.add(resource);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
new file mode 100644
index 0000000..eb7586d
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -0,0 +1,209 @@
+/*
+ * 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.data;
+
+import static org.apache.syncope.core.provisioning.java.data.AbstractAnyDataBinder.LOG;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Transformer;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.AnyObjectMod;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.misc.spring.BeanUtils;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@Transactional(rollbackFor = { Throwable.class })
+public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements AnyObjectDataBinder {
+
+    private static final String[] IGNORE_PROPERTIES = {
+        "realm", "memberships", "plainAttrs", "derAttrs", "virAttrs", "resources"
+    };
+
+    @Transactional(readOnly = true)
+    @Override
+    public AnyObjectTO getAnyObjectTO(final Long key) {
+        return getAnyObjectTO(anyObjectDAO.authFind(key));
+    }
+
+    @Override
+    public AnyObjectTO getAnyObjectTO(final AnyObject anyObject) {
+        AnyObjectTO anyObjectTO = new AnyObjectTO();
+
+        BeanUtils.copyProperties(anyObject, anyObjectTO, IGNORE_PROPERTIES);
+
+        connObjectUtils.retrieveVirAttrValues(anyObject);
+        fillTO(anyObjectTO, anyObject.getRealm().getFullPath(),
+                anyObject.getPlainAttrs(), anyObject.getDerAttrs(), anyObject.getVirAttrs(),
+                anyObjectDAO.findAllResources(anyObject));
+
+        for (AMembership membership : anyObject.getMemberships()) {
+            MembershipTO membershipTO = new MembershipTO();
+
+            membershipTO.setKey(membership.getKey());
+            membershipTO.setRightKey(membership.getRightEnd().getKey());
+            membershipTO.setGroupName(membership.getRightEnd().getName());
+
+            anyObjectTO.getMemberships().add(membershipTO);
+        }
+
+        // dynamic memberships
+        CollectionUtils.collect(anyObjectDAO.findDynGroupMemberships(anyObject), new Transformer<Group, Long>() {
+
+            @Override
+            public Long transform(final Group group) {
+                return group.getKey();
+            }
+        }, anyObjectTO.getDynGroups());
+
+        return anyObjectTO;
+    }
+
+    @Override
+    public void create(final AnyObject anyObject, final AnyObjectTO anyObjectTO) {
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        // memberships
+        for (MembershipTO membershipTO : anyObjectTO.getMemberships()) {
+            Group group = groupDAO.find(membershipTO.getRightKey());
+
+            if (group == null) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Ignoring invalid group " + membershipTO.getGroupName());
+                }
+            } else {
+                AMembership membership = null;
+                if (anyObject.getKey() != null) {
+                    membership = anyObject.getMembership(group.getKey());
+                }
+                if (membership == null) {
+                    membership = entityFactory.newEntity(AMembership.class);
+                    membership.setRightEnd(group);
+                    membership.setLeftEnd(anyObject);
+
+                    anyObject.add(membership);
+                }
+            }
+        }
+
+        // realm, attributes, derived attributes, virtual attributes and resources
+        fill(anyObject, anyObjectTO, anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT), scce);
+    }
+
+    @Override
+    public PropagationByResource update(final AnyObject toBeUpdated, final AnyObjectMod anyObjectMod) {
+        // Re-merge any pending change from workflow tasks
+        final AnyObject anyObject = anyObjectDAO.save(toBeUpdated);
+
+        PropagationByResource propByRes = new PropagationByResource();
+
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        Collection<String> currentResources = anyObjectDAO.findAllResourceNames(anyObject);
+
+        // fetch connObjectKeys before update
+        Map<String, String> oldConnObjectKeys = getConnObjectKeys(anyObject);
+
+        // attributes, derived attributes, virtual attributes and resources
+        propByRes.merge(fill(anyObject, anyObjectMod, anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT), scce));
+
+        // store the group ids of membership required to be added
+        Set<Long> membershipToBeAddedGroupKeys = new HashSet<>(anyObjectMod.getMembershipsToAdd());
+
+        final Set<String> toBeDeprovisioned = new HashSet<>();
+        final Set<String> toBeProvisioned = new HashSet<>();
+
+        // memberships to be removed
+        for (Long groupKey : anyObjectMod.getMembershipsToRemove()) {
+            LOG.debug("Membership to be removed for group {}", groupKey);
+
+            AMembership membership = anyObject.getMembership(groupKey);
+            if (membership == null) {
+                LOG.warn("Invalid group key specified for membership to be removed: {}", groupKey);
+            } else {
+                if (membershipToBeAddedGroupKeys.contains(membership.getRightEnd().getKey())) {
+                    anyObject.remove(membership);
+                } else {
+                    toBeDeprovisioned.addAll(membership.getRightEnd().getResourceNames());
+                }
+            }
+        }
+
+        // memberships to be added
+        for (Long groupKey : anyObjectMod.getMembershipsToAdd()) {
+            LOG.debug("Membership to be added for group {}", groupKey);
+
+            Group group = groupDAO.find(groupKey);
+            if (group == null) {
+                LOG.debug("Ignoring invalid group {}", groupKey);
+            } else {
+                AMembership membership = anyObject.getMembership(group.getKey());
+                if (membership == null) {
+                    membership = entityFactory.newEntity(AMembership.class);
+                    membership.setRightEnd(group);
+                    membership.setLeftEnd(anyObject);
+
+                    anyObject.add(membership);
+
+                    toBeProvisioned.addAll(group.getResourceNames());
+                }
+            }
+        }
+
+        propByRes.addAll(ResourceOperation.DELETE, toBeDeprovisioned);
+        propByRes.addAll(ResourceOperation.UPDATE, toBeProvisioned);
+
+        /**
+         * In case of new memberships all the current resources have to be updated in order to propagate new group and
+         * membership attribute values.
+         */
+        if (!toBeDeprovisioned.isEmpty() || !toBeProvisioned.isEmpty()) {
+            currentResources.removeAll(toBeDeprovisioned);
+            propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+        }
+
+        // check if some connObjectKey was changed by the update above
+        Map<String, String> newcCnnObjectKeys = getConnObjectKeys(anyObject);
+        for (Map.Entry<String, String> entry : oldConnObjectKeys.entrySet()) {
+            if (newcCnnObjectKeys.containsKey(entry.getKey())
+                    && !entry.getValue().equals(newcCnnObjectKeys.get(entry.getKey()))) {
+
+                propByRes.addOldConnObjectKey(entry.getKey(), entry.getValue());
+                propByRes.add(ResourceOperation.UPDATE, entry.getKey());
+            }
+        }
+
+        return propByRes;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
index 6bce1b1..a900e70 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
@@ -30,13 +30,11 @@ import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
-import org.apache.syncope.core.misc.ConnObjectUtils;
 import org.apache.syncope.core.misc.search.SearchCondConverter;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -44,9 +42,6 @@ import org.springframework.transaction.annotation.Transactional;
 @Transactional(rollbackFor = { Throwable.class })
 public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupDataBinder {
 
-    @Autowired
-    private ConnObjectUtils connObjectUtils;
-
     private void setDynMembership(final Group group, final AnyTypeKind anyTypeKind, final String dynMembershipFIQL) {
         SearchCond dynMembershipCond = SearchCondConverter.convert(dynMembershipFIQL);
         if (!dynMembershipCond.isValid()) {
@@ -77,7 +72,7 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
 
         // name
-        SyncopeClientException invalidGroups = SyncopeClientException.build(ClientExceptionType.InvalidGroups);
+        SyncopeClientException invalidGroups = SyncopeClientException.build(ClientExceptionType.InvalidGroup);
         if (groupTO.getName() == null) {
             LOG.error("No name specified for this group");
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index 4930764..20b3c58 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -112,29 +112,34 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
             AnyType anyType = anyTypeDAO.find(provisionTO.getAnyType());
             if (anyType == null) {
                 LOG.warn("Invalid type specified {}, ignoring...", provisionTO.getAnyType());
-            }
-
-            Provision provision = resource.getProvision(anyType);
-            if (provision == null) {
-                provision = entityFactory.newEntity(Provision.class);
-                provision.setResource(resource);
-                resource.add(provision);
-                provision.setAnyType(anyType);
-            }
-
-            provision.setObjectClass(new ObjectClass(provisionTO.getObjectClass()));
-
-            if (provisionTO.getSyncToken() == null) {
-                provision.setSyncToken(null);
-            }
-
-            if (provisionTO.getMapping() == null) {
-                provision.setMapping(null);
             } else {
-                Mapping mapping = entityFactory.newEntity(Mapping.class);
-                mapping.setProvision(provision);
-                provision.setMapping(mapping);
-                populateMapping(provisionTO.getMapping(), mapping, entityFactory.newEntity(MappingItem.class));
+                Provision provision = resource.getProvision(anyType);
+                if (provision == null) {
+                    provision = entityFactory.newEntity(Provision.class);
+                    provision.setResource(resource);
+                    resource.add(provision);
+                    provision.setAnyType(anyType);
+                }
+
+                if (provisionTO.getObjectClass() == null) {
+                    SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidProvision);
+                    sce.getElements().add("Null ObjectClass");
+                    throw sce;
+                }
+                provision.setObjectClass(new ObjectClass(provisionTO.getObjectClass()));
+
+                if (provisionTO.getSyncToken() == null) {
+                    provision.setSyncToken(null);
+                }
+
+                if (provisionTO.getMapping() == null) {
+                    provision.setMapping(null);
+                } else {
+                    Mapping mapping = entityFactory.newEntity(Mapping.class);
+                    mapping.setProvision(provision);
+                    provision.setMapping(mapping);
+                    populateMapping(provisionTO.getMapping(), mapping, entityFactory.newEntity(MappingItem.class));
+                }
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/705bfb86/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index e20e405..54d10bc 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -47,7 +47,6 @@ import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 import org.apache.syncope.core.misc.security.AuthContextUtils;
 import org.apache.syncope.core.misc.security.Encryptor;
 import org.apache.syncope.core.misc.spring.BeanUtils;
-import org.apache.syncope.core.misc.ConnObjectUtils;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
@@ -71,9 +70,6 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
     private ConfDAO confDAO;
 
     @Autowired
-    private ConnObjectUtils connObjectUtils;
-
-    @Autowired
     private SecurityQuestionDAO securityQuestionDAO;
 
     @Resource(name = "adminUser")
@@ -194,14 +190,6 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
         user.setSecurityAnswer(userTO.getSecurityAnswer());
     }
 
-    /**
-     * Update user, given UserMod.
-     *
-     * @param toBeUpdated user to be updated
-     * @param userMod bean containing update request
-     * @return updated user + propagation by resource
-     * @see PropagationByResource
-     */
     @Override
     public PropagationByResource update(final User toBeUpdated, final UserMod userMod) {
         // Re-merge any pending change from workflow tasks
@@ -292,13 +280,10 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             if (membership == null) {
                 LOG.warn("Invalid group key specified for membership to be removed: {}", groupKey);
             } else {
-                if (!membershipToBeAddedGroupKeys.contains(membership.getRightEnd().getKey())) {
-                    toBeDeprovisioned.addAll(membership.getRightEnd().getResourceNames());
-                }
-
-                if (!membershipToBeAddedGroupKeys.contains(membership.getRightEnd().getKey())) {
-                } else {
+                if (membershipToBeAddedGroupKeys.contains(membership.getRightEnd().getKey())) {
                     user.remove(membership);
+                } else {
+                    toBeDeprovisioned.addAll(membership.getRightEnd().getResourceNames());
                 }
             }
         }