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/01/08 14:17:27 UTC

[07/13] syncope git commit: [SYNCOPE-620] server logic in, tests missing

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConfigurationDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConfigurationDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConfigurationDataBinder.java
new file mode 100644
index 0000000..64c4a4e
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConfigurationDataBinder.java
@@ -0,0 +1,75 @@
+/*
+ * 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.server.logic.data;
+
+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.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.persistence.api.entity.conf.CPlainSchema;
+import org.apache.syncope.persistence.api.entity.conf.Conf;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ConfigurationDataBinder extends AbstractAttributableDataBinder {
+
+    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;
+    }
+
+    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;
+    }
+
+    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/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConnInstanceDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConnInstanceDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConnInstanceDataBinder.java
new file mode 100644
index 0000000..1091be1
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConnInstanceDataBinder.java
@@ -0,0 +1,246 @@
+/*
+ * 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.server.logic.data;
+
+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.persistence.api.dao.ConnInstanceDAO;
+import org.apache.syncope.persistence.api.entity.ConnInstance;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.provisioning.api.ConnIdBundleManager;
+import org.apache.syncope.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.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ConnInstanceDataBinder {
+
+    private static final String[] IGNORE_PROPERTIES = { "key", "poolConf" };
+
+    @Autowired
+    private ConnIdBundleManager connIdBundleManager;
+
+    @Autowired
+    private ConnInstanceDAO connInstanceDAO;
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    /**
+     * Merge connector configuration properties avoiding repetition but giving priority to primary set.
+     *
+     * @param primary primary set.
+     * @param secondary secondary set.
+     * @return merged set.
+     */
+    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;
+    }
+
+    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;
+    }
+
+    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;
+    }
+
+    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;
+    }
+
+    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/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/NotificationDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/NotificationDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/NotificationDataBinder.java
new file mode 100644
index 0000000..0ddb74e
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/NotificationDataBinder.java
@@ -0,0 +1,62 @@
+/*
+ * 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.server.logic.data;
+
+import org.apache.syncope.common.lib.to.NotificationTO;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.Notification;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NotificationDataBinder {
+
+    private static final String[] IGNORE_PROPERTIES = { "key", "about", "recipients" };
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    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;
+    }
+
+    public Notification create(final NotificationTO notificationTO) {
+        Notification result = entityFactory.newEntity(Notification.class);
+        update(result, notificationTO);
+        return result;
+    }
+
+    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/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/PolicyDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/PolicyDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/PolicyDataBinder.java
new file mode 100644
index 0000000..57877d2
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/PolicyDataBinder.java
@@ -0,0 +1,186 @@
+/*
+ * 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.server.logic.data;
+
+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.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.Policy;
+import org.apache.syncope.persistence.api.entity.SyncPolicy;
+import org.apache.syncope.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 PolicyDataBinder {
+
+    /**
+     * Logger.
+     */
+    protected 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")
+    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.setId(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")
+    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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ReportDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ReportDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ReportDataBinder.java
new file mode 100644
index 0000000..952de94
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ReportDataBinder.java
@@ -0,0 +1,175 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.syncope.common.lib.report.AbstractReportletConf;
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.common.lib.to.ReportExecTO;
+import org.apache.syncope.common.lib.to.ReportTO;
+import org.apache.syncope.persistence.api.dao.ReportExecDAO;
+import org.apache.syncope.persistence.api.entity.Report;
+import org.apache.syncope.persistence.api.entity.ReportExec;
+import org.apache.syncope.server.logic.init.ImplementationClassNamesLoader;
+import org.apache.syncope.server.logic.report.Reportlet;
+import org.apache.syncope.server.logic.init.JobInstanceLoader;
+import org.apache.syncope.server.logic.report.ReportletConfClass;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ClassUtils;
+
+@Component
+public class ReportDataBinder {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(ReportDataBinder.class);
+
+    private static final String[] IGNORE_REPORT_PROPERTIES = { "key", "reportlets", "executions" };
+
+    private static final String[] IGNORE_REPORT_EXECUTION_PROPERTIES = { "key", "report", "execResult" };
+
+    @Autowired
+    private ReportExecDAO reportExecDAO;
+
+    @Autowired
+    private SchedulerFactoryBean scheduler;
+
+    @Autowired
+    private ImplementationClassNamesLoader classNamesLoader;
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public Set<Class<Reportlet>> getAllReportletClasses() {
+        Set<Class<Reportlet>> reportletClasses = new HashSet<Class<Reportlet>>();
+
+        for (String className : classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.REPORTLET)) {
+            try {
+                Class reportletClass = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader());
+                reportletClasses.add(reportletClass);
+            } catch (ClassNotFoundException e) {
+                LOG.warn("Could not load class {}", className);
+            } catch (LinkageError e) {
+                LOG.warn("Could not link class {}", className);
+            }
+        }
+        return reportletClasses;
+    }
+
+    public Class<? extends ReportletConf> getReportletConfClass(final Class<Reportlet> reportletClass) {
+        Class<? extends ReportletConf> result = null;
+
+        ReportletConfClass annotation = reportletClass.getAnnotation(ReportletConfClass.class);
+        if (annotation != null) {
+            result = annotation.value();
+        }
+
+        return result;
+    }
+
+    public Class<Reportlet> findReportletClassHavingConfClass(final Class<? extends ReportletConf> reportletConfClass) {
+        Class<Reportlet> result = null;
+        for (Class<Reportlet> reportletClass : getAllReportletClasses()) {
+            Class<? extends ReportletConf> found = getReportletConfClass(reportletClass);
+            if (found != null && found.equals(reportletConfClass)) {
+                result = reportletClass;
+            }
+        }
+
+        return result;
+    }
+
+    public void getReport(final Report report, final ReportTO reportTO) {
+        BeanUtils.copyProperties(reportTO, report, IGNORE_REPORT_PROPERTIES);
+        report.getReportletConfs().clear();
+        for (ReportletConf conf : reportTO.getReportletConfs()) {
+            report.addReportletConf(conf);
+        }
+    }
+
+    public ReportTO getReportTO(final Report report) {
+        ReportTO reportTO = new ReportTO();
+        reportTO.setId(report.getKey());
+        BeanUtils.copyProperties(report, reportTO, IGNORE_REPORT_PROPERTIES);
+
+        copyReportletConfs(report, reportTO);
+
+        ReportExec latestExec = reportExecDAO.findLatestStarted(report);
+        reportTO.setLatestExecStatus(latestExec == null
+                ? ""
+                : latestExec.getStatus());
+
+        reportTO.setStartDate(latestExec == null
+                ? null
+                : latestExec.getStartDate());
+
+        reportTO.setEndDate(latestExec == null
+                ? null
+                : latestExec.getEndDate());
+
+        for (ReportExec reportExec : report.getExecs()) {
+            reportTO.getExecutions().add(getReportExecTO(reportExec));
+        }
+
+        String triggerName = JobInstanceLoader.getTriggerName(JobInstanceLoader.getJobName(report));
+
+        Trigger trigger;
+        try {
+            trigger = scheduler.getScheduler().getTrigger(new TriggerKey(triggerName, Scheduler.DEFAULT_GROUP));
+        } catch (SchedulerException e) {
+            LOG.warn("While trying to get to " + triggerName, e);
+            trigger = null;
+        }
+
+        if (trigger != null) {
+            reportTO.setLastExec(trigger.getPreviousFireTime());
+            reportTO.setNextExec(trigger.getNextFireTime());
+        }
+
+        return reportTO;
+    }
+
+    private void copyReportletConfs(final Report report, final ReportTO reportTO) {
+        reportTO.getReportletConfs().clear();
+        for (ReportletConf reportletConf : report.getReportletConfs()) {
+            reportTO.getReportletConfs().add((AbstractReportletConf) reportletConf);
+        }
+    }
+
+    public ReportExecTO getReportExecTO(final ReportExec execution) {
+        ReportExecTO executionTO = new ReportExecTO();
+        executionTO.setKey(execution.getKey());
+        BeanUtils.copyProperties(execution, executionTO, IGNORE_REPORT_EXECUTION_PROPERTIES);
+        if (execution.getKey() != null) {
+            executionTO.setKey(execution.getKey());
+        }
+        executionTO.setReport(execution.getReport().getKey());
+
+        return executionTO;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ResourceDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ResourceDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ResourceDataBinder.java
new file mode 100644
index 0000000..b307eee
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ResourceDataBinder.java
@@ -0,0 +1,389 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.MappingTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.persistence.api.dao.ConnInstanceDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.PolicyDAO;
+import org.apache.syncope.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.persistence.api.entity.ConnInstance;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.Mapping;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.SyncPolicy;
+import org.apache.syncope.persistence.api.entity.role.RMapping;
+import org.apache.syncope.persistence.api.entity.role.RMappingItem;
+import org.apache.syncope.persistence.api.entity.user.UMapping;
+import org.apache.syncope.persistence.api.entity.user.UMappingItem;
+import org.apache.syncope.server.utils.jexl.JexlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ResourceDataBinder {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(ResourceDataBinder.class);
+
+    private static final String[] MAPPINGITEM_IGNORE_PROPERTIES = { "key", "mapping" };
+
+    @Autowired
+    private ConnInstanceDAO connInstanceDAO;
+
+    @Autowired
+    private PolicyDAO policyDAO;
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    public ExternalResource create(final ResourceTO resourceTO) {
+        return update(entityFactory.newEntity(ExternalResource.class), resourceTO);
+    }
+
+    public ExternalResource update(final ExternalResource resource, final ResourceTO resourceTO) {
+        if (resourceTO == null) {
+            return null;
+        }
+
+        resource.setKey(resourceTO.getKey());
+
+        if (resourceTO.getConnectorId() != null) {
+            ConnInstance connector = connInstanceDAO.find(resourceTO.getConnectorId());
+            resource.setConnector(connector);
+
+            if (!connector.getResources().contains(resource)) {
+                connector.addResource(resource);
+            }
+        }
+
+        resource.setEnforceMandatoryCondition(resourceTO.isEnforceMandatoryCondition());
+
+        resource.setPropagationPrimary(resourceTO.isPropagationPrimary());
+
+        resource.setPropagationPriority(resourceTO.getPropagationPriority());
+
+        resource.setRandomPwdIfNotProvided(resourceTO.isRandomPwdIfNotProvided());
+
+        resource.setPropagationMode(resourceTO.getPropagationMode());
+
+        if (resourceTO.getUmapping() == null || resourceTO.getUmapping().getItems().isEmpty()) {
+            resource.setUmapping(null);
+        } else {
+            UMapping mapping = entityFactory.newEntity(UMapping.class);
+            mapping.setResource(resource);
+            resource.setUmapping(mapping);
+            populateMapping(resourceTO.getUmapping(), mapping, entityFactory.newEntity(UMappingItem.class));
+        }
+        if (resourceTO.getRmapping() == null || resourceTO.getRmapping().getItems().isEmpty()) {
+            resource.setRmapping(null);
+        } else {
+            RMapping mapping = entityFactory.newEntity(RMapping.class);
+            mapping.setResource(resource);
+            resource.setRmapping(mapping);
+            populateMapping(resourceTO.getRmapping(), mapping, entityFactory.newEntity(RMappingItem.class));
+        }
+
+        resource.setCreateTraceLevel(resourceTO.getCreateTraceLevel());
+        resource.setUpdateTraceLevel(resourceTO.getUpdateTraceLevel());
+        resource.setDeleteTraceLevel(resourceTO.getDeleteTraceLevel());
+        resource.setSyncTraceLevel(resourceTO.getSyncTraceLevel());
+
+        resource.setPasswordPolicy(resourceTO.getPasswordPolicy() == null
+                ? null : (PasswordPolicy) policyDAO.find(resourceTO.getPasswordPolicy()));
+
+        resource.setAccountPolicy(resourceTO.getAccountPolicy() == null
+                ? null : (AccountPolicy) policyDAO.find(resourceTO.getAccountPolicy()));
+
+        resource.setSyncPolicy(resourceTO.getSyncPolicy() == null
+                ? null : (SyncPolicy) policyDAO.find(resourceTO.getSyncPolicy()));
+
+        resource.setConnInstanceConfiguration(new HashSet<>(resourceTO.getConnConfProperties()));
+
+        if (resourceTO.getUsyncToken() == null) {
+            resource.setUsyncToken(null);
+        }
+        if (resourceTO.getRsyncToken() == null) {
+            resource.setRsyncToken(null);
+        }
+
+        resource.getPropagationActionsClassNames().clear();
+        resource.getPropagationActionsClassNames().addAll(resourceTO.getPropagationActionsClassNames());
+
+        return resource;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private void populateMapping(final MappingTO mappingTO, final Mapping mapping, final MappingItem prototype) {
+        mapping.setAccountLink(mappingTO.getAccountLink());
+
+        for (MappingItem item : getMappingItems(mappingTO.getItems(), prototype)) {
+            item.setMapping(mapping);
+            if (item.isAccountid()) {
+                mapping.setAccountIdItem(item);
+            } else if (item.isPassword()) {
+                ((UMapping) mapping).setPasswordItem((UMappingItem) item);
+            } else {
+                mapping.addItem(item);
+            }
+        }
+    }
+
+    private Set<MappingItem> getMappingItems(final Collection<MappingItemTO> itemTOs, final MappingItem prototype) {
+        Set<MappingItem> items = new HashSet<>(itemTOs.size());
+        for (MappingItemTO itemTO : itemTOs) {
+            items.add(getMappingItem(itemTO, prototype));
+        }
+
+        return items;
+    }
+
+    private MappingItem getMappingItem(final MappingItemTO itemTO, final MappingItem prototype) {
+        if (itemTO == null || itemTO.getIntMappingType() == null) {
+            LOG.error("Null mappingTO provided");
+            return null;
+        }
+
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        SyncopeClientException requiredValuesMissing = SyncopeClientException.build(
+                ClientExceptionType.RequiredValuesMissing);
+
+        if (itemTO.getIntAttrName() == null) {
+            if (IntMappingType.getEmbedded().contains(itemTO.getIntMappingType())) {
+                itemTO.setIntAttrName(itemTO.getIntMappingType().toString());
+            } else {
+                requiredValuesMissing.getElements().add("intAttrName");
+            }
+        }
+
+        // Throw composite exception if there is at least one element set
+        // in the composing exceptions
+        if (!requiredValuesMissing.isEmpty()) {
+            scce.addException(requiredValuesMissing);
+        }
+
+        // no mandatory condition implies mandatory condition false
+        if (!JexlUtil.isExpressionValid(itemTO.getMandatoryCondition() == null
+                ? "false" : itemTO.getMandatoryCondition())) {
+
+            SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
+                    ClientExceptionType.InvalidValues);
+
+            invalidMandatoryCondition.getElements().add(itemTO.getMandatoryCondition());
+
+            scce.addException(invalidMandatoryCondition);
+        }
+
+        if (scce.hasExceptions()) {
+            throw scce;
+        }
+
+        MappingItem item = SerializationUtils.clone(prototype);
+        BeanUtils.copyProperties(itemTO, item, MAPPINGITEM_IGNORE_PROPERTIES);
+        return item;
+    }
+
+    public ConnInstance getConnInstance(final ExternalResource resource) {
+        final ConnInstance connInstanceClone = SerializationUtils.clone(resource.getConnector());
+        return getConnInstance(connInstanceClone, resource.getConnInstanceConfiguration());
+    }
+
+    public ConnInstance getConnInstance(final ResourceTO resourceTO) {
+        ConnInstance connInstance = connInstanceDAO.find(resourceTO.getConnectorId());
+        if (connInstance == null) {
+            throw new NotFoundException("Connector '" + resourceTO.getConnectorId() + "'");
+        }
+
+        final ConnInstance connInstanceClone = SerializationUtils.clone(connInstance);
+        return getConnInstance(connInstanceClone, resourceTO.getConnConfProperties());
+    }
+
+    private ConnInstance getConnInstance(final ConnInstance connInstance, final Set<ConnConfProperty> overridden) {
+        final Set<ConnConfProperty> configuration = new HashSet<>();
+        final Map<String, ConnConfProperty> overridable = new HashMap<>();
+
+        // add not overridable properties
+        for (ConnConfProperty prop : connInstance.getConfiguration()) {
+            if (prop.isOverridable()) {
+                overridable.put(prop.getSchema().getName(), prop);
+            } else {
+                configuration.add(prop);
+            }
+        }
+
+        // add overridden properties
+        for (ConnConfProperty prop : overridden) {
+            if (overridable.containsKey(prop.getSchema().getName()) && !prop.getValues().isEmpty()) {
+                configuration.add(prop);
+                overridable.remove(prop.getSchema().getName());
+            }
+        }
+
+        // add overridable properties not overridden
+        configuration.addAll(overridable.values());
+
+        connInstance.setConfiguration(configuration);
+
+        return connInstance;
+    }
+
+    public List<ResourceTO> getResourceTOs(final Collection<? extends ExternalResource> resources) {
+        List<ResourceTO> resourceTOs = new ArrayList<>();
+        for (ExternalResource resource : resources) {
+            resourceTOs.add(getResourceTO(resource));
+        }
+
+        return resourceTOs;
+    }
+
+    public ResourceTO getResourceTO(final ExternalResource resource) {
+        if (resource == null) {
+            return null;
+        }
+
+        ResourceTO resourceTO = new ResourceTO();
+
+        // set sys info
+        resourceTO.setCreator(resource.getCreator());
+        resourceTO.setCreationDate(resource.getCreationDate());
+        resourceTO.setLastModifier(resource.getLastModifier());
+        resourceTO.setLastChangeDate(resource.getLastChangeDate());
+
+        // set the resource name
+        resourceTO.setKey(resource.getKey());
+
+        // set the connector instance
+        ConnInstance connector = resource.getConnector();
+
+        resourceTO.setConnectorId(connector == null ? null : connector.getKey());
+        resourceTO.setConnectorDisplayName(connector == null ? null : connector.getDisplayName());
+
+        // set the mappings
+        if (resource.getUmapping() != null) {
+            MappingTO mappingTO = new MappingTO();
+            resourceTO.setUmapping(mappingTO);
+            populateMappingTO(resource.getUmapping(), mappingTO);
+        }
+        if (resource.getRmapping() != null) {
+            MappingTO mappingTO = new MappingTO();
+            resourceTO.setRmapping(mappingTO);
+            populateMappingTO(resource.getRmapping(), mappingTO);
+        }
+
+        resourceTO.setEnforceMandatoryCondition(resource.isEnforceMandatoryCondition());
+
+        resourceTO.setPropagationPrimary(resource.isPropagationPrimary());
+
+        resourceTO.setPropagationPriority(resource.getPropagationPriority());
+
+        resourceTO.setRandomPwdIfNotProvided(resource.isRandomPwdIfNotProvided());
+
+        resourceTO.setPropagationMode(resource.getPropagationMode());
+
+        resourceTO.setCreateTraceLevel(resource.getCreateTraceLevel());
+        resourceTO.setUpdateTraceLevel(resource.getUpdateTraceLevel());
+        resourceTO.setDeleteTraceLevel(resource.getDeleteTraceLevel());
+        resourceTO.setSyncTraceLevel(resource.getSyncTraceLevel());
+
+        resourceTO.setPasswordPolicy(resource.getPasswordPolicy() == null
+                ? null : resource.getPasswordPolicy().getKey());
+
+        resourceTO.setAccountPolicy(resource.getAccountPolicy() == null
+                ? null : resource.getAccountPolicy().getKey());
+
+        resourceTO.setSyncPolicy(resource.getSyncPolicy() == null
+                ? null : resource.getSyncPolicy().getKey());
+
+        resourceTO.getConnConfProperties().addAll(resource.getConnInstanceConfiguration());
+
+        resourceTO.setUsyncToken(resource.getSerializedUSyncToken());
+        resourceTO.setRsyncToken(resource.getSerializedRSyncToken());
+
+        resourceTO.getPropagationActionsClassNames().addAll(resource.getPropagationActionsClassNames());
+
+        return resourceTO;
+    }
+
+    private void populateMappingTO(final Mapping<?> mapping, final MappingTO mappingTO) {
+        mappingTO.setAccountLink(mapping.getAccountLink());
+
+        for (MappingItemTO itemTO : getMappingItemTOs(mapping.getItems())) {
+            if (itemTO.isAccountid()) {
+                mappingTO.setAccountIdItem(itemTO);
+            } else if (itemTO.isPassword()) {
+                mappingTO.setPasswordItem(itemTO);
+            } else {
+                mappingTO.addItem(itemTO);
+            }
+        }
+    }
+
+    private Set<MappingItemTO> getMappingItemTOs(final Collection<? extends MappingItem> items) {
+        Set<MappingItemTO> mappingTOs = new HashSet<>();
+        for (MappingItem item : items) {
+            LOG.debug("Asking for TO for {}", item);
+            mappingTOs.add(getMappingItemTO(item));
+        }
+
+        LOG.debug("Collected TOs: {}", mappingTOs);
+
+        return mappingTOs;
+    }
+
+    private MappingItemTO getMappingItemTO(final MappingItem item) {
+        if (item == null) {
+            LOG.error("Provided null mapping");
+
+            return null;
+        }
+
+        MappingItemTO itemTO = new MappingItemTO();
+
+        BeanUtils.copyProperties(item, itemTO, MAPPINGITEM_IGNORE_PROPERTIES);
+
+        itemTO.setKey(item.getKey());
+
+        LOG.debug("Obtained SchemaMappingTO {}", itemTO);
+
+        return itemTO;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/RoleDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/RoleDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/RoleDataBinder.java
new file mode 100644
index 0000000..d8dc0df
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/RoleDataBinder.java
@@ -0,0 +1,429 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.persistence.api.entity.AttrTemplate;
+import org.apache.syncope.persistence.api.entity.Entitlement;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.Schema;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MDerSchema;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MPlainSchema;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MVirSchema;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.RDerAttr;
+import org.apache.syncope.persistence.api.entity.role.RDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RDerSchema;
+import org.apache.syncope.persistence.api.entity.role.RPlainAttr;
+import org.apache.syncope.persistence.api.entity.role.RPlainAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RPlainSchema;
+import org.apache.syncope.persistence.api.entity.role.RVirAttr;
+import org.apache.syncope.persistence.api.entity.role.RVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RVirSchema;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.propagation.PropagationByResource;
+import org.apache.syncope.server.utils.ConnObjectUtil;
+import org.apache.syncope.provisioning.api.WorkflowResult;
+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 RoleDataBinder extends AbstractAttributableDataBinder {
+
+    @Autowired
+    private RoleDAO roleDAO;
+
+    @Autowired
+    private ConnObjectUtil connObjectUtil;
+
+    @Autowired
+    private EntitlementDAO entitlementDAO;
+
+    @Transactional(readOnly = true)
+    public List<WorkflowResult<Long>> getUsersOnResourcesOnlyBecauseOfRole(final Long roleId) {
+        Role role = roleDAO.authFetchRole(roleId);
+
+        List<WorkflowResult<Long>> result = new ArrayList<WorkflowResult<Long>>();
+
+        for (Membership membership : roleDAO.findMemberships(role)) {
+            User user = membership.getUser();
+
+            PropagationByResource propByRes = new PropagationByResource();
+            for (ExternalResource resource : role.getResources()) {
+                if (!user.getOwnResources().contains(resource)) {
+                    propByRes.add(ResourceOperation.DELETE, resource.getKey());
+                }
+
+                if (!propByRes.isEmpty()) {
+                    result.add(new WorkflowResult<Long>(user.getKey(), propByRes, Collections.<String>emptySet()));
+                }
+            }
+        }
+
+        return result;
+    }
+
+    private <T extends AttrTemplate<S>, S extends Schema> void setAttrTemplates(
+            final Role role, final List<String> schemaNames,
+            final Class<T> templateClass, final Class<S> schemaClass) {
+
+        List<T> toRemove = new ArrayList<T>();
+        for (T template : role.getAttrTemplates(templateClass)) {
+            if (!schemaNames.contains(template.getSchema().getKey())) {
+                toRemove.add(template);
+            }
+        }
+        role.getAttrTemplates(templateClass).removeAll(toRemove);
+
+        for (String schemaName : schemaNames) {
+            if (role.getAttrTemplate(templateClass, schemaName) == null) {
+                S schema = getSchema(schemaName, schemaClass);
+                if (schema != null) {
+                    try {
+                        T template = templateClass.newInstance();
+                        template.setSchema(schema);
+                        template.setOwner(role);
+                        role.getAttrTemplates(templateClass).add(template);
+                    } catch (Exception e) {
+                        LOG.error("Could not create template for {}", templateClass, e);
+                    }
+                }
+            }
+        }
+    }
+
+    public Role create(final Role role, final RoleTO roleTO) {
+        role.setInheritOwner(roleTO.isInheritOwner());
+
+        role.setInheritPlainAttrs(roleTO.isInheritAttrs());
+        role.setInheritDerAttrs(roleTO.isInheritDerAttrs());
+        role.setInheritVirAttrs(roleTO.isInheritVirAttrs());
+
+        role.setInheritTemplates(roleTO.isInheritTemplates());
+
+        role.setInheritPasswordPolicy(roleTO.isInheritPasswordPolicy());
+        role.setInheritAccountPolicy(roleTO.isInheritAccountPolicy());
+
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        // name and parent
+        SyncopeClientException invalidRoles = SyncopeClientException.build(ClientExceptionType.InvalidRoles);
+        if (roleTO.getName() == null) {
+            LOG.error("No name specified for this role");
+
+            invalidRoles.getElements().add("No name specified for this role");
+        } else {
+            role.setName(roleTO.getName());
+        }
+        Long parentRoleKey = null;
+        if (roleTO.getParent() != 0) {
+            Role parentRole = roleDAO.find(roleTO.getParent());
+            if (parentRole == null) {
+                LOG.error("Could not find role with id " + roleTO.getParent());
+
+                invalidRoles.getElements().add(String.valueOf(roleTO.getParent()));
+                scce.addException(invalidRoles);
+            } else {
+                role.setParent(parentRole);
+                parentRoleKey = role.getParent().getKey();
+            }
+        }
+
+        Role otherRole = roleDAO.find(roleTO.getName(), parentRoleKey);
+        if (otherRole != null) {
+            LOG.error("Another role exists with the same name " + "and the same parent role: " + otherRole);
+
+            invalidRoles.getElements().add(roleTO.getName());
+        }
+
+        // attribute templates
+        setAttrTemplates(role, roleTO.getRAttrTemplates(), RPlainAttrTemplate.class, RPlainSchema.class);
+        setAttrTemplates(role, roleTO.getRDerAttrTemplates(), RDerAttrTemplate.class, RDerSchema.class);
+        setAttrTemplates(role, roleTO.getRVirAttrTemplates(), RVirAttrTemplate.class, RVirSchema.class);
+        setAttrTemplates(role, roleTO.getMAttrTemplates(), MPlainAttrTemplate.class, MPlainSchema.class);
+        setAttrTemplates(role, roleTO.getMDerAttrTemplates(), MDerAttrTemplate.class, MDerSchema.class);
+        setAttrTemplates(role, roleTO.getMVirAttrTemplates(), MVirAttrTemplate.class, MVirSchema.class);
+
+        // attributes, derived attributes, virtual attributes and resources
+        fill(role, roleTO, attrUtilFactory.getInstance(AttributableType.ROLE), scce);
+
+        // entitlements
+        for (String entitlementName : roleTO.getEntitlements()) {
+            Entitlement entitlement = entitlementDAO.find(entitlementName);
+            if (entitlement == null) {
+                LOG.warn("Ignoring invalid entitlement {}", entitlementName);
+            } else {
+                role.addEntitlement(entitlement);
+            }
+        }
+
+        // owner
+        if (roleTO.getUserOwner() != null) {
+            User owner = userDAO.find(roleTO.getUserOwner());
+            if (owner == null) {
+                LOG.warn("Ignoring invalid user specified as owner: {}", roleTO.getUserOwner());
+            } else {
+                role.setUserOwner(owner);
+            }
+        }
+        if (roleTO.getRoleOwner() != null) {
+            Role owner = roleDAO.find(roleTO.getRoleOwner());
+            if (owner == null) {
+                LOG.warn("Ignoring invalid role specified as owner: {}", roleTO.getRoleOwner());
+            } else {
+                role.setRoleOwner(owner);
+            }
+        }
+
+        // policies
+        if (roleTO.getPasswordPolicy() != null) {
+            role.setPasswordPolicy((PasswordPolicy) policyDAO.find(roleTO.getPasswordPolicy()));
+        }
+        if (roleTO.getAccountPolicy() != null) {
+            role.setAccountPolicy((AccountPolicy) policyDAO.find(roleTO.getAccountPolicy()));
+        }
+
+        return role;
+    }
+
+    public PropagationByResource update(final Role role, final RoleMod roleMod) {
+        PropagationByResource propByRes = new PropagationByResource();
+
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        Set<String> currentResources = role.getResourceNames();
+
+        // name
+        SyncopeClientException invalidRoles = SyncopeClientException.build(ClientExceptionType.InvalidRoles);
+        if (roleMod.getName() != null) {
+            Role otherRole = roleDAO.find(roleMod.getName(),
+                    role.getParent() == null ? null : role.getParent().getKey());
+            if (otherRole == null || role.equals(otherRole)) {
+                if (!roleMod.getName().equals(role.getName())) {
+                    propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+                    for (String resource : currentResources) {
+                        propByRes.addOldAccountId(resource, role.getName());
+                    }
+
+                    role.setName(roleMod.getName());
+                }
+            } else {
+                LOG.error("Another role exists with the same name and the same parent role: " + otherRole);
+
+                invalidRoles.getElements().add(roleMod.getName());
+                scce.addException(invalidRoles);
+            }
+        }
+
+        if (roleMod.getInheritOwner() != null) {
+            role.setInheritOwner(roleMod.getInheritOwner());
+        }
+
+        if (roleMod.getInheritTemplates() != null) {
+            role.setInheritTemplates(roleMod.getInheritTemplates());
+        }
+
+        if (roleMod.getInheritPlainAttrs() != null) {
+            role.setInheritPlainAttrs(roleMod.getInheritPlainAttrs());
+        }
+        if (roleMod.getInheritDerAttrs() != null) {
+            role.setInheritDerAttrs(roleMod.getInheritDerAttrs());
+        }
+        if (roleMod.getInheritVirAttrs() != null) {
+            role.setInheritVirAttrs(roleMod.getInheritVirAttrs());
+        }
+
+        if (roleMod.getInheritPasswordPolicy() != null) {
+            role.setInheritPasswordPolicy(roleMod.getInheritPasswordPolicy());
+        }
+        if (roleMod.getInheritAccountPolicy() != null) {
+            role.setInheritAccountPolicy(roleMod.getInheritAccountPolicy());
+        }
+
+        // entitlements
+        if (roleMod.isModEntitlements()) {
+            role.getEntitlements().clear();
+            for (String entitlementName : roleMod.getEntitlements()) {
+                Entitlement entitlement = entitlementDAO.find(entitlementName);
+                if (entitlement == null) {
+                    LOG.warn("Ignoring invalid entitlement {}", entitlementName);
+                } else {
+                    role.addEntitlement(entitlement);
+                }
+            }
+        }
+
+        // attribute templates
+        if (roleMod.isModRAttrTemplates()) {
+            setAttrTemplates(role, roleMod.getRPlainAttrTemplates(), RPlainAttrTemplate.class, RPlainSchema.class);
+        }
+        if (roleMod.isModRDerAttrTemplates()) {
+            setAttrTemplates(role, roleMod.getRDerAttrTemplates(), RDerAttrTemplate.class, RDerSchema.class);
+        }
+        if (roleMod.isModRVirAttrTemplates()) {
+            setAttrTemplates(role, roleMod.getRVirAttrTemplates(), RVirAttrTemplate.class, RVirSchema.class);
+        }
+        if (roleMod.isModMAttrTemplates()) {
+            setAttrTemplates(role, roleMod.getMPlainAttrTemplates(), MPlainAttrTemplate.class, MPlainSchema.class);
+        }
+        if (roleMod.isModMDerAttrTemplates()) {
+            setAttrTemplates(role, roleMod.getMDerAttrTemplates(), MDerAttrTemplate.class, MDerSchema.class);
+        }
+        if (roleMod.isModMVirAttrTemplates()) {
+            setAttrTemplates(role, roleMod.getMVirAttrTemplates(), MVirAttrTemplate.class, MVirSchema.class);
+        }
+
+        // policies
+        if (roleMod.getPasswordPolicy() != null) {
+            role.setPasswordPolicy(roleMod.getPasswordPolicy().getKey() == null
+                    ? null
+                    : (PasswordPolicy) policyDAO.find(roleMod.getPasswordPolicy().getKey()));
+        }
+        if (roleMod.getAccountPolicy() != null) {
+            role.setAccountPolicy(roleMod.getAccountPolicy().getKey() == null
+                    ? null
+                    : (AccountPolicy) policyDAO.find(roleMod.getAccountPolicy().getKey()));
+        }
+
+        // owner
+        if (roleMod.getUserOwner() != null) {
+            role.setUserOwner(roleMod.getUserOwner().getKey() == null
+                    ? null
+                    : userDAO.find(roleMod.getUserOwner().getKey()));
+        }
+        if (roleMod.getRoleOwner() != null) {
+            role.setRoleOwner(roleMod.getRoleOwner().getKey() == null
+                    ? null
+                    : roleDAO.find(roleMod.getRoleOwner().getKey()));
+        }
+
+        // attributes, derived attributes, virtual attributes and resources
+        propByRes.merge(fill(role, roleMod, attrUtilFactory.getInstance(AttributableType.ROLE), scce));
+
+        return propByRes;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Transactional(readOnly = true)
+    public RoleTO getRoleTO(final Role role) {
+        connObjectUtil.retrieveVirAttrValues(role, attrUtilFactory.getInstance(AttributableType.ROLE));
+
+        RoleTO roleTO = new RoleTO();
+
+        // set sys info
+        roleTO.setCreator(role.getCreator());
+        roleTO.setCreationDate(role.getCreationDate());
+        roleTO.setLastModifier(role.getLastModifier());
+        roleTO.setLastChangeDate(role.getLastChangeDate());
+
+        roleTO.setKey(role.getKey());
+        roleTO.setName(role.getName());
+
+        roleTO.setInheritOwner(role.isInheritOwner());
+
+        roleTO.setInheritTemplates(role.isInheritTemplates());
+
+        roleTO.setInheritAttrs(role.isInheritPlainAttrs());
+        roleTO.setInheritDerAttrs(role.isInheritDerAttrs());
+        roleTO.setInheritVirAttrs(role.isInheritVirAttrs());
+
+        roleTO.setInheritPasswordPolicy(role.isInheritPasswordPolicy());
+        roleTO.setInheritAccountPolicy(role.isInheritAccountPolicy());
+
+        if (role.getParent() != null) {
+            roleTO.setParent(role.getParent().getKey());
+        }
+
+        if (role.getUserOwner() != null) {
+            roleTO.setUserOwner(role.getUserOwner().getKey());
+        }
+        if (role.getRoleOwner() != null) {
+            roleTO.setRoleOwner(role.getRoleOwner().getKey());
+        }
+
+        // -------------------------
+        // Retrieve all [derived/virtual] attributes (inherited and not)
+        // -------------------------        
+        final List<? extends RPlainAttr> allAttributes = role.findLastInheritedAncestorPlainAttrs();
+
+        final List<? extends RDerAttr> allDerAttributes = role.findLastInheritedAncestorDerAttrs();
+
+        final List<? extends RVirAttr> allVirAttributes = role.findLastInheritedAncestorVirAttrs();
+        // -------------------------
+
+        fillTO(roleTO, allAttributes, allDerAttributes, allVirAttributes, role.getResources());
+
+        for (Entitlement entitlement : role.getEntitlements()) {
+            roleTO.getEntitlements().add(entitlement.getKey());
+        }
+
+        for (RPlainAttrTemplate template : role.findInheritedTemplates(RPlainAttrTemplate.class)) {
+            roleTO.getRAttrTemplates().add(template.getSchema().getKey());
+        }
+        for (RDerAttrTemplate template : role.findInheritedTemplates(RDerAttrTemplate.class)) {
+            roleTO.getRDerAttrTemplates().add(template.getSchema().getKey());
+        }
+        for (RVirAttrTemplate template : role.findInheritedTemplates(RVirAttrTemplate.class)) {
+            roleTO.getRVirAttrTemplates().add(template.getSchema().getKey());
+        }
+        for (MPlainAttrTemplate template : role.findInheritedTemplates(MPlainAttrTemplate.class)) {
+            roleTO.getMAttrTemplates().add(template.getSchema().getKey());
+        }
+        for (MDerAttrTemplate template : role.findInheritedTemplates(MDerAttrTemplate.class)) {
+            roleTO.getMDerAttrTemplates().add(template.getSchema().getKey());
+        }
+        for (MVirAttrTemplate template : role.findInheritedTemplates(MVirAttrTemplate.class)) {
+            roleTO.getMVirAttrTemplates().add(template.getSchema().getKey());
+        }
+
+        roleTO.setPasswordPolicy(role.getPasswordPolicy() == null
+                ? null
+                : role.getPasswordPolicy().getKey());
+        roleTO.setAccountPolicy(role.getAccountPolicy() == null
+                ? null
+                : role.getAccountPolicy().getKey());
+
+        return roleTO;
+    }
+
+    @Transactional(readOnly = true)
+    public RoleTO getRoleTO(final Long key) {
+        return getRoleTO(roleDAO.authFetchRole(key));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SchemaDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SchemaDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SchemaDataBinder.java
new file mode 100644
index 0000000..79cb4a5
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SchemaDataBinder.java
@@ -0,0 +1,163 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.List;
+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.to.DerSchemaTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.DerSchema;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.VirSchema;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.apache.syncope.server.utils.jexl.JexlUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SchemaDataBinder {
+
+    @Autowired
+    private PlainSchemaDAO schemaDAO;
+
+    // --------------- PLAIN -----------------
+    private <T extends PlainSchema> void fill(final T schema, final PlainSchemaTO schemaTO) {
+        if (!JexlUtil.isExpressionValid(schemaTO.getMandatoryCondition())) {
+            SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+            sce.getElements().add(schemaTO.getMandatoryCondition());
+            throw sce;
+        }
+
+        BeanUtils.copyProperties(schemaTO, schema);
+    }
+
+    public <T extends PlainSchema> void create(final PlainSchemaTO schemaTO, final T schema) {
+        fill(schema, schemaTO);
+    }
+
+    public <T extends PlainSchema> void update(final PlainSchemaTO schemaTO, final T schema,
+            final AttributableUtil attributableUtil) {
+
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        List<PlainAttr> attrs = schemaDAO.findAttrs(schema, attributableUtil.plainAttrClass());
+        if (!attrs.isEmpty()) {
+            if (schema.getType() != schemaTO.getType()) {
+                SyncopeClientException e = SyncopeClientException.build(
+                        ClientExceptionType.valueOf("Invalid" + schema.getClass().getSimpleName()));
+                e.getElements().add("Cannot change type since " + schema.getKey() + " has attributes");
+
+                scce.addException(e);
+            }
+            if (schema.isUniqueConstraint() != schemaTO.isUniqueConstraint()) {
+                SyncopeClientException e = SyncopeClientException.build(ClientExceptionType.valueOf("Invalid"
+                        + schema.getClass().getSimpleName()));
+                e.getElements().add("Cannot alter unique contraint since " + schema.getKey() + " has attributes");
+
+                scce.addException(e);
+            }
+        }
+
+        if (scce.hasExceptions()) {
+            throw scce;
+        }
+
+        fill(schema, schemaTO);
+    }
+
+    public <T extends PlainSchema> PlainSchemaTO getSchemaTO(
+            final T schema, final AttributableUtil attributableUtil) {
+
+        PlainSchemaTO schemaTO = new PlainSchemaTO();
+        BeanUtils.copyProperties(schema, schemaTO);
+
+        return schemaTO;
+    }
+
+    // --------------- DERIVED -----------------
+    private <T extends DerSchema> T populate(final T derSchema, final DerSchemaTO derSchemaTO) {
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        if (StringUtils.isBlank(derSchemaTO.getExpression())) {
+            SyncopeClientException requiredValuesMissing =
+                    SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+            requiredValuesMissing.getElements().add("expression");
+
+            scce.addException(requiredValuesMissing);
+        } else if (!JexlUtil.isExpressionValid(derSchemaTO.getExpression())) {
+            SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
+                    ClientExceptionType.InvalidValues);
+            invalidMandatoryCondition.getElements().add(derSchemaTO.getExpression());
+
+            scce.addException(invalidMandatoryCondition);
+        }
+
+        if (scce.hasExceptions()) {
+            throw scce;
+        }
+
+        BeanUtils.copyProperties(derSchemaTO, derSchema);
+
+        return derSchema;
+    }
+
+    public <T extends DerSchema> T create(final DerSchemaTO derSchemaTO, final T derSchema) {
+        return populate(derSchema, derSchemaTO);
+    }
+
+    public <T extends DerSchema> T update(final DerSchemaTO derSchemaTO, final T derSchema) {
+        return populate(derSchema, derSchemaTO);
+    }
+
+    public <T extends DerSchema> DerSchemaTO getDerSchemaTO(final T derSchema) {
+        DerSchemaTO derSchemaTO = new DerSchemaTO();
+        BeanUtils.copyProperties(derSchema, derSchemaTO);
+
+        return derSchemaTO;
+    }
+
+    // --------------- VIRTUAL -----------------
+    private <T extends VirSchema> T fill(final T virSchema, final VirSchemaTO virSchemaTO) {
+        BeanUtils.copyProperties(virSchemaTO, virSchema);
+
+        return virSchema;
+    }
+
+    public <T extends VirSchema> T create(final VirSchemaTO virSchemaTO, final T virSchema) {
+        return fill(virSchema, virSchemaTO);
+    }
+
+    public <T extends VirSchema> T update(final VirSchemaTO virSchemaTO, final T virSchema) {
+        return fill(virSchema, virSchemaTO);
+    }
+
+    public <T extends VirSchema> VirSchemaTO getVirSchemaTO(final T virSchema) {
+        VirSchemaTO virSchemaTO = new VirSchemaTO();
+        BeanUtils.copyProperties(virSchema, virSchemaTO);
+
+        return virSchemaTO;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SecurityQuestionDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SecurityQuestionDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SecurityQuestionDataBinder.java
new file mode 100644
index 0000000..b8dce1d
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SecurityQuestionDataBinder.java
@@ -0,0 +1,51 @@
+/*
+ * 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.server.logic.data;
+
+import org.apache.syncope.common.lib.to.SecurityQuestionTO;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SecurityQuestionDataBinder {
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    public SecurityQuestionTO getSecurityQuestionTO(final SecurityQuestion securityQuestion) {
+        SecurityQuestionTO securityQuestionTO = new SecurityQuestionTO();
+
+        BeanUtils.copyProperties(securityQuestion, securityQuestionTO);
+
+        return securityQuestionTO;
+    }
+
+    public SecurityQuestion create(final SecurityQuestionTO securityQuestionTO) {
+        SecurityQuestion result = entityFactory.newEntity(SecurityQuestion.class);
+        update(result, securityQuestionTO);
+        return result;
+    }
+
+    public void update(final SecurityQuestion securityQuestion, final SecurityQuestionTO securityQuestionTO) {
+        BeanUtils.copyProperties(securityQuestionTO, securityQuestion, "key");
+    }
+}