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 2016/06/01 16:54:23 UTC

[1/6] syncope git commit: Upgrading Font Awesome [Forced Update!]

Repository: syncope
Updated Branches:
  refs/heads/SYNCOPE-862 2b44232ad -> 35fb19988 (forced update)


Upgrading Font Awesome


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

Branch: refs/heads/SYNCOPE-862
Commit: b9b6d961b296591b096e786a641dcf7ddfa2ce17
Parents: 4e16b02
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Wed Jun 1 18:53:17 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Wed Jun 1 18:53:17 2016 +0200

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/b9b6d961/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index cbdbfc5..a428c29 100644
--- a/pom.xml
+++ b/pom.xml
@@ -388,7 +388,7 @@ under the License.
     <bootstrap.version>3.3.6</bootstrap.version>
     <bootstrap-select.version>1.7.3</bootstrap-select.version>
     <bootbox.version>4.4.0</bootbox.version>
-    <font-awesome.version>4.6.2</font-awesome.version>
+    <font-awesome.version>4.6.3</font-awesome.version>
     <ionicons.version>2.0.1</ionicons.version>
     <highlightjs.version>9.2.0</highlightjs.version>
     <codemirror.version>5.13.2</codemirror.version>


[5/6] syncope git commit: Fixing OpenJPA warnings about 'Supplied parameters do not match expected parameters'

Posted by il...@apache.org.
Fixing OpenJPA warnings about 'Supplied parameters do not match expected parameters'


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

Branch: refs/heads/SYNCOPE-862
Commit: 35fb199889eb9db05e98af5644f51168ca4499fc
Parents: b900829
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Wed Jun 1 18:52:42 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Wed Jun 1 18:53:54 2016 +0200

----------------------------------------------------------------------
 .../persistence/jpa/dao/JPAAnyObjectDAO.java    | 30 ++++++++--
 .../core/persistence/jpa/dao/JPAUserDAO.java    | 60 ++++++++++++++++----
 .../persistence/jpa/dao/JPAVirSchemaDAO.java    | 45 +++++++++++++--
 .../persistence/jpa/outer/ResourceTest.java     |  8 +--
 4 files changed, 115 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/35fb1998/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index 5280c3c..c527a15 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -56,6 +56,7 @@ import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADynGroupMembership;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAARelationship;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAnyObject;
+import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAURelationship;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
@@ -211,12 +212,29 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
     @Override
     public List<Group> findDynGroupMemberships(final AnyObject anyObject) {
-        TypedQuery<Group> query = entityManager().createQuery(
-                "SELECT e.group FROM " + JPAADynGroupMembership.class.getSimpleName()
-                + " e WHERE :anyObject MEMBER OF e.anyObjects", Group.class);
-        query.setParameter("anyObject", anyObject);
-
-        return query.getResultList();
+        Query query = entityManager().createNativeQuery(
+                "SELECT t2.id FROM " + JPAADynGroupMembership.TABLE + " t0 "
+                + "INNER JOIN ADynGroupMembership_AnyObject t1 "
+                + "ON t0.id = t1.aDynGroupMembership_id "
+                + "LEFT OUTER JOIN " + JPAGroup.TABLE + " t2 "
+                + "ON t0.GROUP_ID = t2.id "
+                + "WHERE t1.anyObject_id = ?1");
+        query.setParameter(1, anyObject.getKey());
+
+        List<Group> result = new ArrayList<>();
+        for (Object key : query.getResultList()) {
+            String actualKey = key instanceof Object[]
+                    ? (String) ((Object[]) key)[0]
+                    : ((String) key);
+
+            Group group = groupDAO.find(actualKey);
+            if (group == null) {
+                LOG.error("Could not find group with id {}, even though returned by the native query", actualKey);
+            } else if (!result.contains(group)) {
+                result.add(group);
+            }
+        }
+        return result;
     }
 
     @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)

http://git-wip-us.apache.org/repos/asf/syncope/blob/35fb1998/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
index 5c3b241..9b894d7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -66,6 +66,8 @@ import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
+import org.apache.syncope.core.persistence.jpa.entity.JPARole;
+import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPADynRoleMembership;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUDynGroupMembership;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
@@ -418,23 +420,57 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
     @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
     @Override
     public List<Role> findDynRoleMemberships(final User user) {
-        TypedQuery<Role> query = entityManager().createQuery(
-                "SELECT e.role FROM " + JPADynRoleMembership.class.getSimpleName()
-                + " e WHERE :user MEMBER OF e.users", Role.class);
-        query.setParameter("user", user);
-
-        return query.getResultList();
+        Query query = entityManager().createNativeQuery(
+                "SELECT t2.id FROM " + JPADynRoleMembership.TABLE + " t0 "
+                + "INNER JOIN " + JPADynRoleMembership.TABLE + "_User t1 "
+                + "ON t0.id = t1.dynRoleMembership_id "
+                + "LEFT OUTER JOIN " + JPARole.TABLE + " t2 "
+                + "ON t0.ROLE_ID = t2.id "
+                + "WHERE (t1.user_id = ?1)");
+        query.setParameter(1, user.getKey());
+
+        List<Role> result = new ArrayList<>();
+        for (Object key : query.getResultList()) {
+            String actualKey = key instanceof Object[]
+                    ? (String) ((Object[]) key)[0]
+                    : ((String) key);
+
+            Role role = roleDAO.find(actualKey);
+            if (role == null) {
+                LOG.error("Could not find role with id {}, even though returned by the native query", actualKey);
+            } else if (!result.contains(role)) {
+                result.add(role);
+            }
+        }
+        return result;
     }
 
     @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
     @Override
     public List<Group> findDynGroupMemberships(final User user) {
-        TypedQuery<Group> query = entityManager().createQuery(
-                "SELECT e.group FROM " + JPAUDynGroupMembership.class.getSimpleName()
-                + " e WHERE :user MEMBER OF e.users", Group.class);
-        query.setParameter("user", user);
-
-        return query.getResultList();
+        Query query = entityManager().createNativeQuery(
+                "SELECT t2.id FROM " + JPAUDynGroupMembership.TABLE + " t0 "
+                + "INNER JOIN " + JPAUDynGroupMembership.TABLE + "_User t1 "
+                + "ON t0.id = t1.uDynGroupMembership_id "
+                + "LEFT OUTER JOIN " + JPAGroup.TABLE + " t2 "
+                + "ON t0.GROUP_ID = t2.id "
+                + "WHERE (t1.user_id = ?1)");
+        query.setParameter(1, user.getKey());
+
+        List<Group> result = new ArrayList<>();
+        for (Object key : query.getResultList()) {
+            String actualKey = key instanceof Object[]
+                    ? (String) ((Object[]) key)[0]
+                    : ((String) key);
+
+            Group group = groupDAO.find(actualKey);
+            if (group == null) {
+                LOG.error("Could not find group with id {}, even though returned by the native query", actualKey);
+            } else if (!result.contains(group)) {
+                result.add(group);
+            }
+        }
+        return result;
     }
 
     @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)

http://git-wip-us.apache.org/repos/asf/syncope/blob/35fb1998/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
index 9a42b17..61db7b3 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
@@ -18,8 +18,10 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import javax.persistence.Query;
 import javax.persistence.TypedQuery;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
@@ -29,8 +31,17 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.jpa.entity.JPAAnyType;
+import org.apache.syncope.core.persistence.jpa.entity.JPAAnyTypeClass;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
+import org.apache.syncope.core.persistence.jpa.entity.JPAConnInstance;
 import org.apache.syncope.core.persistence.jpa.entity.JPAVirSchema;
+import org.apache.syncope.core.persistence.jpa.entity.policy.JPAAccountPolicy;
+import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPasswordPolicy;
+import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPullPolicy;
+import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource;
+import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMapping;
+import org.apache.syncope.core.persistence.jpa.entity.resource.JPAProvision;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 
@@ -62,12 +73,34 @@ public class JPAVirSchemaDAO extends AbstractDAO<VirSchema> implements VirSchema
 
     @Override
     public List<VirSchema> findByProvision(final Provision provision) {
-        TypedQuery<VirSchema> query = entityManager().createQuery(
-                "SELECT e FROM " + JPAVirSchema.class.getSimpleName()
-                + " e WHERE e.provision=:provision", VirSchema.class);
-        query.setParameter("provision", provision);
-
-        return query.getResultList();
+        Query query = entityManager().createNativeQuery(
+                "SELECT t0.id FROM VirSchema t0 "
+                + "LEFT OUTER JOIN " + JPAAnyTypeClass.TABLE + " t1 ON t0.ANYTYPECLASS_ID = t1.id "
+                + "LEFT OUTER JOIN " + JPAProvision.TABLE + " t2 ON t0.PROVISION_ID = t2.id "
+                + "LEFT OUTER JOIN " + JPAAnyType.TABLE + " t3 ON t2.ANYTYPE_ID = t3.id "
+                + "LEFT OUTER JOIN " + JPAMapping.TABLE + " t4 ON t2.id = t4.PROVISION_ID "
+                + "LEFT OUTER JOIN " + JPAExternalResource.TABLE + " t5 ON t2.RESOURCE_ID = t5.id "
+                + "LEFT OUTER JOIN " + JPAAccountPolicy.TABLE + " t6 ON t5.ACCOUNTPOLICY_ID = t6.id "
+                + "LEFT OUTER JOIN " + JPAConnInstance.TABLE + " t7 ON t5.CONNECTOR_ID = t7.id "
+                + "LEFT OUTER JOIN " + JPAPasswordPolicy.TABLE + " t8 ON t5.PASSWORDPOLICY_ID = t8.id "
+                + "LEFT OUTER JOIN " + JPAPullPolicy.TABLE + " t9 ON t5.PULLPOLICY_ID = t9.id "
+                + "WHERE t0.PROVISION_ID = ?1");
+        query.setParameter(1, provision.getKey());
+
+        List<VirSchema> result = new ArrayList<>();
+        for (Object key : query.getResultList()) {
+            String actualKey = key instanceof Object[]
+                    ? (String) ((Object[]) key)[0]
+                    : ((String) key);
+
+            VirSchema virSchema = find(actualKey);
+            if (virSchema == null) {
+                LOG.error("Could not find schema with id {}, even though returned by the native query", actualKey);
+            } else if (!result.contains(virSchema)) {
+                result.add(virSchema);
+            }
+        }
+        return result;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/35fb1998/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java
index d536d66..a8540bd 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ResourceTest.java
@@ -266,6 +266,9 @@ public class ResourceTest extends AbstractTest {
         assertNotNull(ldap.getProvision(anyTypeDAO.findUser()).getMapping());
         assertNotNull(ldap.getProvision(anyTypeDAO.findGroup()).getMapping());
 
+        // need to avoid any class not defined in this Maven module
+        ldap.getPropagationActionsClassNames().clear();
+
         List<? extends MappingItem> items = ldap.getProvision(anyTypeDAO.findGroup()).getMapping().getItems();
         assertNotNull(items);
         assertFalse(items.isEmpty());
@@ -275,13 +278,10 @@ public class ResourceTest extends AbstractTest {
         }
 
         Provision groupProvision = ldap.getProvision(anyTypeDAO.findGroup());
-        ldap.getProvisions().remove(groupProvision);
         for (VirSchema schema : virSchemaDAO.findByProvision(groupProvision)) {
             virSchemaDAO.delete(schema.getKey());
         }
-
-        // need to avoid any class not defined in this Maven module
-        ldap.getPropagationActionsClassNames().clear();
+        ldap.getProvisions().remove(groupProvision);
 
         resourceDAO.save(ldap);
         resourceDAO.flush();


[6/6] syncope git commit: [SYNCOPE-862] Now managing any object's name via admin console

Posted by il...@apache.org.
[SYNCOPE-862] Now managing any object's name via admin console


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

Branch: refs/heads/SYNCOPE-862
Commit: b900829703819f221c7d879c0f3cf56dd48ef305
Parents: 297396d
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Wed Jun 1 12:57:33 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Wed Jun 1 18:53:54 2016 +0200

----------------------------------------------------------------------
 .../console/wizards/any/AnyObjectDetails.java   | 53 ++++++++++++++++++++
 .../wizards/any/AnyObjectWizardBuilder.java     | 22 +++++++-
 .../console/wizards/any/AnyWizardBuilder.java   |  3 --
 .../console/wizards/any/GroupDetails.java       |  4 +-
 .../console/wizards/any/AnyObjectDetails.html   | 25 +++++++++
 .../syncope/fit/core/MembershipITCase.java      | 44 ++++++++++++++++
 6 files changed, 144 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/b9008297/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.java
new file mode 100644
index 0000000..5d149e7
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.java
@@ -0,0 +1,53 @@
+/*
+ * 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.client.console.wizards.any;
+
+import java.util.List;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.PropertyModel;
+
+public class AnyObjectDetails extends Details<AnyObjectTO> {
+
+    private static final long serialVersionUID = 855618618337931784L;
+
+    public AnyObjectDetails(
+            final AnyWrapper<AnyObjectTO> wrapper,
+            final IModel<List<StatusBean>> statusModel,
+            final boolean templateMode,
+            final boolean includeStatusPanel,
+            final PageReference pageRef) {
+
+        super(wrapper, statusModel, includeStatusPanel, pageRef);
+
+        AnyObjectTO anyObjectTO = wrapper.getInnerObject();
+
+        AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
+                new PropertyModel<String>(anyObjectTO, "name"), false);
+        if (templateMode) {
+            name.enableJexlHelp();
+        } else {
+            name.addRequiredLabel();
+        }
+        this.add(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/b9008297/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
index f92bb31..5952017 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
@@ -19,20 +19,27 @@
 package org.apache.syncope.client.console.wizards.any;
 
 import java.io.Serializable;
-
+import java.util.Collections;
 import java.util.List;
+import org.apache.syncope.client.console.commons.status.StatusBean;
 import org.apache.syncope.client.console.layout.AnyObjectForm;
 import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
+import org.apache.syncope.client.console.rest.AnyObjectRestClient;
+import org.apache.syncope.client.console.wizards.AjaxWizard;
 import org.apache.syncope.common.lib.AnyOperations;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.model.util.ListModel;
 
 public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implements AnyObjectForm {
 
     private static final long serialVersionUID = -2480279868319546243L;
 
+    private final AnyObjectRestClient anyObjectRestClient = new AnyObjectRestClient();
+
     public AnyObjectWizardBuilder(
             final AnyObjectTO anyObjectTO,
             final List<String> anyTypeClasses,
@@ -48,7 +55,7 @@ public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implem
 
         ProvisioningResult<AnyObjectTO> actual;
         if (inner.getKey() == null) {
-            actual = anyObjectRestClient.create(AnyObjectTO.class.cast(inner));
+            actual = anyObjectRestClient.create(inner);
         } else {
             AnyObjectPatch patch = AnyOperations.diff(inner, getOriginalItem().getInnerObject(), false);
 
@@ -63,4 +70,15 @@ public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implem
 
         return actual;
     }
+
+    @Override
+    protected AnyObjectWizardBuilder addOptionalDetailsPanel(
+            final AnyWrapper<AnyObjectTO> modelObject, final WizardModel wizardModel) {
+        wizardModel.add(new AnyObjectDetails(
+                modelObject,
+                new ListModel<>(Collections.<StatusBean>emptyList()),
+                mode == AjaxWizard.Mode.TEMPLATE,
+                modelObject.getInnerObject().getKey() != null, pageRef));
+        return this;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/b9008297/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
index a63a757..41fa6bb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
@@ -26,7 +26,6 @@ import org.apache.syncope.client.console.layout.AnyForm;
 import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
 import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
 import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
-import org.apache.syncope.client.console.rest.AnyObjectRestClient;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
 import org.apache.syncope.client.console.wizards.AjaxWizardBuilder;
 import org.apache.syncope.common.lib.to.AnyTO;
@@ -40,8 +39,6 @@ public abstract class AnyWizardBuilder<A extends AnyTO> extends AjaxWizardBuilde
 
     private static final long serialVersionUID = -2480279868319546243L;
 
-    protected final AnyObjectRestClient anyObjectRestClient = new AnyObjectRestClient();
-
     protected final List<String> anyTypeClasses;
 
     protected AbstractAnyFormLayout<A, ? extends AnyForm<A>> formLayoutInfo;

http://git-wip-us.apache.org/repos/asf/syncope/blob/b9008297/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
index 7b4f4ce..e61e89c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
@@ -39,9 +39,9 @@ public class GroupDetails extends Details<GroupTO> {
 
         super(wrapper, statusModel, includeStatusPanel, pageRef);
 
-        final GroupTO groupTO = GroupWrapper.class.cast(wrapper).getInnerObject();
+        GroupTO groupTO = GroupWrapper.class.cast(wrapper).getInnerObject();
 
-        final AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
+        AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
                 new PropertyModel<String>(groupTO, "name"), false);
         if (templateMode) {
             name.enableJexlHelp();

http://git-wip-us.apache.org/repos/asf/syncope/blob/b9008297/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.html
new file mode 100644
index 0000000..4d821fe
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/AnyObjectDetails.html
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <div class="form-group">
+      <span wicket:id="name"/>
+    </div>
+  </wicket:extend>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/b9008297/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
index 09a560c..38b3631 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
@@ -31,8 +31,11 @@ import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.TypeExtensionTO;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.fit.AbstractITCase;
@@ -159,4 +162,45 @@ public class MembershipITCase extends AbstractITCase {
 
         userService.delete(user.getKey());
     }
+
+    @Test
+    public void onGroupDelete() {
+        // pre: create group with type extension
+        TypeExtensionTO typeExtension = new TypeExtensionTO();
+        typeExtension.setAnyType(AnyTypeKind.USER.name());
+        typeExtension.getAuxClasses().add("csv");
+        typeExtension.getAuxClasses().add("other");
+
+        GroupTO groupTO = GroupITCase.getBasicSampleTO("typeExt");
+        groupTO.getTypeExtensions().add(typeExtension);
+        groupTO = createGroup(groupTO).getAny();
+        assertNotNull(groupTO);
+
+        // pre: create user with membership to such group
+        UserTO user = UserITCase.getUniqueSampleTO("typeExt@apache.org");
+
+        MembershipTO membership = new MembershipTO.Builder().group(groupTO.getKey()).build();
+        membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1454").build());
+        user.getMemberships().add(membership);
+
+        user = createUser(user).getAny();
+
+        // verify that 'aLong' is correctly populated for user's membership
+        assertEquals(1, user.getMemberships().size());
+        membership = user.getMembershipMap().get(groupTO.getKey());
+        assertNotNull(membership);
+        assertEquals(1, membership.getPlainAttrMap().get("aLong").getValues().size());
+        assertEquals("1454", membership.getPlainAttrMap().get("aLong").getValues().get(0));
+
+        // verify that derived attrbutes from 'csv' and 'other' are also populated for user's membership
+        assertFalse(membership.getDerAttrMap().get("csvuserid").getValues().isEmpty());
+        assertFalse(membership.getDerAttrMap().get("noschema").getValues().isEmpty());
+
+        // now remove the group -> all related memberships should have been removed as well
+        groupService.delete(groupTO.getKey());
+
+        // re-read user and verify that no memberships are available any more
+        user = userService.read(user.getKey());
+        assertTrue(user.getMemberships().isEmpty());
+    }
 }


[4/6] syncope git commit: [SYNCOPE-862] Preliminary work

Posted by il...@apache.org.
[SYNCOPE-862] Preliminary work


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

Branch: refs/heads/SYNCOPE-862
Commit: 297396d1e4e48e786be9a1ff616e19200fd4fd6b
Parents: b9b6d96
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Tue May 31 17:59:00 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Wed Jun 1 18:53:54 2016 +0200

----------------------------------------------------------------------
 .../AnyObjectDisplayAttributesModalPanel.java   |   2 +-
 .../panels/ConnObjectDirectoryPanel.java        |   8 +-
 .../html/repeater/data/table/AttrColumn.java    |  19 +-
 .../data/table/ConnObjectAttrColumn.java        |  63 +++++
 .../console/wizards/any/ConnObjectPanel.java    |   4 +-
 .../client/console/wizards/any/Groups.java      |   1 -
 .../wizards/resources/ResourceMappingPanel.java |   1 +
 .../syncope/common/lib/AnyOperations.java       |  90 +++++--
 .../common/lib/patch/AnyObjectPatch.java        |  10 +
 .../syncope/common/lib/patch/AnyPatch.java      |  10 +-
 .../common/lib/patch/AttributablePatch.java     |  38 +++
 .../common/lib/patch/MembershipPatch.java       |  33 ++-
 .../syncope/common/lib/to/AnyObjectTO.java      |  10 +
 .../org/apache/syncope/common/lib/to/AnyTO.java |  34 ++-
 .../syncope/common/lib/to/AttributableTO.java   |  53 ++++
 .../syncope/common/lib/to/ConnObjectTO.java     |   9 +-
 .../syncope/common/lib/to/MembershipTO.java     |  75 +++++-
 .../syncope/common/lib/to/RelationshipTO.java   |  26 --
 .../common/lib/types/EntityViolationType.java   |   4 +-
 .../common/lib/types/IntMappingType.java        |   8 +-
 .../persistence/api/dao/AllowedSchemas.java     | 114 +++++++++
 .../core/persistence/api/dao/AnyDAO.java        |   3 +-
 .../core/persistence/api/dao/AnyObjectDAO.java  |   4 +
 .../core/persistence/api/entity/Any.java        |   2 +
 .../core/persistence/api/entity/AnyUtils.java   |   3 +-
 .../api/entity/GroupablePlainAttr.java          |  26 ++
 .../api/entity/GroupableRelatable.java          | 100 ++++++++
 .../api/entity/anyobject/APlainAttr.java        |   4 +-
 .../api/entity/anyobject/AnyObject.java         |  24 +-
 .../persistence/api/entity/user/UPlainAttr.java |   4 +-
 .../core/persistence/api/entity/user/User.java  |  32 +--
 .../persistence/jpa/dao/AbstractAnyDAO.java     |  56 +++--
 .../persistence/jpa/dao/JPAAnyObjectDAO.java    |  34 +++
 .../core/persistence/jpa/dao/JPAConfDAO.java    |  12 +-
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |  32 ++-
 .../persistence/jpa/dao/JPAPlainAttrDAO.java    |   2 +-
 .../persistence/jpa/entity/AbstractAny.java     |  28 ---
 .../jpa/entity/AbstractGroupableRelatable.java  | 158 ++++++++++++
 .../persistence/jpa/entity/JPAAnyUtils.java     |  13 +-
 .../jpa/entity/anyobject/JPAAPlainAttr.java     |  22 +-
 .../jpa/entity/anyobject/JPAAnyObject.java      |  95 +++----
 .../persistence/jpa/entity/conf/JPAConf.java    |   8 +-
 .../jpa/entity/group/JPAGPlainAttr.java         |   4 +-
 .../persistence/jpa/entity/group/JPAGroup.java  |  45 +++-
 .../jpa/entity/resource/JPAMappingItem.java     |   4 +
 .../jpa/entity/user/JPAUPlainAttr.java          |  22 +-
 .../persistence/jpa/entity/user/JPAUser.java    |  73 ++----
 .../jpa/validation/entity/AnyValidator.java     |  55 ++--
 .../entity/EntityValidationListener.java        |   5 +-
 .../entity/PlainAttrValueValidator.java         |   2 +-
 .../persistence/jpa/inner/AnyObjectTest.java    |   1 +
 .../persistence/jpa/inner/PlainAttrTest.java    |   2 +-
 .../core/persistence/jpa/outer/ConfTest.java    |  72 ++++++
 .../core/persistence/jpa/outer/GroupTest.java   |   1 +
 .../core/persistence/jpa/outer/UserTest.java    |  91 ++++++-
 .../test/resources/domains/MasterContent.xml    |  11 +-
 .../core/provisioning/api/DerAttrHandler.java   |  23 +-
 .../core/provisioning/api/VirAttrHandler.java   |  28 ++-
 .../provisioning/java/DerAttrHandlerImpl.java   |  32 ++-
 .../provisioning/java/MappingManagerImpl.java   |  20 ++
 .../provisioning/java/VirAttrHandlerImpl.java   |  36 ++-
 .../java/data/AbstractAnyDataBinder.java        | 248 ++++++++++++-------
 .../java/data/AnyObjectDataBinderImpl.java      | 115 +++++++--
 .../java/data/GroupDataBinderImpl.java          |   6 +-
 .../java/data/UserDataBinderImpl.java           |  90 +++++--
 .../java/job/SetUMembershipsJob.java            |   3 +-
 .../provisioning/java/pushpull/PullUtils.java   |   8 +
 .../java/utils/ConnObjectUtils.java             |   2 +-
 .../activiti/ActivitiUserWorkflowAdapter.java   |   2 +-
 fit/build-tools/src/main/resources/testdb.sql   |   1 +
 .../syncope/fit/console/AnyObjectsITCase.java   |   6 +-
 .../syncope/fit/console/BulkActionITCase.java   |   2 +-
 .../fit/console/DisplayAttributesITCase.java    |   4 +-
 .../syncope/fit/core/AnyObjectITCase.java       |   1 +
 .../syncope/fit/core/AuthenticationITCase.java  |   1 +
 .../syncope/fit/core/CamelRouteITCase.java      |   6 +-
 .../syncope/fit/core/MembershipITCase.java      | 162 ++++++++++++
 .../org/apache/syncope/fit/core/UserITCase.java |  13 +-
 .../apache/syncope/fit/core/UserSelfITCase.java |   3 +-
 .../resources/scriptedsql/CreateScript.groovy   |   3 +-
 .../resources/scriptedsql/SchemaScript.groovy   |   1 +
 .../resources/scriptedsql/SearchScript.groovy   |   2 +-
 .../resources/scriptedsql/SyncScript.groovy     |   3 +-
 .../resources/scriptedsql/TestScript.groovy     |   2 +-
 .../resources/scriptedsql/UpdateScript.groovy   |   7 +-
 85 files changed, 1945 insertions(+), 547 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
index b99a323..39f30ad 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
@@ -35,7 +35,7 @@ public class AnyObjectDisplayAttributesModalPanel<T extends Serializable> extend
 
     private static final long serialVersionUID = 5194630813773543054L;
 
-    public static final String[] DEFAULT_SELECTION = { "key" };
+    public static final String[] DEFAULT_SELECTION = { "key", "name" };
 
     public AnyObjectDisplayAttributesModalPanel(
             final BaseModal<T> modal,

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
index 99dde2e..d80130b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
@@ -30,7 +30,7 @@ import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.panels.ConnObjectDirectoryPanel.ConnObjectDataProvider;
 import org.apache.syncope.client.console.rest.ResourceRestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
-import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AttrColumn;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ConnObjectAttrColumn;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
@@ -101,9 +101,9 @@ public abstract class ConnObjectDirectoryPanel
     protected List<IColumn<ConnObjectTO, String>> getColumns() {
         final List<IColumn<ConnObjectTO, String>> columns = new ArrayList<>();
 
-        columns.add(new AttrColumn<>(ConnIdSpecialAttributeName.UID, SchemaType.PLAIN));
-        columns.add(new AttrColumn<>(ConnIdSpecialAttributeName.NAME, SchemaType.PLAIN));
-        columns.add(new AttrColumn<>(ConnIdSpecialAttributeName.ENABLE, SchemaType.PLAIN));
+        columns.add(new ConnObjectAttrColumn(ConnIdSpecialAttributeName.UID, SchemaType.PLAIN));
+        columns.add(new ConnObjectAttrColumn(ConnIdSpecialAttributeName.NAME, SchemaType.PLAIN));
+        columns.add(new ConnObjectAttrColumn(ConnIdSpecialAttributeName.ENABLE, SchemaType.PLAIN));
 
         columns.add(new ActionColumn<ConnObjectTO, String>(new ResourceModel("actions")) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
index 9a90ef6..b756a05 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
@@ -26,10 +26,9 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.ResourceModel;
-import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.AttributableTO;
 
-public class AttrColumn<T extends ConnObjectTO> extends AbstractColumn<T, String> {
+public class AttrColumn<T extends AttributableTO> extends AbstractColumn<T, String> {
 
     private static final long serialVersionUID = 2624734332447371372L;
 
@@ -59,20 +58,14 @@ public class AttrColumn<T extends ConnObjectTO> extends AbstractColumn<T, String
                 break;
 
             case DERIVED:
-                if (rowModel.getObject() instanceof AnyTO) {
-                    AnyTO obj = AnyTO.class.cast(rowModel.getObject());
-                    if (obj.getDerAttrMap().containsKey(name)) {
-                        values = obj.getDerAttrMap().get(name).getValues();
-                    }
+                if (rowModel.getObject().getDerAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getDerAttrMap().get(name).getValues();
                 }
                 break;
 
             case VIRTUAL:
-                if (rowModel.getObject() instanceof AnyTO) {
-                    AnyTO obj = AnyTO.class.cast(rowModel.getObject());
-                    if (obj.getVirAttrMap().containsKey(name)) {
-                        values = obj.getVirAttrMap().get(name).getValues();
-                    }
+                if (rowModel.getObject().getVirAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getVirAttrMap().get(name).getValues();
                 }
                 break;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
new file mode 100644
index 0000000..56ead58
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
@@ -0,0 +1,63 @@
+/*
+ * 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.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.List;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+
+public class ConnObjectAttrColumn extends AbstractColumn<ConnObjectTO, String> {
+
+    private static final long serialVersionUID = 2624734332447371372L;
+
+    private final String name;
+
+    public ConnObjectAttrColumn(final String name, final SchemaType schemaType) {
+        // set sortProperty to schematype#name (e.g. derivedSchema#cn, 
+        // for use with SortableUserProviderComparator.AttrModel#getObject)
+        super(new ResourceModel(name, name), schemaType.name() + "#" + name);
+        this.name = name;
+    }
+
+    @Override
+    public void populateItem(
+            final Item<ICellPopulator<ConnObjectTO>> cellItem,
+            final String componentId,
+            final IModel<ConnObjectTO> rowModel) {
+
+        List<String> values = null;
+        if (rowModel.getObject().getPlainAttrMap().containsKey(name)) {
+            values = rowModel.getObject().getPlainAttrMap().get(name).getValues();
+        }
+
+        if (values == null || values.isEmpty()) {
+            cellItem.add(new Label(componentId, ""));
+        } else if (values.size() == 1) {
+            cellItem.add(new Label(componentId, values.get(0)));
+        } else {
+            cellItem.add(new Label(componentId, values.toString()));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
index 14e3e33..49f6801 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
@@ -57,7 +57,7 @@ public class ConnObjectPanel extends Panel {
             protected List<AttrTO> load() {
                 List<AttrTO> attrs = new ArrayList<>(connObjectTOs == null || connObjectTOs.getRight() == null
                         ? Collections.<AttrTO>emptyList()
-                        : connObjectTOs.getRight().getPlainAttrs());
+                        : connObjectTOs.getRight().getAttrs());
 
                 Collections.sort(attrs, new Comparator<AttrTO>() {
 
@@ -77,7 +77,7 @@ public class ConnObjectPanel extends Panel {
             }
         };
 
-        final Map<String, AttrTO> beforeProfile = connObjectTOs.getLeft() == null
+        final Map<String, AttrTO> beforeProfile = connObjectTOs == null || connObjectTOs.getLeft() == null
                 ? null
                 : connObjectTOs.getLeft().getPlainAttrMap();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
index 8c84cda..401f8e0 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
@@ -105,7 +105,6 @@ public class Groups extends WizardStep {
                     public MembershipTO transform(final GroupTO input) {
                         return new MembershipTO.Builder().
                                 group(input.getKey(), input.getName()).
-                                left(anyTO.getKey(), anyTO.getType()).
                                 build();
                     }
                 }, new ArrayList<MembershipTO>());

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
index 5020bd7..06ea7c8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
@@ -570,6 +570,7 @@ public class ResourceMappingPanel extends Panel {
                 case GroupKey:
                 case GroupName:
                 case AnyObjectKey:
+                case AnyObjectName:
                 default:
                     toBeUpdated.setRequired(false);
                     toBeUpdated.setEnabled(false);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
index 39fbc63..1f985a4 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
@@ -25,6 +25,7 @@ import java.util.Set;
 import org.apache.commons.collections4.Closure;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
@@ -173,7 +174,10 @@ public final class AnyOperations {
 
         diff(updated, original, result, incremental);
 
-        // 1. relationships
+        // 1. name
+        result.setName(replacePatchItem(updated.getName(), original.getName(), new StringReplacePatchItem()));
+
+        // 2. relationships
         Map<Pair<String, String>, RelationshipTO> updatedRels = updated.getRelationshipMap();
         Map<Pair<String, String>, RelationshipTO> originalRels = original.getRelationshipMap();
 
@@ -193,21 +197,21 @@ public final class AnyOperations {
             }
         }
 
-        // 2. memberships
+        // 3. memberships
         Map<String, MembershipTO> updatedMembs = updated.getMembershipMap();
         Map<String, MembershipTO> originalMembs = original.getMembershipMap();
 
         for (Map.Entry<String, MembershipTO> entry : updatedMembs.entrySet()) {
             if (!originalMembs.containsKey(entry.getKey())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.ADD_REPLACE).membershipTO(entry.getValue()).build());
+                        operation(PatchOperation.ADD_REPLACE).group(entry.getValue().getGroupKey()).build());
             }
         }
 
         if (!incremental) {
             for (String key : CollectionUtils.subtract(originalMembs.keySet(), updatedMembs.keySet())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.DELETE).membershipTO(originalMembs.get(key)).build());
+                        operation(PatchOperation.DELETE).group(originalMembs.get(key).getGroupKey()).build());
             }
         }
 
@@ -294,14 +298,14 @@ public final class AnyOperations {
         for (Map.Entry<String, MembershipTO> entry : updatedMembs.entrySet()) {
             if (!originalMembs.containsKey(entry.getKey())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.ADD_REPLACE).membershipTO(entry.getValue()).build());
+                        operation(PatchOperation.ADD_REPLACE).group(entry.getValue().getGroupKey()).build());
             }
         }
 
         if (!incremental) {
             for (String key : CollectionUtils.subtract(originalMembs.keySet(), updatedMembs.keySet())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.DELETE).membershipTO(originalMembs.get(key)).build());
+                        operation(PatchOperation.DELETE).group(originalMembs.get(key).getGroupKey()).build());
             }
         }
 
@@ -410,7 +414,7 @@ public final class AnyOperations {
 
         // 2. plain attributes
         result.getPlainAttrs().clear();
-        result.getPlainAttrs().addAll(AnyOperations.patch(to.getPlainAttrMap(), patch.getPlainAttrs()));
+        result.getPlainAttrs().addAll(patch(to.getPlainAttrMap(), patch.getPlainAttrs()));
 
         // 3. virtual attributes
         result.getVirAttrs().clear();
@@ -432,7 +436,7 @@ public final class AnyOperations {
 
     public static GroupTO patch(final GroupTO groupTO, final GroupPatch groupPatch) {
         GroupTO result = SerializationUtils.clone(groupTO);
-        AnyOperations.patch(groupTO, groupPatch, result);
+        patch(groupTO, groupPatch, result);
 
         if (groupPatch.getName() != null) {
             result.setName(groupPatch.getName().getValue());
@@ -454,10 +458,10 @@ public final class AnyOperations {
 
     public static AnyObjectTO patch(final AnyObjectTO anyObjectTO, final AnyObjectPatch anyObjectPatch) {
         AnyObjectTO result = SerializationUtils.clone(anyObjectTO);
-        AnyOperations.patch(anyObjectTO, anyObjectPatch, result);
+        patch(anyObjectTO, anyObjectPatch, result);
 
         // 1. relationships
-        for (final RelationshipPatch relPatch : anyObjectPatch.getRelationships()) {
+        for (RelationshipPatch relPatch : anyObjectPatch.getRelationships()) {
             if (relPatch.getRelationshipTO() == null) {
                 LOG.warn("Invalid {} specified: {}", RelationshipPatch.class.getName(), relPatch);
             } else {
@@ -470,12 +474,37 @@ public final class AnyOperations {
 
         // 2. memberships
         for (final MembershipPatch membPatch : anyObjectPatch.getMemberships()) {
-            if (membPatch.getMembershipTO() == null) {
+            if (membPatch.getGroup() == null) {
                 LOG.warn("Invalid {} specified: {}", MembershipPatch.class.getName(), membPatch);
             } else {
-                result.getMemberships().remove(membPatch.getMembershipTO());
+                MembershipTO memb = IterableUtils.find(result.getMemberships(), new Predicate<MembershipTO>() {
+
+                    @Override
+                    public boolean evaluate(final MembershipTO object) {
+                        return membPatch.getGroup().equals(object.getGroupKey());
+                    }
+                });
+                if (memb != null) {
+                    result.getMemberships().remove(memb);
+                }
+
                 if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    result.getMemberships().add(membPatch.getMembershipTO());
+                    MembershipTO newMembershipTO = new MembershipTO();
+                    newMembershipTO.setGroupKey(membPatch.getGroup());
+
+                    if (memb == null) {
+                        for (AttrPatch attrPatch : membPatch.getPlainAttrs()) {
+                            newMembershipTO.getPlainAttrs().add(attrPatch.getAttrTO());
+                        }
+                    } else {
+                        newMembershipTO.getPlainAttrs().addAll(
+                                patch(memb.getPlainAttrMap(), membPatch.getPlainAttrs()));
+                    }
+
+                    // 3. virtual attributes
+                    newMembershipTO.getVirAttrs().addAll(membPatch.getVirAttrs());
+
+                    result.getMemberships().add(newMembershipTO);
                 }
             }
         }
@@ -485,7 +514,7 @@ public final class AnyOperations {
 
     public static UserTO patch(final UserTO userTO, final UserPatch userPatch) {
         UserTO result = SerializationUtils.clone(userTO);
-        AnyOperations.patch(userTO, userPatch, result);
+        patch(userTO, userPatch, result);
 
         // 1. password
         if (userPatch.getPassword() != null) {
@@ -498,7 +527,7 @@ public final class AnyOperations {
         }
 
         // 3. relationships
-        for (final RelationshipPatch relPatch : userPatch.getRelationships()) {
+        for (RelationshipPatch relPatch : userPatch.getRelationships()) {
             if (relPatch.getRelationshipTO() == null) {
                 LOG.warn("Invalid {} specified: {}", RelationshipPatch.class.getName(), relPatch);
             } else {
@@ -511,12 +540,37 @@ public final class AnyOperations {
 
         // 4. memberships
         for (final MembershipPatch membPatch : userPatch.getMemberships()) {
-            if (membPatch.getMembershipTO() == null) {
+            if (membPatch.getGroup() == null) {
                 LOG.warn("Invalid {} specified: {}", MembershipPatch.class.getName(), membPatch);
             } else {
-                result.getMemberships().remove(membPatch.getMembershipTO());
+                MembershipTO memb = IterableUtils.find(result.getMemberships(), new Predicate<MembershipTO>() {
+
+                    @Override
+                    public boolean evaluate(final MembershipTO object) {
+                        return membPatch.getGroup().equals(object.getGroupKey());
+                    }
+                });
+                if (memb != null) {
+                    result.getMemberships().remove(memb);
+                }
+
                 if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    result.getMemberships().add(membPatch.getMembershipTO());
+                    MembershipTO newMembershipTO = new MembershipTO();
+                    newMembershipTO.setGroupKey(membPatch.getGroup());
+
+                    if (memb == null) {
+                        for (AttrPatch attrPatch : membPatch.getPlainAttrs()) {
+                            newMembershipTO.getPlainAttrs().add(attrPatch.getAttrTO());
+                        }
+                    } else {
+                        newMembershipTO.getPlainAttrs().addAll(
+                                patch(memb.getPlainAttrMap(), membPatch.getPlainAttrs()));
+                    }
+
+                    // 3. virtual attributes
+                    newMembershipTO.getVirAttrs().addAll(membPatch.getVirAttrs());
+
+                    result.getMemberships().add(newMembershipTO);
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
index e473e06..ddb4ac3 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
@@ -32,10 +32,20 @@ public class AnyObjectPatch extends AnyPatch {
 
     private static final long serialVersionUID = -1644118942622556097L;
 
+    private StringReplacePatchItem name;
+
     private final Set<RelationshipPatch> relationships = new HashSet<>();
 
     private final Set<MembershipPatch> memberships = new HashSet<>();
 
+    public StringReplacePatchItem getName() {
+        return name;
+    }
+
+    public void setName(final StringReplacePatchItem name) {
+        this.name = name;
+    }
+
     @XmlElementWrapper(name = "relationships")
     @XmlElement(name = "relationship")
     @JsonProperty("relationships")

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
index 3ec141d..78e61dd 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
@@ -30,7 +30,7 @@ import org.apache.syncope.common.lib.AbstractBaseBean;
 import org.apache.syncope.common.lib.to.AttrTO;
 
 @XmlType
-public abstract class AnyPatch extends AbstractBaseBean {
+public abstract class AnyPatch extends AbstractBaseBean implements AttributablePatch {
 
     private static final long serialVersionUID = -7445489774552440544L;
 
@@ -70,16 +70,12 @@ public abstract class AnyPatch extends AbstractBaseBean {
         return auxClasses;
     }
 
-    @XmlElementWrapper(name = "plainAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("plainAttrs")
+    @Override
     public Set<AttrPatch> getPlainAttrs() {
         return plainAttrs;
     }
 
-    @XmlElementWrapper(name = "virAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrs")
+    @Override
     public Set<AttrTO> getVirAttrs() {
         return virAttrs;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java
new file mode 100644
index 0000000..fa9d189
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.patch;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import org.apache.syncope.common.lib.to.AttrTO;
+
+public interface AttributablePatch {
+
+    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("plainAttrs")
+    Set<AttrPatch> getPlainAttrs();
+
+    @XmlElementWrapper(name = "virAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrs")
+    Set<AttrTO> getVirAttrs();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
index b29a6de..0ed42c1 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
@@ -18,13 +18,15 @@
  */
 package org.apache.syncope.common.lib.patch;
 
+import java.util.HashSet;
+import java.util.Set;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
-import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.AttrTO;
 
 @XmlRootElement(name = "membershipPatch")
 @XmlType
-public class MembershipPatch extends AbstractPatch {
+public class MembershipPatch extends AbstractPatch implements AttributablePatch {
 
     private static final long serialVersionUID = -6783121761221554433L;
 
@@ -35,20 +37,33 @@ public class MembershipPatch extends AbstractPatch {
             return new MembershipPatch();
         }
 
-        public Builder membershipTO(final MembershipTO membershipTO) {
-            getInstance().setMembershipTO(membershipTO);
+        public Builder group(final String group) {
+            getInstance().setGroup(group);
             return this;
         }
     }
 
-    private MembershipTO membershipTO;
+    private String group;
 
-    public MembershipTO getMembershipTO() {
-        return membershipTO;
+    private final Set<AttrPatch> plainAttrs = new HashSet<>();
+
+    private final Set<AttrTO> virAttrs = new HashSet<>();
+
+    public String getGroup() {
+        return group;
     }
 
-    public void setMembershipTO(final MembershipTO membershipTO) {
-        this.membershipTO = membershipTO;
+    public void setGroup(final String group) {
+        this.group = group;
     }
 
+    @Override
+    public Set<AttrPatch> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Set<AttrTO> getVirAttrs() {
+        return virAttrs;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
index f652d76..d0bf7d4 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
@@ -37,12 +37,22 @@ public class AnyObjectTO extends AnyTO implements RelatableTO, GroupableTO {
 
     private static final long serialVersionUID = 8841697496476959639L;
 
+    private String name;
+
     private final List<RelationshipTO> relationships = new ArrayList<>();
 
     private final List<MembershipTO> memberships = new ArrayList<>();
 
     private final List<String> dynGroups = new ArrayList<>();
 
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
     @XmlElementWrapper(name = "relationships")
     @XmlElement(name = "relationship")
     @JsonProperty("relationships")

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
index 4651835..7732bcc 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.common.lib.to;
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import java.util.ArrayList;
@@ -30,15 +29,13 @@ import java.util.Map;
 import java.util.Set;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
 
-@XmlRootElement(name = "any")
 @XmlType
 @XmlSeeAlso({ UserTO.class, GroupTO.class, AnyObjectTO.class })
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
-public abstract class AnyTO extends ConnObjectTO implements EntityTO {
+public abstract class AnyTO extends AbstractAnnotatedBean implements EntityTO, AttributableTO {
 
     private static final long serialVersionUID = -754311920679872084L;
 
@@ -52,6 +49,8 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
 
     private final List<String> auxClasses = new ArrayList<>();
 
+    private final Set<AttrTO> plainAttrs = new HashSet<>();
+
     private final Set<AttrTO> derAttrs = new HashSet<>();
 
     private final Set<AttrTO> virAttrs = new HashSet<>();
@@ -99,14 +98,27 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
         return auxClasses;
     }
 
-    @XmlElementWrapper(name = "derAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("derAttrs")
+    @Override
+    public Set<AttrTO> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getPlainAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(plainAttrs.size());
+        for (AttrTO attributeTO : plainAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
     public Set<AttrTO> getDerAttrs() {
         return derAttrs;
     }
 
-    @JsonIgnore
+    @Override
     public Map<String, AttrTO> getDerAttrMap() {
         Map<String, AttrTO> result = new HashMap<>(derAttrs.size());
         for (AttrTO attributeTO : derAttrs) {
@@ -116,14 +128,12 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
         return Collections.unmodifiableMap(result);
     }
 
-    @XmlElementWrapper(name = "virAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrs")
+    @Override
     public Set<AttrTO> getVirAttrs() {
         return virAttrs;
     }
 
-    @JsonIgnore
+    @Override
     public Map<String, AttrTO> getVirAttrMap() {
         Map<String, AttrTO> result = new HashMap<>(virAttrs.size());
         for (AttrTO attributeTO : virAttrs) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java
new file mode 100644
index 0000000..51ee0fc
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+
+public interface AttributableTO {
+
+    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("plainAttrs")
+    Set<AttrTO> getPlainAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getPlainAttrMap();
+
+    @XmlElementWrapper(name = "derAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("derAttrs")
+    Set<AttrTO> getDerAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getDerAttrMap();
+
+    @XmlElementWrapper(name = "virAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrs")
+    Set<AttrTO> getVirAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getVirAttrMap();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
index 82878f8..8f65b70 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
@@ -29,19 +29,20 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
 
 @XmlRootElement(name = "connObject")
 @XmlType
-public class ConnObjectTO extends AbstractAnnotatedBean {
+public class ConnObjectTO extends AbstractBaseBean {
 
     private static final long serialVersionUID = 5139554911265442497L;
 
     private final Set<AttrTO> attrs = new LinkedHashSet<>();
 
-    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElementWrapper(name = "attrs")
     @XmlElement(name = "attribute")
-    @JsonProperty("plainAttrs")
-    public Set<AttrTO> getPlainAttrs() {
+    @JsonProperty("attrs")
+    public Set<AttrTO> getAttrs() {
         return attrs;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
index 6ded46b..58f3d9d 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
@@ -18,13 +18,19 @@
  */
 package org.apache.syncope.common.lib.to;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 
 @XmlRootElement(name = "membership")
 @XmlType
-public class MembershipTO extends RelationshipTO {
+public class MembershipTO extends RelationshipTO implements AttributableTO {
 
     private static final long serialVersionUID = 5992828670273935861L;
 
@@ -32,12 +38,6 @@ public class MembershipTO extends RelationshipTO {
 
         private final MembershipTO instance = new MembershipTO();
 
-        public Builder left(final String leftType, final String leftKey) {
-            instance.setLeftType(leftType);
-            instance.setLeftKey(leftKey);
-            return this;
-        }
-
         public Builder group(final String groupKey) {
             instance.setRightKey(groupKey);
             return this;
@@ -56,6 +56,12 @@ public class MembershipTO extends RelationshipTO {
 
     private String groupName;
 
+    private final Set<AttrTO> plainAttrs = new HashSet<>();
+
+    private final Set<AttrTO> derAttrs = new HashSet<>();
+
+    private final Set<AttrTO> virAttrs = new HashSet<>();
+
     @Override
     public String getType() {
         return "Membership";
@@ -76,6 +82,15 @@ public class MembershipTO extends RelationshipTO {
         // ignore
     }
 
+    @JsonIgnore
+    public String getGroupKey() {
+        return getRightKey();
+    }
+
+    public void setGroupKey(final String groupKey) {
+        setRightKey(groupKey);
+    }
+
     public String getGroupName() {
         return groupName;
     }
@@ -83,4 +98,50 @@ public class MembershipTO extends RelationshipTO {
     public void setGroupName(final String groupName) {
         this.groupName = groupName;
     }
+
+    @Override
+    public Set<AttrTO> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getPlainAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(plainAttrs.size());
+        for (AttrTO attributeTO : plainAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Set<AttrTO> getDerAttrs() {
+        return derAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getDerAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(derAttrs.size());
+        for (AttrTO attributeTO : derAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Set<AttrTO> getVirAttrs() {
+        return virAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getVirAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(virAttrs.size());
+        for (AttrTO attributeTO : virAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
index 29326c2..fc5de4f 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
@@ -37,12 +37,6 @@ public class RelationshipTO extends AbstractBaseBean {
             return this;
         }
 
-        public Builder left(final String leftType, final String leftKey) {
-            instance.setLeftType(leftType);
-            instance.setLeftKey(leftKey);
-            return this;
-        }
-
         public Builder right(final String rightType, final String rightKey) {
             instance.setRightType(rightType);
             instance.setRightKey(rightKey);
@@ -56,10 +50,6 @@ public class RelationshipTO extends AbstractBaseBean {
 
     private String type;
 
-    private String leftType;
-
-    private String leftKey;
-
     private String rightType;
 
     private String rightKey;
@@ -72,22 +62,6 @@ public class RelationshipTO extends AbstractBaseBean {
         this.type = type;
     }
 
-    public String getLeftType() {
-        return leftType;
-    }
-
-    public void setLeftType(final String leftType) {
-        this.leftType = leftType;
-    }
-
-    public String getLeftKey() {
-        return leftKey;
-    }
-
-    public void setLeftKey(final String leftKey) {
-        this.leftKey = leftKey;
-    }
-
     public String getRightType() {
         return rightType;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
index 7532730..db3e329 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
@@ -43,9 +43,7 @@ public enum EntityViolationType {
     InvalidSchemaMultivalueUnique("org.apache.syncope.core.persistence.validation.schema.multivalueUnique"),
     InvalidSchedTask("org.apache.syncope.core.persistence.validation.schedtask"),
     InvalidProvisioningTask("org.apache.syncope.core.persistence.validation.provisioningtask"),
-    InvalidPlainSchema("org.apache.syncope.core.persistence.validation.attrvalue.plainSchema"),
-    InvalidDerSchema("org.apache.syncope.core.persistence.validation.attrvalue.derSchema"),
-    InvalidVirSchema("org.apache.syncope.core.persistence.validation.attrvalue.virSchema"),
+    InvalidPlainAttr("org.apache.syncope.core.persistence.validation.plainattr"),
     InvalidUsername("org.apache.syncope.core.persistence.validation.user.username"),
     InvalidValueList("org.apache.syncope.core.persistence.validation.attr.valueList"),
     MoreThanOneNonNull("org.apache.syncope.core.persistence.validation.attrvalue.moreThanOneNonNull");

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
index eccb89d..8553348 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
@@ -56,7 +56,8 @@ public enum IntMappingType {
     AnyObjectPlainSchema(AnyTypeKind.ANY_OBJECT),
     AnyObjectDerivedSchema(AnyTypeKind.ANY_OBJECT),
     AnyObjectVirtualSchema(AnyTypeKind.ANY_OBJECT),
-    AnyObjectKey(AnyTypeKind.ANY_OBJECT);
+    AnyObjectKey(AnyTypeKind.ANY_OBJECT),
+    AnyObjectName(AnyTypeKind.ANY_OBJECT);
 
     private final AnyTypeKind anyTypeKind;
 
@@ -119,7 +120,7 @@ public enum IntMappingType {
     public static Set<IntMappingType> getEmbedded() {
         return EnumSet.of(IntMappingType.UserKey, IntMappingType.Username, IntMappingType.Password,
                 IntMappingType.GroupKey, IntMappingType.GroupName, IntMappingType.GroupOwnerSchema,
-                IntMappingType.AnyObjectKey);
+                IntMappingType.AnyObjectKey, IntMappingType.AnyObjectName);
     }
 
     /**
@@ -195,7 +196,8 @@ public enum IntMappingType {
         AnyObjectPlainSchema,
         AnyObjectDerivedSchema,
         AnyObjectVirtualSchema,
-        AnyObjectKey;
+        AnyObjectKey,
+        AnyObjectName;
 
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
new file mode 100644
index 0000000..6c04ac4
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
@@ -0,0 +1,114 @@
+/*
+ * 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.persistence.api.dao;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.PredicateUtils;
+import org.apache.commons.collections4.SetUtils;
+import org.apache.syncope.core.persistence.api.entity.Schema;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+
+public class AllowedSchemas<S extends Schema> {
+
+    private final Set<S> forSelf = new HashSet<>();
+
+    private final Map<Group, Set<S>> forMemberships = new HashMap<>();
+
+    public Set<S> getForSelf() {
+        return forSelf;
+    }
+
+    public Set<S> getForMembership(final Group group) {
+        return SetUtils.emptyIfNull(forMemberships.get(group));
+    }
+
+    public Map<Group, Set<S>> getForMemberships() {
+        return forMemberships;
+    }
+
+    public boolean forSelfContains(final S schema) {
+        return forSelf.contains(schema);
+    }
+
+    public boolean forSelfContains(final String schema) {
+        return IterableUtils.matchesAny(forSelf, new KeyMatches(schema));
+    }
+
+    public boolean forMembershipsContains(final Group group, final S schema) {
+        return IterableUtils.matchesAny(forMemberships.get(group), PredicateUtils.equalPredicate(schema));
+    }
+
+    public boolean forMembershipsContains(final S schema) {
+        for (Map.Entry<Group, Set<S>> entry : forMemberships.entrySet()) {
+            if (entry.getValue().contains(schema)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean forMembershipsContains(final Group group, final String schema) {
+        return IterableUtils.matchesAny(forMemberships.get(group), new KeyMatches(schema));
+    }
+
+    public boolean forMembershipsContains(final String schema) {
+        KeyMatches keyMatches = new KeyMatches(schema);
+
+        for (Map.Entry<Group, Set<S>> entry : forMemberships.entrySet()) {
+            if (IterableUtils.matchesAny(entry.getValue(), keyMatches)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean contains(final S schema) {
+        if (forSelfContains(schema)) {
+            return true;
+        }
+        return forMembershipsContains(schema);
+    }
+
+    public boolean contains(final String schema) {
+        if (forSelfContains(schema)) {
+            return true;
+        }
+        return forMembershipsContains(schema);
+    }
+
+    private class KeyMatches implements Predicate<S> {
+
+        private final String schema;
+
+        KeyMatches(final String schema) {
+            this.schema = schema;
+        }
+
+        @Override
+        public boolean evaluate(final S object) {
+            return object.getKey().equals(schema);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
index b6d78fd..6b2fd4e 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.core.persistence.api.dao;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
@@ -72,7 +71,7 @@ public interface AnyDAO<A extends Any<?>> extends DAO<A> {
      */
     List<A> findAll(Set<String> adminRealms, int page, int itemsPerPage, List<OrderByClause> orderBy);
 
-    <S extends Schema> Collection<S> findAllowedSchemas(A any, Class<S> reference);
+    <S extends Schema> AllowedSchemas<S> findAllowedSchemas(A any, Class<S> reference);
 
     int count(Set<String> adminRealms);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
index bdf9642..c24b37d 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
@@ -40,6 +40,10 @@ public interface AnyObjectDAO extends AnyDAO<AnyObject> {
 
     Map<String, Integer> countByRealm(AnyType anyType);
 
+    AnyObject findByName(String name);
+
+    AnyObject authFindByName(String name);
+
     List<Group> findDynGroupMemberships(AnyObject anyObject);
 
     List<ARelationship> findARelationships(AnyObject anyObject);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/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 b1580e3..82359e9 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
@@ -41,6 +41,8 @@ public interface Any<P extends PlainAttr<?>> extends AnnotatedEntity {
 
     boolean add(P attr);
 
+    boolean remove(P attr);
+
     P getPlainAttr(String plainSchemaName);
 
     List<? extends P> getPlainAttrs();

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
index 377f7fe..0e0c8cc 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
@@ -22,6 +22,7 @@ import java.util.Set;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 
 public interface AnyUtils {
@@ -52,5 +53,5 @@ public interface AnyUtils {
 
     Set<ExternalResource> getAllResources(Any<?> any);
 
-    <S extends Schema> Set<S> getAllowedSchemas(Any<?> any, Class<S> reference);
+    <S extends Schema> AllowedSchemas<S> getAllowedSchemas(Any<?> any, Class<S> reference);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
new file mode 100644
index 0000000..7e345a5
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
@@ -0,0 +1,26 @@
+/*
+ * 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.persistence.api.entity;
+
+public interface GroupablePlainAttr<A extends Any<?>, M extends Membership<A>> extends PlainAttr<A> {
+
+    M getMembership();
+
+    void setMembership(M membership);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
new file mode 100644
index 0000000..147f469
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
@@ -0,0 +1,100 @@
+/*
+ * 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.persistence.api.entity;
+
+import java.util.Collection;
+import java.util.List;
+
+public interface GroupableRelatable<
+        L extends Any<P>, 
+        M extends Membership<L>, 
+        P extends GroupablePlainAttr<L, M>,
+        R extends Any<?>,
+        REL extends Relationship<L, R>> extends Any<P> {
+
+    @Override
+    boolean add(final P attr);
+
+    @Override
+    boolean remove(final P attr);
+
+    /**
+     * Returns the plain attribute for this instance and the given schema name - if found, {@code NULL} otherwise.
+     * <b>IMPORTANT:</b> This method won't return any attribute related to memberships.
+     *
+     * @param plainSchemaName plain schema name
+     * @return plain attribute for this instance and the given schema name - if found, {@code NULL} otherwise
+     */
+    @Override
+    P getPlainAttr(String plainSchemaName);
+
+    /**
+     * Returns the plain attribute for this instance, the given schema name and the given membership -
+     * if found, {@code NULL} otherwise.
+     *
+     * @param plainSchemaName plain schema name
+     * @param membership membership
+     * @return plain attribute for this instance, the given schema name and the given membership -
+     * if found, {@code NULL} otherwise
+     */
+    P getPlainAttr(String plainSchemaName, Membership<?> membership);
+
+    /**
+     * Returns the plain attributes for this instance.
+     * <b>IMPORTANT:</b> This method won't return any attribute related to memberships.
+     *
+     * @return plain attribute for this instance
+     */
+    @Override
+    List<? extends P> getPlainAttrs();
+
+    /**
+     * Returns the list of plain attributes for this instance and the given schema name (including membeship attributes,
+     * as opposite to {@link Any#getPlainAttr(java.lang.String)}).
+     *
+     * @param plainSchemaName plain schema name
+     * @return list of plain attributes for this instance and the given schema name (including membeship attributes)
+     */
+    Collection<? extends P> getPlainAttrs(String plainSchemaName);
+
+    /**
+     * Returns the list of plain attributes for this instance and the given membership.
+     *
+     * @param membership membership
+     * @return list of plain attributes for this instance and the given membership
+     */
+    Collection<? extends P> getPlainAttrs(Membership<?> membership);
+
+    boolean add(M membership);
+
+    M getMembership(String groupKey);
+
+    List<? extends M> getMemberships();
+
+    boolean add(REL relationship);
+
+    REL getRelationship(RelationshipType relationshipType, String otherEndKey);
+
+    Collection<? extends REL> getRelationships(String otherEndKey);
+
+    Collection<? extends REL> getRelationships(RelationshipType relationshipType);
+
+    List<? extends REL> getRelationships();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
index 46d2297..64a58ce 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
@@ -19,9 +19,9 @@
 package org.apache.syncope.core.persistence.api.entity.anyobject;
 
 import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 
-public interface APlainAttr extends PlainAttr<AnyObject> {
+public interface APlainAttr extends GroupablePlainAttr<AnyObject, AMembership> {
 
     @Override
     List<? extends APlainAttrValue> getValues();

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
index ac5fda0..7b0f434 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
@@ -18,27 +18,13 @@
  */
 package org.apache.syncope.core.persistence.api.entity.anyobject;
 
-import java.util.Collection;
-import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.RelationshipType;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 
-public interface AnyObject extends Any<APlainAttr> {
+public interface AnyObject extends
+        GroupableRelatable<AnyObject, AMembership, APlainAttr, AnyObject, ARelationship> {
 
-    boolean add(ARelationship relationship);
+    String getName();
 
-    ARelationship getRelationship(RelationshipType relationshipType, String anyObjectKey);
-
-    Collection<? extends ARelationship> getRelationships(String anyObjectKey);
-
-    Collection<? extends ARelationship> getRelationships(RelationshipType relationshipType);
-
-    List<? extends ARelationship> getRelationships();
-
-    boolean add(AMembership membership);
-
-    AMembership getMembership(String membershipKey);
-
-    List<? extends AMembership> getMemberships();
+    void setName(String name);
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
index 5c91acf..503352f 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
@@ -19,9 +19,9 @@
 package org.apache.syncope.core.persistence.api.entity.user;
 
 import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 
-public interface UPlainAttr extends PlainAttr<User> {
+public interface UPlainAttr extends GroupablePlainAttr<User, UMembership> {
 
     @Override
     List<? extends UPlainAttrValue> getValues();

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
index b7e14bf..fa81fd1 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
@@ -18,15 +18,15 @@
  */
 package org.apache.syncope.core.persistence.api.entity.user;
 
-import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 
-public interface User extends Any<UPlainAttr> {
+public interface User extends
+        GroupableRelatable<User, UMembership, UPlainAttr, AnyObject, URelationship> {
 
     String getUsername();
 
@@ -92,32 +92,8 @@ public interface User extends Any<UPlainAttr> {
 
     void setMustChangePassword(boolean mustChangePassword);
 
-    @Override
-    boolean add(UPlainAttr attr);
-
-    @Override
-    UPlainAttr getPlainAttr(String plainSchemaName);
-
-    @Override
-    List<? extends UPlainAttr> getPlainAttrs();
-
     boolean add(Role role);
 
     List<? extends Role> getRoles();
 
-    boolean add(URelationship relationship);
-
-    URelationship getRelationship(RelationshipType relationshipType, String anyObjectKey);
-
-    Collection<? extends URelationship> getRelationships(String anyObjectKey);
-
-    Collection<? extends URelationship> getRelationships(RelationshipType relationshipType);
-
-    List<? extends URelationship> getRelationships();
-
-    boolean add(UMembership membership);
-
-    UMembership getMembership(String groupKey);
-
-    List<? extends UMembership> getMemberships();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
index 379d386..0eb38ac 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
@@ -23,8 +23,10 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 import javax.persistence.NoResultException;
@@ -35,6 +37,7 @@ import org.apache.commons.jexl3.parser.ParserConstants;
 import org.apache.commons.jexl3.parser.Token;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
@@ -54,6 +57,7 @@ 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.Group;
 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;
@@ -420,33 +424,55 @@ public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> im
     @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
     @Override
     @SuppressWarnings("unchecked")
-    public <S extends Schema> Collection<S> findAllowedSchemas(final A any, final Class<S> reference) {
-        Set<AnyTypeClass> classes = new HashSet<>();
-        classes.addAll(any.getType().getClasses());
-        classes.addAll(any.getAuxClasses());
+    public <S extends Schema> AllowedSchemas<S> findAllowedSchemas(final A any, final Class<S> reference) {
+        AllowedSchemas<S> result = new AllowedSchemas<>();
+
+        // schemas given by type and aux classes
+        Set<AnyTypeClass> typeOwnClasses = new HashSet<>();
+        typeOwnClasses.addAll(any.getType().getClasses());
+        typeOwnClasses.addAll(any.getAuxClasses());
+
+        for (AnyTypeClass typeClass : typeOwnClasses) {
+            if (reference.equals(PlainSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getPlainSchemas());
+            } else if (reference.equals(DerSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getDerSchemas());
+            } else if (reference.equals(VirSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getVirSchemas());
+            }
+        }
+
+        // schemas given by type extensions
+        Map<Group, List<? extends AnyTypeClass>> typeExtensionClasses = new HashMap<>();
         if (any instanceof User) {
             for (UMembership memb : ((User) any).getMemberships()) {
                 for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
-                    classes.addAll(typeExtension.getAuxClasses());
+                    typeExtensionClasses.put(memb.getRightEnd(), typeExtension.getAuxClasses());
                 }
             }
         } else if (any instanceof AnyObject) {
             for (AMembership memb : ((AnyObject) any).getMemberships()) {
                 for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
-                    classes.addAll(typeExtension.getAuxClasses());
+                    if (any.getType().equals(typeExtension.getAnyType())) {
+                        typeExtensionClasses.put(memb.getRightEnd(), typeExtension.getAuxClasses());
+                    }
                 }
             }
         }
 
-        Set<S> result = new HashSet<>();
-
-        for (AnyTypeClass typeClass : classes) {
-            if (reference.equals(PlainSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getPlainSchemas());
-            } else if (reference.equals(DerSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getDerSchemas());
-            } else if (reference.equals(VirSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getVirSchemas());
+        for (Map.Entry<Group, List<? extends AnyTypeClass>> entry : typeExtensionClasses.entrySet()) {
+            result.getForMemberships().put(entry.getKey(), new HashSet<S>());
+            for (AnyTypeClass typeClass : entry.getValue()) {
+                if (reference.equals(PlainSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getPlainSchemas());
+                } else if (reference.equals(DerSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getDerSchemas());
+                } else if (reference.equals(VirSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getVirSchemas());
+                }
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index 60be1fe..5280c3c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -27,6 +27,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.persistence.NoResultException;
 import javax.persistence.Query;
 import javax.persistence.TypedQuery;
 import org.apache.commons.collections4.CollectionUtils;
@@ -40,6 +41,7 @@ import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -124,6 +126,38 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     }
 
     @Override
+    public AnyObject findByName(final String name) {
+        TypedQuery<AnyObject> query = entityManager().createQuery(
+                "SELECT e FROM " + JPAAnyObject.class.getSimpleName() + " e WHERE e.name = :name", AnyObject.class);
+        query.setParameter("name", name);
+
+        AnyObject result = null;
+        try {
+            result = query.getSingleResult();
+        } catch (NoResultException e) {
+            LOG.debug("No any object found with name {}", name, e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public AnyObject authFindByName(final String name) {
+        if (name == null) {
+            throw new NotFoundException("Null name");
+        }
+
+        AnyObject anyObject = findByName(name);
+        if (anyObject == null) {
+            throw new NotFoundException("Any Object " + name);
+        }
+
+        securityChecks(anyObject);
+
+        return anyObject;
+    }
+
+    @Override
     public List<ARelationship> findARelationships(final AnyObject anyObject) {
         TypedQuery<ARelationship> query = entityManager().createQuery(
                 "SELECT e FROM " + JPAARelationship.class.getSimpleName()

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
index 07e18e2..d1df518 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.persistence.jpa.dao;
 
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
@@ -40,9 +39,6 @@ public class JPAConfDAO extends AbstractDAO<Conf> implements ConfDAO {
     @Autowired
     private PlainSchemaDAO schemaDAO;
 
-    @Autowired
-    private PlainAttrDAO attrDAO;
-
     @Override
     public Conf get() {
         Conf instance = entityManager().find(JPAConf.class, KEY);
@@ -96,8 +92,8 @@ public class JPAConfDAO extends AbstractDAO<Conf> implements ConfDAO {
         if (old != null && (!attr.getSchema().isUniqueConstraint()
                 || (!attr.getUniqueValue().getStringValue().equals(old.getUniqueValue().getStringValue())))) {
 
-            instance.getPlainAttrs().remove(old);
-            attrDAO.delete(old.getKey(), CPlainAttr.class);
+            old.setOwner(null);
+            instance.remove(old);
         }
 
         instance.add(attr);
@@ -111,8 +107,8 @@ public class JPAConfDAO extends AbstractDAO<Conf> implements ConfDAO {
         Conf instance = get();
         CPlainAttr attr = instance.getPlainAttr(key);
         if (attr != null) {
-            instance.getPlainAttrs().remove(attr);
-            attrDAO.delete(attr.getKey(), CPlainAttr.class);
+            attr.setOwner(null);
+            instance.remove(attr);
 
             instance = entityManager().merge(instance);
         }


[2/6] syncope git commit: [SYNCOPE-862] Preliminary work

Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/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 a144d67..0ccbe14 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
@@ -26,7 +26,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
@@ -41,6 +40,7 @@ import org.apache.syncope.common.lib.to.RelationshipTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
@@ -59,6 +59,7 @@ import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
 import org.apache.syncope.core.provisioning.java.MappingManagerImpl;
 import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
@@ -73,6 +74,7 @@ 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.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Relationship;
@@ -88,6 +90,7 @@ import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 
 abstract class AbstractAnyDataBinder {
 
@@ -150,7 +153,7 @@ abstract class AbstractAnyDataBinder {
     protected DerAttrHandler derAttrHandler;
 
     @Autowired
-    protected VirAttrHandler virAttrHander;
+    protected VirAttrHandler virAttrHandler;
 
     @Autowired
     protected ConnObjectUtils connObjectUtils;
@@ -186,20 +189,12 @@ abstract class AbstractAnyDataBinder {
         return schema;
     }
 
-    private DerSchema getDerSchema(final String derSchemaName) {
-        DerSchema schema = null;
-        if (StringUtils.isNotBlank(derSchemaName)) {
-            schema = derSchemaDAO.find(derSchemaName);
-            if (schema == null) {
-                LOG.debug("Ignoring invalid derived schema {}", derSchemaName);
-            }
-        }
-
-        return schema;
-    }
-
-    private void fillAttr(final List<String> values, final AnyUtils anyUtils,
-            final PlainSchema schema, final PlainAttr<?> attr, final SyncopeClientException invalidValues) {
+    private void fillAttr(
+            final List<String> values,
+            final AnyUtils anyUtils,
+            final PlainSchema schema,
+            final PlainAttr<?> attr,
+            final SyncopeClientException invalidValues) {
 
         // if schema is multivalue, all values are considered for addition;
         // otherwise only the fist one - if provided - is considered
@@ -210,7 +205,7 @@ abstract class AbstractAnyDataBinder {
                         : Collections.singletonList(values.iterator().next()));
 
         for (String value : valuesProvided) {
-            if (value == null || value.isEmpty()) {
+            if (StringUtils.isBlank(value)) {
                 LOG.debug("Null value for {}, ignoring", schema.getKey());
             } else {
                 try {
@@ -265,18 +260,37 @@ abstract class AbstractAnyDataBinder {
         return reqValMissing;
     }
 
+    private void checkMandatory(
+            final PlainSchema schema,
+            final PlainAttr<?> attr,
+            final Any<?> any,
+            final SyncopeClientException reqValMissing) {
+
+        if (attr == null
+                && !schema.isReadonly()
+                && JexlUtils.evaluateMandatoryCondition(schema.getMandatoryCondition(), any)) {
+
+            LOG.error("Mandatory schema " + schema.getKey() + " not provided with values");
+
+            reqValMissing.getElements().add(schema.getKey());
+        }
+    }
+
     private SyncopeClientException checkMandatory(final Any<?> any, final AnyUtils anyUtils) {
         SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
 
         // Check if there is some mandatory schema defined for which no value has been provided
-        for (PlainSchema schema : anyUtils.getAllowedSchemas(any, PlainSchema.class)) {
-            if (any.getPlainAttr(schema.getKey()) == null
-                    && !schema.isReadonly()
-                    && JexlUtils.evaluateMandatoryCondition(schema.getMandatoryCondition(), any)) {
-
-                LOG.error("Mandatory schema " + schema.getKey() + " not provided with values");
-
-                reqValMissing.getElements().add(schema.getKey());
+        AllowedSchemas<PlainSchema> allowedPlainSchemas = anyUtils.getAllowedSchemas(any, PlainSchema.class);
+        for (PlainSchema schema : allowedPlainSchemas.getForSelf()) {
+            checkMandatory(schema, any.getPlainAttr(schema.getKey()), any, reqValMissing);
+        }
+        for (Map.Entry<Group, Set<PlainSchema>> entry : allowedPlainSchemas.getForMemberships().entrySet()) {
+            if (any instanceof GroupableRelatable) {
+                GroupableRelatable<?, ?, ?, ?, ?> groupable = GroupableRelatable.class.cast(any);
+                Membership<?> membership = groupable.getMembership(entry.getKey().getKey());
+                for (PlainSchema schema : entry.getValue()) {
+                    checkMandatory(schema, groupable.getPlainAttr(schema.getKey(), membership), any, reqValMissing);
+                }
             }
         }
 
@@ -284,28 +298,16 @@ abstract class AbstractAnyDataBinder {
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    private void processAttrPatch(final Any any, final AttrPatch patch, final PlainSchema schema,
-            final AnyUtils anyUtils, final Set<ExternalResource> resources, final PropagationByResource propByRes,
+    protected void processAttrPatch(
+            final Any any,
+            final AttrPatch patch,
+            final PlainSchema schema,
+            final PlainAttr<?> attr,
+            final AnyUtils anyUtils,
+            final Set<ExternalResource> resources,
+            final PropagationByResource propByRes,
             final SyncopeClientException invalidValues) {
 
-        PlainAttr<?> attr = any.getPlainAttr(schema.getKey());
-        if (attr == null) {
-            LOG.debug("No plain attribute found for schema {}", schema);
-
-            switch (patch.getOperation()) {
-                case ADD_REPLACE:
-                    attr = anyUtils.newPlainAttr();
-                    ((PlainAttr) attr).setOwner(any);
-                    attr.setSchema(schema);
-                    any.add(attr);
-                    break;
-
-                case DELETE:
-                default:
-                    return;
-            }
-        }
-
         switch (patch.getOperation()) {
             case ADD_REPLACE:
                 // 1.1 remove values
@@ -317,14 +319,8 @@ abstract class AbstractAnyDataBinder {
                         plainAttrValueDAO.delete(attr.getUniqueValue().getKey(), anyUtils.plainAttrUniqueValueClass());
                     }
                 } else {
-                    Collection<String> valuesToBeRemoved = CollectionUtils.collect(attr.getValues(),
-                            new Transformer<PlainAttrValue, String>() {
-
-                        @Override
-                        public String transform(final PlainAttrValue input) {
-                            return input.getKey();
-                        }
-                    });
+                    Collection<String> valuesToBeRemoved =
+                            CollectionUtils.collect(attr.getValues(), EntityUtils.keyTransformer());
                     for (String attrValueKey : valuesToBeRemoved) {
                         plainAttrValueDAO.delete(attrValueKey, anyUtils.plainAttrValueClass());
                     }
@@ -347,13 +343,14 @@ abstract class AbstractAnyDataBinder {
 
             case DELETE:
             default:
-                any.getPlainAttrs().remove(attr);
+                any.remove(attr);
                 plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass());
         }
 
         for (ExternalResource resource : resources) {
-            for (MappingItem mapItem : MappingManagerImpl.getPropagationMappingItems(resource.
-                    getProvision(any.getType()))) {
+            for (MappingItem mapItem
+                    : MappingManagerImpl.getPropagationMappingItems(resource.getProvision(any.getType()))) {
+
                 if (schema.getKey().equals(mapItem.getIntAttrName())
                         && mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) {
 
@@ -367,7 +364,11 @@ abstract class AbstractAnyDataBinder {
         }
     }
 
-    protected PropagationByResource fill(final Any<?> any, final AnyPatch anyPatch, final AnyUtils anyUtils,
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected PropagationByResource fill(
+            final Any any,
+            final AnyPatch anyPatch,
+            final AnyUtils anyUtils,
             final SyncopeClientCompositeException scce) {
 
         PropagationByResource propByRes = new PropagationByResource();
@@ -421,7 +422,21 @@ abstract class AbstractAnyDataBinder {
                     LOG.debug("Invalid " + PlainSchema.class.getSimpleName()
                             + "{}, ignoring...", patch.getAttrTO().getSchema());
                 } else {
-                    processAttrPatch(any, patch, schema, anyUtils, resources, propByRes, invalidValues);
+                    PlainAttr<?> attr = any.getPlainAttr(schema.getKey());
+                    if (attr == null) {
+                        LOG.debug("No plain attribute found for schema {}", schema);
+
+                        if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
+                            attr = anyUtils.newPlainAttr();
+                            ((PlainAttr) attr).setOwner(any);
+                            attr.setSchema(schema);
+                            any.add(attr);
+
+                        }
+                    }
+                    if (attr != null) {
+                        processAttrPatch(any, patch, schema, attr, anyUtils, resources, propByRes, invalidValues);
+                    }
                 }
             }
         }
@@ -443,7 +458,10 @@ abstract class AbstractAnyDataBinder {
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     protected void fill(
-            final Any any, final AnyTO anyTO, final AnyUtils anyUtils, final SyncopeClientCompositeException scce) {
+            final Any any,
+            final AnyTO anyTO,
+            final AnyUtils anyUtils,
+            final SyncopeClientCompositeException scce) {
 
         // 0. aux classes
         any.getAuxClasses().clear();
@@ -459,9 +477,9 @@ abstract class AbstractAnyDataBinder {
         // 1. attributes
         SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
 
-        // Only consider attributeTO with values
         for (AttrTO attrTO : anyTO.getPlainAttrs()) {
-            if (attrTO.getValues() != null && !attrTO.getValues().isEmpty()) {
+            // Only consider attributeTO with values
+            if (!attrTO.getValues().isEmpty()) {
                 PlainSchema schema = getPlainSchema(attrTO.getSchema());
                 if (schema != null) {
                     PlainAttr attr = any.getPlainAttr(schema.getKey());
@@ -506,6 +524,44 @@ abstract class AbstractAnyDataBinder {
         }
     }
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected void fill(
+            final Any any,
+            final Membership membership,
+            final MembershipTO membershipTO,
+            final AnyUtils anyUtils,
+            final SyncopeClientCompositeException scce) {
+
+        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
+        for (AttrTO attrTO : membershipTO.getPlainAttrs()) {
+            if (!attrTO.getValues().isEmpty()) {
+                PlainSchema schema = getPlainSchema(attrTO.getSchema());
+                if (schema != null) {
+                    GroupablePlainAttr attr = GroupableRelatable.class.cast(any).
+                            getPlainAttr(schema.getKey(), membership);
+                    if (attr == null) {
+                        attr = anyUtils.newPlainAttr();
+                        attr.setOwner(any);
+                        attr.setMembership(membership);
+                        attr.setSchema(schema);
+                    }
+                    fillAttr(attrTO.getValues(), anyUtils, schema, attr, invalidValues);
+
+                    if (attr.getValuesAsStrings().isEmpty()) {
+                        attr.setOwner(null);
+                    } else {
+                        any.add(attr);
+                    }
+                }
+            }
+        }
+
+        if (!invalidValues.isEmpty()) {
+            scce.addException(invalidValues);
+        }
+    }
+
     protected void fillTO(final AnyTO anyTO,
             final String realmFullPath,
             final Collection<? extends AnyTypeClass> auxClasses,
@@ -519,30 +575,27 @@ abstract class AbstractAnyDataBinder {
         CollectionUtils.collect(auxClasses, EntityUtils.<AnyTypeClass>keyTransformer(), anyTO.getAuxClasses());
 
         for (PlainAttr<?> plainAttr : plainAttrs) {
-            AttrTO attrTO = new AttrTO();
-            attrTO.setSchema(plainAttr.getSchema().getKey());
-            attrTO.getValues().addAll(plainAttr.getValuesAsStrings());
-            attrTO.setReadonly(plainAttr.getSchema().isReadonly());
-
-            anyTO.getPlainAttrs().add(attrTO);
+            anyTO.getPlainAttrs().add(new AttrTO.Builder().
+                    schema(plainAttr.getSchema().getKey()).
+                    values(plainAttr.getValuesAsStrings()).
+                    readonly(plainAttr.getSchema().isReadonly()).
+                    build());
         }
 
         for (Map.Entry<DerSchema, String> entry : derAttrs.entrySet()) {
-            AttrTO attrTO = new AttrTO();
-            attrTO.setSchema(entry.getKey().getKey());
-            attrTO.getValues().add(entry.getValue());
-            attrTO.setReadonly(true);
-
-            anyTO.getDerAttrs().add(attrTO);
+            anyTO.getDerAttrs().add(new AttrTO.Builder().
+                    schema(entry.getKey().getKey()).
+                    value(entry.getValue()).
+                    readonly(true).
+                    build());
         }
 
         for (Map.Entry<VirSchema, List<String>> entry : virAttrs.entrySet()) {
-            AttrTO attrTO = new AttrTO();
-            attrTO.setSchema(entry.getKey().getKey());
-            attrTO.getValues().addAll(entry.getValue());
-            attrTO.setReadonly(entry.getKey().isReadonly());
-
-            anyTO.getVirAttrs().add(attrTO);
+            anyTO.getVirAttrs().add(new AttrTO.Builder().
+                    schema(entry.getKey().getKey()).
+                    values(entry.getValue()).
+                    readonly(entry.getKey().isReadonly()).
+                    build());
         }
 
         for (ExternalResource resource : resources) {
@@ -553,16 +606,45 @@ abstract class AbstractAnyDataBinder {
     protected RelationshipTO getRelationshipTO(final Relationship<? extends Any<?>, AnyObject> relationship) {
         return new RelationshipTO.Builder().
                 type(relationship.getType().getKey()).
-                left(relationship.getLeftEnd().getType().getKey(), relationship.getLeftEnd().getKey()).
                 right(relationship.getRightEnd().getType().getKey(), relationship.getRightEnd().getKey()).
                 build();
     }
 
-    protected MembershipTO getMembershipTO(final Membership<? extends Any<?>> membership) {
-        return new MembershipTO.Builder().
-                left(membership.getLeftEnd().getType().getKey(), membership.getLeftEnd().getKey()).
+    protected MembershipTO getMembershipTO(
+            final Collection<? extends PlainAttr<?>> plainAttrs,
+            final Map<DerSchema, String> derAttrs,
+            final Map<VirSchema, List<String>> virAttrs,
+            final Membership<? extends Any<?>> membership) {
+
+        MembershipTO membershipTO = new MembershipTO.Builder().
                 group(membership.getRightEnd().getKey(), membership.getRightEnd().getName()).
                 build();
+
+        for (PlainAttr<?> plainAttr : plainAttrs) {
+            membershipTO.getPlainAttrs().add(new AttrTO.Builder().
+                    schema(plainAttr.getSchema().getKey()).
+                    values(plainAttr.getValuesAsStrings()).
+                    readonly(plainAttr.getSchema().isReadonly()).
+                    build());
+        }
+
+        for (Map.Entry<DerSchema, String> entry : derAttrs.entrySet()) {
+            membershipTO.getDerAttrs().add(new AttrTO.Builder().
+                    schema(entry.getKey().getKey()).
+                    value(entry.getValue()).
+                    readonly(true).
+                    build());
+        }
+
+        for (Map.Entry<VirSchema, List<String>> entry : virAttrs.entrySet()) {
+            membershipTO.getVirAttrs().add(new AttrTO.Builder().
+                    schema(entry.getKey().getKey()).
+                    values(entry.getValue()).
+                    readonly(entry.getKey().isReadonly()).
+                    build());
+        }
+
+        return membershipTO;
     }
 
     protected Map<String, String> getConnObjectKeys(final Any<?> any) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/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
index 0e19eb7..d129dcb 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -29,7 +29,9 @@ import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
+import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.RelationshipPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
@@ -46,14 +48,17 @@ import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+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.RelationshipType;
 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.APlainAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -74,7 +79,9 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
     @Transactional(readOnly = true)
     @Override
     public AnyObjectTO getAnyObjectTO(final String key) {
-        return getAnyObjectTO(anyObjectDAO.authFind(key), true);
+        return SyncopeConstants.UUID_PATTERN.matcher(key).matches()
+                ? getAnyObjectTO(anyObjectDAO.authFind(key), true)
+                : getAnyObjectTO(anyObjectDAO.authFindByName(key), true);
     }
 
     @Override
@@ -84,12 +91,15 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
         BeanUtils.copyProperties(anyObject, anyObjectTO, IGNORE_PROPERTIES);
 
-        Map<DerSchema, String> derAttrValues = derAttrHandler.getValues(anyObject);
         Map<VirSchema, List<String>> virAttrValues = details
-                ? virAttrHander.getValues(anyObject)
+                ? virAttrHandler.getValues(anyObject)
                 : Collections.<VirSchema, List<String>>emptyMap();
-        fillTO(anyObjectTO, anyObject.getRealm().getFullPath(), anyObject.getAuxClasses(),
-                anyObject.getPlainAttrs(), derAttrValues, virAttrValues, anyObjectDAO.findAllResources(anyObject));
+        fillTO(anyObjectTO, anyObject.getRealm().getFullPath(),
+                anyObject.getAuxClasses(),
+                anyObject.getPlainAttrs(),
+                derAttrHandler.getValues(anyObject),
+                virAttrValues,
+                anyObjectDAO.findAllResources(anyObject));
 
         if (details) {
             // relationships
@@ -107,7 +117,11 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
                 @Override
                 public MembershipTO transform(final AMembership membership) {
-                    return AnyObjectDataBinderImpl.this.getMembershipTO(membership);
+                    return getMembershipTO(
+                            anyObject.getPlainAttrs(membership),
+                            derAttrHandler.getValues(anyObject, membership),
+                            virAttrHandler.getValues(anyObject, membership),
+                            membership);
                 }
             }, anyObjectTO.getMemberships());
 
@@ -131,6 +145,16 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
 
+        // name
+        SyncopeClientException invalidGroups = SyncopeClientException.build(ClientExceptionType.InvalidGroup);
+        if (anyObjectTO.getName() == null) {
+            LOG.error("No name specified for this anyObject");
+
+            invalidGroups.getElements().add("No name specified for this anyObject");
+        } else {
+            anyObject.setName(anyObjectTO.getName());
+        }
+
         // realm
         Realm realm = realmDAO.findByFullPath(anyObjectTO.getRealm());
         if (realm == null) {
@@ -140,6 +164,7 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
         }
         anyObject.setRealm(realm);
 
+        AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT);
         if (anyObject.getRealm() != null) {
             AssignableCond assignableCond = new AssignableCond();
             assignableCond.setRealmFullPath(anyObject.getRealm().getFullPath());
@@ -199,6 +224,9 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
                     membership.setLeftEnd(anyObject);
 
                     anyObject.add(membership);
+
+                    // membership attributes
+                    fill(anyObject, membership, membershipTO, anyUtils, scce);
                 } else {
                     LOG.error("{} cannot be assigned to {}", group, anyObject);
 
@@ -210,8 +238,8 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
             }
         }
 
-        // attributes, derived attributes, virtual attributes and resources
-        fill(anyObject, anyObjectTO, anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT), scce);
+        // attributes and resources
+        fill(anyObject, anyObjectTO, anyUtils, scce);
 
         // Throw composite exception if there is at least one element set in the composing exceptions
         if (scce.hasExceptions()) {
@@ -233,8 +261,19 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
         // fetch connObjectKeys before update
         Map<String, String> oldConnObjectKeys = getConnObjectKeys(anyObject);
 
-        // attributes, derived attributes, virtual attributes and resources
-        propByRes.merge(fill(anyObject, anyObjectPatch, anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT), scce));
+        // realm
+        setRealm(anyObject, anyObjectPatch);
+
+        // name
+        if (anyObjectPatch.getName() != null && StringUtils.isNotBlank(anyObjectPatch.getName().getValue())) {
+            propByRes.addAll(ResourceOperation.UPDATE, anyObject.getResourceNames());
+
+            anyObject.setName(anyObjectPatch.getName().getValue());
+        }
+
+        AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT);
+        // attributes and resources
+        propByRes.merge(fill(anyObject, anyObjectPatch, anyUtils, scce));
 
         Set<String> toBeDeprovisioned = new HashSet<>();
         Set<String> toBeProvisioned = new HashSet<>();
@@ -253,6 +292,8 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
                             anyObject.getRelationship(relationshipType, patch.getRelationshipTO().getRightKey());
                     if (relationship != null) {
                         anyObject.getRelationships().remove(relationship);
+                        relationship.setLeftEnd(null);
+
                         toBeDeprovisioned.addAll(relationship.getRightEnd().getResourceNames());
                     }
 
@@ -293,22 +334,31 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
             }
         }
 
+        Set<ExternalResource> resources = anyUtils.getAllResources(anyObject);
+        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
         // memberships
         List<Group> assignableGroups =
                 searchDAO.searchAssignable(anyObject.getRealm().getFullPath(), AnyTypeKind.GROUP);
 
-        for (MembershipPatch patch : anyObjectPatch.getMemberships()) {
-            if (patch.getMembershipTO() != null) {
-                AMembership membership = anyObject.getMembership(patch.getMembershipTO().getRightKey());
+        for (MembershipPatch membPatch : anyObjectPatch.getMemberships()) {
+            if (membPatch.getGroup() != null) {
+                AMembership membership = anyObject.getMembership(membPatch.getGroup());
                 if (membership != null) {
                     anyObject.getMemberships().remove(membership);
+                    membership.setLeftEnd(null);
+                    for (APlainAttr attr : anyObject.getPlainAttrs(membership)) {
+                        anyObject.remove(attr);
+                        attr.setOwner(null);
+                    }
+
                     toBeDeprovisioned.addAll(membership.getRightEnd().getResourceNames());
                 }
 
-                if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    Group group = groupDAO.find(patch.getMembershipTO().getRightKey());
+                if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
+                    Group group = groupDAO.find(membPatch.getGroup());
                     if (group == null) {
-                        LOG.debug("Ignoring invalid group {}", patch.getMembershipTO().getRightKey());
+                        LOG.debug("Ignoring invalid group {}", membPatch.getGroup());
                     } else if (assignableGroups.contains(group)) {
                         membership = entityFactory.newEntity(AMembership.class);
                         membership.setRightEnd(group);
@@ -316,6 +366,37 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
                         anyObject.add(membership);
 
+                        for (AttrPatch patch : membPatch.getPlainAttrs()) {
+                            if (patch.getAttrTO() != null) {
+                                PlainSchema schema = getPlainSchema(patch.getAttrTO().getSchema());
+                                if (schema == null) {
+                                    LOG.debug("Invalid " + PlainSchema.class.getSimpleName()
+                                            + "{}, ignoring...", patch.getAttrTO().getSchema());
+                                } else {
+                                    APlainAttr attr = anyObject.getPlainAttr(schema.getKey(), membership);
+                                    if (attr == null) {
+                                        LOG.debug("No plain attribute found for {} and membership of {}",
+                                                schema, membership.getRightEnd());
+
+                                        if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
+                                            attr = anyUtils.newPlainAttr();
+                                            attr.setOwner(anyObject);
+                                            attr.setMembership(membership);
+                                            attr.setSchema(schema);
+                                            anyObject.add(attr);
+
+                                            processAttrPatch(
+                                                    anyObject, patch, schema, attr, anyUtils,
+                                                    resources, propByRes, invalidValues);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        if (!invalidValues.isEmpty()) {
+                            scce.addException(invalidValues);
+                        }
+
                         toBeProvisioned.addAll(group.getResourceNames());
                     } else {
                         LOG.error("{} cannot be assigned to {}", group, anyObject);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/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 0aba4b9..38f1811 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
@@ -110,7 +110,7 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
         }
         group.setRealm(realm);
 
-        // attributes, derived attributes, virtual attributes and resources
+        // attributes and resources
         fill(group, groupTO, anyUtilsFactory.getInstance(AnyTypeKind.GROUP), scce);
 
         // owner
@@ -211,7 +211,7 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
                     : groupDAO.find(groupPatch.getGroupOwner().getValue()));
         }
 
-        // attributes, derived attributes, virtual attributes and resources
+        // attributes and resources
         propByRes.merge(fill(group, groupPatch, anyUtilsFactory.getInstance(AnyTypeKind.GROUP), scce));
 
         // check if some connObjectKey was changed by the update above
@@ -325,7 +325,7 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
 
         Map<DerSchema, String> derAttrValues = derAttrHandler.getValues(group);
         Map<VirSchema, List<String>> virAttrValues = details
-                ? virAttrHander.getValues(group)
+                ? virAttrHandler.getValues(group)
                 : Collections.<VirSchema, List<String>>emptyMap();
         fillTO(groupTO, group.getRealm().getFullPath(), group.getAuxClasses(),
                 group.getPlainAttrs(), derAttrValues, virAttrValues, group.getResources());

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/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 0a7f0a8..1581463 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
@@ -34,6 +34,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.PasswordPatch;
 import org.apache.syncope.common.lib.patch.RelationshipPatch;
@@ -62,7 +63,8 @@ import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+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.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
@@ -72,6 +74,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.user.URelationship;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -188,6 +191,7 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
         }
         user.setRealm(realm);
 
+        AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.USER);
         if (user.getRealm() != null) {
             AssignableCond assignableCond = new AssignableCond();
             assignableCond.setRealmFullPath(user.getRealm().getFullPath());
@@ -237,6 +241,9 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
                     membership.setLeftEnd(user);
 
                     user.add(membership);
+
+                    // membership attributes
+                    fill(user, membership, membershipTO, anyUtils, scce);
                 } else {
                     LOG.error("{} cannot be assigned to {}", group, user);
 
@@ -248,8 +255,8 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             }
         }
 
-        // attributes, derived attributes, virtual attributes and resources
-        fill(user, userTO, anyUtilsFactory.getInstance(AnyTypeKind.USER), scce);
+        // attributes and resources
+        fill(user, userTO, anyUtils, scce);
 
         // set password
         if (StringUtils.isBlank(userTO.getPassword()) || !storePassword) {
@@ -371,8 +378,9 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             }
         }
 
-        // attributes, derived attributes, virtual attributes and resources
-        propByRes.merge(fill(user, userPatch, anyUtilsFactory.getInstance(AnyTypeKind.USER), scce));
+        AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.USER);
+        // attributes and resources
+        propByRes.merge(fill(user, userPatch, anyUtils, scce));
 
         Set<String> toBeDeprovisioned = new HashSet<>();
         Set<String> toBeProvisioned = new HashSet<>();
@@ -391,6 +399,8 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
                             user.getRelationship(relationshipType, patch.getRelationshipTO().getRightKey());
                     if (relationship != null) {
                         user.getRelationships().remove(relationship);
+                        relationship.setLeftEnd(null);
+
                         toBeDeprovisioned.addAll(relationship.getRightEnd().getResourceNames());
                     }
 
@@ -420,22 +430,32 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             }
         }
 
+        Set<ExternalResource> resources = anyUtils.getAllResources(user);
+        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
         // memberships
         List<Group> assignableGroups =
                 searchDAO.searchAssignable(user.getRealm().getFullPath(), AnyTypeKind.GROUP);
 
-        for (MembershipPatch patch : userPatch.getMemberships()) {
-            if (patch.getMembershipTO() != null) {
-                UMembership membership = user.getMembership(patch.getMembershipTO().getRightKey());
+        for (MembershipPatch membPatch : userPatch.getMemberships()) {
+            if (membPatch.getGroup() != null) {
+                UMembership membership = user.getMembership(membPatch.getGroup());
                 if (membership != null) {
                     user.getMemberships().remove(membership);
+                    membership.setLeftEnd(null);
+                    for (UPlainAttr attr : user.getPlainAttrs(membership)) {
+                        user.remove(attr);
+                        attr.setOwner(null);
+                        attr.setMembership(null);
+                    }
+
                     toBeDeprovisioned.addAll(membership.getRightEnd().getResourceNames());
                 }
 
-                if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    Group group = groupDAO.find(patch.getMembershipTO().getRightKey());
+                if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
+                    Group group = groupDAO.find(membPatch.getGroup());
                     if (group == null) {
-                        LOG.debug("Ignoring invalid group {}", patch.getMembershipTO().getRightKey());
+                        LOG.debug("Ignoring invalid group {}", membPatch.getGroup());
                     } else if (assignableGroups.contains(group)) {
                         membership = entityFactory.newEntity(UMembership.class);
                         membership.setRightEnd(group);
@@ -443,6 +463,37 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
 
                         user.add(membership);
 
+                        for (AttrPatch patch : membPatch.getPlainAttrs()) {
+                            if (patch.getAttrTO() != null) {
+                                PlainSchema schema = getPlainSchema(patch.getAttrTO().getSchema());
+                                if (schema == null) {
+                                    LOG.debug("Invalid " + PlainSchema.class.getSimpleName()
+                                            + "{}, ignoring...", patch.getAttrTO().getSchema());
+                                } else {
+                                    UPlainAttr attr = user.getPlainAttr(schema.getKey(), membership);
+                                    if (attr == null) {
+                                        LOG.debug("No plain attribute found for {} and membership of {}",
+                                                schema, membership.getRightEnd());
+
+                                        if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
+                                            attr = anyUtils.newPlainAttr();
+                                            attr.setOwner(user);
+                                            attr.setMembership(membership);
+                                            attr.setSchema(schema);
+                                            user.add(attr);
+
+                                            processAttrPatch(
+                                                    user, patch, schema, attr, anyUtils,
+                                                    resources, propByRes, invalidValues);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        if (!invalidValues.isEmpty()) {
+                            scce.addException(invalidValues);
+                        }
+
                         toBeProvisioned.addAll(group.getResourceNames());
 
                         // SYNCOPE-686: if password is invertible and we are adding resources with password mapping,
@@ -509,12 +560,15 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             userTO.setSecurityQuestion(user.getSecurityQuestion().getKey());
         }
 
-        Map<DerSchema, String> derAttrValues = derAttrHandler.getValues(user);
         Map<VirSchema, List<String>> virAttrValues = details
-                ? virAttrHander.getValues(user)
+                ? virAttrHandler.getValues(user)
                 : Collections.<VirSchema, List<String>>emptyMap();
-        fillTO(userTO, user.getRealm().getFullPath(), user.getAuxClasses(),
-                user.getPlainAttrs(), derAttrValues, virAttrValues, userDAO.findAllResources(user));
+        fillTO(userTO, user.getRealm().getFullPath(),
+                user.getAuxClasses(),
+                user.getPlainAttrs(),
+                derAttrHandler.getValues(user),
+                virAttrValues,
+                userDAO.findAllResources(user));
 
         if (details) {
             // roles
@@ -536,7 +590,11 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
 
                 @Override
                 public MembershipTO transform(final UMembership membership) {
-                    return UserDataBinderImpl.this.getMembershipTO(membership);
+                    return getMembershipTO(
+                            user.getPlainAttrs(membership),
+                            derAttrHandler.getValues(user, membership),
+                            virAttrHandler.getValues(user, membership),
+                            membership);
                 }
             }, userTO.getMemberships());
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
index ead65e2..1b509d7 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
@@ -22,7 +22,6 @@ import java.util.Map;
 import java.util.Set;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.UserPatch;
-import org.apache.syncope.common.lib.to.MembershipTO;
 import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
 import org.apache.syncope.core.provisioning.api.job.JobManager;
@@ -70,7 +69,7 @@ public class SetUMembershipsJob extends AbstractInterruptableJob {
                             userPatch.getMemberships().add(
                                     new MembershipPatch.Builder().
                                     operation(PatchOperation.ADD_REPLACE).
-                                    membershipTO(new MembershipTO.Builder().group(groupKey).build()).
+                                    group(groupKey).
                                     build());
                         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 599aabf..995f483 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -39,6 +39,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
@@ -237,6 +238,13 @@ public class PullUtils {
                 }
                 break;
 
+            case AnyObjectName:
+                AnyObject anyObject = anyObjectDAO.findByName(transfUid);
+                if (anyObject != null) {
+                    result.add(anyObject.getKey());
+                }
+                break;
+                
             default:
                 LOG.error("Invalid connObjectKey type '{}'", connObjectKeyItem.getIntMappingType());
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index 124724f..af2631c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -260,7 +260,7 @@ public class ConnObjectUtils {
                     }
                 }
 
-                connObjectTO.getPlainAttrs().add(attrTO);
+                connObjectTO.getAttrs().add(attrTO);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
index bbfa9ad..e7993ff 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
@@ -162,7 +162,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
         List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(user.getWorkflowId()).list();
         if (tasks.isEmpty() || tasks.size() > 1) {
-            LOG.warn("While checking if form task: unexpected task number ({})", tasks.size());
+            LOG.debug("While checking if form task: unexpected task number ({})", tasks.size());
         } else {
             try {
                 TaskFormData formData = engine.getFormService().getTaskFormData(tasks.get(0).getId());

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/build-tools/src/main/resources/testdb.sql
----------------------------------------------------------------------
diff --git a/fit/build-tools/src/main/resources/testdb.sql b/fit/build-tools/src/main/resources/testdb.sql
index df929da..610c8a3 100644
--- a/fit/build-tools/src/main/resources/testdb.sql
+++ b/fit/build-tools/src/main/resources/testdb.sql
@@ -45,5 +45,6 @@ lastModification TIMESTAMP);
 DROP TABLE testPRINTER IF EXISTS;
 CREATE TABLE testPRINTER (
 id CHAR(36) PRIMARY KEY,
+printername VARCHAR(80),
 location VARCHAR(80),
 lastModification TIMESTAMP);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java
index 40befd3..bfd04fe 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java
@@ -69,7 +69,7 @@ public class AnyObjectsITCase extends AbstractConsoleITCase {
                 "8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
         assertNotNull(component);
 
-        wicketTester.clickLink(component.getPageRelativePath() + ":cells:3:cell:panelClone:cloneLink");
+        wicketTester.clickLink(component.getPageRelativePath() + ":cells:4:cell:panelClone:cloneLink");
 
         FormTester formTester = wicketTester.newFormTester(tabPanel + "outerObjectsRepeater:0:outer:form:content:form");
         assertNotNull(formTester);
@@ -87,7 +87,7 @@ public class AnyObjectsITCase extends AbstractConsoleITCase {
                 "8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
         assertNotNull(component);
 
-        wicketTester.clickLink(component.getPageRelativePath() + ":cells:3:cell:panelEdit:editLink");
+        wicketTester.clickLink(component.getPageRelativePath() + ":cells:4:cell:panelEdit:editLink");
 
         wicketTester.assertComponent(tabPanel + "outerObjectsRepeater:0:outer:form:content:form:view:status:"
                 + "resources:firstLevelContainer:first:container:content:group:beans:0:fields:0", ListItem.class);
@@ -138,7 +138,7 @@ public class AnyObjectsITCase extends AbstractConsoleITCase {
                 "8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
         assertNotNull(component);
 
-        wicketTester.assertComponent(component.getPageRelativePath() + ":cells:3:cell:panelDelete:deleteLink",
+        wicketTester.assertComponent(component.getPageRelativePath() + ":cells:4:cell:panelDelete:deleteLink",
                 IndicatingOnConfirmAjaxLink.class);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
index 2407a15..cf82980 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
@@ -236,7 +236,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
         assertNotNull(component);
 
         wicketTester.clickLink(component.getPageRelativePath()
-                + ":cells:3:cell:panelManageResources:manageResourcesLink");
+                + ":cells:4:cell:panelManageResources:manageResourcesLink");
 
         wicketTester.assertComponent(tabPanel + "outerObjectsRepeater:1:outer:form:content:status:"
                 + "firstLevelContainer:first:container:content:searchContainer:resultTable:tablePanel:groupForm:"

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java
index 7627467..e0e02b9 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java
@@ -42,7 +42,7 @@ public class DisplayAttributesITCase extends AbstractConsoleITCase {
         wicketTester.clickLink("body:content:body:tabbedPanel:panel:"
                 + "searchResult:container:content:searchContainer:resultTable:"
                 + "tablePanel:groupForm:checkgroup:dataTable:topToolbars:"
-                + "toolbars:1:headers:3:header:label:panelChangeView:changeViewLink");
+                + "toolbars:1:headers:4:header:label:panelChangeView:changeViewLink");
 
         wicketTester.assertComponent(
                 "body:content:body:tabbedPanel:panel:searchResult:outerObjectsRepeater:2:outer", Modal.class);
@@ -54,7 +54,7 @@ public class DisplayAttributesITCase extends AbstractConsoleITCase {
         wicketTester.clickLink("body:content:body:tabbedPanel:panel:"
                 + "searchResult:container:content:searchContainer:resultTable:"
                 + "tablePanel:groupForm:checkgroup:dataTable:topToolbars:"
-                + "toolbars:1:headers:3:header:label:panelChangeView:changeViewLink");
+                + "toolbars:1:headers:4:header:label:panelChangeView:changeViewLink");
 
         wicketTester.assertComponent(
                 "body:content:body:tabbedPanel:panel:searchResult:outerObjectsRepeater:2:outer", Modal.class);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
index b653de8..7356c5c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
@@ -50,6 +50,7 @@ public class AnyObjectITCase extends AbstractITCase {
 
     public static AnyObjectTO getSampleTO(final String location) {
         AnyObjectTO anyObjectTO = new AnyObjectTO();
+        anyObjectTO.setName(location + getUUIDString());
         anyObjectTO.setRealm(SyncopeConstants.ROOT_REALM);
         anyObjectTO.setType("PRINTER");
         anyObjectTO.getPlainAttrs().add(attrTO("location", location + getUUIDString()));

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
index 781f89b..61c9945 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
@@ -432,6 +432,7 @@ public class AuthenticationITCase extends AbstractITCase {
 
         // 3. attempt to create an instance of the type above: fail because no entitlement was assigned
         AnyObjectTO folder = new AnyObjectTO();
+        folder.setName("home");
         folder.setRealm(SyncopeConstants.ROOT_REALM);
         folder.setType(anyTypeKey);
         folder.getPlainAttrs().add(attrTO(path.getKey(), "/home"));

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java
index 20c290f..b355799 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java
@@ -24,7 +24,6 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
 import java.util.List;
-import org.apache.commons.collections4.IterableUtils;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.CamelRouteTO;
@@ -123,8 +122,7 @@ public class CamelRouteITCase extends AbstractITCase {
                 + "    </setProperty>\n"
                 + "    <setBody>\n"
                 + "     <groovy>\n"
-                + "       org.apache.commons.collections4."
-                + "CollectionUtils.get(request.body.getPlainAttrs(), 3).getValues().set(0,\"true\")\n"
+                + "request.body.getPlainAttrMap().get(\"camelAttribute\").getValues().set(0,\"true\")\n"
                 + "       return request.body\n"
                 + "     </groovy>\n"
                 + "    </setBody>\n"
@@ -169,7 +167,7 @@ public class CamelRouteITCase extends AbstractITCase {
 
             userTO = createUser(userTO).getAny();
             assertNotNull(userTO);
-            assertEquals("true", IterableUtils.get(userTO.getPlainAttrs(), 3).getValues().get(0));
+            assertEquals("true", userTO.getPlainAttrMap().get("camelAttribute").getValues().get(0));
         } finally {
             doUpdate(oldRoute.getKey(), oldRoute.getContent());
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
new file mode 100644
index 0000000..09a560c
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
@@ -0,0 +1,162 @@
+/*
+ * 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.fit.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.patch.MembershipPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.PatchOperation;
+import org.apache.syncope.fit.AbstractITCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.JVM)
+public class MembershipITCase extends AbstractITCase {
+
+    @Test
+    public void misc() {
+        UserTO user = UserITCase.getUniqueSampleTO("memb@apache.org");
+        user.setRealm("/even/two");
+        user.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1976").build());
+        user.getPlainAttrs().remove(user.getPlainAttrMap().get("ctype"));
+
+        // the group 034740a9-fa10-453b-af37-dc7897e98fb1 has USER type extensions for 'csv' and 'other' 
+        // any type classes
+        MembershipTO membership = new MembershipTO.Builder().group("034740a9-fa10-453b-af37-dc7897e98fb1").build();
+        membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1977").build());
+
+        // 'fullname' is in 'minimal user', so it is not allowed for this membership
+        membership.getPlainAttrs().add(new AttrTO.Builder().schema("fullname").value("discarded").build());
+
+        user.getMemberships().add(membership);
+
+        // user creation fails because of fullname
+        try {
+            createUser(user);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidUser, e.getType());
+            assertTrue(e.getMessage().contains("InvalidPlainAttr: fullname not allowed for membership of group"));
+        }
+
+        // remove fullname and try again
+        CollectionUtils.filterInverse(membership.getPlainAttrs(), new Predicate<AttrTO>() {
+
+            @Override
+            public boolean evaluate(final AttrTO object) {
+                return "fullname".equals(object.getSchema());
+            }
+        });
+        try {
+            user = createUser(user).getAny();
+
+            // 1. verify that 'aLong' is correctly populated for user
+            assertEquals(1, user.getPlainAttrMap().get("aLong").getValues().size());
+            assertEquals("1976", user.getPlainAttrMap().get("aLong").getValues().get(0));
+
+            // 2. verify that 'aLong' is correctly populated for user's membership
+            assertEquals(1, user.getMemberships().size());
+            membership = user.getMembershipMap().get("034740a9-fa10-453b-af37-dc7897e98fb1");
+            assertNotNull(membership);
+            assertEquals(1, membership.getPlainAttrMap().get("aLong").getValues().size());
+            assertEquals("1977", membership.getPlainAttrMap().get("aLong").getValues().get(0));
+
+            // 3. verify that derived attrbutes from 'csv' and 'other' are also populated for user's membership
+            assertFalse(membership.getDerAttrMap().get("csvuserid").getValues().isEmpty());
+            assertFalse(membership.getDerAttrMap().get("noschema").getValues().isEmpty());
+
+            // update user - change some values and add new membership attribute
+            UserPatch userPatch = new UserPatch();
+            userPatch.setKey(user.getKey());
+
+            userPatch.getPlainAttrs().add(new AttrPatch.Builder().
+                    attrTO(new AttrTO.Builder().schema("aLong").value("1977").build()).build());
+
+            MembershipPatch membershipPatch = new MembershipPatch.Builder().group(membership.getGroupKey()).build();
+            membershipPatch.getPlainAttrs().add(new AttrPatch.Builder().
+                    attrTO(new AttrTO.Builder().schema("aLong").value("1976").build()).build());
+            membershipPatch.getPlainAttrs().add(new AttrPatch.Builder().
+                    attrTO(new AttrTO.Builder().schema("ctype").value("membership type").build()).build());
+            userPatch.getMemberships().add(membershipPatch);
+
+            user = updateUser(userPatch).getAny();
+
+            // 4. verify that 'aLong' is correctly populated for user
+            assertEquals(1, user.getPlainAttrMap().get("aLong").getValues().size());
+            assertEquals("1977", user.getPlainAttrMap().get("aLong").getValues().get(0));
+            assertFalse(user.getPlainAttrMap().containsKey("ctype"));
+
+            // 5. verify that 'aLong' is correctly populated for user's membership
+            assertEquals(1, user.getMemberships().size());
+            membership = user.getMembershipMap().get("034740a9-fa10-453b-af37-dc7897e98fb1");
+            assertNotNull(membership);
+            assertEquals(1, membership.getPlainAttrMap().get("aLong").getValues().size());
+            assertEquals("1976", membership.getPlainAttrMap().get("aLong").getValues().get(0));
+
+            // 6. verify that 'ctype' is correctly populated for user's membership
+            assertEquals("membership type", membership.getPlainAttrMap().get("ctype").getValues().get(0));
+
+            // finally remove membership
+            userPatch = new UserPatch();
+            userPatch.setKey(user.getKey());
+
+            membershipPatch = new MembershipPatch.Builder().group(membership.getGroupKey()).
+                    operation(PatchOperation.DELETE).build();
+            userPatch.getMemberships().add(membershipPatch);
+
+            user = updateUser(userPatch).getAny();
+
+            assertTrue(user.getMemberships().isEmpty());
+        } finally {
+            if (user.getKey() != null) {
+                userService.delete(user.getKey());
+            }
+        }
+    }
+
+    @Test
+    public void deleteUserWithMembership() {
+        UserTO user = UserITCase.getUniqueSampleTO("memb@apache.org");
+        user.setRealm("/even/two");
+        user.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1976").build());
+
+        MembershipTO membership = new MembershipTO.Builder().group("034740a9-fa10-453b-af37-dc7897e98fb1").build();
+        membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1977").build());
+        user.getMemberships().add(membership);
+
+        user = createUser(user).getAny();
+        assertNotNull(user.getKey());
+
+        userService.delete(user.getKey());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
index 5a76218..4e4af92 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
@@ -646,10 +646,9 @@ public class UserITCase extends AbstractITCase {
         userPatch.getPlainAttrs().add(attrAddReplacePatch("fullname", newFullName));
 
         userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                membershipTO(new MembershipTO.Builder().
-                        group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build()).build());
+                group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
         userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                membershipTO(userTO.getMemberships().get(0)).build());
+                group(userTO.getMemberships().get(0).getGroupKey()).build());
 
         userTO = updateUser(userPatch).getAny();
         assertNotNull(userTO);
@@ -1218,7 +1217,7 @@ public class UserITCase extends AbstractITCase {
         userPatch.setKey(userTO.getKey());
 
         userPatch.getMemberships().add(new MembershipPatch.Builder().
-                operation(PatchOperation.DELETE).membershipTO(userTO.getMemberships().get(0)).build());
+                operation(PatchOperation.DELETE).group(userTO.getMemberships().get(0).getGroupKey()).build());
 
         userTO = updateUser(userPatch).getAny();
         assertNotNull(userTO);
@@ -1253,7 +1252,7 @@ public class UserITCase extends AbstractITCase {
         userPatch.setKey(userTO.getKey());
 
         userPatch.getMemberships().add(new MembershipPatch.Builder().
-                operation(PatchOperation.DELETE).membershipTO(userTO.getMemberships().get(0)).build());
+                operation(PatchOperation.DELETE).group(userTO.getMemberships().get(0).getGroupKey()).build());
 
         userTO = updateUser(userPatch).getAny();
         assertNotNull(userTO);
@@ -1635,7 +1634,7 @@ public class UserITCase extends AbstractITCase {
         UserPatch userPatch = new UserPatch();
         userPatch.setKey(userTO.getKey());
         userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.DELETE).
-                membershipTO(userTO.getMemberships().get(0)).build());
+                group(userTO.getMemberships().get(0).getGroupKey()).build());
 
         userTO = updateUser(userPatch).getAny();
         assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP));
@@ -2503,7 +2502,7 @@ public class UserITCase extends AbstractITCase {
             UserPatch userPatch = new UserPatch();
             userPatch.setKey(userTO.getKey());
             userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                    membershipTO(new MembershipTO.Builder().group(group.getKey()).build()).build());
+                    group(group.getKey()).build());
 
             ProvisioningResult<UserTO> result = updateUser(userPatch);
             assertNotNull(result);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
index 6d412a8..beb6c6e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
@@ -182,8 +182,7 @@ public class UserSelfITCase extends AbstractITCase {
         userPatch.setUsername(new StringReplacePatchItem.Builder().value(created.getUsername() + "XX").build());
         userPatch.getMemberships().add(new MembershipPatch.Builder().
                 operation(PatchOperation.ADD_REPLACE).
-                membershipTO(new MembershipTO.Builder().
-                        group("bf825fe1-7320-4a54-bd64-143b5c18ab97").build()).
+                group("bf825fe1-7320-4a54-bd64-143b5c18ab97").
                 build());
         userPatch.getResources().add(new StringPatchItem.Builder().
                 operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_TESTDB).build());

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy
index 5ee8d55..a5e1a5e 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy
@@ -37,9 +37,10 @@ def sql = new Sql(connection);
 
 switch ( objectClass ) {  
 case "__PRINTER__":
-  sql.execute("INSERT INTO TESTPRINTER (id, location, lastmodification) values (?,?,?)",
+  sql.execute("INSERT INTO TESTPRINTER (id, printername, location, lastmodification) values (?,?,?,?)",
     [
       id,
+      attributes.get("PRINTERNAME").get(0),
       attributes.get("LOCATION").get(0),
       new Date()
     ])

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy
index 18ba61d..e13f058 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy
@@ -42,6 +42,7 @@ idAIB.setRequired(true);
 
 orgAttrsInfo = new HashSet<AttributeInfo>();
 orgAttrsInfo.add(idAIB.build());
+orgAttrsInfo.add(AttributeInfoBuilder.build("PRINTERNAME", String.class));
 orgAttrsInfo.add(AttributeInfoBuilder.build("LOCATION", String.class));
 // Create the organization Object class
 ObjectClassInfo ociOrg = new ObjectClassInfoBuilder().setType("__PRINTER__").addAllAttributeInfo(orgAttrsInfo).build();

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy
index 3e65581..bb02d80 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy
@@ -84,7 +84,7 @@ if (query != null)  {
 switch ( objectClass ) {
 case "__PRINTER__":
   sql.eachRow("SELECT * FROM TESTPRINTER " + where, 
-    {result.add([__UID__:it.id, __NAME__:it.id, ID:it.id, LOCATION:it.location])} );
+    {result.add([__UID__:it.id, __NAME__:it.id, ID:it.id, PRINTERNAME:it.printername, LOCATION:it.location])} );
   break
 
 default:

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy
index 69f8d79..f7ff18f 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy
@@ -71,7 +71,7 @@ if (action.equalsIgnoreCase("GET_LATEST_SYNC_TOKEN")) {
   }
 
   switch (objectClass) {
-  case "__PRINTER__":    
+  case "__PRINTER__":
     sql.eachRow("SELECT * FROM TESTPRINTER WHERE lastmodification > ${lastmodification}",
       {
         result.add([
@@ -82,6 +82,7 @@ if (action.equalsIgnoreCase("GET_LATEST_SYNC_TOKEN")) {
               __UID__:it.id.toString(),
               __NAME__:it.id.toString(),
               ID:it.id.toString(),
+              PRINTERNAME:it.printername,
               LOCATION:it.location
             ]
           ]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy
index 5b8f4b5..1de9d9f 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy
@@ -28,4 +28,4 @@ import groovy.sql.DataSet;
 log.info("Entering " + action + " Script");
 def sql = new Sql(connection);
 
-sql.eachRow("select * from TESTPRINTER", { println it.uid} );
\ No newline at end of file
+sql.eachRow("select * from TESTPRINTER", { println it.id} );
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy
index 4d1ce5e..9df30f8 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy
@@ -51,8 +51,11 @@ def sql = new Sql(connection);
 switch (action) {
 case "UPDATE":
   if (attributes.get("LOCATION").get(0) != null) {
-    sql.executeUpdate("UPDATE TESTPRINTER SET location = ?, lastmodification = ? where id = ?", 
-      [attributes.get("LOCATION").get(0), new Date(), attributes.get("__NAME__").get(0)])
+    sql.executeUpdate("UPDATE TESTPRINTER SET printername = ?, location = ?, lastmodification = ? where id = ?", 
+      [attributes.get("PRINTERNAME").get(0), 
+        attributes.get("LOCATION").get(0), 
+        new Date(), 
+        attributes.get("__NAME__").get(0)])
     
     return attributes.get("__NAME__").get(0);
   }


[3/6] syncope git commit: [SYNCOPE-862] Preliminary work

Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 38d4add..af5220f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -44,6 +44,7 @@ import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.Any;
@@ -52,9 +53,11 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
 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.UPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPATypeExtension;
@@ -72,6 +75,9 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     @Autowired
     private UserDAO userDAO;
 
+    @Autowired
+    private PlainAttrDAO plainAttrDAO;
+
     @Override
     protected AnyUtils init() {
         return new JPAAnyUtilsFactory().getInstance(AnyTypeKind.GROUP);
@@ -242,16 +248,30 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     @Override
     public void delete(final Group group) {
         for (AMembership membership : findAMemberships(group)) {
-            membership.getLeftEnd().getMemberships().remove(membership);
-            anyObjectDAO.save(membership.getLeftEnd());
+            AnyObject leftEnd = membership.getLeftEnd();
+            leftEnd.getMemberships().remove(membership);
+            membership.setRightEnd(null);
+            for (APlainAttr attr : leftEnd.getPlainAttrs(membership)) {
+                leftEnd.remove(attr);
+                attr.setOwner(null);
+                attr.setMembership(null);
+                plainAttrDAO.delete(attr);
+            }
 
-            entityManager().remove(membership);
+            anyObjectDAO.save(leftEnd);
         }
         for (UMembership membership : findUMemberships(group)) {
-            membership.getLeftEnd().getMemberships().remove(membership);
-            userDAO.save(membership.getLeftEnd());
+            User leftEnd = membership.getLeftEnd();
+            leftEnd.getMemberships().remove(membership);
+            membership.setRightEnd(null);
+            for (UPlainAttr attr : leftEnd.getPlainAttrs(membership)) {
+                leftEnd.remove(attr);
+                attr.setOwner(null);
+                attr.setMembership(null);
+                plainAttrDAO.delete(attr);
+            }
 
-            entityManager().remove(membership);
+            userDAO.save(leftEnd);
         }
 
         entityManager().remove(group);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
index 3e8a38c..d4ba926 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
@@ -68,7 +68,7 @@ public class JPAPlainAttrDAO extends AbstractDAO<PlainAttr<?>> implements PlainA
     @SuppressWarnings("unchecked")
     public <T extends PlainAttr<?>> void delete(final T plainAttr) {
         if (plainAttr.getOwner() != null) {
-            ((Any<T>) plainAttr.getOwner()).getPlainAttrs().remove(plainAttr);
+            ((Any<T>) plainAttr.getOwner()).remove(plainAttr);
         }
 
         entityManager().remove(plainAttr);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/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 496e689..cf3ede1 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
@@ -25,14 +25,11 @@ import javax.persistence.FetchType;
 import javax.persistence.ManyToOne;
 import javax.persistence.MappedSuperclass;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
-import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource;
 import org.apache.syncope.core.persistence.jpa.validation.entity.AnyCheck;
 
 @AnyCheck
@@ -81,33 +78,8 @@ public abstract class AbstractAny<P extends PlainAttr<?>> extends AbstractAnnota
     }
 
     @Override
-    public P getPlainAttr(final String plainSchemaName) {
-        return IterableUtils.find(getPlainAttrs(), new Predicate<P>() {
-
-            @Override
-            public boolean evaluate(final P plainAttr) {
-                return plainAttr != null && plainAttr.getSchema() != null
-                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
-            }
-        });
-    }
-
-    protected abstract List<JPAExternalResource> internalGetResources();
-
-    @Override
-    public boolean add(final ExternalResource resource) {
-        checkType(resource, JPAExternalResource.class);
-        return internalGetResources().add((JPAExternalResource) resource);
-    }
-
-    @Override
     public List<String> getResourceNames() {
         return CollectionUtils.collect(
                 getResources(), EntityUtils.<ExternalResource>keyTransformer(), new ArrayList<String>());
     }
-
-    @Override
-    public List<? extends ExternalResource> getResources() {
-        return internalGetResources();
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractGroupableRelatable.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractGroupableRelatable.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractGroupableRelatable.java
new file mode 100644
index 0000000..a2a41fa
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractGroupableRelatable.java
@@ -0,0 +1,158 @@
+/*
+ * 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.persistence.jpa.entity;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
+import org.apache.syncope.core.persistence.api.entity.Membership;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
+import org.apache.syncope.core.persistence.api.entity.Relationship;
+import org.apache.syncope.core.persistence.api.entity.RelationshipType;
+
+public abstract class AbstractGroupableRelatable<
+        L extends Any<P>, 
+        M extends Membership<L>, 
+        P extends GroupablePlainAttr<L, M>,
+        R extends Any<?>,
+        REL extends Relationship<L, R>>
+        extends AbstractAny<P> implements GroupableRelatable<L, M, P, R, REL> {
+
+    private static final long serialVersionUID = -2269285197388729673L;
+
+    protected abstract List<? extends P> internalGetPlainAttrs();
+
+    @Override
+    public boolean remove(final P attr) {
+        return internalGetPlainAttrs().remove(attr);
+    }
+
+    @Override
+    public P getPlainAttr(final String plainSchemaName) {
+        return IterableUtils.find(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainAttr.getMembership() == null
+                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
+            }
+        });
+    }
+
+    @Override
+    public P getPlainAttr(final String plainSchemaName, final Membership<?> membership) {
+        return IterableUtils.find(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainAttr.getMembership() != null && plainAttr.getMembership().equals(membership)
+                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
+            }
+        });
+    }
+
+    @Override
+    public List<? extends P> getPlainAttrs() {
+        return CollectionUtils.select(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainAttr.getMembership() == null;
+            }
+        }, new ArrayList<P>());
+    }
+
+    @Override
+    public Collection<? extends P> getPlainAttrs(final String plainSchemaName) {
+        return CollectionUtils.select(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
+            }
+        });
+    }
+
+    @Override
+    public Collection<? extends P> getPlainAttrs(final Membership<?> membership) {
+        return CollectionUtils.select(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && membership.equals(plainAttr.getMembership());
+            }
+        });
+    }
+
+    @Override
+    public M getMembership(final String groupKey) {
+        return IterableUtils.find(getMemberships(), new Predicate<M>() {
+
+            @Override
+            public boolean evaluate(final M membership) {
+                return groupKey != null && groupKey.equals(membership.getRightEnd().getKey());
+            }
+        });
+    }
+
+    @Override
+    public REL getRelationship(final RelationshipType relationshipType, final String otherEndKey) {
+        return IterableUtils.find(getRelationships(), new Predicate<REL>() {
+
+            @Override
+            public boolean evaluate(final REL relationship) {
+                return otherEndKey != null && otherEndKey.equals(relationship.getRightEnd().getKey())
+                        && ((relationshipType == null && relationship.getType() == null)
+                        || (relationshipType != null && relationshipType.equals(relationship.getType())));
+            }
+        });
+    }
+
+    @Override
+    public Collection<? extends REL> getRelationships(final RelationshipType relationshipType) {
+        return CollectionUtils.select(getRelationships(), new Predicate<REL>() {
+
+            @Override
+            public boolean evaluate(final REL relationship) {
+                return relationshipType != null && relationshipType.equals(relationship.getType());
+            }
+        });
+    }
+
+    @Override
+    public Collection<? extends REL> getRelationships(final String otherEndKey) {
+        return CollectionUtils.select(getRelationships(), new Predicate<REL>() {
+
+            @Override
+            public boolean evaluate(final REL relationship) {
+                return otherEndKey != null && otherEndKey.equals(relationship.getRightEnd().getKey());
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
index a4d6eea..5c1b203 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
@@ -26,6 +26,7 @@ import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -342,17 +343,17 @@ public class JPAAnyUtils implements AnyUtils {
 
     @Transactional(readOnly = true)
     @Override
-    public <S extends Schema> Set<S> getAllowedSchemas(final Any<?> any, final Class<S> reference) {
-        Set<S> schemas = new HashSet<>();
+    public <S extends Schema> AllowedSchemas<S> getAllowedSchemas(final Any<?> any, final Class<S> reference) {
+        AllowedSchemas<S> result = null;
 
         if (any instanceof User) {
-            schemas.addAll(userDAO.findAllowedSchemas((User) any, reference));
+            result = userDAO.findAllowedSchemas((User) any, reference);
         } else if (any instanceof Group) {
-            schemas.addAll(groupDAO.findAllowedSchemas((Group) any, reference));
+            result = groupDAO.findAllowedSchemas((Group) any, reference);
         } else if (any instanceof AnyObject) {
-            schemas.addAll(anyObjectDAO.findAllowedSchemas((AnyObject) any, reference));
+            result = anyObjectDAO.findAllowedSchemas((AnyObject) any, reference);
         }
 
-        return schemas;
+        return result;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java
index f9a8151..044faae 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java
@@ -27,9 +27,11 @@ import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 import javax.validation.Valid;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
@@ -37,7 +39,8 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
 
 @Entity
-@Table(name = JPAAPlainAttr.TABLE)
+@Table(name = JPAAPlainAttr.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "owner_id", "membership_id", "schema_id" }))
 public class JPAAPlainAttr extends AbstractPlainAttr<AnyObject> implements APlainAttr {
 
     private static final long serialVersionUID = 8066058729580952116L;
@@ -47,6 +50,12 @@ public class JPAAPlainAttr extends AbstractPlainAttr<AnyObject> implements APlai
     @ManyToOne(fetch = FetchType.EAGER)
     private JPAAnyObject owner;
 
+    /**
+     * The membership of this attribute; might be {@code NULL} if this attribute is not related to a membership.
+     */
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAAMembership membership;
+
     @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true, mappedBy = "attribute")
     @Valid
     private List<JPAAPlainAttrValue> values = new ArrayList<>();
@@ -67,6 +76,17 @@ public class JPAAPlainAttr extends AbstractPlainAttr<AnyObject> implements APlai
     }
 
     @Override
+    public AMembership getMembership() {
+        return membership;
+    }
+
+    @Override
+    public void setMembership(final AMembership membership) {
+        checkType(membership, JPAAMembership.class);
+        this.membership = (JPAAMembership) membership;
+    }
+
+    @Override
     protected boolean addForMultiValue(final PlainAttrValue attrValue) {
         checkType(attrValue, JPAAPlainAttrValue.class);
         return values.add((JPAAPlainAttrValue) attrValue);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
index 44f55df..d790082 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
@@ -19,10 +19,10 @@
 package org.apache.syncope.core.persistence.jpa.entity.anyobject;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import javax.persistence.Cacheable;
 import javax.persistence.CascadeType;
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
@@ -33,17 +33,14 @@ import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IterableUtils;
-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.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractAny;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractGroupableRelatable;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyType;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyTypeClass;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource;
@@ -51,12 +48,18 @@ import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResour
 @Entity
 @Table(name = JPAAnyObject.TABLE)
 @Cacheable
-public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
+public class JPAAnyObject
+        extends AbstractGroupableRelatable<AnyObject, AMembership, APlainAttr, AnyObject, ARelationship>
+        implements AnyObject {
 
     private static final long serialVersionUID = 9063766472970643492L;
 
     public static final String TABLE = "AnyObject";
 
+    @Column(unique = true)
+    @NotNull
+    private String name;
+
     @NotNull
     @ManyToOne(fetch = FetchType.EAGER, optional = false)
     private JPAAnyType type;
@@ -79,15 +82,25 @@ public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
             @JoinColumn(name = "anyTypeClass_id"))
     private List<JPAAnyTypeClass> auxClasses = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "leftEnd")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "leftEnd")
     @Valid
     private List<JPAARelationship> relationships = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "leftEnd")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "leftEnd")
     @Valid
     private List<JPAAMembership> memberships = new ArrayList<>();
 
     @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    @Override
     public AnyType getType() {
         return type;
     }
@@ -99,22 +112,28 @@ public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
     }
 
     @Override
+    public boolean add(final ExternalResource resource) {
+        checkType(resource, JPAExternalResource.class);
+        return resources.add((JPAExternalResource) resource);
+    }
+
+    @Override
+    public List<? extends ExternalResource> getResources() {
+        return resources;
+    }
+
+    @Override
     public boolean add(final APlainAttr attr) {
         checkType(attr, JPAAPlainAttr.class);
         return plainAttrs.add((JPAAPlainAttr) attr);
     }
 
     @Override
-    public List<? extends APlainAttr> getPlainAttrs() {
+    protected List<? extends APlainAttr> internalGetPlainAttrs() {
         return plainAttrs;
     }
 
     @Override
-    protected List<JPAExternalResource> internalGetResources() {
-        return resources;
-    }
-
-    @Override
     public boolean add(final AnyTypeClass auxClass) {
         checkType(auxClass, JPAAnyTypeClass.class);
         return this.auxClasses.add((JPAAnyTypeClass) auxClass);
@@ -132,41 +151,6 @@ public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
     }
 
     @Override
-    public ARelationship getRelationship(final RelationshipType relationshipType, final String anyObjectKey) {
-        return IterableUtils.find(getRelationships(), new Predicate<ARelationship>() {
-
-            @Override
-            public boolean evaluate(final ARelationship relationship) {
-                return anyObjectKey != null && anyObjectKey.equals(relationship.getRightEnd().getKey())
-                        && ((relationshipType == null && relationship.getType() == null)
-                        || (relationshipType != null && relationshipType.equals(relationship.getType())));
-            }
-        });
-    }
-
-    @Override
-    public Collection<? extends ARelationship> getRelationships(final RelationshipType relationshipType) {
-        return CollectionUtils.select(getRelationships(), new Predicate<ARelationship>() {
-
-            @Override
-            public boolean evaluate(final ARelationship relationship) {
-                return relationshipType != null && relationshipType.equals(relationship.getType());
-            }
-        });
-    }
-
-    @Override
-    public Collection<? extends ARelationship> getRelationships(final String anyObjectKey) {
-        return CollectionUtils.select(getRelationships(), new Predicate<ARelationship>() {
-
-            @Override
-            public boolean evaluate(final ARelationship relationship) {
-                return anyObjectKey != null && anyObjectKey.equals(relationship.getRightEnd().getKey());
-            }
-        });
-    }
-
-    @Override
     public List<? extends ARelationship> getRelationships() {
         return relationships;
     }
@@ -178,17 +162,6 @@ public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
     }
 
     @Override
-    public AMembership getMembership(final String groupKey) {
-        return IterableUtils.find(getMemberships(), new Predicate<AMembership>() {
-
-            @Override
-            public boolean evaluate(final AMembership membership) {
-                return groupKey != null && groupKey.equals(membership.getRightEnd().getKey());
-            }
-        });
-    }
-
-    @Override
     public List<? extends AMembership> getMemberships() {
         return memberships;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/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 1ceaaa7..88ce38f 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
@@ -47,7 +47,7 @@ public class JPAConf extends AbstractProvidedKeyEntity implements Conf {
 
     public static final String TABLE = "SyncopeConf";
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "owner")
     @Valid
     private List<JPACPlainAttr> plainAttrs = new ArrayList<>();
 
@@ -58,6 +58,12 @@ public class JPAConf extends AbstractProvidedKeyEntity implements Conf {
     }
 
     @Override
+    public boolean remove(final CPlainAttr attr) {
+        checkType(attr, JPACPlainAttr.class);
+        return plainAttrs.remove((JPACPlainAttr) attr);
+    }
+
+    @Override
     public CPlainAttr getPlainAttr(final String plainSchemaName) {
         return IterableUtils.find(plainAttrs, new Predicate<CPlainAttr>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java
index 644fa27..53cf335 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java
@@ -27,6 +27,7 @@ import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 import javax.validation.Valid;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
@@ -37,7 +38,8 @@ import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
 
 @Entity
-@Table(name = JPAGPlainAttr.TABLE)
+@Table(name = JPAGPlainAttr.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "owner_id", "schema_id" }))
 public class JPAGPlainAttr extends AbstractPlainAttr<Group> implements GPlainAttr {
 
     private static final long serialVersionUID = 2848159565890995780L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
index 8afb1ae..bcfa9b0 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
@@ -44,6 +44,7 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembers
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 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.UDynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractAny;
@@ -74,7 +75,7 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     @ManyToOne
     private JPAGroup groupOwner;
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "owner")
     @Valid
     private List<JPAGPlainAttr> plainAttrs = new ArrayList<>();
 
@@ -104,6 +105,16 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     private List<JPATypeExtension> typeExtensions = new ArrayList<>();
 
     @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    @Override
     public AnyType getType() {
         return ApplicationContextProvider.getBeanFactory().getBean(AnyTypeDAO.class).findGroup();
     }
@@ -114,18 +125,14 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     }
 
     @Override
-    protected List<JPAExternalResource> internalGetResources() {
-        return resources;
-    }
-
-    @Override
-    public String getName() {
-        return name;
+    public boolean add(final ExternalResource resource) {
+        checkType(resource, JPAExternalResource.class);
+        return resources.add((JPAExternalResource) resource);
     }
 
     @Override
-    public void setName(final String name) {
-        this.name = name;
+    public List<? extends ExternalResource> getResources() {
+        return resources;
     }
 
     @Override
@@ -157,6 +164,24 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     }
 
     @Override
+    public boolean remove(final GPlainAttr attr) {
+        checkType(attr, JPAGPlainAttr.class);
+        return plainAttrs.remove((JPAGPlainAttr) attr);
+    }
+
+    @Override
+    public GPlainAttr getPlainAttr(final String plainSchemaName) {
+        return IterableUtils.find(getPlainAttrs(), new Predicate<GPlainAttr>() {
+
+            @Override
+            public boolean evaluate(final GPlainAttr plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
+            }
+        });
+    }
+
+    @Override
     public List<? extends GPlainAttr> getPlainAttrs() {
         return plainAttrs;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
index 438994f..1d00f89 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
@@ -183,6 +183,10 @@ public class JPAMappingItem extends AbstractGeneratedKeyEntity implements Mappin
                 name = "groupOwnerSchema";
                 break;
 
+            case AnyObjectName:
+                name = "anyObjectName";
+                break;
+                
             default:
                 name = intAttrName;
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java
index 84c9c84..bdabf2c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java
@@ -27,9 +27,11 @@ import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 import javax.validation.Valid;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
@@ -37,7 +39,8 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
 
 @Entity
-@Table(name = JPAUPlainAttr.TABLE)
+@Table(name = JPAUPlainAttr.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "owner_id", "membership_id", "schema_id" }))
 public class JPAUPlainAttr extends AbstractPlainAttr<User> implements UPlainAttr {
 
     private static final long serialVersionUID = 6333601983691157406L;
@@ -51,6 +54,12 @@ public class JPAUPlainAttr extends AbstractPlainAttr<User> implements UPlainAttr
     private JPAUser owner;
 
     /**
+     * The membership of this attribute; might be {@code NULL} if this attribute is not related to a membership.
+     */
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAUMembership membership;
+
+    /**
      * Values of this attribute (if schema is not UNIQUE).
      */
     @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true, mappedBy = "attribute")
@@ -76,6 +85,17 @@ public class JPAUPlainAttr extends AbstractPlainAttr<User> implements UPlainAttr
     }
 
     @Override
+    public UMembership getMembership() {
+        return membership;
+    }
+
+    @Override
+    public void setMembership(final UMembership membership) {
+        checkType(membership, JPAUMembership.class);
+        this.membership = (JPAUMembership) membership;
+    }
+
+    @Override
     protected boolean addForMultiValue(final PlainAttrValue attrValue) {
         checkType(attrValue, JPAUPlainAttrValue.class);
         return values.add((JPAUPlainAttrValue) attrValue);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
index a0ecf00..f207cfe 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
@@ -20,7 +20,6 @@ package org.apache.syncope.core.persistence.jpa.entity.user;
 
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import javax.persistence.Basic;
@@ -47,9 +46,6 @@ import javax.validation.Valid;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 import javax.validation.constraints.NotNull;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
@@ -62,18 +58,21 @@ import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 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.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+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.URelationship;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractAny;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractGroupableRelatable;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyTypeClass;
 import org.apache.syncope.core.persistence.jpa.entity.JPARole;
 
 @Entity
 @Table(name = JPAUser.TABLE)
 @Cacheable
-public class JPAUser extends AbstractAny<UPlainAttr> implements User {
+public class JPAUser
+        extends AbstractGroupableRelatable<User, UMembership, UPlainAttr, AnyObject, URelationship>
+        implements User {
 
     private static final long serialVersionUID = -3905046855521446823L;
 
@@ -172,11 +171,11 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
             @JoinColumn(name = "anyTypeClass_id"))
     private List<JPAAnyTypeClass> auxClasses = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "leftEnd")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "leftEnd")
     @Valid
     private List<JPAURelationship> relationships = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "leftEnd")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "leftEnd")
     @Valid
     private List<JPAUMembership> memberships = new ArrayList<>();
 
@@ -197,7 +196,13 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
     }
 
     @Override
-    protected List<JPAExternalResource> internalGetResources() {
+    public boolean add(final ExternalResource resource) {
+        checkType(resource, JPAExternalResource.class);
+        return resources.add((JPAExternalResource) resource);
+    }
+
+    @Override
+    public List<? extends ExternalResource> getResources() {
         return resources;
     }
 
@@ -270,7 +275,7 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
     }
 
     @Override
-    public List<? extends UPlainAttr> getPlainAttrs() {
+    protected List<? extends UPlainAttr> internalGetPlainAttrs() {
         return plainAttrs;
     }
 
@@ -471,41 +476,6 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
     }
 
     @Override
-    public URelationship getRelationship(final RelationshipType relationshipType, final String anyObjectKey) {
-        return IterableUtils.find(getRelationships(), new Predicate<URelationship>() {
-
-            @Override
-            public boolean evaluate(final URelationship relationship) {
-                return anyObjectKey != null && anyObjectKey.equals(relationship.getRightEnd().getKey())
-                        && ((relationshipType == null && relationship.getType() == null)
-                        || (relationshipType != null && relationshipType.equals(relationship.getType())));
-            }
-        });
-    }
-
-    @Override
-    public Collection<? extends URelationship> getRelationships(final RelationshipType relationshipType) {
-        return CollectionUtils.select(getRelationships(), new Predicate<URelationship>() {
-
-            @Override
-            public boolean evaluate(final URelationship relationship) {
-                return relationshipType != null && relationshipType.equals(relationship.getType());
-            }
-        });
-    }
-
-    @Override
-    public Collection<? extends URelationship> getRelationships(final String anyObjectKey) {
-        return CollectionUtils.select(getRelationships(), new Predicate<URelationship>() {
-
-            @Override
-            public boolean evaluate(final URelationship relationship) {
-                return anyObjectKey != null && anyObjectKey.equals(relationship.getRightEnd().getKey());
-            }
-        });
-    }
-
-    @Override
     public List<? extends URelationship> getRelationships() {
         return relationships;
     }
@@ -517,17 +487,6 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
     }
 
     @Override
-    public UMembership getMembership(final String groupKey) {
-        return IterableUtils.find(getMemberships(), new Predicate<UMembership>() {
-
-            @Override
-            public boolean evaluate(final UMembership membership) {
-                return groupKey != null && groupKey.equals(membership.getRightEnd().getKey());
-            }
-        });
-    }
-
-    @Override
     public List<? extends UMembership> getMemberships() {
         return memberships;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
index fb28c4e..37e227f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
@@ -18,42 +18,63 @@
  */
 package org.apache.syncope.core.persistence.jpa.validation.entity;
 
-import java.util.Collection;
 import javax.validation.ConstraintValidatorContext;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 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.conf.Conf;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
 
 @SuppressWarnings("rawtypes")
 public class AnyValidator extends AbstractValidator<AnyCheck, Any> {
 
+    private boolean raiseNotAllowedViolation(
+            final ConstraintValidatorContext context,
+            final String schema,
+            final Group group) {
+
+        if (group == null) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidPlainAttr,
+                            schema + " not allowed for this instance")).
+                    addPropertyNode("plainAttrs").addConstraintViolation();
+        } else {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidPlainAttr,
+                            schema + " not allowed for membership of group " + group.getName())).
+                    addPropertyNode("plainAttrs").addConstraintViolation();
+        }
+        return false;
+    }
+
     @Override
     public boolean isValid(final Any any, final ConstraintValidatorContext context) {
         context.disableDefaultConstraintViolation();
 
         if (!(any instanceof Conf)) {
-            Collection<String> allowedPlainSchemas = CollectionUtils.collect(new JPAAnyUtilsFactory().
-                    getInstance(any.getType().getKind()).getAllowedSchemas(any, PlainSchema.class),
-                    new Transformer<PlainSchema, String>() {
+            AllowedSchemas<PlainSchema> allowedPlainSchemas = new JPAAnyUtilsFactory().
+                    getInstance(any.getType().getKind()).getAllowedSchemas(any, PlainSchema.class);
 
-                @Override
-                public String transform(final PlainSchema schema) {
-                    return schema.getKey();
+            for (PlainAttr<?> attr : ((Any<?>) any).getPlainAttrs()) {
+                if (attr != null && !allowedPlainSchemas.forSelfContains(attr.getSchema().getKey())) {
+                    return raiseNotAllowedViolation(context, attr.getSchema().getKey(), null);
                 }
-            });
+            }
+            if (any instanceof GroupableRelatable) {
+                for (Membership<?> membership : ((GroupableRelatable<?, ?, ?, ?, ?>) any).getMemberships()) {
+                    for (PlainAttr<?> attr : ((GroupableRelatable<?, ?, ?, ?, ?>) any).getPlainAttrs(membership)) {
+                        if (attr != null && !allowedPlainSchemas.forMembershipsContains(
+                                membership.getRightEnd(), attr.getSchema().getKey())) {
 
-            for (PlainAttr<?> attr : ((Any<?>) any).getPlainAttrs()) {
-                if (attr != null && !allowedPlainSchemas.contains(attr.getSchema().getKey())) {
-                    context.buildConstraintViolationWithTemplate(
-                            getTemplate(EntityViolationType.InvalidPlainSchema,
-                                    attr.getSchema().getKey() + " not allowed for this instance")).
-                            addPropertyNode("plainAttrs").addConstraintViolation();
-                    return false;
+                            return raiseNotAllowedViolation(
+                                    context, attr.getSchema().getKey(), membership.getRightEnd());
+                        }
+                    }
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
index 387e368..e1bdf68 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
@@ -29,6 +29,7 @@ import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.entity.AnnotatedEntity;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 import org.apache.syncope.core.persistence.api.entity.Policy;
 import org.apache.syncope.core.persistence.api.entity.ProvidedKeyEntity;
 import org.apache.syncope.core.persistence.api.entity.Schema;
@@ -41,9 +42,6 @@ import org.slf4j.LoggerFactory;
  */
 public class EntityValidationListener {
 
-    /**
-     * Logger.
-     */
     private static final Logger LOG = LoggerFactory.getLogger(EntityValidationListener.class);
 
     @PrePersist
@@ -62,6 +60,7 @@ public class EntityValidationListener {
                         && !Schema.class.equals(interf)
                         && !Task.class.equals(interf)
                         && !Policy.class.equals(interf)
+                        && !GroupableRelatable.class.equals(interf)
                         && !Any.class.equals(interf)
                         && Entity.class.isAssignableFrom(interf)) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
index da00ebd..64ec693 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
@@ -74,7 +74,7 @@ public class PlainAttrValueValidator extends AbstractValidator<PlainAttrValueChe
                             + "]" + " is " + uniqueValueSchema + ", while owning attribute schema is " + attrSchema);
 
                     context.disableDefaultConstraintViolation();
-                    context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidPlainSchema,
+                    context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidPlainAttr,
                             "Unique value schema is " + uniqueValueSchema
                             + ", while owning attribute schema is " + attrSchema)).addPropertyNode("schema").
                             addConstraintViolation();

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
index f12e913..cc324c6 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
@@ -62,6 +62,7 @@ public class AnyObjectTest extends AbstractTest {
     @Test
     public void save() {
         AnyObject anyObject = entityFactory.newEntity(AnyObject.class);
+        anyObject.setName("a name");
         anyObject.setType(anyTypeDAO.find("PRINTER"));
         anyObject.setRealm(realmDAO.findByFullPath(SyncopeConstants.ROOT_REALM));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
index 712aa51..2b7f441 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
@@ -170,7 +170,7 @@ public class PlainAttrTest extends AbstractTest {
         // for attribute
         assertTrue(iee.hasViolation(EntityViolationType.InvalidValueList));
         // for uauv
-        assertTrue(iee.hasViolation(EntityViolationType.InvalidPlainSchema));
+        assertTrue(iee.hasViolation(EntityViolationType.InvalidPlainAttr));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
new file mode 100644
index 0000000..f9bcff1
--- /dev/null
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.persistence.jpa.outer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.syncope.core.persistence.api.dao.ConfDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.persistence.jpa.entity.conf.JPACPlainAttrValue;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional("Master")
+public class ConfTest extends AbstractTest {
+
+    @Autowired
+    private ConfDAO confDAO;
+
+    @Autowired
+    private PlainSchemaDAO plainSchemaDAO;
+
+    private void add(final CPlainAttr newAttr, final String value) {
+        JPACPlainAttrValue attrValue;
+        if (newAttr.getSchema().isUniqueConstraint()) {
+            attrValue = new JPACPlainAttrValue();
+            ((PlainAttrUniqueValue) attrValue).setSchema(newAttr.getSchema());
+        } else {
+            attrValue = new JPACPlainAttrValue();
+        }
+        newAttr.add(value, attrValue);
+    }
+
+    @Test
+    public void update() {
+        CPlainAttr expireTime = confDAO.find("token.expireTime");
+        assertNotNull(expireTime);
+        long value = expireTime.getValues().get(0).getLongValue();
+        value++;
+
+        CPlainAttr attr = entityFactory.newEntity(CPlainAttr.class);
+        attr.setSchema(plainSchemaDAO.find("token.expireTime"));
+        add(attr, String.valueOf(value));
+
+        confDAO.save(expireTime);
+        confDAO.flush();
+
+        CPlainAttr actual = confDAO.find("token.expireTime");
+        assertEquals(expireTime, actual);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
index ae450aa..8037a2b 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
@@ -271,6 +271,7 @@ public class GroupTest extends AbstractTest {
     public void adynMembership() {
         // 0. create any object matching the condition below
         AnyObject anyObject = entityFactory.newEntity(AnyObject.class);
+        anyObject.setName("name");
         anyObject.setType(anyTypeDAO.find("PRINTER"));
         anyObject.setRealm(realmDAO.findByFullPath("/even/two"));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
index 1a5a62d..cdb3067 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
@@ -23,9 +23,14 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.util.List;
 import java.util.UUID;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
@@ -145,7 +150,91 @@ public class UserTest extends AbstractTest {
                 user.getRelationships().get(0).getRightEnd().getKey());
     }
 
-    @Test // search by derived attribute
+    @Test
+    public void membershipWithAttrs() {
+        User user = userDAO.findByUsername("vivaldi");
+        assertNotNull(user);
+        assertTrue(user.getMemberships().isEmpty());
+
+        // add 'obscure' to user (no membership): works because 'obscure' is from 'other', default class for USER
+        UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
+        attr.setOwner(user);
+        attr.setSchema(plainSchemaDAO.find("obscure"));
+        attr.add("testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+        user.add(attr);
+
+        // add 'obscure' to user (via 'artDirector' membership): does not work because 'obscure' is from 'other'
+        // but 'artDirector' defines no type extension
+        UMembership membership = entityFactory.newEntity(UMembership.class);
+        membership.setLeftEnd(user);
+        membership.setRightEnd(groupDAO.findByName("artDirector"));
+        user.add(membership);
+
+        attr = entityFactory.newEntity(UPlainAttr.class);
+        attr.setOwner(user);
+        attr.setMembership(membership);
+        attr.setSchema(plainSchemaDAO.find("obscure"));
+        attr.add("testvalue2", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+        user.add(attr);
+
+        try {
+            userDAO.save(user);
+            fail();
+        } catch (InvalidEntityException e) {
+            assertNotNull(e);
+        }
+
+        // replace 'artDirector' with 'additional', which defines type extension with class 'other' and 'csv':
+        // now it works
+        membership = user.getMembership(groupDAO.findByName("artDirector").getKey());
+        user.remove(user.getPlainAttr("obscure", membership));
+        user.getMemberships().remove(membership);
+        membership.setLeftEnd(null);
+
+        membership = entityFactory.newEntity(UMembership.class);
+        membership.setLeftEnd(user);
+        membership.setRightEnd(groupDAO.findByName("additional"));
+        user.add(membership);
+
+        attr = entityFactory.newEntity(UPlainAttr.class);
+        attr.setOwner(user);
+        attr.setMembership(membership);
+        attr.setSchema(plainSchemaDAO.find("obscure"));
+        attr.add("testvalue2", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+        user.add(attr);
+
+        userDAO.save(user);
+        userDAO.flush();
+
+        user = userDAO.findByUsername("vivaldi");
+        assertEquals(1, user.getMemberships().size());
+
+        final UMembership newM = user.getMembership(groupDAO.findByName("additional").getKey());
+        assertEquals(1, user.getPlainAttrs(newM).size());
+
+        assertNull(user.getPlainAttr("obscure").getMembership());
+        assertEquals(2, user.getPlainAttrs("obscure").size());
+        assertTrue(user.getPlainAttrs("obscure").contains(user.getPlainAttr("obscure")));
+        assertTrue(IterableUtils.matchesAny(user.getPlainAttrs("obscure"), new Predicate<UPlainAttr>() {
+
+            @Override
+            public boolean evaluate(final UPlainAttr object) {
+                return object.getMembership() == null;
+            }
+        }));
+        assertTrue(IterableUtils.matchesAny(user.getPlainAttrs("obscure"), new Predicate<UPlainAttr>() {
+
+            @Override
+            public boolean evaluate(final UPlainAttr object) {
+                return newM.equals(object.getMembership());
+            }
+        }));
+    }
+
+    /**
+     * Search by derived attribute.
+     */
+    @Test
     public void issueSYNCOPE800() {
         // create derived attribute (literal as prefix)
         DerSchema prefix = entityFactory.newEntity(DerSchema.class);

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 37fc8a1..e956a90 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -175,15 +175,15 @@ under the License.
          accountPolicy_id="20ab5a8c-4b0c-432c-b957-f7fb9784d9f7"
          passwordPolicy_id="ce93fcda-dc3a-4369-a7b0-a6108c261c85"/>
   
-  <AnyObject id="fc6dbc3a-6c07-4965-8781-921e7401a4a5"
+  <AnyObject id="fc6dbc3a-6c07-4965-8781-921e7401a4a5" name="HP LJ 1300n"
              realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" type_id="PRINTER"
              creator="admin" lastModifier="admin" 
              creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
-  <AnyObject id="8559d14d-58c2-46eb-a2d4-a7d35161e8f8"
+  <AnyObject id="8559d14d-58c2-46eb-a2d4-a7d35161e8f8" name="Canon MF 8030cn"
              realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" type_id="PRINTER"
              creator="admin" lastModifier="admin" 
              creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
-  <AnyObject id="9e1d130c-d6a3-48b1-98b3-182477ed0688"
+  <AnyObject id="9e1d130c-d6a3-48b1-98b3-182477ed0688" name="Epson Stylus Color"
              realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c" type_id="PRINTER"
              creator="admin" lastModifier="admin" 
              creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
@@ -966,6 +966,9 @@ under the License.
   <MappingItem id="23aa0299-ddbb-4e59-8918-0ab2a32465fa" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="ID" 
                intMappingType="AnyObjectKey" mandatoryCondition="true"
                connObjectKey="1" password="0" purpose="BOTH"/>
+  <MappingItem id="3dc96af0-5d0a-4ec1-be84-244716d88401" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="PRINTERNAME" 
+               intMappingType="AnyObjectName" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="BOTH"/>
   <MappingItem id="f3ef9f8b-e667-4b18-969f-ba98c3d78bc0" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="LOCATION" 
                intAttrName="location" intMappingType="AnyObjectPlainSchema"
                mandatoryCondition="false" connObjectKey="0" password="0" purpose="BOTH"/>
@@ -985,7 +988,7 @@ under the License.
         pullMode="INCREMENTAL" unmatchingRule="ASSIGN" matchingRule="UPDATE" active="1"/>
   <AnyTemplatePullTask id="3a6173a9-8c34-4e37-b3b1-0c2ea385fac0"
                        pullTask_id="c41b9b71-9bfa-4f90-89f2-84787def4c5c" anyType_id="USER"
-                       template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":["csv"],"derAttrs":[{"schema":"cn","readonly":false,"values":[""]}],"virAttrs":[],"resources":["resource-testdb"],"relationships":[],"memberships":[{"leftType":null,"leftKey":0,"rightType":"GROUP","rightKey":"f779c0d4-633b-4be5-8f57-32eb478a3ca5","groupName":null}],"dynGroups":[],"roles":[],"dynRoles":[],"plainAttrs":[{"schema":"ctype","readonly":false,"values":["email == &apos;test8@syncope.apache.org&apos;? &apos;TYPE_8&apos;: &apos;TYPE_OTHER&apos;"]}]}'/>
+                       template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":["csv"],"derAttrs":[{"schema":"cn","readonly":false,"values":[""]}],"virAttrs":[],"resources":["resource-testdb"],"relationships":[],"memberships":[{"rightType":"GROUP","rightKey":"f779c0d4-633b-4be5-8f57-32eb478a3ca5","groupName":null}],"dynGroups":[],"roles":[],"dynRoles":[],"plainAttrs":[{"schema":"ctype","readonly":false,"values":["email == &apos;test8@syncope.apache.org&apos;? &apos;TYPE_8&apos;: &apos;TYPE_OTHER&apos;"]}]}'/>
   <AnyTemplatePullTask id="b3772d66-ec06-4133-bf38-b3273845ac5b"
                        pullTask_id="c41b9b71-9bfa-4f90-89f2-84787def4c5c" anyType_id="GROUP"
                        template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"plainAttrs":[]}'/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
index bc70fb8..c4f44bd 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.provisioning.api;
 import java.util.Map;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 
 public interface DerAttrHandler {
 
@@ -37,7 +38,27 @@ public interface DerAttrHandler {
      * Calculates derived attributes values associated to the given any.
      *
      * @param any any object
-     * @return derived attribute values, either for local cache or external resources
+     * @return derived attribute values
      */
     Map<DerSchema, String> getValues(Any<?> any);
+
+    /**
+     * Calculates derived attribute value associated to the given any, for the given membership and
+     * derived schema.
+     *
+     * @param any any object
+     * @param membership membership
+     * @param schema derived schema
+     * @return derived attribute value
+     */
+    String getValue(Any<?> any, Membership<?> membership, DerSchema schema);
+
+    /**
+     * Calculates derived attributes values associated to the given any, for the given membership.
+     *
+     * @param any any object
+     * @param membership membership
+     * @return derived attribute values
+     */
+    Map<DerSchema, String> getValues(final Any<?> any, final Membership<?> membership);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
index 0b8d60f..72bb198 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
@@ -21,13 +21,14 @@ package org.apache.syncope.core.provisioning.api;
 import java.util.List;
 import java.util.Map;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 
 public interface VirAttrHandler {
 
     /**
      * Query external resource (or cache, if configured) associated to the given any for values associated to the given
-     * virtual schema.
+     * virtual schema, not related to any membership.
      *
      * @param any any object
      * @param schema virtual schema
@@ -37,13 +38,36 @@ public interface VirAttrHandler {
     List<String> getValues(Any<?> any, VirSchema schema);
 
     /**
+     * Query external resource (or cache, if configured) associated to the given any for values associated to the given
+     * virtual schema, for the given membership.
+     *
+     * @param any any object
+     * @param membership membership
+     * @param schema virtual schema
+     * @return virtual attribute values, either for local cache or external resource, if resource is owned by the given
+     * any and associated to the given virtual schema; empty list otherwise.
+     */
+    List<String> getValues(Any<?> any, Membership<?> membership, VirSchema schema);
+
+    /**
      * Query external resources (or cache, if configured) associated to the given any for values associated to all
      * {@link VirSchema} instances in the {@link org.apache.syncope.core.persistence.api.entity.AnyTypeClass}
-     * associated to the given any.
+     * associated to the given any, with no membership.
      *
      * @param any any object
      * @return virtual attribute values, either for local cache or external resources
      */
     Map<VirSchema, List<String>> getValues(Any<?> any);
 
+    /**
+     * Query external resources (or cache, if configured) associated to the given any for values associated to all
+     * {@link VirSchema} instances in the {@link org.apache.syncope.core.persistence.api.entity.AnyTypeClass}
+     * associated to the given any, for the given membership.
+     *
+     * @param any any object
+     * @param membership membership
+     * @return virtual attribute values, either for local cache or external resources
+     */
+    Map<VirSchema, List<String>> getValues(Any<?> any, Membership<?> membership);
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java
index f827f46..0261752 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java
@@ -28,6 +28,7 @@ import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.provisioning.api.DerAttrHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,6 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
+@Transactional(readOnly = true)
 @Component
 public class DerAttrHandlerImpl implements DerAttrHandler {
 
@@ -57,10 +59,23 @@ public class DerAttrHandlerImpl implements DerAttrHandler {
         return result;
     }
 
-    @Transactional(readOnly = true)
     @Override
     public String getValue(final Any<?> any, final DerSchema schema) {
-        if (!anyUtilsFactory.getInstance(any).getAllowedSchemas(any, DerSchema.class).contains(schema)) {
+        if (!anyUtilsFactory.getInstance(any).
+                getAllowedSchemas(any, DerSchema.class).forSelfContains(schema)) {
+
+            LOG.debug("{} not allowed for {}", schema, any);
+            return null;
+        }
+
+        return getValues(any, Collections.singleton(schema)).get(schema);
+    }
+
+    @Override
+    public String getValue(final Any<?> any, final Membership<?> membership, final DerSchema schema) {
+        if (!anyUtilsFactory.getInstance(any).
+                getAllowedSchemas(any, DerSchema.class).getForMembership(membership.getRightEnd()).contains(schema)) {
+
             LOG.debug("{} not allowed for {}", schema, any);
             return null;
         }
@@ -68,10 +83,19 @@ public class DerAttrHandlerImpl implements DerAttrHandler {
         return getValues(any, Collections.singleton(schema)).get(schema);
     }
 
-    @Transactional(readOnly = true)
     @Override
     public Map<DerSchema, String> getValues(final Any<?> any) {
-        return getValues(any, anyUtilsFactory.getInstance(any).getAllowedSchemas(any, DerSchema.class));
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).getAllowedSchemas(any, DerSchema.class).getForSelf());
+    }
+
+    @Override
+    public Map<DerSchema, String> getValues(final Any<?> any, final Membership<?> membership) {
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).getAllowedSchemas(any, DerSchema.class).
+                getForMembership(membership.getRightEnd()));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index c742c1a..b84799a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -32,6 +32,7 @@ import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.GroupTO;
@@ -68,6 +69,7 @@ import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 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.APlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
@@ -698,6 +700,16 @@ public class MappingManagerImpl implements MappingManager {
                 }
                 break;
 
+            case AnyObjectName:
+                for (Any<?> any : anys) {
+                    if (any instanceof AnyObject) {
+                        APlainAttrValue attrValue = entityFactory.newEntity(APlainAttrValue.class);
+                        attrValue.setStringValue(((AnyObject) any).getName());
+                        values.add(attrValue);
+                    }
+                }
+                break;
+
             default:
         }
 
@@ -800,6 +812,14 @@ public class MappingManagerImpl implements MappingManager {
                 }
                 break;
 
+            case AnyObjectName:
+                if (anyTO instanceof AnyObjectTO) {
+                    ((AnyObjectTO) anyTO).setName(values.isEmpty() || values.get(0) == null
+                            ? null
+                            : values.get(0).toString());
+                }
+                break;
+
             case UserPlainSchema:
             case GroupPlainSchema:
             case AnyObjectPlainSchema:

http://git-wip-us.apache.org/repos/asf/syncope/blob/297396d1/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
index b65cc79..67a821c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
@@ -29,6 +29,7 @@ import org.apache.commons.collections4.ListUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
@@ -48,6 +49,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
+@Transactional(readOnly = true)
 @Component
 public class VirAttrHandlerImpl implements VirAttrHandler {
 
@@ -122,7 +124,8 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
                             if (attr != null) {
                                 VirAttrCacheValue virAttrCacheValue = new VirAttrCacheValue();
                                 virAttrCacheValue.setValues(attr.getValue());
-                                virAttrCache.put(any.getType().getKey(), any.getKey(), schema.getKey(),
+                                virAttrCache.put(
+                                        any.getType().getKey(), any.getKey(), schema.getKey(),
                                         virAttrCacheValue);
                                 LOG.debug("Values for {} set in cache: {}", schema, virAttrCacheValue);
 
@@ -139,10 +142,23 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
         return result;
     }
 
-    @Transactional(readOnly = true)
     @Override
     public List<String> getValues(final Any<?> any, final VirSchema schema) {
-        if (!anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class).contains(schema)) {
+        if (!anyUtilsFactory.getInstance(any).
+                getAllowedSchemas(any, VirSchema.class).forSelfContains(schema)) {
+
+            LOG.debug("{} not allowed for {}", schema, any);
+            return Collections.emptyList();
+        }
+
+        return ListUtils.emptyIfNull(getValues(any, Collections.singleton(schema)).get(schema));
+    }
+
+    @Override
+    public List<String> getValues(final Any<?> any, final Membership<?> membership, final VirSchema schema) {
+        if (!anyUtilsFactory.getInstance(any).
+                getAllowedSchemas(any, VirSchema.class).getForMembership(membership.getRightEnd()).contains(schema)) {
+
             LOG.debug("{} not allowed for {}", schema, any);
             return Collections.emptyList();
         }
@@ -150,9 +166,19 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
         return ListUtils.emptyIfNull(getValues(any, Collections.singleton(schema)).get(schema));
     }
 
-    @Transactional(readOnly = true)
     @Override
     public Map<VirSchema, List<String>> getValues(final Any<?> any) {
-        return getValues(any, anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class));
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class).getForSelf());
     }
+
+    @Override
+    public Map<VirSchema, List<String>> getValues(final Any<?> any, final Membership<?> membership) {
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class).
+                getForMembership(membership.getRightEnd()));
+    }
+
 }