syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [08/70] syncope git commit: [SYNCOPE-666] Initial commit, Travis CI builds disabled
Date Thu, 11 Jun 2015 14:16:58 GMT
http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/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
new file mode 100644
index 0000000..3551a80
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -0,0 +1,663 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java.data;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+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.mod.AnyMod;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+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.ResourceOperation;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.dao.DerAttrDAO;
+import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.DerAttr;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+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.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.core.provisioning.java.VirAttrHandler;
+import org.apache.syncope.core.misc.MappingUtils;
+import org.apache.syncope.core.misc.jexl.JexlUtils;
+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.RealmDAO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+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.Realm;
+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.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+abstract class AbstractAnyDataBinder {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(AbstractAnyDataBinder.class);
+
+    @Autowired
+    protected RealmDAO realmDAO;
+
+    @Autowired
+    protected AnyObjectDAO anyObjectDAO;
+
+    @Autowired
+    protected UserDAO userDAO;
+
+    @Autowired
+    protected GroupDAO groupDAO;
+
+    @Autowired
+    protected PlainSchemaDAO plainSchemaDAO;
+
+    @Autowired
+    protected DerSchemaDAO derSchemaDAO;
+
+    @Autowired
+    protected VirSchemaDAO virSchemaDAO;
+
+    @Autowired
+    protected PlainAttrDAO plainAttrDAO;
+
+    @Autowired
+    protected DerAttrDAO derAttrDAO;
+
+    @Autowired
+    protected VirAttrDAO virAttrDAO;
+
+    @Autowired
+    protected PlainAttrValueDAO plainAttrValueDAO;
+
+    @Autowired
+    protected ExternalResourceDAO resourceDAO;
+
+    @Autowired
+    protected PolicyDAO policyDAO;
+
+    @Autowired
+    protected EntityFactory entityFactory;
+
+    @Autowired
+    protected AnyUtilsFactory anyUtilsFactory;
+
+    @Autowired
+    protected VirAttrHandler virtAttrHander;
+
+    protected void setRealm(final Any<?, ?, ?> any, final AnyMod anyMod) {
+        if (StringUtils.isNotBlank(anyMod.getRealm())) {
+            Realm newRealm = realmDAO.find(anyMod.getRealm());
+            if (newRealm == null) {
+                LOG.warn("Invalid realm specified: {}, ignoring", anyMod.getRealm());
+            } else {
+                any.setRealm(newRealm);
+            }
+        }
+    }
+
+    protected PlainSchema getPlainSchema(final String schemaName) {
+        PlainSchema schema = null;
+        if (StringUtils.isNotBlank(schemaName)) {
+            schema = plainSchemaDAO.find(schemaName);
+
+            // safely ignore invalid schemas from AttrTO
+            if (schema == null) {
+                LOG.debug("Ignoring invalid schema {}", schemaName);
+            } else if (schema.isReadonly()) {
+                schema = null;
+
+                LOG.debug("Ignoring readonly schema {}", schemaName);
+            }
+        }
+
+        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;
+    }
+
+    protected void fillAttribute(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
+        List<String> valuesProvided = schema.isMultivalue()
+                ? values
+                : (values.isEmpty()
+                        ? Collections.<String>emptyList()
+                        : Collections.singletonList(values.iterator().next()));
+
+        for (String value : valuesProvided) {
+            if (value == null || value.isEmpty()) {
+                LOG.debug("Null value for {}, ignoring", schema.getKey());
+            } else {
+                try {
+                    attr.add(value, anyUtils);
+                } catch (InvalidPlainAttrValueException e) {
+                    LOG.warn("Invalid value for attribute " + schema.getKey() + ": " + value, e);
+
+                    invalidValues.getElements().add(schema.getKey() + ": " + value + " - " + e.getMessage());
+                }
+            }
+        }
+    }
+
+    private boolean evaluateMandatoryCondition(final AnyUtils anyUtils, final ExternalResource resource,
+            final Any<?, ?, ?> any, final String intAttrName, final IntMappingType intMappingType) {
+
+        boolean result = false;
+
+        Collection<MappingItem> mappings = MappingUtils.getMatchingMappingItems(
+                anyUtils.getMappingItems(resource.getProvision(any.getType()), MappingPurpose.PROPAGATION),
+                intAttrName, intMappingType);
+        for (Iterator<MappingItem> itor = mappings.iterator(); itor.hasNext() && !result;) {
+            MappingItem mapping = itor.next();
+            result |= JexlUtils.evaluateMandatoryCondition(mapping.getMandatoryCondition(), any);
+        }
+
+        return result;
+    }
+
+    private boolean evaluateMandatoryCondition(final AnyUtils anyUtils,
+            final Any<?, ?, ?> any, final String intAttrName, final IntMappingType intMappingType) {
+
+        boolean result = false;
+
+        Iterable<? extends ExternalResource> iterable = any instanceof User
+                ? userDAO.findAllResources((User) any)
+                : any instanceof Group
+                        ? ((Group) any).getResources()
+                        : Collections.<ExternalResource>emptySet();
+
+        for (Iterator<? extends ExternalResource> itor = iterable.iterator(); itor.hasNext() && !result;) {
+            ExternalResource resource = itor.next();
+            if (resource.isEnforceMandatoryCondition()) {
+                result |= evaluateMandatoryCondition(
+                        anyUtils, resource, any, intAttrName, intMappingType);
+            }
+        }
+
+        return result;
+    }
+
+    private SyncopeClientException checkMandatory(final AnyUtils anyUtils, final Any<?, ?, ?> any) {
+        SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+
+        // Check if there is some mandatory schema defined for which no value has been provided
+        List<PlainSchema> plainSchemas = plainSchemaDAO.findAll();
+        for (PlainSchema schema : plainSchemas) {
+            if (any.getPlainAttr(schema.getKey()) == null
+                    && !schema.isReadonly()
+                    && (JexlUtils.evaluateMandatoryCondition(schema.getMandatoryCondition(), any)
+                    || evaluateMandatoryCondition(anyUtils, any, schema.getKey(),
+                            anyUtils.plainIntMappingType()))) {
+
+                LOG.error("Mandatory schema " + schema.getKey() + " not provided with values");
+
+                reqValMissing.getElements().add(schema.getKey());
+            }
+        }
+
+        List<DerSchema> derSchemas = derSchemaDAO.findAll();
+        for (DerSchema derSchema : derSchemas) {
+            if (any.getDerAttr(derSchema.getKey()) == null
+                    && evaluateMandatoryCondition(anyUtils, any, derSchema.getKey(),
+                            anyUtils.derIntMappingType())) {
+
+                LOG.error("Mandatory derived schema " + derSchema.getKey() + " does not evaluate to any value");
+
+                reqValMissing.getElements().add(derSchema.getKey());
+            }
+        }
+
+        List<VirSchema> virSchemas = virSchemaDAO.findAll();
+        for (VirSchema virSchema : virSchemas) {
+            if (any.getVirAttr(virSchema.getKey()) == null
+                    && !virSchema.isReadonly()
+                    && evaluateMandatoryCondition(anyUtils, any, virSchema.getKey(),
+                            anyUtils.virIntMappingType())) {
+
+                LOG.error("Mandatory virtual schema " + virSchema.getKey() + " not provided with values");
+
+                reqValMissing.getElements().add(virSchema.getKey());
+            }
+        }
+
+        return reqValMissing;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected PropagationByResource fill(final Any any, final AnyMod anyMod, final AnyUtils anyUtils,
+            final SyncopeClientCompositeException scce) {
+
+        PropagationByResource propByRes = new PropagationByResource();
+
+        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
+        // 1. resources to be removed
+        for (String resourceToBeRemoved : anyMod.getResourcesToRemove()) {
+            ExternalResource resource = resourceDAO.find(resourceToBeRemoved);
+            if (resource != null) {
+                propByRes.add(ResourceOperation.DELETE, resource.getKey());
+                ((Any<?, ?, ?>) any).remove(resource);
+            }
+        }
+
+        LOG.debug("Resources to be removed:\n{}", propByRes);
+
+        // 2. resources to be added
+        for (String resourceToBeAdded : anyMod.getResourcesToAdd()) {
+            ExternalResource resource = resourceDAO.find(resourceToBeAdded);
+            if (resource != null) {
+                propByRes.add(ResourceOperation.CREATE, resource.getKey());
+                ((Any<?, ?, ?>) any).add(resource);
+            }
+        }
+
+        LOG.debug("Resources to be added:\n{}", propByRes);
+
+        Set<ExternalResource> externalResources = new HashSet<>();
+        if (any instanceof User) {
+            externalResources.addAll(userDAO.findAllResources((User) any));
+        } else if (any instanceof Group) {
+            externalResources.addAll(((Group) any).getResources());
+        } else if (any instanceof AnyObject) {
+            externalResources.addAll(anyObjectDAO.findAllResources((AnyObject) any));
+        }
+
+        // 3. attributes to be removed
+        for (String attributeToBeRemoved : anyMod.getPlainAttrsToRemove()) {
+            PlainSchema schema = getPlainSchema(attributeToBeRemoved);
+            if (schema != null) {
+                PlainAttr<?> attr = any.getPlainAttr(schema.getKey());
+                if (attr == null) {
+                    LOG.debug("No attribute found for schema {}", schema);
+                } else {
+                    String newValue = null;
+                    for (AttrMod mod : anyMod.getPlainAttrsToUpdate()) {
+                        if (schema.getKey().equals(mod.getSchema())) {
+                            newValue = mod.getValuesToBeAdded().get(0);
+                        }
+                    }
+
+                    if (!schema.isUniqueConstraint()
+                            || (!attr.getUniqueValue().getStringValue().equals(newValue))) {
+
+                        any.remove(attr);
+                        plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass());
+                    }
+                }
+
+                for (ExternalResource resource : externalResources) {
+                    for (MappingItem mapItem : anyUtils.getMappingItems(
+                            resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) {
+
+                        if (schema.getKey().equals(mapItem.getIntAttrName())
+                                && mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) {
+
+                            propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+                            if (mapItem.isConnObjectKey() && attr != null && !attr.getValuesAsStrings().isEmpty()) {
+                                propByRes.addOldAccountId(resource.getKey(), attr.getValuesAsStrings().get(0));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        LOG.debug("Attributes to be removed:\n{}", propByRes);
+
+        // 4. attributes to be updated
+        for (AttrMod attributeMod : anyMod.getPlainAttrsToUpdate()) {
+            PlainSchema schema = getPlainSchema(attributeMod.getSchema());
+            PlainAttr attr = null;
+            if (schema != null) {
+                attr = any.getPlainAttr(schema.getKey());
+                if (attr == null) {
+                    attr = anyUtils.newPlainAttr();
+                    attr.setSchema(schema);
+                    if (attr.getSchema() == null) {
+                        LOG.debug("Ignoring {} because no valid schema or template was found", attributeMod);
+                    } else {
+                        attr.setOwner(any);
+                        any.add(attr);
+                    }
+                }
+            }
+
+            if (schema != null && attr != null && attr.getSchema() != null) {
+                virtAttrHander.updateOnResourcesIfMappingMatches(any, anyUtils, schema.getKey(),
+                        externalResources, anyUtils.plainIntMappingType(), propByRes);
+
+                // 1.1 remove values
+                Set<Long> valuesToBeRemoved = new HashSet<>();
+                for (String valueToBeRemoved : attributeMod.getValuesToBeRemoved()) {
+                    if (attr.getSchema().isUniqueConstraint()) {
+                        if (attr.getUniqueValue() != null
+                                && valueToBeRemoved.equals(attr.getUniqueValue().getValueAsString())) {
+
+                            valuesToBeRemoved.add(attr.getUniqueValue().getKey());
+                        }
+                    } else {
+                        for (PlainAttrValue mav : ((PlainAttr<?>) attr).getValues()) {
+                            if (valueToBeRemoved.equals(mav.getValueAsString())) {
+                                valuesToBeRemoved.add(mav.getKey());
+                            }
+                        }
+                    }
+                }
+                for (Long attributeValueId : valuesToBeRemoved) {
+                    plainAttrValueDAO.delete(attributeValueId, anyUtils.plainAttrValueClass());
+                }
+
+                // 1.2 add values
+                List<String> valuesToBeAdded = attributeMod.getValuesToBeAdded();
+                if (valuesToBeAdded != null && !valuesToBeAdded.isEmpty()
+                        && (!schema.isUniqueConstraint() || attr.getUniqueValue() == null
+                        || !valuesToBeAdded.iterator().next().equals(attr.getUniqueValue().getValueAsString()))) {
+
+                    fillAttribute(attributeMod.getValuesToBeAdded(), anyUtils, schema, attr, invalidValues);
+                }
+
+                // if no values are in, the attribute can be safely removed
+                if (attr.getValuesAsStrings().isEmpty()) {
+                    plainAttrDAO.delete(attr);
+                }
+            }
+        }
+
+        if (!invalidValues.isEmpty()) {
+            scce.addException(invalidValues);
+        }
+
+        LOG.debug("Attributes to be updated:\n{}", propByRes);
+
+        // 5. derived attributes to be removed
+        for (String derAttrToBeRemoved : anyMod.getDerAttrsToRemove()) {
+            DerSchema derSchema = getDerSchema(derAttrToBeRemoved);
+            if (derSchema != null) {
+                DerAttr derAttr = any.getDerAttr(derSchema.getKey());
+                if (derAttr == null) {
+                    LOG.debug("No derived attribute found for schema {}", derSchema.getKey());
+                } else {
+                    derAttrDAO.delete(derAttr);
+                }
+
+                for (ExternalResource resource : externalResources) {
+                    for (MappingItem mapItem : anyUtils.getMappingItems(
+                            resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) {
+
+                        if (derSchema.getKey().equals(mapItem.getIntAttrName())
+                                && mapItem.getIntMappingType() == anyUtils.derIntMappingType()) {
+
+                            propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+                            if (mapItem.isConnObjectKey() && derAttr != null
+                                    && !derAttr.getValue(any.getPlainAttrs()).isEmpty()) {
+
+                                propByRes.addOldAccountId(resource.getKey(),
+                                        derAttr.getValue(any.getPlainAttrs()));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        LOG.debug("Derived attributes to be removed:\n{}", propByRes);
+
+        // 6. derived attributes to be added
+        for (String derAttrToBeAdded : anyMod.getDerAttrsToAdd()) {
+            DerSchema derSchema = getDerSchema(derAttrToBeAdded);
+            if (derSchema != null) {
+                virtAttrHander.updateOnResourcesIfMappingMatches(any, anyUtils, derSchema.getKey(),
+                        externalResources, anyUtils.derIntMappingType(), propByRes);
+
+                DerAttr derAttr = anyUtils.newDerAttr();
+                derAttr.setSchema(derSchema);
+                if (derAttr.getSchema() == null) {
+                    LOG.debug("Ignoring {} because no valid schema or template was found", derAttrToBeAdded);
+                } else {
+                    derAttr.setOwner(any);
+                    any.add(derAttr);
+                }
+            }
+        }
+
+        LOG.debug("Derived attributes to be added:\n{}", propByRes);
+
+        // Finally, check if mandatory values are missing
+        SyncopeClientException requiredValuesMissing = checkMandatory(anyUtils, any);
+        if (!requiredValuesMissing.isEmpty()) {
+            scce.addException(requiredValuesMissing);
+        }
+
+        // Throw composite exception if there is at least one element set in the composing exceptions
+        if (scce.hasExceptions()) {
+            throw scce;
+        }
+
+        return propByRes;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected void fill(final Any any, final AnyTO anyTO,
+            final AnyUtils anyUtils, final SyncopeClientCompositeException scce) {
+
+        // 1. attributes
+        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
+        // Only consider attributeTO with values
+        for (AttrTO attributeTO : anyTO.getPlainAttrs()) {
+            if (attributeTO.getValues() != null && !attributeTO.getValues().isEmpty()) {
+                PlainSchema schema = getPlainSchema(attributeTO.getSchema());
+
+                if (schema != null) {
+                    PlainAttr attr = any.getPlainAttr(schema.getKey());
+                    if (attr == null) {
+                        attr = anyUtils.newPlainAttr();
+                        attr.setSchema(schema);
+                    }
+                    if (attr.getSchema() == null) {
+                        LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
+                    } else {
+                        fillAttribute(attributeTO.getValues(), anyUtils, schema, attr, invalidValues);
+
+                        if (!attr.getValuesAsStrings().isEmpty()) {
+                            any.add(attr);
+                            attr.setOwner(any);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!invalidValues.isEmpty()) {
+            scce.addException(invalidValues);
+        }
+
+        // 2. derived attributes
+        for (AttrTO attributeTO : anyTO.getDerAttrs()) {
+            DerSchema derSchema = getDerSchema(attributeTO.getSchema());
+
+            if (derSchema != null) {
+                DerAttr derAttr = anyUtils.newDerAttr();
+                derAttr.setSchema(derSchema);
+                if (derAttr.getSchema() == null) {
+                    LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
+                } else {
+                    derAttr.setOwner(any);
+                    any.add(derAttr);
+                }
+            }
+        }
+
+        // 3. virtual attributes
+        for (AttrTO vattrTO : anyTO.getVirAttrs()) {
+            VirSchema virSchema = virtAttrHander.getVirSchema(vattrTO.getSchema());
+
+            if (virSchema != null) {
+                VirAttr virAttr = anyUtils.newVirAttr();
+                virAttr.setSchema(virSchema);
+                if (virAttr.getSchema() == null) {
+                    LOG.debug("Ignoring {} because no valid schema or template was found", vattrTO);
+                } else {
+                    virAttr.setOwner(any);
+                    any.add(virAttr);
+                }
+            }
+        }
+
+        virtAttrHander.fillVirtual(any, anyTO.getVirAttrs(), anyUtils);
+
+        // 4. realm & resources
+        Realm realm = realmDAO.find(anyTO.getRealm());
+        if (realm == null) {
+            SyncopeClientException noRealm = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
+            noRealm.getElements().add(
+                    "Invalid or null realm specified: " + anyTO.getRealm());
+            scce.addException(noRealm);
+        }
+        ((Any<?, ?, ?>) any).setRealm(realm);
+
+        for (String resourceName : anyTO.getResources()) {
+            ExternalResource resource = resourceDAO.find(resourceName);
+
+            if (resource != null) {
+                ((Any<?, ?, ?>) any).add(resource);
+            }
+        }
+
+        SyncopeClientException requiredValuesMissing = checkMandatory(anyUtils, any);
+        if (!requiredValuesMissing.isEmpty()) {
+            scce.addException(requiredValuesMissing);
+        }
+
+        // Throw composite exception if there is at least one element set in the composing exceptions
+        if (scce.hasExceptions()) {
+            throw scce;
+        }
+    }
+
+    protected void fillTO(final AnyTO anyTO,
+            final String realmFullPath,
+            final Collection<? extends PlainAttr<?>> attrs,
+            final Collection<? extends DerAttr<?>> derAttrs,
+            final Collection<? extends VirAttr<?>> virAttrs,
+            final Collection<? extends ExternalResource> resources) {
+
+        AttrTO attributeTO;
+        for (PlainAttr<?> attr : attrs) {
+            attributeTO = new AttrTO();
+            attributeTO.setSchema(attr.getSchema().getKey());
+            attributeTO.getValues().addAll(attr.getValuesAsStrings());
+            attributeTO.setReadonly(attr.getSchema().isReadonly());
+
+            anyTO.getPlainAttrs().add(attributeTO);
+        }
+
+        for (DerAttr<?> derAttr : derAttrs) {
+            attributeTO = new AttrTO();
+            attributeTO.setSchema(derAttr.getSchema().getKey());
+            attributeTO.getValues().add(derAttr.getValue(attrs));
+            attributeTO.setReadonly(true);
+
+            anyTO.getDerAttrs().add(attributeTO);
+        }
+
+        for (VirAttr<?> virAttr : virAttrs) {
+            attributeTO = new AttrTO();
+            attributeTO.setSchema(virAttr.getSchema().getKey());
+            attributeTO.getValues().addAll(virAttr.getValues());
+            attributeTO.setReadonly(virAttr.getSchema().isReadonly());
+
+            anyTO.getVirAttrs().add(attributeTO);
+        }
+
+        anyTO.setRealm(realmFullPath);
+        for (ExternalResource resource : resources) {
+            anyTO.getResources().add(resource.getKey());
+        }
+    }
+
+    protected Map<String, String> getConnObjectKeys(final Any<?, ?, ?> any) {
+        Map<String, String> connObjectKeys = new HashMap<>();
+
+        Iterable<? extends ExternalResource> iterable = any instanceof User
+                ? userDAO.findAllResources((User) any)
+                : any instanceof AnyObject
+                        ? anyObjectDAO.findAllResources((AnyObject) any)
+                        : ((Group) any).getResources();
+        for (ExternalResource resource : iterable) {
+            Provision provision = resource.getProvision(any.getType());
+            if (provision.getMapping() != null) {
+                MappingItem connObjectKeyItem = anyUtilsFactory.getInstance(any).getConnObjectKeyItem(provision);
+                if (connObjectKeyItem == null) {
+                    throw new NotFoundException(
+                            "ConnObjectKey mapping for " + any.getType().getKey() + " " + any.getKey()
+                            + " on resource '" + resource.getKey() + "'");
+                }
+
+                connObjectKeys.put(resource.getKey(), MappingUtils.getConnObjectKeyValue(any, provision));
+            }
+        }
+
+        return connObjectKeys;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
deleted file mode 100644
index b94ffa2..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
+++ /dev/null
@@ -1,805 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.provisioning.java.data;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-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.mod.AbstractAttributableMod;
-import org.apache.syncope.common.lib.mod.AbstractSubjectMod;
-import org.apache.syncope.common.lib.mod.AttrMod;
-import org.apache.syncope.common.lib.to.AbstractAttributableTO;
-import org.apache.syncope.common.lib.to.AbstractSubjectTO;
-import org.apache.syncope.common.lib.to.AttrTO;
-import org.apache.syncope.common.lib.types.AttributableType;
-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.ResourceOperation;
-import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
-import org.apache.syncope.core.persistence.api.dao.DerAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
-import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
-import org.apache.syncope.core.persistence.api.dao.MembershipDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
-import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
-import org.apache.syncope.core.persistence.api.dao.GroupDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
-import org.apache.syncope.core.persistence.api.entity.Attributable;
-import org.apache.syncope.core.persistence.api.entity.AttributableUtils;
-import org.apache.syncope.core.persistence.api.entity.AttributableUtilsFactory;
-import org.apache.syncope.core.persistence.api.entity.DerAttr;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
-import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.api.entity.ExternalResource;
-import org.apache.syncope.core.persistence.api.entity.MappingItem;
-import org.apache.syncope.core.persistence.api.entity.PlainAttr;
-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.Schema;
-import org.apache.syncope.core.persistence.api.entity.Subject;
-import org.apache.syncope.core.persistence.api.entity.VirAttr;
-import org.apache.syncope.core.persistence.api.entity.VirSchema;
-import org.apache.syncope.core.persistence.api.entity.membership.MDerAttr;
-import org.apache.syncope.core.persistence.api.entity.membership.MDerAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.membership.MPlainAttr;
-import org.apache.syncope.core.persistence.api.entity.membership.MPlainAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.membership.MVirAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.membership.Membership;
-import org.apache.syncope.core.persistence.api.entity.group.GDerAttr;
-import org.apache.syncope.core.persistence.api.entity.group.GDerAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
-import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.group.GVirAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.group.Group;
-import org.apache.syncope.core.persistence.api.entity.user.UDerAttr;
-import org.apache.syncope.core.persistence.api.entity.user.UDerSchema;
-import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
-import org.apache.syncope.core.persistence.api.entity.user.UPlainSchema;
-import org.apache.syncope.common.lib.types.PropagationByResource;
-import org.apache.syncope.core.provisioning.java.VirAttrHandler;
-import org.apache.syncope.core.misc.MappingUtils;
-import org.apache.syncope.core.misc.jexl.JexlUtils;
-import org.apache.syncope.core.persistence.api.dao.NotFoundException;
-import org.apache.syncope.core.persistence.api.dao.RealmDAO;
-import org.apache.syncope.core.persistence.api.entity.Realm;
-import org.apache.syncope.core.persistence.api.entity.user.User;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-
-abstract class AbstractAttributableDataBinder {
-
-    /**
-     * Logger.
-     */
-    protected static final Logger LOG = LoggerFactory.getLogger(AbstractAttributableDataBinder.class);
-
-    @Autowired
-    protected RealmDAO realmDAO;
-
-    @Autowired
-    protected GroupDAO groupDAO;
-
-    @Autowired
-    protected PlainSchemaDAO plainSchemaDAO;
-
-    @Autowired
-    protected DerSchemaDAO derSchemaDAO;
-
-    @Autowired
-    protected VirSchemaDAO virSchemaDAO;
-
-    @Autowired
-    protected PlainAttrDAO plainAttrDAO;
-
-    @Autowired
-    protected DerAttrDAO derAttrDAO;
-
-    @Autowired
-    protected VirAttrDAO virAttrDAO;
-
-    @Autowired
-    protected PlainAttrValueDAO plainAttrValueDAO;
-
-    @Autowired
-    protected UserDAO userDAO;
-
-    @Autowired
-    protected ExternalResourceDAO resourceDAO;
-
-    @Autowired
-    protected MembershipDAO membershipDAO;
-
-    @Autowired
-    protected PolicyDAO policyDAO;
-
-    @Autowired
-    protected EntityFactory entityFactory;
-
-    @Autowired
-    protected AttributableUtilsFactory attrUtilsFactory;
-
-    @Autowired
-    protected VirAttrHandler virtAttrHander;
-
-    protected void setRealm(final Subject<?, ?, ?> subject, final AbstractSubjectMod subjectMod) {
-        if (StringUtils.isNotBlank(subjectMod.getRealm())) {
-            Realm newRealm = realmDAO.find(subjectMod.getRealm());
-            if (newRealm == null) {
-                LOG.warn("Invalid realm specified: {}, ignoring", subjectMod.getRealm());
-            } else {
-                subject.setRealm(newRealm);
-            }
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    protected <T extends Schema> T getSchema(final String schemaName, final Class<T> reference) {
-        T result = null;
-
-        if (PlainSchema.class.isAssignableFrom(reference)) {
-            result = (T) getPlainSchema(schemaName, (Class<? extends PlainSchema>) reference);
-        } else if (DerSchema.class.isAssignableFrom(reference)) {
-            result = (T) getDerSchema(schemaName, (Class<? extends DerSchema>) reference);
-        } else if (VirSchema.class.isAssignableFrom(reference)) {
-            result = (T) virtAttrHander.getVirSchema(schemaName, (Class<? extends VirSchema>) reference);
-        }
-
-        return result;
-    }
-
-    protected <T extends PlainSchema> T getPlainSchema(final String schemaName, final Class<T> reference) {
-        T schema = null;
-        if (StringUtils.isNotBlank(schemaName)) {
-            schema = plainSchemaDAO.find(schemaName, reference);
-
-            // safely ignore invalid schemas from AttrTO
-            if (schema == null) {
-                LOG.debug("Ignoring invalid schema {}", schemaName);
-            } else if (schema.isReadonly()) {
-                schema = null;
-
-                LOG.debug("Ignoring readonly schema {}", schemaName);
-            }
-        }
-
-        return schema;
-    }
-
-    private <T extends DerSchema> T getDerSchema(final String derSchemaName, final Class<T> reference) {
-        T derivedSchema = null;
-        if (StringUtils.isNotBlank(derSchemaName)) {
-            derivedSchema = derSchemaDAO.find(derSchemaName, reference);
-            if (derivedSchema == null) {
-                LOG.debug("Ignoring invalid derived schema {}", derSchemaName);
-            }
-        }
-
-        return derivedSchema;
-    }
-
-    protected void fillAttribute(final List<String> values, final AttributableUtils attributableUtil,
-            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
-        List<String> valuesProvided = schema.isMultivalue()
-                ? values
-                : (values.isEmpty()
-                        ? Collections.<String>emptyList()
-                        : Collections.singletonList(values.iterator().next()));
-
-        for (String value : valuesProvided) {
-            if (value == null || value.isEmpty()) {
-                LOG.debug("Null value for {}, ignoring", schema.getKey());
-            } else {
-                try {
-                    attr.addValue(value, attributableUtil);
-                } catch (InvalidPlainAttrValueException e) {
-                    LOG.warn("Invalid value for attribute " + schema.getKey() + ": " + value, e);
-
-                    invalidValues.getElements().add(schema.getKey() + ": " + value + " - " + e.getMessage());
-                }
-            }
-        }
-    }
-
-    private boolean evaluateMandatoryCondition(final AttributableUtils attrUtils, final ExternalResource resource,
-            final Attributable<?, ?, ?> attributable, final String intAttrName, final IntMappingType intMappingType) {
-
-        boolean result = false;
-
-        Collection<MappingItem> mappings = MappingUtils.getMatchingMappingItems(
-                attrUtils.getMappingItems(resource, MappingPurpose.PROPAGATION), intAttrName, intMappingType);
-        for (Iterator<MappingItem> itor = mappings.iterator(); itor.hasNext() && !result;) {
-            MappingItem mapping = itor.next();
-            result |= JexlUtils.evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributable);
-        }
-
-        return result;
-    }
-
-    private boolean evaluateMandatoryCondition(final AttributableUtils attrUtils,
-            final Attributable<?, ?, ?> attributable, final String intAttrName, final IntMappingType intMappingType) {
-
-        boolean result = false;
-
-        Iterable<? extends ExternalResource> iterable = attributable instanceof User
-                ? userDAO.findAllResources((User) attributable)
-                : attributable instanceof Group
-                        ? ((Group) attributable).getResources()
-                        : Collections.<ExternalResource>emptySet();
-
-        for (Iterator<? extends ExternalResource> itor = iterable.iterator(); itor.hasNext() && !result;) {
-            ExternalResource resource = itor.next();
-            if (resource.isEnforceMandatoryCondition()) {
-                result |= evaluateMandatoryCondition(
-                        attrUtils, resource, attributable, intAttrName, intMappingType);
-            }
-        }
-
-        return result;
-    }
-
-    private SyncopeClientException checkMandatory(final AttributableUtils attrUtils,
-            final Attributable<?, ?, ?> attributable) {
-
-        SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
-
-        // Check if there is some mandatory schema defined for which no value has been provided
-        List<? extends PlainSchema> plainSchemas;
-        switch (attrUtils.getType()) {
-            case GROUP:
-                plainSchemas = ((Group) attributable).getAttrTemplateSchemas(GPlainAttrTemplate.class);
-                break;
-
-            case MEMBERSHIP:
-                plainSchemas = ((Membership) attributable).getGroup().getAttrTemplateSchemas(MPlainAttrTemplate.class);
-                break;
-
-            case USER:
-            default:
-                plainSchemas = plainSchemaDAO.findAll(attrUtils.plainSchemaClass());
-        }
-        for (PlainSchema schema : plainSchemas) {
-            if (attributable.getPlainAttr(schema.getKey()) == null
-                    && !schema.isReadonly()
-                    && (JexlUtils.evaluateMandatoryCondition(schema.getMandatoryCondition(), attributable)
-                    || evaluateMandatoryCondition(attrUtils, attributable, schema.getKey(),
-                            attrUtils.plainIntMappingType()))) {
-
-                LOG.error("Mandatory schema " + schema.getKey() + " not provided with values");
-
-                reqValMissing.getElements().add(schema.getKey());
-            }
-        }
-
-        List<? extends DerSchema> derSchemas;
-        switch (attrUtils.getType()) {
-            case GROUP:
-                derSchemas = ((Group) attributable).getAttrTemplateSchemas(GDerAttrTemplate.class);
-                break;
-
-            case MEMBERSHIP:
-                derSchemas = ((Membership) attributable).getGroup().getAttrTemplateSchemas(MDerAttrTemplate.class);
-                break;
-
-            case USER:
-            default:
-                derSchemas = derSchemaDAO.findAll(attrUtils.derSchemaClass());
-        }
-        for (DerSchema derSchema : derSchemas) {
-            if (attributable.getDerAttr(derSchema.getKey()) == null
-                    && evaluateMandatoryCondition(attrUtils, attributable, derSchema.getKey(),
-                            attrUtils.derIntMappingType())) {
-
-                LOG.error("Mandatory derived schema " + derSchema.getKey() + " does not evaluate to any value");
-
-                reqValMissing.getElements().add(derSchema.getKey());
-            }
-        }
-
-        List<? extends VirSchema> virSchemas;
-        switch (attrUtils.getType()) {
-            case GROUP:
-                virSchemas = ((Group) attributable).getAttrTemplateSchemas(GVirAttrTemplate.class);
-                break;
-
-            case MEMBERSHIP:
-                virSchemas = ((Membership) attributable).getGroup().getAttrTemplateSchemas(MVirAttrTemplate.class);
-                break;
-
-            case USER:
-            default:
-                virSchemas = virSchemaDAO.findAll(attrUtils.virSchemaClass());
-        }
-        for (VirSchema virSchema : virSchemas) {
-            if (attributable.getVirAttr(virSchema.getKey()) == null
-                    && !virSchema.isReadonly()
-                    && evaluateMandatoryCondition(attrUtils, attributable, virSchema.getKey(),
-                            attrUtils.virIntMappingType())) {
-
-                LOG.error("Mandatory virtual schema " + virSchema.getKey() + " not provided with values");
-
-                reqValMissing.getElements().add(virSchema.getKey());
-            }
-        }
-
-        return reqValMissing;
-    }
-
-    private void setPlainAttrSchema(final Attributable<?, ?, ?> attributable,
-            final PlainAttr attr, final PlainSchema schema) {
-
-        if (attr instanceof UPlainAttr) {
-            ((UPlainAttr) attr).setSchema((UPlainSchema) schema);
-        } else if (attr instanceof GPlainAttr) {
-            GPlainAttrTemplate template =
-                    ((Group) attributable).getAttrTemplate(GPlainAttrTemplate.class, schema.getKey());
-            if (template != null) {
-                ((GPlainAttr) attr).setTemplate(template);
-            }
-        } else if (attr instanceof MPlainAttr) {
-            MPlainAttrTemplate template = ((Membership) attributable).getGroup().
-                    getAttrTemplate(MPlainAttrTemplate.class, schema.getKey());
-            if (template != null) {
-                ((MPlainAttr) attr).setTemplate(template);
-            }
-        }
-    }
-
-    private void setDerAttrSchema(final Attributable<?, ?, ?> attributable,
-            final DerAttr derAttr, final DerSchema derSchema) {
-
-        if (derAttr instanceof UDerAttr) {
-            ((UDerAttr) derAttr).setSchema((UDerSchema) derSchema);
-        } else if (derAttr instanceof GDerAttr) {
-            GDerAttrTemplate template = ((Group) attributable).
-                    getAttrTemplate(GDerAttrTemplate.class, derSchema.getKey());
-            if (template != null) {
-                ((GDerAttr) derAttr).setTemplate(template);
-            }
-        } else if (derAttr instanceof MDerAttr) {
-            MDerAttrTemplate template = ((Membership) attributable).getGroup().
-                    getAttrTemplate(MDerAttrTemplate.class, derSchema.getKey());
-            if (template != null) {
-                ((MDerAttr) derAttr).setTemplate(template);
-            }
-        }
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    protected PropagationByResource fill(final Attributable attributable,
-            final AbstractAttributableMod attributableMod, final AttributableUtils attrUtils,
-            final SyncopeClientCompositeException scce) {
-
-        PropagationByResource propByRes = new PropagationByResource();
-
-        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
-
-        if (attributable instanceof Subject && attributableMod instanceof AbstractSubjectMod) {
-            // 1. resources to be removed
-            for (String resourceToBeRemoved : ((AbstractSubjectMod) attributableMod).getResourcesToRemove()) {
-                ExternalResource resource = resourceDAO.find(resourceToBeRemoved);
-                if (resource != null) {
-                    propByRes.add(ResourceOperation.DELETE, resource.getKey());
-                    ((Subject<?, ?, ?>) attributable).removeResource(resource);
-                }
-            }
-
-            LOG.debug("Resources to be removed:\n{}", propByRes);
-
-            // 2. resources to be added
-            for (String resourceToBeAdded : ((AbstractSubjectMod) attributableMod).getResourcesToAdd()) {
-                ExternalResource resource = resourceDAO.find(resourceToBeAdded);
-                if (resource != null) {
-                    propByRes.add(ResourceOperation.CREATE, resource.getKey());
-                    ((Subject<?, ?, ?>) attributable).addResource(resource);
-                }
-            }
-
-            LOG.debug("Resources to be added:\n{}", propByRes);
-        }
-
-        Set<ExternalResource> externalResources = new HashSet<>();
-        if (attributable instanceof User) {
-            externalResources.addAll(userDAO.findAllResources((User) attributable));
-        } else if (attributable instanceof Group) {
-            externalResources.addAll(((Group) attributable).getResources());
-        } else if (attributable instanceof Membership) {
-            externalResources.addAll(userDAO.findAllResources(((Membership) attributable).getUser()));
-            externalResources.addAll(((Membership) attributable).getGroup().getResources());
-        }
-
-        // 3. attributes to be removed
-        for (String attributeToBeRemoved : attributableMod.getPlainAttrsToRemove()) {
-            PlainSchema schema = getPlainSchema(attributeToBeRemoved, attrUtils.plainSchemaClass());
-            if (schema != null) {
-                PlainAttr attr = attributable.getPlainAttr(schema.getKey());
-                if (attr == null) {
-                    LOG.debug("No attribute found for schema {}", schema);
-                } else {
-                    String newValue = null;
-                    for (AttrMod mod : attributableMod.getPlainAttrsToUpdate()) {
-                        if (schema.getKey().equals(mod.getSchema())) {
-                            newValue = mod.getValuesToBeAdded().get(0);
-                        }
-                    }
-
-                    if (!schema.isUniqueConstraint()
-                            || (!attr.getUniqueValue().getStringValue().equals(newValue))) {
-
-                        attributable.removePlainAttr(attr);
-                        plainAttrDAO.delete(attr.getKey(), attrUtils.plainAttrClass());
-                    }
-                }
-
-                if (attributable instanceof Subject) {
-                    for (ExternalResource resource : externalResources) {
-                        for (MappingItem mapItem : attrUtils.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
-                            if (schema.getKey().equals(mapItem.getIntAttrName())
-                                    && mapItem.getIntMappingType() == attrUtils.plainIntMappingType()) {
-
-                                propByRes.add(ResourceOperation.UPDATE, resource.getKey());
-
-                                if (mapItem.isAccountid() && attr != null && !attr.getValuesAsStrings().isEmpty()) {
-                                    propByRes.addOldAccountId(resource.getKey(), attr.getValuesAsStrings().get(0));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        LOG.debug("Attributes to be removed:\n{}", propByRes);
-
-        // 4. attributes to be updated
-        for (AttrMod attributeMod : attributableMod.getPlainAttrsToUpdate()) {
-            PlainSchema schema = getPlainSchema(attributeMod.getSchema(), attrUtils.plainSchemaClass());
-            PlainAttr attr = null;
-            if (schema != null) {
-                attr = attributable.getPlainAttr(schema.getKey());
-                if (attr == null) {
-                    attr = attrUtils.newPlainAttr();
-                    setPlainAttrSchema(attributable, attr, schema);
-                    if (attr.getSchema() == null) {
-                        LOG.debug("Ignoring {} because no valid schema or template was found", attributeMod);
-                    } else {
-                        attr.setOwner(attributable);
-                        attributable.addPlainAttr(attr);
-                    }
-                }
-            }
-
-            if (schema != null && attr != null && attr.getSchema() != null) {
-                if (attributable instanceof Subject) {
-                    virtAttrHander.updateOnResourcesIfMappingMatches(attrUtils, schema.getKey(),
-                            externalResources, attrUtils.plainIntMappingType(), propByRes);
-                } else if (attributable instanceof Membership) {
-                    virtAttrHander.updateOnResourcesIfMappingMatches(attrUtils, schema.getKey(),
-                            externalResources, IntMappingType.MembershipPlainSchema, propByRes);
-                }
-
-                // 1.1 remove values
-                Set<Long> valuesToBeRemoved = new HashSet<>();
-                for (String valueToBeRemoved : attributeMod.getValuesToBeRemoved()) {
-                    if (attr.getSchema().isUniqueConstraint()) {
-                        if (attr.getUniqueValue() != null
-                                && valueToBeRemoved.equals(attr.getUniqueValue().getValueAsString())) {
-
-                            valuesToBeRemoved.add(attr.getUniqueValue().getKey());
-                        }
-                    } else {
-                        for (PlainAttrValue mav : attr.getValues()) {
-                            if (valueToBeRemoved.equals(mav.getValueAsString())) {
-                                valuesToBeRemoved.add(mav.getKey());
-                            }
-                        }
-                    }
-                }
-                for (Long attributeValueId : valuesToBeRemoved) {
-                    plainAttrValueDAO.delete(attributeValueId, attrUtils.plainAttrValueClass());
-                }
-
-                // 1.2 add values
-                List<String> valuesToBeAdded = attributeMod.getValuesToBeAdded();
-                if (valuesToBeAdded != null && !valuesToBeAdded.isEmpty()
-                        && (!schema.isUniqueConstraint() || attr.getUniqueValue() == null
-                        || !valuesToBeAdded.iterator().next().equals(attr.getUniqueValue().getValueAsString()))) {
-
-                    fillAttribute(attributeMod.getValuesToBeAdded(), attrUtils, schema, attr, invalidValues);
-                }
-
-                // if no values are in, the attribute can be safely removed
-                if (attr.getValuesAsStrings().isEmpty()) {
-                    plainAttrDAO.delete(attr);
-                }
-            }
-        }
-
-        if (!invalidValues.isEmpty()) {
-            scce.addException(invalidValues);
-        }
-
-        LOG.debug("Attributes to be updated:\n{}", propByRes);
-
-        // 5. derived attributes to be removed
-        for (String derAttrToBeRemoved : attributableMod.getDerAttrsToRemove()) {
-            DerSchema derSchema = getDerSchema(derAttrToBeRemoved, attrUtils.derSchemaClass());
-            if (derSchema != null) {
-                DerAttr derAttr = attributable.getDerAttr(derSchema.getKey());
-                if (derAttr == null) {
-                    LOG.debug("No derived attribute found for schema {}", derSchema.getKey());
-                } else {
-                    derAttrDAO.delete(derAttr);
-                }
-
-                if (attributable instanceof Subject) {
-                    for (ExternalResource resource : externalResources) {
-                        for (MappingItem mapItem : attrUtils.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
-                            if (derSchema.getKey().equals(mapItem.getIntAttrName())
-                                    && mapItem.getIntMappingType() == attrUtils.derIntMappingType()) {
-
-                                propByRes.add(ResourceOperation.UPDATE, resource.getKey());
-
-                                if (mapItem.isAccountid() && derAttr != null
-                                        && !derAttr.getValue(attributable.getPlainAttrs()).isEmpty()) {
-
-                                    propByRes.addOldAccountId(resource.getKey(),
-                                            derAttr.getValue(attributable.getPlainAttrs()));
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        LOG.debug("Derived attributes to be removed:\n{}", propByRes);
-
-        // 6. derived attributes to be added
-        for (String derAttrToBeAdded : attributableMod.getDerAttrsToAdd()) {
-            DerSchema derSchema = getDerSchema(derAttrToBeAdded, attrUtils.derSchemaClass());
-            if (derSchema != null) {
-                if (attributable instanceof Subject) {
-                    virtAttrHander.updateOnResourcesIfMappingMatches(attrUtils, derSchema.getKey(),
-                            externalResources, attrUtils.derIntMappingType(), propByRes);
-                } else if (attributable instanceof Membership) {
-                    virtAttrHander.updateOnResourcesIfMappingMatches(attrUtils, derSchema.getKey(),
-                            externalResources, IntMappingType.MembershipDerivedSchema, propByRes);
-                }
-
-                DerAttr derAttr = attrUtils.newDerAttr();
-                setDerAttrSchema(attributable, derAttr, derSchema);
-                if (derAttr.getSchema() == null) {
-                    LOG.debug("Ignoring {} because no valid schema or template was found", derAttrToBeAdded);
-                } else {
-                    derAttr.setOwner(attributable);
-                    attributable.addDerAttr(derAttr);
-                }
-            }
-        }
-
-        LOG.debug("Derived attributes to be added:\n{}", propByRes);
-
-        // 7. virtual attributes: for users and groups this is delegated to PropagationManager
-        if (AttributableType.USER != attrUtils.getType() && AttributableType.GROUP != attrUtils.getType()) {
-            virtAttrHander.fillVirtual(attributable, attributableMod.getVirAttrsToRemove(),
-                    attributableMod.getVirAttrsToUpdate(), attrUtils);
-        }
-
-        // Finally, check if mandatory values are missing
-        SyncopeClientException requiredValuesMissing = checkMandatory(attrUtils, attributable);
-        if (!requiredValuesMissing.isEmpty()) {
-            scce.addException(requiredValuesMissing);
-        }
-
-        // Throw composite exception if there is at least one element set in the composing exceptions
-        if (scce.hasExceptions()) {
-            throw scce;
-        }
-
-        return propByRes;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    protected void fill(final Attributable attributable, final AbstractAttributableTO attributableTO,
-            final AttributableUtils attrUtils, final SyncopeClientCompositeException scce) {
-
-        // 1. attributes
-        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
-
-        // Only consider attributeTO with values
-        for (AttrTO attributeTO : attributableTO.getPlainAttrs()) {
-            if (attributeTO.getValues() != null && !attributeTO.getValues().isEmpty()) {
-                PlainSchema schema = getPlainSchema(attributeTO.getSchema(), attrUtils.plainSchemaClass());
-
-                if (schema != null) {
-                    PlainAttr attr = attributable.getPlainAttr(schema.getKey());
-                    if (attr == null) {
-                        attr = attrUtils.newPlainAttr();
-                        setPlainAttrSchema(attributable, attr, schema);
-                    }
-                    if (attr.getSchema() == null) {
-                        LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
-                    } else {
-                        fillAttribute(attributeTO.getValues(), attrUtils, schema, attr, invalidValues);
-
-                        if (!attr.getValuesAsStrings().isEmpty()) {
-                            attributable.addPlainAttr(attr);
-                            attr.setOwner(attributable);
-                        }
-                    }
-                }
-            }
-        }
-
-        if (!invalidValues.isEmpty()) {
-            scce.addException(invalidValues);
-        }
-
-        // 2. derived attributes
-        for (AttrTO attributeTO : attributableTO.getDerAttrs()) {
-            DerSchema derSchema = getDerSchema(attributeTO.getSchema(), attrUtils.derSchemaClass());
-
-            if (derSchema != null) {
-                DerAttr derAttr = attrUtils.newDerAttr();
-                setDerAttrSchema(attributable, derAttr, derSchema);
-                if (derAttr.getSchema() == null) {
-                    LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
-                } else {
-                    derAttr.setOwner(attributable);
-                    attributable.addDerAttr(derAttr);
-                }
-            }
-        }
-
-        // 3. user and group virtual attributes will be evaluated by the propagation manager only (if needed).
-        if (AttributableType.USER == attrUtils.getType() || AttributableType.GROUP == attrUtils.getType()) {
-            for (AttrTO vattrTO : attributableTO.getVirAttrs()) {
-                VirSchema virSchema = virtAttrHander.getVirSchema(vattrTO.getSchema(), attrUtils.virSchemaClass());
-
-                if (virSchema != null) {
-                    VirAttr virAttr = attrUtils.newVirAttr();
-                    virtAttrHander.setVirAttrSchema(attributable, virAttr, virSchema);
-                    if (virAttr.getSchema() == null) {
-                        LOG.debug("Ignoring {} because no valid schema or template was found", vattrTO);
-                    } else {
-                        virAttr.setOwner(attributable);
-                        attributable.addVirAttr(virAttr);
-                    }
-                }
-            }
-        }
-
-        virtAttrHander.fillVirtual(attributable, attributableTO.getVirAttrs(), attrUtils);
-
-        // 4. realm & resources
-        if (attributable instanceof Subject && attributableTO instanceof AbstractSubjectTO) {
-            Realm realm = realmDAO.find(((AbstractSubjectTO) attributableTO).getRealm());
-            if (realm == null) {
-                SyncopeClientException noRealm = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
-                noRealm.getElements().add(
-                        "Invalid or null realm specified: " + ((AbstractSubjectTO) attributableTO).getRealm());
-                scce.addException(noRealm);
-            }
-            ((Subject<?, ?, ?>) attributable).setRealm(realm);
-
-            for (String resourceName : ((AbstractSubjectTO) attributableTO).getResources()) {
-                ExternalResource resource = resourceDAO.find(resourceName);
-
-                if (resource != null) {
-                    ((Subject<?, ?, ?>) attributable).addResource(resource);
-                }
-            }
-        }
-
-        SyncopeClientException requiredValuesMissing = checkMandatory(attrUtils, attributable);
-        if (!requiredValuesMissing.isEmpty()) {
-            scce.addException(requiredValuesMissing);
-        }
-
-        // Throw composite exception if there is at least one element set in the composing exceptions
-        if (scce.hasExceptions()) {
-            throw scce;
-        }
-    }
-
-    protected void fillTO(final AbstractAttributableTO attributableTO,
-            final String realmFullPath,
-            final Collection<? extends PlainAttr> attrs,
-            final Collection<? extends DerAttr> derAttrs,
-            final Collection<? extends VirAttr> virAttrs,
-            final Collection<? extends ExternalResource> resources) {
-
-        AttrTO attributeTO;
-        for (PlainAttr attr : attrs) {
-            attributeTO = new AttrTO();
-            attributeTO.setSchema(attr.getSchema().getKey());
-            attributeTO.getValues().addAll(attr.getValuesAsStrings());
-            attributeTO.setReadonly(attr.getSchema().isReadonly());
-
-            attributableTO.getPlainAttrs().add(attributeTO);
-        }
-
-        for (DerAttr derAttr : derAttrs) {
-            attributeTO = new AttrTO();
-            attributeTO.setSchema(derAttr.getSchema().getKey());
-            attributeTO.getValues().add(derAttr.getValue(attrs));
-            attributeTO.setReadonly(true);
-
-            attributableTO.getDerAttrs().add(attributeTO);
-        }
-
-        for (VirAttr virAttr : virAttrs) {
-            attributeTO = new AttrTO();
-            attributeTO.setSchema(virAttr.getSchema().getKey());
-            attributeTO.getValues().addAll(virAttr.getValues());
-            attributeTO.setReadonly(virAttr.getSchema().isReadonly());
-
-            attributableTO.getVirAttrs().add(attributeTO);
-        }
-
-        if (attributableTO instanceof AbstractSubjectTO) {
-            AbstractSubjectTO subjectTO = AbstractSubjectTO.class.cast(attributableTO);
-            subjectTO.setRealm(realmFullPath);
-            for (ExternalResource resource : resources) {
-                subjectTO.getResources().add(resource.getKey());
-            }
-        }
-    }
-
-    protected Map<String, String> getAccountIds(final Subject<?, ?, ?> subject, final AttributableType type) {
-        Map<String, String> accountIds = new HashMap<>();
-
-        Iterable<? extends ExternalResource> iterable = subject instanceof User
-                ? userDAO.findAllResources((User) subject)
-                : ((Group) subject).getResources();
-        for (ExternalResource resource : iterable) {
-            if ((type == AttributableType.USER && resource.getUmapping() != null)
-                    || (type == AttributableType.GROUP && resource.getGmapping() != null)) {
-
-                MappingItem accountIdItem = attrUtilsFactory.getInstance(type).getAccountIdItem(resource);
-                if (accountIdItem == null) {
-                    throw new NotFoundException(
-                            "AccountId mapping for " + type + " " + subject.getKey()
-                            + " on resource '" + resource.getKey() + "'");
-                }
-
-                accountIds.put(resource.getKey(), MappingUtils.getAccountIdValue(subject, resource, accountIdItem));
-            }
-        }
-
-        return accountIds;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
index 5e2dc1b..fe5668d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
@@ -18,26 +18,33 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
+import static org.apache.syncope.core.provisioning.java.data.AbstractAnyDataBinder.LOG;
+
 import org.apache.syncope.core.provisioning.api.data.ConfigurationDataBinder;
 import java.util.Collections;
+import java.util.List;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.ConfTO;
-import org.apache.syncope.common.lib.types.AttributableType;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
-import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+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.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
-import org.apache.syncope.core.persistence.api.entity.conf.CPlainSchema;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.springframework.stereotype.Component;
 
 @Component
-public class ConfigurationDataBinderImpl extends AbstractAttributableDataBinder implements ConfigurationDataBinder {
+public class ConfigurationDataBinderImpl extends AbstractAnyDataBinder implements ConfigurationDataBinder {
 
     @Override
     public ConfTO getConfTO(final Conf conf) {
-        final ConfTO confTO = new ConfTO();
+        ConfTO confTO = new ConfTO();
         confTO.setKey(conf.getKey());
 
         fillTO(confTO, null, conf.getPlainAttrs(),
@@ -48,7 +55,7 @@ public class ConfigurationDataBinderImpl extends AbstractAttributableDataBinder
 
     @Override
     public AttrTO getAttrTO(final CPlainAttr attr) {
-        final AttrTO attributeTO = new AttrTO();
+        AttrTO attributeTO = new AttrTO();
         attributeTO.setSchema(attr.getSchema().getKey());
         attributeTO.getValues().addAll(attr.getValuesAsStrings());
         attributeTO.setReadonly(attr.getSchema().isReadonly());
@@ -56,9 +63,43 @@ public class ConfigurationDataBinderImpl extends AbstractAttributableDataBinder
         return attributeTO;
     }
 
+    private void fillAttribute(final List<String> values,
+            final PlainSchema schema, final CPlainAttr attr, final SyncopeClientException invalidValues) {
+
+        // if schema is multivalue, all values are considered for addition;
+        // otherwise only the fist one - if provided - is considered
+        List<String> valuesProvided = schema.isMultivalue()
+                ? values
+                : (values.isEmpty()
+                        ? Collections.<String>emptyList()
+                        : Collections.singletonList(values.iterator().next()));
+
+        for (String value : valuesProvided) {
+            if (value == null || value.isEmpty()) {
+                LOG.debug("Null value for {}, ignoring", schema.getKey());
+            } else {
+                try {
+                    PlainAttrValue attrValue;
+                    if (schema.isUniqueConstraint()) {
+                        attrValue = entityFactory.newEntity(CPlainAttrUniqueValue.class);
+                        ((PlainAttrUniqueValue) attrValue).setSchema(schema);
+                    } else {
+                        attrValue = entityFactory.newEntity(CPlainAttrValue.class);
+                    }
+
+                    attr.add(value, attrValue);
+                } catch (InvalidPlainAttrValueException e) {
+                    LOG.warn("Invalid value for attribute " + schema.getKey() + ": " + value, e);
+
+                    invalidValues.getElements().add(schema.getKey() + ": " + value + " - " + e.getMessage());
+                }
+            }
+        }
+    }
+
     @Override
     public CPlainAttr getAttribute(final AttrTO attributeTO) {
-        CPlainSchema schema = getPlainSchema(attributeTO.getSchema(), CPlainSchema.class);
+        PlainSchema schema = getPlainSchema(attributeTO.getSchema());
         if (schema == null) {
             throw new NotFoundException("Conf schema " + attributeTO.getSchema());
         } else {
@@ -66,8 +107,7 @@ public class ConfigurationDataBinderImpl extends AbstractAttributableDataBinder
 
             CPlainAttr attr = entityFactory.newEntity(CPlainAttr.class);
             attr.setSchema(schema);
-            fillAttribute(attributeTO.getValues(), attrUtilsFactory.getInstance(AttributableType.CONFIGURATION),
-                    schema, attr, invalidValues);
+            fillAttribute(attributeTO.getValues(), schema, attr, invalidValues);
 
             if (!invalidValues.isEmpty()) {
                 throw invalidValues;

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/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 efe7771..17370e6 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
@@ -18,30 +18,14 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.mod.GroupMod;
 import org.apache.syncope.common.lib.to.GroupTO;
-import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.ResourceOperation;
-import org.apache.syncope.core.persistence.api.entity.AttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.Schema;
-import org.apache.syncope.core.persistence.api.entity.membership.MDerAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.membership.MDerSchema;
-import org.apache.syncope.core.persistence.api.entity.membership.MPlainAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.membership.MPlainSchema;
-import org.apache.syncope.core.persistence.api.entity.membership.MVirAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.membership.MVirSchema;
-import org.apache.syncope.core.persistence.api.entity.group.GDerAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.group.GDerSchema;
-import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.group.GPlainSchema;
-import org.apache.syncope.core.persistence.api.entity.group.GVirAttrTemplate;
-import org.apache.syncope.core.persistence.api.entity.group.GVirSchema;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.common.lib.types.PropagationByResource;
@@ -50,47 +34,20 @@ import org.apache.syncope.core.misc.ConnObjectUtils;
 import org.apache.syncope.core.misc.search.SearchCondConverter;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.DynGroupMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
+import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
 @Component
 @Transactional(rollbackFor = { Throwable.class })
-public class GroupDataBinderImpl extends AbstractAttributableDataBinder implements GroupDataBinder {
+public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupDataBinder {
 
     @Autowired
     private ConnObjectUtils connObjectUtils;
 
-    private <T extends AttrTemplate<S>, S extends Schema> void setAttrTemplates(
-            final Group group, final List<String> schemaNames,
-            final Class<T> templateClass, final Class<S> schemaClass) {
-
-        List<T> toRemove = new ArrayList<>();
-        for (T template : group.getAttrTemplates(templateClass)) {
-            if (!schemaNames.contains(template.getSchema().getKey())) {
-                toRemove.add(template);
-            }
-        }
-        group.getAttrTemplates(templateClass).removeAll(toRemove);
-
-        for (String schemaName : schemaNames) {
-            if (group.getAttrTemplate(templateClass, schemaName) == null) {
-                S schema = getSchema(schemaName, schemaClass);
-                if (schema != null) {
-                    try {
-                        T template = entityFactory.newEntity(templateClass);
-                        template.setSchema(schema);
-                        template.setOwner(group);
-                        group.getAttrTemplates(templateClass).add(template);
-                    } catch (Exception e) {
-                        LOG.error("Could not create template for {}", templateClass, e);
-                    }
-                }
-            }
-        }
-    }
-
-    private void setDynMembership(final Group group, final String dynMembershipFIQL) {
+    private void setDynMembership(final Group group, final AnyTypeKind anyTypeKind, final String dynMembershipFIQL) {
         SearchCond dynMembershipCond = SearchCondConverter.convert(dynMembershipFIQL);
         if (!dynMembershipCond.isValid()) {
             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSearchExpression);
@@ -98,13 +55,19 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
             throw sce;
         }
 
-        DynGroupMembership dynMembership;
-        if (group.getDynMembership() == null) {
-            dynMembership = entityFactory.newEntity(DynGroupMembership.class);
+        DynGroupMembership<?> dynMembership;
+        if (anyTypeKind == AnyTypeKind.ANY_OBJECT && group.getADynMembership() == null) {
+            dynMembership = entityFactory.newEntity(ADynGroupMembership.class);
             dynMembership.setGroup(group);
-            group.setDynMembership(dynMembership);
+            group.setADynMembership((ADynGroupMembership) dynMembership);
+        } else if (anyTypeKind == AnyTypeKind.USER && group.getUDynMembership() == null) {
+            dynMembership = entityFactory.newEntity(UDynGroupMembership.class);
+            dynMembership.setGroup(group);
+            group.setUDynMembership((UDynGroupMembership) dynMembership);
         } else {
-            dynMembership = group.getDynMembership();
+            dynMembership = anyTypeKind == AnyTypeKind.ANY_OBJECT
+                    ? group.getADynMembership()
+                    : group.getUDynMembership();
         }
         dynMembership.setFIQLCond(dynMembershipFIQL);
     }
@@ -123,16 +86,8 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
             group.setName(groupTO.getName());
         }
 
-        // attribute templates
-        setAttrTemplates(group, groupTO.getGPlainAttrTemplates(), GPlainAttrTemplate.class, GPlainSchema.class);
-        setAttrTemplates(group, groupTO.getGDerAttrTemplates(), GDerAttrTemplate.class, GDerSchema.class);
-        setAttrTemplates(group, groupTO.getGVirAttrTemplates(), GVirAttrTemplate.class, GVirSchema.class);
-        setAttrTemplates(group, groupTO.getMPlainAttrTemplates(), MPlainAttrTemplate.class, MPlainSchema.class);
-        setAttrTemplates(group, groupTO.getMDerAttrTemplates(), MDerAttrTemplate.class, MDerSchema.class);
-        setAttrTemplates(group, groupTO.getMVirAttrTemplates(), MVirAttrTemplate.class, MVirSchema.class);
-
         // attributes, derived attributes, virtual attributes and resources
-        fill(group, groupTO, attrUtilsFactory.getInstance(AttributableType.GROUP), scce);
+        fill(group, groupTO, anyUtilsFactory.getInstance(AnyTypeKind.GROUP), scce);
 
         // owner
         if (groupTO.getUserOwner() != null) {
@@ -152,8 +107,11 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
             }
         }
 
-        if (groupTO.getDynMembershipCond() != null) {
-            setDynMembership(group, groupTO.getDynMembershipCond());
+        if (groupTO.getADynMembershipCond() != null) {
+            setDynMembership(group, AnyTypeKind.ANY_OBJECT, groupTO.getADynMembershipCond());
+        }
+        if (groupTO.getADynMembershipCond() != null) {
+            setDynMembership(group, AnyTypeKind.USER, groupTO.getUDynMembershipCond());
         }
 
         return group;
@@ -169,7 +127,7 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
 
         // fetch account ids before update
-        Map<String, String> oldAccountIds = getAccountIds(group, AttributableType.GROUP);
+        Map<String, String> oldConnObjectKeys = getConnObjectKeys(group);
 
         // realm
         setRealm(group, groupMod);
@@ -180,26 +138,6 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
             group.setName(groupMod.getName());
         }
 
-        // attribute templates
-        if (groupMod.isModGAttrTemplates()) {
-            setAttrTemplates(group, groupMod.getGPlainAttrTemplates(), GPlainAttrTemplate.class, GPlainSchema.class);
-        }
-        if (groupMod.isModGDerAttrTemplates()) {
-            setAttrTemplates(group, groupMod.getGDerAttrTemplates(), GDerAttrTemplate.class, GDerSchema.class);
-        }
-        if (groupMod.isModGVirAttrTemplates()) {
-            setAttrTemplates(group, groupMod.getGVirAttrTemplates(), GVirAttrTemplate.class, GVirSchema.class);
-        }
-        if (groupMod.isModMAttrTemplates()) {
-            setAttrTemplates(group, groupMod.getMPlainAttrTemplates(), MPlainAttrTemplate.class, MPlainSchema.class);
-        }
-        if (groupMod.isModMDerAttrTemplates()) {
-            setAttrTemplates(group, groupMod.getMDerAttrTemplates(), MDerAttrTemplate.class, MDerSchema.class);
-        }
-        if (groupMod.isModMVirAttrTemplates()) {
-            setAttrTemplates(group, groupMod.getMVirAttrTemplates(), MVirAttrTemplate.class, MVirSchema.class);
-        }
-
         // owner
         if (groupMod.getUserOwner() != null) {
             group.setUserOwner(groupMod.getUserOwner().getKey() == null
@@ -213,13 +151,13 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
         }
 
         // attributes, derived attributes, virtual attributes and resources
-        propByRes.merge(fill(group, groupMod, attrUtilsFactory.getInstance(AttributableType.GROUP), scce));
+        propByRes.merge(fill(group, groupMod, anyUtilsFactory.getInstance(AnyTypeKind.GROUP), scce));
 
         // check if some account id was changed by the update above
-        Map<String, String> newAccountIds = getAccountIds(group, AttributableType.GROUP);
-        for (Map.Entry<String, String> entry : oldAccountIds.entrySet()) {
-            if (newAccountIds.containsKey(entry.getKey())
-                    && !entry.getValue().equals(newAccountIds.get(entry.getKey()))) {
+        Map<String, String> newConnObjectKeys = getConnObjectKeys(group);
+        for (Map.Entry<String, String> entry : oldConnObjectKeys.entrySet()) {
+            if (newConnObjectKeys.containsKey(entry.getKey())
+                    && !entry.getValue().equals(newConnObjectKeys.get(entry.getKey()))) {
 
                 propByRes.addOldAccountId(entry.getKey(), entry.getValue());
                 propByRes.add(ResourceOperation.UPDATE, entry.getKey());
@@ -227,15 +165,25 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
         }
 
         // dynamic membership
-        if (group.getDynMembership() != null && groupMod.getDynMembershipCond() == null) {
-            group.setDynMembership(null);
-        } else if (group.getDynMembership() == null && groupMod.getDynMembershipCond() != null) {
-            setDynMembership(group, groupMod.getDynMembershipCond());
-        } else if (group.getDynMembership() != null && groupMod.getDynMembershipCond() != null
-                && !group.getDynMembership().getFIQLCond().equals(groupMod.getDynMembershipCond())) {
-
-            group.getDynMembership().getUsers().clear();
-            setDynMembership(group, groupMod.getDynMembershipCond());
+        if (group.getADynMembership() != null && groupMod.getADynMembershipCond() == null) {
+            group.setADynMembership(null);
+        } else if (group.getADynMembership() == null && groupMod.getADynMembershipCond() != null) {
+            setDynMembership(group, AnyTypeKind.ANY_OBJECT, groupMod.getADynMembershipCond());
+        } else if (group.getADynMembership() != null && groupMod.getADynMembershipCond() != null
+                && !group.getADynMembership().getFIQLCond().equals(groupMod.getADynMembershipCond())) {
+
+            group.getADynMembership().getMembers().clear();
+            setDynMembership(group, AnyTypeKind.ANY_OBJECT, groupMod.getADynMembershipCond());
+        }
+        if (group.getUDynMembership() != null && groupMod.getUDynMembershipCond() == null) {
+            group.setUDynMembership(null);
+        } else if (group.getUDynMembership() == null && groupMod.getUDynMembershipCond() != null) {
+            setDynMembership(group, AnyTypeKind.USER, groupMod.getUDynMembershipCond());
+        } else if (group.getUDynMembership() != null && groupMod.getUDynMembershipCond() != null
+                && !group.getUDynMembership().getFIQLCond().equals(groupMod.getUDynMembershipCond())) {
+
+            group.getUDynMembership().getMembers().clear();
+            setDynMembership(group, AnyTypeKind.USER, groupMod.getUDynMembershipCond());
         }
 
         return propByRes;
@@ -245,7 +193,7 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
     @Transactional(readOnly = true)
     @Override
     public GroupTO getGroupTO(final Group group) {
-        connObjectUtils.retrieveVirAttrValues(group, attrUtilsFactory.getInstance(AttributableType.GROUP));
+        connObjectUtils.retrieveVirAttrValues(group);
 
         GroupTO groupTO = new GroupTO();
 
@@ -268,27 +216,11 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
         fillTO(groupTO, group.getRealm().getFullPath(),
                 group.getPlainAttrs(), group.getDerAttrs(), group.getVirAttrs(), group.getResources());
 
-        for (GPlainAttrTemplate template : group.getAttrTemplates(GPlainAttrTemplate.class)) {
-            groupTO.getGPlainAttrTemplates().add(template.getSchema().getKey());
+        if (group.getADynMembership() != null) {
+            groupTO.setADynMembershipCond(group.getADynMembership().getFIQLCond());
         }
-        for (GDerAttrTemplate template : group.getAttrTemplates(GDerAttrTemplate.class)) {
-            groupTO.getGDerAttrTemplates().add(template.getSchema().getKey());
-        }
-        for (GVirAttrTemplate template : group.getAttrTemplates(GVirAttrTemplate.class)) {
-            groupTO.getGVirAttrTemplates().add(template.getSchema().getKey());
-        }
-        for (MPlainAttrTemplate template : group.getAttrTemplates(MPlainAttrTemplate.class)) {
-            groupTO.getMPlainAttrTemplates().add(template.getSchema().getKey());
-        }
-        for (MDerAttrTemplate template : group.getAttrTemplates(MDerAttrTemplate.class)) {
-            groupTO.getMDerAttrTemplates().add(template.getSchema().getKey());
-        }
-        for (MVirAttrTemplate template : group.getAttrTemplates(MVirAttrTemplate.class)) {
-            groupTO.getMVirAttrTemplates().add(template.getSchema().getKey());
-        }
-
-        if (group.getDynMembership() != null) {
-            groupTO.setDynMembershipCond(group.getDynMembership().getFIQLCond());
+        if (group.getUDynMembership() != null) {
+            groupTO.setUDynMembershipCond(group.getUDynMembership().getFIQLCond());
         }
 
         return groupTO;
@@ -297,6 +229,6 @@ public class GroupDataBinderImpl extends AbstractAttributableDataBinder implemen
     @Transactional(readOnly = true)
     @Override
     public GroupTO getGroupTO(final Long key) {
-        return getGroupTO(groupDAO.authFetch(key));
+        return getGroupTO(groupDAO.authFind(key));
     }
 }


Mime
View raw message