You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/02/12 10:14:26 UTC

[21/54] [abbrv] [partial] syncope git commit: [SYNCOPE-620] Renaming 'server' after 'core', to provide continuity with older releases (especially for archetype)

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java
new file mode 100644
index 0000000..6f0e38e
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandler.java
@@ -0,0 +1,308 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+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.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.AttributableUtil;
+import org.apache.syncope.core.persistence.api.entity.AttributableUtilFactory;
+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.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.MVirAttr;
+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.role.RVirAttr;
+import org.apache.syncope.core.persistence.api.entity.role.RVirAttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.role.Role;
+import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UVirSchema;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+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 VirAttrHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(VirAttrHandler.class);
+
+    @Autowired
+    private ExternalResourceDAO resourceDAO;
+
+    @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
+    @Autowired
+    private VirAttrDAO virAttrDAO;
+
+    @Autowired
+    private UserDAO userDAO;
+
+    @Autowired
+    private MembershipDAO membershipDAO;
+
+    @Autowired
+    private AttributableUtilFactory attrUtilFactory;
+
+    public <T extends VirSchema> T getVirSchema(final String virSchemaName, final Class<T> reference) {
+        T virtualSchema = null;
+        if (StringUtils.isNotBlank(virSchemaName)) {
+            virtualSchema = virSchemaDAO.find(virSchemaName, reference);
+
+            if (virtualSchema == null) {
+                LOG.debug("Ignoring invalid virtual schema {}", virSchemaName);
+            }
+        }
+
+        return virtualSchema;
+    }
+
+    public void setVirAttrSchema(final Attributable<?, ?, ?> attributable,
+            final VirAttr virAttr, final VirSchema virSchema) {
+
+        if (virAttr instanceof UVirAttr) {
+            ((UVirAttr) virAttr).setSchema((UVirSchema) virSchema);
+        } else if (virAttr instanceof RVirAttr) {
+            RVirAttrTemplate template = ((Role) attributable).
+                    getAttrTemplate(RVirAttrTemplate.class, virSchema.getKey());
+            if (template != null) {
+                ((RVirAttr) virAttr).setTemplate(template);
+            }
+        } else if (virAttr instanceof MVirAttr) {
+            MVirAttrTemplate template =
+                    ((Membership) attributable).getRole().
+                    getAttrTemplate(MVirAttrTemplate.class, virSchema.getKey());
+            if (template != null) {
+                ((MVirAttr) virAttr).setTemplate(template);
+            }
+        }
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public PropagationByResource fillVirtual(final Attributable attributable,
+            final Set<String> vAttrsToBeRemoved, final Set<AttrMod> vAttrsToBeUpdated,
+            final AttributableUtil attrUtil) {
+
+        PropagationByResource propByRes = new PropagationByResource();
+
+        final Set<ExternalResource> externalResources = new HashSet<>();
+        if (attributable instanceof Subject) {
+            externalResources.addAll(((Subject<?, ?, ?>) attributable).getResources());
+        }
+
+        if (attributable instanceof Membership) {
+            externalResources.clear();
+            externalResources.addAll(((Membership) attributable).getUser().getResources());
+        }
+
+        // 1. virtual attributes to be removed
+        for (String vAttrToBeRemoved : vAttrsToBeRemoved) {
+            VirSchema virSchema = getVirSchema(vAttrToBeRemoved, attrUtil.virSchemaClass());
+            if (virSchema != null) {
+                VirAttr virAttr = attributable.getVirAttr(virSchema.getKey());
+                if (virAttr == null) {
+                    LOG.debug("No virtual attribute found for schema {}", virSchema.getKey());
+                } else {
+                    attributable.removeVirAttr(virAttr);
+                    virAttrDAO.delete(virAttr);
+                }
+
+                for (ExternalResource resource : resourceDAO.findAll()) {
+                    for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+                        if (virSchema.getKey().equals(mapItem.getIntAttrName())
+                                && mapItem.getIntMappingType() == attrUtil.virIntMappingType()
+                                && externalResources.contains(resource)) {
+
+                            propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+                            // Using virtual attribute as AccountId must be avoided
+                            if (mapItem.isAccountid() && virAttr != null && !virAttr.getValues().isEmpty()) {
+                                propByRes.addOldAccountId(resource.getKey(), virAttr.getValues().get(0));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        LOG.debug("Virtual attributes to be removed:\n{}", propByRes);
+
+        // 2. virtual attributes to be updated
+        for (AttrMod vAttrToBeUpdated : vAttrsToBeUpdated) {
+            VirSchema virSchema = getVirSchema(vAttrToBeUpdated.getSchema(), attrUtil.virSchemaClass());
+            VirAttr virAttr = null;
+            if (virSchema != null) {
+                virAttr = attributable.getVirAttr(virSchema.getKey());
+                if (virAttr == null) {
+                    virAttr = attrUtil.newVirAttr();
+                    setVirAttrSchema(attributable, virAttr, virSchema);
+                    if (virAttr.getSchema() == null) {
+                        LOG.debug("Ignoring {} because no valid schema or template was found", vAttrToBeUpdated);
+                    } else {
+                        attributable.addVirAttr(virAttr);
+                    }
+                }
+            }
+
+            if (virSchema != null && virAttr != null && virAttr.getSchema() != null) {
+                for (ExternalResource resource : resourceDAO.findAll()) {
+                    for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+                        if (virSchema.getKey().equals(mapItem.getIntAttrName())
+                                && mapItem.getIntMappingType() == attrUtil.virIntMappingType()
+                                && externalResources.contains(resource)) {
+
+                            propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                        }
+                    }
+                }
+
+                final List<String> values = new ArrayList<>(virAttr.getValues());
+                values.removeAll(vAttrToBeUpdated.getValuesToBeRemoved());
+                values.addAll(vAttrToBeUpdated.getValuesToBeAdded());
+
+                virAttr.getValues().clear();
+                virAttr.getValues().addAll(values);
+
+                // Owner cannot be specified before otherwise a virtual attribute remove will be invalidated.
+                virAttr.setOwner(attributable);
+            }
+        }
+
+        LOG.debug("Virtual attributes to be added:\n{}", propByRes);
+
+        return propByRes;
+    }
+
+    /**
+     * Add virtual attributes and specify values to be propagated.
+     *
+     * @param attributable attributable.
+     * @param vAttrs virtual attributes to be added.
+     * @param attrUtil attributable util.
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void fillVirtual(final Attributable attributable, final Collection<AttrTO> vAttrs,
+            final AttributableUtil attrUtil) {
+
+        for (AttrTO attributeTO : vAttrs) {
+            VirAttr virAttr = attributable.getVirAttr(attributeTO.getSchema());
+            if (virAttr == null) {
+                VirSchema virSchema = getVirSchema(attributeTO.getSchema(), attrUtil.virSchemaClass());
+                if (virSchema != null) {
+                    virAttr = attrUtil.newVirAttr();
+                    setVirAttrSchema(attributable, virAttr, virSchema);
+                    if (virAttr.getSchema() == null) {
+                        LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
+                    } else {
+                        virAttr.setOwner(attributable);
+                        attributable.addVirAttr(virAttr);
+                        virAttr.getValues().clear();
+                        virAttr.getValues().addAll(attributeTO.getValues());
+                    }
+                }
+            } else {
+                virAttr.getValues().clear();
+                virAttr.getValues().addAll(attributeTO.getValues());
+            }
+        }
+    }
+
+    /**
+     * SYNCOPE-459: build virtual attribute changes in case no other changes were made.
+     *
+     * @param key user id
+     * @param vAttrsToBeRemoved virtual attributes to be removed.
+     * @param vAttrsToBeUpdated virtual attributes to be updated.
+     * @return operations to be performed on external resources for virtual attributes changes
+     */
+    public PropagationByResource fillVirtual(
+            final Long key, final Set<String> vAttrsToBeRemoved, final Set<AttrMod> vAttrsToBeUpdated) {
+
+        return fillVirtual(
+                userDAO.authFetch(key),
+                vAttrsToBeRemoved,
+                vAttrsToBeUpdated,
+                attrUtilFactory.getInstance(AttributableType.USER));
+    }
+
+    /**
+     * SYNCOPE-501: build membership virtual attribute changes in case no other changes were made.
+     *
+     * @param key user key
+     * @param roleKey role key
+     * @param membershipKey membership key
+     * @param vAttrsToBeRemoved virtual attributes to be removed.
+     * @param vAttrsToBeUpdated virtual attributes to be updated.
+     * @param isRemoval flag to check if fill is on removed or added membership
+     * @return operations to be performed on external resources for membership virtual attributes changes
+     */
+    public PropagationByResource fillMembershipVirtual(
+            final Long key, final Long roleKey, final Long membershipKey, final Set<String> vAttrsToBeRemoved,
+            final Set<AttrMod> vAttrsToBeUpdated, final boolean isRemoval) {
+
+        final Membership membership = membershipKey == null
+                ? userDAO.authFetch(key).getMembership(roleKey)
+                : membershipDAO.authFetch(membershipKey);
+
+        return membership == null ? new PropagationByResource() : isRemoval
+                ? fillVirtual(
+                        membership,
+                        membership.getVirAttrs() == null
+                                ? Collections.<String>emptySet()
+                                : getAttrNames(membership.getVirAttrs()),
+                        vAttrsToBeUpdated,
+                        attrUtilFactory.getInstance(AttributableType.MEMBERSHIP))
+                : fillVirtual(
+                        membership,
+                        vAttrsToBeRemoved,
+                        vAttrsToBeUpdated,
+                        attrUtilFactory.getInstance(AttributableType.MEMBERSHIP));
+    }
+
+    private Set<String> getAttrNames(final List<? extends VirAttr> virAttrs) {
+        final Set<String> virAttrNames = new HashSet<>();
+        for (VirAttr attr : virAttrs) {
+            virAttrNames.add(attr.getSchema().getKey());
+        }
+        return virAttrNames;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/cache/DisabledVirAttrCache.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/cache/DisabledVirAttrCache.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/cache/DisabledVirAttrCache.java
new file mode 100644
index 0000000..d1e0dda
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/cache/DisabledVirAttrCache.java
@@ -0,0 +1,52 @@
+/*
+ * 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.cache;
+
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
+
+/**
+ * Empty virtual attribute value cache implementation.
+ */
+public class DisabledVirAttrCache implements VirAttrCache {
+
+    @Override
+    public void expire(final AttributableType type, final Long id, final String schemaName) {
+        // nothing to do
+    }
+
+    @Override
+    public VirAttrCacheValue get(final AttributableType type, final Long id, final String schemaName) {
+        return null;
+    }
+
+    @Override
+    public boolean isValidEntry(VirAttrCacheValue value) {
+        return false;
+    }
+
+    @Override
+    public void put(
+            final AttributableType type, final Long id, final String schemaName, final VirAttrCacheValue value) {
+
+        // nothing to do
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/cache/MemoryVirAttrCache.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/cache/MemoryVirAttrCache.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/cache/MemoryVirAttrCache.java
new file mode 100644
index 0000000..d746ae4
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/cache/MemoryVirAttrCache.java
@@ -0,0 +1,151 @@
+/*
+ * 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.cache;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheKey;
+import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
+
+/**
+ * In-memory (HashMap) virtual attribute value cache implementation.
+ */
+public class MemoryVirAttrCache implements VirAttrCache {
+
+    /**
+     * Elapsed time in seconds.
+     */
+    protected int ttl;
+
+    /**
+     * Max cache size.
+     */
+    protected int maxCacheSize;
+
+    /**
+     * Cache entries.
+     */
+    protected final Map<VirAttrCacheKey, VirAttrCacheValue> cache = new HashMap<VirAttrCacheKey, VirAttrCacheValue>();
+
+    public MemoryVirAttrCache(final int ttl, final int maxCacheSize) {
+        this.ttl = ttl;
+        this.maxCacheSize = maxCacheSize;
+    }
+
+    /**
+     * Cache virtual attribute values.
+     *
+     * @param type user or role
+     * @param key user or role id
+     * @param schemaName virtual attribute name
+     * @param value virtual attribute values
+     */
+    @Override
+    public void put(
+            final AttributableType type,
+            final Long key,
+            final String schemaName,
+            final VirAttrCacheValue value) {
+
+        synchronized (cache) {
+            // this operations (retrieve cache space and put entry on) have to be thread safe.
+            if (this.cache.size() >= this.maxCacheSize) {
+                free();
+            }
+
+            cache.put(new VirAttrCacheKey(type, key, schemaName), value);
+        }
+    }
+
+    /**
+     * Retrieve cached value. Return null in case of virtual attribute not cached.
+     *
+     * @param type user or role
+     * @param id user or role id
+     * @param schemaName virtual attribute schema name.
+     * @return cached values or null if virtual attribute is not cached.
+     */
+    @Override
+    public VirAttrCacheValue get(final AttributableType type, final Long id, final String schemaName) {
+        return cache.get(new VirAttrCacheKey(type, id, schemaName));
+    }
+
+    /**
+     * Force entry expiring.
+     *
+     * @param type user or role
+     * @param id user or role id
+     * @param schemaName virtual attribute schema name
+     */
+    @Override
+    public void expire(final AttributableType type, final Long id, final String schemaName) {
+        final VirAttrCacheValue value = cache.get(new VirAttrCacheKey(type, id, schemaName));
+        if (isValidEntry(value)) {
+            synchronized (cache) {
+                value.forceExpiring();
+            }
+        }
+    }
+
+    /**
+     * Remove expired entries if exist. If required, one entry at least (the latest recently used) will be taken off.
+     * This method is not thread safe: the caller have to take care to synchronize the call.
+     */
+    private void free() {
+        final Set<VirAttrCacheKey> toBeRemoved = new HashSet<VirAttrCacheKey>();
+
+        Map.Entry<VirAttrCacheKey, VirAttrCacheValue> latest = null;
+
+        for (Map.Entry<VirAttrCacheKey, VirAttrCacheValue> entry : cache.entrySet()) {
+            if (isValidEntry(entry.getValue())) {
+                final Date date = entry.getValue().getLastAccessDate();
+                if (latest == null || latest.getValue().getLastAccessDate().after(date)) {
+                    latest = entry;
+                }
+            } else {
+                toBeRemoved.add(entry.getKey());
+            }
+        }
+
+        if (toBeRemoved.isEmpty() && latest != null) {
+            // remove the oldest entry
+            cache.remove(latest.getKey());
+        } else {
+            // remove expired entries
+            cache.keySet().removeAll(toBeRemoved);
+        }
+    }
+
+    /**
+     * Cache entry is valid if and only if value exist and it is not expired.
+     *
+     * @param value cache entry value.
+     * @return TRUE if the value is valid; FALSE otherwise.
+     */
+    @Override
+    public boolean isValidEntry(final VirAttrCacheValue value) {
+        final Date expiringDate = new Date(value == null ? 0 : value.getCreationDate().getTime() + ttl * 1000);
+        return expiringDate.after(new Date());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
new file mode 100644
index 0000000..fb8d8d4
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAttributableDataBinder.java
@@ -0,0 +1,779 @@
+/*
+ * 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.RoleDAO;
+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.AttributableUtil;
+import org.apache.syncope.core.persistence.api.entity.AttributableUtilFactory;
+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.role.RDerAttr;
+import org.apache.syncope.core.persistence.api.entity.role.RDerAttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.role.RPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.role.RPlainAttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.role.RVirAttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.role.Role;
+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.MappingUtil;
+import org.apache.syncope.core.misc.jexl.JexlUtil;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+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 RoleDAO roleDAO;
+
+    @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 AttributableUtilFactory attrUtilFactory;
+
+    @Autowired
+    protected VirAttrHandler virtAttrHander;
+
+    @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
+            // see http://code.google.com/p/syncope/issues/detail?id=17
+            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 AttributableUtil 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 AttributableUtil attrUtil, final ExternalResource resource,
+            final Attributable<?, ?, ?> attributable, final String intAttrName, final IntMappingType intMappingType) {
+
+        boolean result = false;
+
+        final List<MappingItem> mappings = MappingUtil.getMatchingMappingItems(
+                attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION), intAttrName, intMappingType);
+        for (Iterator<MappingItem> itor = mappings.iterator(); itor.hasNext() && !result;) {
+            final MappingItem mapping = itor.next();
+            result |= JexlUtil.evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributable);
+        }
+
+        return result;
+    }
+
+    private boolean evaluateMandatoryCondition(final AttributableUtil attrUtil,
+            final Attributable<?, ?, ?> attributable, final String intAttrName, final IntMappingType intMappingType) {
+
+        boolean result = false;
+
+        if (attributable instanceof Subject) {
+            for (Iterator<? extends ExternalResource> itor = ((Subject<?, ?, ?>) attributable).getResources().iterator();
+                    itor.hasNext() && !result;) {
+
+                final ExternalResource resource = itor.next();
+                if (resource.isEnforceMandatoryCondition()) {
+                    result |= evaluateMandatoryCondition(attrUtil, resource, attributable, intAttrName, intMappingType);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    private SyncopeClientException checkMandatory(final AttributableUtil attrUtil,
+            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 (attrUtil.getType()) {
+            case ROLE:
+                plainSchemas = ((Role) attributable).getAttrTemplateSchemas(RPlainAttrTemplate.class);
+                break;
+
+            case MEMBERSHIP:
+                plainSchemas = ((Membership) attributable).getRole().getAttrTemplateSchemas(MPlainAttrTemplate.class);
+                break;
+
+            case USER:
+            default:
+                plainSchemas = plainSchemaDAO.findAll(attrUtil.plainSchemaClass());
+        }
+        for (PlainSchema schema : plainSchemas) {
+            if (attributable.getPlainAttr(schema.getKey()) == null
+                    && !schema.isReadonly()
+                    && (JexlUtil.evaluateMandatoryCondition(schema.getMandatoryCondition(), attributable)
+                    || evaluateMandatoryCondition(attrUtil, attributable, schema.getKey(),
+                            attrUtil.intMappingType()))) {
+
+                LOG.error("Mandatory schema " + schema.getKey() + " not provided with values");
+
+                reqValMissing.getElements().add(schema.getKey());
+            }
+        }
+
+        List<? extends DerSchema> derSchemas;
+        switch (attrUtil.getType()) {
+            case ROLE:
+                derSchemas = ((Role) attributable).getAttrTemplateSchemas(RDerAttrTemplate.class);
+                break;
+
+            case MEMBERSHIP:
+                derSchemas = ((Membership) attributable).getRole().getAttrTemplateSchemas(MDerAttrTemplate.class);
+                break;
+
+            case USER:
+            default:
+                derSchemas = derSchemaDAO.findAll(attrUtil.derSchemaClass());
+        }
+        for (DerSchema derSchema : derSchemas) {
+            if (attributable.getDerAttr(derSchema.getKey()) == null
+                    && evaluateMandatoryCondition(attrUtil, attributable, derSchema.getKey(),
+                            attrUtil.derIntMappingType())) {
+
+                LOG.error("Mandatory derived schema " + derSchema.getKey() + " does not evaluate to any value");
+
+                reqValMissing.getElements().add(derSchema.getKey());
+            }
+        }
+
+        List<? extends VirSchema> virSchemas;
+        switch (attrUtil.getType()) {
+            case ROLE:
+                virSchemas = ((Role) attributable).getAttrTemplateSchemas(RVirAttrTemplate.class);
+                break;
+
+            case MEMBERSHIP:
+                virSchemas = ((Membership) attributable).getRole().getAttrTemplateSchemas(MVirAttrTemplate.class);
+                break;
+
+            case USER:
+            default:
+                virSchemas = virSchemaDAO.findAll(attrUtil.virSchemaClass());
+        }
+        for (VirSchema virSchema : virSchemas) {
+            if (attributable.getVirAttr(virSchema.getKey()) == null
+                    && !virSchema.isReadonly()
+                    && evaluateMandatoryCondition(attrUtil, attributable, virSchema.getKey(),
+                            attrUtil.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 RPlainAttr) {
+            RPlainAttrTemplate template =
+                    ((Role) attributable).getAttrTemplate(RPlainAttrTemplate.class, schema.getKey());
+            if (template != null) {
+                ((RPlainAttr) attr).setTemplate(template);
+            }
+        } else if (attr instanceof MPlainAttr) {
+            MPlainAttrTemplate template = ((Membership) attributable).getRole().
+                    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 RDerAttr) {
+            RDerAttrTemplate template = ((Role) attributable).
+                    getAttrTemplate(RDerAttrTemplate.class, derSchema.getKey());
+            if (template != null) {
+                ((RDerAttr) derAttr).setTemplate(template);
+            }
+        } else if (derAttr instanceof MDerAttr) {
+            MDerAttrTemplate template = ((Membership) attributable).getRole().
+                    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 AttributableUtil attrUtil,
+            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);
+        }
+
+        // 3. attributes to be removed
+        for (String attributeToBeRemoved : attributableMod.getPlainAttrsToRemove()) {
+            PlainSchema schema = getPlainSchema(attributeToBeRemoved, attrUtil.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(), attrUtil.plainAttrClass());
+                    }
+                }
+
+                if (attributable instanceof Subject) {
+                    for (ExternalResource resource : resourceDAO.findAll()) {
+                        for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+                            if (schema.getKey().equals(mapItem.getIntAttrName())
+                                    && mapItem.getIntMappingType() == attrUtil.intMappingType()
+                                    && ((Subject<?, ?, ?>) attributable).getResources().contains(resource)) {
+
+                                propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+                                if (mapItem.isAccountid() && attr != null
+                                        && !attr.getValuesAsStrings().isEmpty()) {
+
+                                    propByRes.addOldAccountId(resource.getKey(),
+                                            attr.getValuesAsStrings().iterator().next());
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        LOG.debug("Attributes to be removed:\n{}", propByRes);
+
+        // 4. attributes to be updated
+        for (AttrMod attributeMod : attributableMod.getPlainAttrsToUpdate()) {
+            PlainSchema schema = getPlainSchema(attributeMod.getSchema(), attrUtil.plainSchemaClass());
+            PlainAttr attr = null;
+            if (schema != null) {
+                attr = attributable.getPlainAttr(schema.getKey());
+                if (attr == null) {
+                    attr = attrUtil.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) {
+                    for (ExternalResource resource : resourceDAO.findAll()) {
+                        for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+                            if (schema.getKey().equals(mapItem.getIntAttrName())
+                                    && mapItem.getIntMappingType() == attrUtil.intMappingType()
+                                    && ((Subject<?, ?, ?>) attributable).getResources().contains(resource)) {
+
+                                propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                            }
+                        }
+                    }
+                }
+
+                // 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, attrUtil.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(), attrUtil, 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, attrUtil.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 : resourceDAO.findAll()) {
+                        for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+                            if (derSchema.getKey().equals(mapItem.getIntAttrName())
+                                    && mapItem.getIntMappingType() == attrUtil.derIntMappingType()
+                                    && ((Subject<?, ?, ?>) attributable).getResources().contains(resource)) {
+
+                                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, attrUtil.derSchemaClass());
+            if (derSchema != null) {
+                if (attributable instanceof Subject) {
+                    for (ExternalResource resource : resourceDAO.findAll()) {
+                        for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+                            if (derSchema.getKey().equals(mapItem.getIntAttrName())
+                                    && mapItem.getIntMappingType() == attrUtil.derIntMappingType()
+                                    && ((Subject<?, ?, ?>) attributable).getResources().contains(resource)) {
+
+                                propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+                            }
+                        }
+                    }
+                }
+
+                DerAttr derAttr = attrUtil.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 roles this is delegated to PropagationManager
+        if (AttributableType.USER != attrUtil.getType() && AttributableType.ROLE != attrUtil.getType()) {
+            virtAttrHander.fillVirtual(attributable, attributableMod.getVirAttrsToRemove(),
+                    attributableMod.getVirAttrsToUpdate(), attrUtil);
+        }
+
+        // Finally, check if mandatory values are missing
+        SyncopeClientException requiredValuesMissing = checkMandatory(attrUtil, 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 AttributableUtil attrUtil, 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(), attrUtil.plainSchemaClass());
+
+                if (schema != null) {
+                    PlainAttr attr = attributable.getPlainAttr(schema.getKey());
+                    if (attr == null) {
+                        attr = attrUtil.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(), attrUtil, 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(), attrUtil.derSchemaClass());
+
+            if (derSchema != null) {
+                DerAttr derAttr = attrUtil.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 role virtual attributes will be evaluated by the propagation manager only (if needed).
+        if (AttributableType.USER == attrUtil.getType()
+                || AttributableType.ROLE == attrUtil.getType()) {
+
+            for (AttrTO vattrTO : attributableTO.getVirAttrs()) {
+                VirSchema virSchema = virtAttrHander.getVirSchema(vattrTO.getSchema(), attrUtil.virSchemaClass());
+
+                if (virSchema != null) {
+                    VirAttr virAttr = attrUtil.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(), attrUtil);
+
+        // 4. resources
+        if (attributable instanceof Subject && attributableTO instanceof AbstractSubjectTO) {
+            for (String resourceName : ((AbstractSubjectTO) attributableTO).getResources()) {
+                ExternalResource resource = resourceDAO.find(resourceName);
+
+                if (resource != null) {
+                    ((Subject<?, ?, ?>) attributable).addResource(resource);
+                }
+            }
+        }
+
+        SyncopeClientException requiredValuesMissing = checkMandatory(attrUtil, 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 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) {
+            for (ExternalResource resource : resources) {
+                ((AbstractSubjectTO) attributableTO).getResources().add(resource.getKey());
+            }
+        }
+    }
+
+    protected Map<String, String> getAccountIds(final Subject<?, ?, ?> subject, final AttributableType type) {
+        Map<String, String> accountIds = new HashMap<>();
+
+        for (ExternalResource resource : subject.getResources()) {
+            if ((type == AttributableType.USER && resource.getUmapping() != null)
+                    || (type == AttributableType.ROLE && resource.getRmapping() != null)) {
+
+                MappingItem accountIdItem =
+                        attrUtilFactory.getInstance(type).getAccountIdItem(resource);
+                if (accountIdItem == null) {
+                    throw new NotFoundException(
+                            "AccountId mapping for " + type + " " + subject.getKey()
+                            + " on resource '" + resource.getKey() + "'");
+                }
+
+                accountIds.put(resource.getKey(), MappingUtil.getAccountIdValue(subject, resource, accountIdItem));
+            }
+        }
+
+        return accountIds;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
new file mode 100644
index 0000000..f1d9020
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConfigurationDataBinderImpl.java
@@ -0,0 +1,79 @@
+/*
+ * 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 org.apache.syncope.core.provisioning.api.data.ConfigurationDataBinder;
+import java.util.Collections;
+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.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+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.Conf;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ConfigurationDataBinderImpl extends AbstractAttributableDataBinder implements ConfigurationDataBinder {
+
+    @Override
+    public ConfTO getConfTO(final Conf conf) {
+        final ConfTO confTO = new ConfTO();
+        confTO.setKey(conf.getKey());
+
+        fillTO(confTO, conf.getPlainAttrs(),
+                conf.getDerAttrs(), conf.getVirAttrs(), Collections.<ExternalResource>emptySet());
+
+        return confTO;
+    }
+
+    @Override
+    public AttrTO getAttrTO(final CPlainAttr attr) {
+        final AttrTO attributeTO = new AttrTO();
+        attributeTO.setSchema(attr.getSchema().getKey());
+        attributeTO.getValues().addAll(attr.getValuesAsStrings());
+        attributeTO.setReadonly(attr.getSchema().isReadonly());
+
+        return attributeTO;
+    }
+
+    @Override
+    public CPlainAttr getAttribute(final AttrTO attributeTO) {
+        CPlainSchema schema = getPlainSchema(attributeTO.getSchema(), CPlainSchema.class);
+        if (schema == null) {
+            throw new NotFoundException("Conf schema " + attributeTO.getSchema());
+        } else {
+            SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
+            CPlainAttr attr = entityFactory.newEntity(CPlainAttr.class);
+            attr.setSchema(schema);
+            fillAttribute(attributeTO.getValues(), attrUtilFactory.getInstance(AttributableType.CONFIGURATION),
+                    schema, attr, invalidValues);
+
+            if (!invalidValues.isEmpty()) {
+                throw invalidValues;
+            }
+            return attr;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
new file mode 100644
index 0000000..fbb687e
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ConnInstanceDataBinderImpl.java
@@ -0,0 +1,245 @@
+/*
+ * 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 org.apache.syncope.core.provisioning.api.data.ConnInstanceDataBinder;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.ConnInstanceTO;
+import org.apache.syncope.common.lib.to.ConnPoolConfTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ConnConfPropSchema;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
+import org.apache.syncope.core.persistence.api.entity.ConnInstance;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
+import org.apache.syncope.core.provisioning.api.ConnPoolConfUtil;
+import org.identityconnectors.framework.api.ConfigurationProperties;
+import org.identityconnectors.framework.api.ConfigurationProperty;
+import org.identityconnectors.framework.impl.api.ConfigurationPropertyImpl;
+import org.apache.syncope.core.misc.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ConnInstanceDataBinderImpl implements ConnInstanceDataBinder {
+
+    private static final String[] IGNORE_PROPERTIES = { "key", "poolConf" };
+
+    @Autowired
+    private ConnIdBundleManager connIdBundleManager;
+
+    @Autowired
+    private ConnInstanceDAO connInstanceDAO;
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    @Override
+    public Set<ConnConfProperty> mergeConnConfProperties(final Set<ConnConfProperty> primary,
+            final Set<ConnConfProperty> secondary) {
+
+        final Set<ConnConfProperty> conf = new HashSet<>();
+
+        // to be used to control managed prop (needed by overridden mechanism)
+        final Set<String> propertyNames = new HashSet<>();
+
+        // get overridden connector configuration properties
+        for (ConnConfProperty prop : primary) {
+            if (!propertyNames.contains(prop.getSchema().getName())) {
+                conf.add(prop);
+                propertyNames.add(prop.getSchema().getName());
+            }
+        }
+
+        // get connector configuration properties
+        for (ConnConfProperty prop : secondary) {
+            if (!propertyNames.contains(prop.getSchema().getName())) {
+                conf.add(prop);
+                propertyNames.add(prop.getSchema().getName());
+            }
+        }
+
+        return conf;
+    }
+
+    @Override
+    public ConnInstance getConnInstance(final ConnInstanceTO connInstanceTO) {
+        SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+
+        if (connInstanceTO.getLocation() == null) {
+            sce.getElements().add("location");
+        }
+
+        if (connInstanceTO.getBundleName() == null) {
+            sce.getElements().add("bundlename");
+        }
+
+        if (connInstanceTO.getVersion() == null) {
+            sce.getElements().add("bundleversion");
+        }
+
+        if (connInstanceTO.getConnectorName() == null) {
+            sce.getElements().add("connectorname");
+        }
+
+        if (connInstanceTO.getConfiguration() == null || connInstanceTO.getConfiguration().isEmpty()) {
+            sce.getElements().add("configuration");
+        }
+
+        ConnInstance connInstance = entityFactory.newEntity(ConnInstance.class);
+
+        BeanUtils.copyProperties(connInstanceTO, connInstance, IGNORE_PROPERTIES);
+        if (connInstanceTO.getLocation() != null) {
+            connInstance.setLocation(connInstanceTO.getLocation());
+        }
+        if (connInstanceTO.getPoolConf() != null) {
+            connInstance.setPoolConf(
+                    ConnPoolConfUtil.getConnPoolConf(connInstanceTO.getPoolConf(), entityFactory.newConnPoolConf()));
+        }
+
+        // Throw exception if there is at least one element set
+        if (!sce.isEmpty()) {
+            throw sce;
+        }
+
+        return connInstance;
+    }
+
+    @Override
+    public ConnInstance updateConnInstance(final long connInstanceId, final ConnInstanceTO connInstanceTO) {
+        SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+
+        if (connInstanceId == 0) {
+            sce.getElements().add("connector id");
+        }
+
+        ConnInstance connInstance = connInstanceDAO.find(connInstanceId);
+        connInstance.getCapabilities().clear();
+        connInstance.getCapabilities().addAll(connInstanceTO.getCapabilities());
+
+        if (connInstanceTO.getLocation() != null) {
+            connInstance.setLocation(connInstanceTO.getLocation());
+        }
+
+        if (connInstanceTO.getBundleName() != null) {
+            connInstance.setBundleName(connInstanceTO.getBundleName());
+        }
+
+        if (connInstanceTO.getVersion() != null) {
+            connInstance.setVersion(connInstanceTO.getVersion());
+        }
+
+        if (connInstanceTO.getConnectorName() != null) {
+            connInstance.setConnectorName(connInstanceTO.getConnectorName());
+        }
+
+        if (connInstanceTO.getConfiguration() != null && !connInstanceTO.getConfiguration().isEmpty()) {
+            connInstance.setConfiguration(connInstanceTO.getConfiguration());
+        }
+
+        if (connInstanceTO.getDisplayName() != null) {
+            connInstance.setDisplayName(connInstanceTO.getDisplayName());
+        }
+
+        if (connInstanceTO.getConnRequestTimeout() != null) {
+            connInstance.setConnRequestTimeout(connInstanceTO.getConnRequestTimeout());
+        }
+
+        if (connInstanceTO.getPoolConf() == null) {
+            connInstance.setPoolConf(null);
+        } else {
+            connInstance.setPoolConf(
+                    ConnPoolConfUtil.getConnPoolConf(connInstanceTO.getPoolConf(), entityFactory.newConnPoolConf()));
+        }
+
+        if (!sce.isEmpty()) {
+            throw sce;
+        }
+
+        return connInstance;
+    }
+
+    @Override
+    public ConnConfPropSchema buildConnConfPropSchema(final ConfigurationProperty property) {
+        ConnConfPropSchema connConfPropSchema = new ConnConfPropSchema();
+
+        connConfPropSchema.setName(property.getName());
+        connConfPropSchema.setDisplayName(property.getDisplayName(property.getName()));
+        connConfPropSchema.setHelpMessage(property.getHelpMessage(property.getName()));
+        connConfPropSchema.setRequired(property.isRequired());
+        connConfPropSchema.setType(property.getType().getName());
+        connConfPropSchema.setOrder(((ConfigurationPropertyImpl) property).getOrder());
+        connConfPropSchema.setConfidential(property.isConfidential());
+
+        if (property.getValue() != null) {
+            if (property.getValue().getClass().isArray()) {
+                connConfPropSchema.getDefaultValues().addAll(Arrays.asList((Object[]) property.getValue()));
+            } else if (property.getValue() instanceof Collection<?>) {
+                connConfPropSchema.getDefaultValues().addAll((Collection<?>) property.getValue());
+            } else {
+                connConfPropSchema.getDefaultValues().add(property.getValue());
+            }
+        }
+
+        return connConfPropSchema;
+    }
+
+    @Override
+    public ConnInstanceTO getConnInstanceTO(final ConnInstance connInstance) {
+        ConnInstanceTO connInstanceTO = new ConnInstanceTO();
+        connInstanceTO.setKey(connInstance.getKey() == null ? 0L : connInstance.getKey());
+
+        // retrieve the ConfigurationProperties
+        ConfigurationProperties properties = connIdBundleManager.getConfigurationProperties(
+                connIdBundleManager.getConnectorInfo(connInstance.getLocation(),
+                        connInstance.getBundleName(), connInstance.getVersion(), connInstance.getConnectorName()));
+
+        BeanUtils.copyProperties(connInstance, connInstanceTO, IGNORE_PROPERTIES);
+
+        final Map<String, ConnConfProperty> connInstanceToConfMap = connInstanceTO.getConfigurationMap();
+
+        for (String propName : properties.getPropertyNames()) {
+            ConnConfPropSchema schema = buildConnConfPropSchema(properties.getProperty(propName));
+
+            ConnConfProperty property;
+            if (connInstanceToConfMap.containsKey(propName)) {
+                property = connInstanceToConfMap.get(propName);
+            } else {
+                property = new ConnConfProperty();
+                connInstanceTO.getConfiguration().add(property);
+            }
+
+            property.setSchema(schema);
+        }
+
+        if (connInstance.getPoolConf() != null) {
+            ConnPoolConfTO poolConf = new ConnPoolConfTO();
+            BeanUtils.copyProperties(connInstance.getPoolConf(), poolConf);
+            connInstanceTO.setPoolConf(poolConf);
+        }
+
+        return connInstanceTO;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
new file mode 100644
index 0000000..c18e079
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
@@ -0,0 +1,66 @@
+/*
+ * 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 org.apache.syncope.core.provisioning.api.data.NotificationDataBinder;
+import org.apache.syncope.common.lib.to.NotificationTO;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.Notification;
+import org.apache.syncope.core.misc.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NotificationDataBinderImpl implements NotificationDataBinder {
+
+    private static final String[] IGNORE_PROPERTIES = { "key", "about", "recipients" };
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    @Override
+    public NotificationTO getNotificationTO(final Notification notification) {
+        NotificationTO result = new NotificationTO();
+
+        BeanUtils.copyProperties(notification, result, IGNORE_PROPERTIES);
+
+        result.setKey(notification.getKey());
+        result.setUserAbout(notification.getUserAbout());
+        result.setRoleAbout(notification.getRoleAbout());
+        result.setRecipients(notification.getRecipients());
+
+        return result;
+    }
+
+    @Override
+    public Notification create(final NotificationTO notificationTO) {
+        Notification result = entityFactory.newEntity(Notification.class);
+        update(result, notificationTO);
+        return result;
+    }
+
+    @Override
+    public void update(final Notification notification, final NotificationTO notificationTO) {
+        BeanUtils.copyProperties(notificationTO, notification, IGNORE_PROPERTIES);
+
+        notification.setUserAbout(notificationTO.getUserAbout());
+        notification.setRoleAbout(notificationTO.getRoleAbout());
+        notification.setRecipients(notificationTO.getRecipients());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java
new file mode 100644
index 0000000..ec735b6
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java
@@ -0,0 +1,189 @@
+/*
+ * 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 org.apache.syncope.core.provisioning.api.data.PolicyDataBinder;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractPolicyTO;
+import org.apache.syncope.common.lib.to.AccountPolicyTO;
+import org.apache.syncope.common.lib.to.PasswordPolicyTO;
+import org.apache.syncope.common.lib.to.SyncPolicyTO;
+import org.apache.syncope.common.lib.types.AccountPolicySpec;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.PasswordPolicySpec;
+import org.apache.syncope.common.lib.types.SyncPolicySpec;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
+import org.apache.syncope.core.persistence.api.entity.AccountPolicy;
+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.PasswordPolicy;
+import org.apache.syncope.core.persistence.api.entity.Policy;
+import org.apache.syncope.core.persistence.api.entity.SyncPolicy;
+import org.apache.syncope.core.persistence.api.entity.role.Role;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PolicyDataBinderImpl implements PolicyDataBinder {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(PolicyDataBinder.class);
+
+    @Autowired
+    private ExternalResourceDAO resourceDAO;
+
+    @Autowired
+    private RoleDAO roleDAO;
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    /**
+     * Get policy TO from policy bean.
+     *
+     * @param policy bean.
+     * @return policy TO.
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends AbstractPolicyTO> T getPolicyTO(final Policy policy) {
+        final T policyTO;
+
+        switch (policy.getType()) {
+            case GLOBAL_PASSWORD:
+            case PASSWORD:
+                policyTO = (T) new PasswordPolicyTO(policy.getType().isGlobal());
+                ((PasswordPolicyTO) policyTO).setSpecification(policy.getSpecification(PasswordPolicySpec.class));
+                break;
+
+            case GLOBAL_ACCOUNT:
+            case ACCOUNT:
+                policyTO = (T) new AccountPolicyTO(policy.getType().isGlobal());
+                ((AccountPolicyTO) policyTO).setSpecification(policy.getSpecification(AccountPolicySpec.class));
+                ((AccountPolicyTO) policyTO).getResources().addAll(((AccountPolicy) policy).getResourceNames());
+                break;
+
+            case GLOBAL_SYNC:
+            case SYNC:
+            default:
+                policyTO = (T) new SyncPolicyTO(policy.getType().isGlobal());
+                ((SyncPolicyTO) policyTO).setSpecification(policy.getSpecification(SyncPolicySpec.class));
+        }
+
+        policyTO.setKey(policy.getKey());
+        policyTO.setDescription(policy.getDescription());
+
+        for (ExternalResource resource : resourceDAO.findByPolicy(policy)) {
+            policyTO.getUsedByResources().add(resource.getKey());
+        }
+        if (policy.getType().isGlobal()) {
+            for (ExternalResource resource : resourceDAO.findWithoutPolicy(policy.getType())) {
+                policyTO.getUsedByResources().add(resource.getKey());
+            }
+        }
+        for (Role role : roleDAO.findByPolicy(policy)) {
+            policyTO.getUsedByRoles().add(role.getKey());
+        }
+        if (policy.getType().isGlobal()) {
+            for (Role role : roleDAO.findWithoutPolicy(policy.getType())) {
+                policyTO.getUsedByRoles().add(role.getKey());
+            }
+        }
+
+        return policyTO;
+    }
+
+    private ExternalResource getResource(final String resourceName) {
+        ExternalResource resource = resourceDAO.find(resourceName);
+        if (resource == null) {
+            LOG.debug("Ignoring invalid resource {} ", resourceName);
+        }
+
+        return resource;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Policy> T getPolicy(T policy, final AbstractPolicyTO policyTO) {
+        if (policy != null && policy.getType() != policyTO.getType()) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidPolicy);
+            sce.getElements().add(String.format("Cannot update %s from %s", policy.getType(), policyTO.getType()));
+            throw sce;
+        }
+
+        switch (policyTO.getType()) {
+            case GLOBAL_PASSWORD:
+            case PASSWORD:
+                if (!(policyTO instanceof PasswordPolicyTO)) {
+                    throw new ClassCastException("Expected " + PasswordPolicyTO.class.getName()
+                            + ", found " + policyTO.getClass().getName());
+                }
+                if (policy == null) {
+                    policy = (T) entityFactory.newPolicy(PasswordPolicy.class, policyTO.getType().isGlobal());
+                }
+                policy.setSpecification(((PasswordPolicyTO) policyTO).getSpecification());
+                break;
+
+            case GLOBAL_ACCOUNT:
+            case ACCOUNT:
+                if (!(policyTO instanceof AccountPolicyTO)) {
+                    throw new ClassCastException("Expected " + AccountPolicyTO.class.getName()
+                            + ", found " + policyTO.getClass().getName());
+                }
+                if (policy == null) {
+                    policy = (T) entityFactory.newPolicy(AccountPolicy.class, policyTO.getType().isGlobal());
+                }
+                policy.setSpecification(((AccountPolicyTO) policyTO).getSpecification());
+
+                if (((AccountPolicy) policy).getResources() != null
+                        && !((AccountPolicy) policy).getResources().isEmpty()) {
+                    ((AccountPolicy) policy).getResources().clear();
+                }
+                for (String resourceName : ((AccountPolicyTO) policyTO).getResources()) {
+                    ExternalResource resource = getResource(resourceName);
+
+                    if (resource != null) {
+                        ((AccountPolicy) policy).addResource(resource);
+                    }
+                }
+                break;
+
+            case GLOBAL_SYNC:
+            case SYNC:
+            default:
+                if (!(policyTO instanceof SyncPolicyTO)) {
+                    throw new ClassCastException("Expected " + SyncPolicyTO.class.getName()
+                            + ", found " + policyTO.getClass().getName());
+                }
+                if (policy == null) {
+                    policy = (T) entityFactory.newPolicy(SyncPolicy.class, policyTO.getType().isGlobal());
+                }
+                policy.setSpecification(((SyncPolicyTO) policyTO).getSpecification());
+        }
+
+        policy.setDescription(policyTO.getDescription());
+
+        return policy;
+    }
+}