syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [07/13] syncope git commit: [SYNCOPE-862] Preliminary work
Date Tue, 14 Jun 2016 16:22:30 GMT
http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/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/0f738186/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);
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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/0f738186/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:


Mime
View raw message