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:25 UTC

[20/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/data/ReportDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ReportDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ReportDataBinderImpl.java
new file mode 100644
index 0000000..e98bc7d
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ReportDataBinderImpl.java
@@ -0,0 +1,142 @@
+/*
+ * 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.HashSet;
+import java.util.Set;
+import org.apache.syncope.core.provisioning.api.data.ReportDataBinder;
+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.core.persistence.api.dao.ReportExecDAO;
+import org.apache.syncope.core.persistence.api.entity.Report;
+import org.apache.syncope.core.persistence.api.entity.ReportExec;
+import org.apache.syncope.core.provisioning.api.job.JobNamer;
+import org.apache.syncope.core.misc.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;
+
+@Component
+public class ReportDataBinderImpl implements 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;
+
+    @Override
+    public void getReport(final Report report, final ReportTO reportTO) {
+        BeanUtils.copyProperties(reportTO, report, IGNORE_REPORT_PROPERTIES);
+
+        // 1. remove all reportlet confs
+        Set<ReportletConf> toRemove = new HashSet<>();
+        for (ReportletConf conf : report.getReportletConfs()) {
+            toRemove.add(conf);
+        }
+        for (ReportletConf conf : toRemove) {
+            report.removeReportletConf(conf);
+        }
+
+        // 2. take all reportlet confs from reportTO
+        for (ReportletConf conf : reportTO.getReportletConfs()) {
+            report.addReportletConf(conf);
+        }
+    }
+
+    @Override
+    public ReportTO getReportTO(final Report report) {
+        ReportTO reportTO = new ReportTO();
+        reportTO.setKey(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 = JobNamer.getTriggerName(JobNamer.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);
+        }
+    }
+
+    @Override
+    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/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
new file mode 100644
index 0000000..2bf756f
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -0,0 +1,362 @@
+/*
+ * 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.ResourceDataBinder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+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.IntMappingType;
+import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
+import org.apache.syncope.core.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.core.persistence.api.entity.ConnInstance;
+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.Mapping;
+import org.apache.syncope.core.persistence.api.entity.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.core.persistence.api.entity.SyncPolicy;
+import org.apache.syncope.core.persistence.api.entity.role.RMapping;
+import org.apache.syncope.core.persistence.api.entity.role.RMappingItem;
+import org.apache.syncope.core.persistence.api.entity.user.UMapping;
+import org.apache.syncope.core.persistence.api.entity.user.UMappingItem;
+import org.apache.syncope.core.provisioning.api.ConnectorRegistry;
+import org.apache.syncope.core.misc.jexl.JexlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.syncope.core.misc.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ResourceDataBinderImpl implements ResourceDataBinder {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(ResourceDataBinder.class);
+
+    private static final String[] MAPPINGITEM_IGNORE_PROPERTIES = { "key", "mapping" };
+
+    @Autowired
+    private ConnectorRegistry connRegistry;
+
+    @Autowired
+    private ConnInstanceDAO connInstanceDAO;
+
+    @Autowired
+    private PolicyDAO policyDAO;
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    @Override
+    public ExternalResource create(final ResourceTO resourceTO) {
+        return update(entityFactory.newEntity(ExternalResource.class), resourceTO);
+    }
+
+    @Override
+    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;
+    }
+
+    @Override
+    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 connRegistry.getOverriddenConnInstance(connInstanceClone, resourceTO.getConnConfProperties());
+    }
+
+    @Override
+    public List<ResourceTO> getResourceTOs(final Collection<? extends ExternalResource> resources) {
+        List<ResourceTO> resourceTOs = new ArrayList<>();
+        for (ExternalResource resource : resources) {
+            resourceTOs.add(getResourceTO(resource));
+        }
+
+        return resourceTOs;
+    }
+
+    @Override
+    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/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
new file mode 100644
index 0000000..2e12820
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RoleDataBinderImpl.java
@@ -0,0 +1,411 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.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.core.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.core.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.core.persistence.api.entity.AttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.Entitlement;
+import org.apache.syncope.core.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.core.persistence.api.entity.Schema;
+import org.apache.syncope.core.persistence.api.entity.membership.MDerAttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.membership.MDerSchema;
+import org.apache.syncope.core.persistence.api.entity.membership.MPlainAttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.membership.MPlainSchema;
+import org.apache.syncope.core.persistence.api.entity.membership.MVirAttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.membership.MVirSchema;
+import org.apache.syncope.core.persistence.api.entity.role.RDerAttr;
+import org.apache.syncope.core.persistence.api.entity.role.RDerAttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.role.RDerSchema;
+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.RPlainSchema;
+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.RVirSchema;
+import org.apache.syncope.core.persistence.api.entity.role.Role;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.core.provisioning.api.data.RoleDataBinder;
+import org.apache.syncope.core.misc.ConnObjectUtil;
+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 RoleDataBinderImpl extends AbstractAttributableDataBinder implements RoleDataBinder {
+
+    @Autowired
+    private ConnObjectUtil connObjectUtil;
+
+    @Autowired
+    private EntitlementDAO entitlementDAO;
+
+    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<>();
+        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 = entityFactory.newEntity(templateClass);
+                        template.setSchema(schema);
+                        template.setOwner(role);
+                        role.getAttrTemplates(templateClass).add(template);
+                    } catch (Exception e) {
+                        LOG.error("Could not create template for {}", templateClass, e);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public Role create(final Role role, final RoleTO roleTO) {
+        role.setInheritOwner(roleTO.isInheritOwner());
+
+        role.setInheritPlainAttrs(roleTO.isInheritPlainAttrs());
+        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.getRPlainAttrTemplates(), RPlainAttrTemplate.class, RPlainSchema.class);
+        setAttrTemplates(role, roleTO.getRDerAttrTemplates(), RDerAttrTemplate.class, RDerSchema.class);
+        setAttrTemplates(role, roleTO.getRVirAttrTemplates(), RVirAttrTemplate.class, RVirSchema.class);
+        setAttrTemplates(role, roleTO.getMPlainAttrTemplates(), 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;
+    }
+
+    @Override
+    public PropagationByResource update(final Role role, final RoleMod roleMod) {
+        PropagationByResource propByRes = new PropagationByResource();
+
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        // fetch account ids before update
+        Map<String, String> oldAccountIds = getAccountIds(role, AttributableType.ROLE);
+
+        // 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, role.getResourceNames());
+
+                    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));
+
+        // check if some account id was changed by the update above
+        Map<String, String> newAccountIds = getAccountIds(role, AttributableType.ROLE);
+        for (Map.Entry<String, String> entry : oldAccountIds.entrySet()) {
+            if (newAccountIds.containsKey(entry.getKey())
+                    && !entry.getValue().equals(newAccountIds.get(entry.getKey()))) {
+
+                propByRes.addOldAccountId(entry.getKey(), entry.getValue());
+                propByRes.add(ResourceOperation.UPDATE, entry.getKey());
+            }
+        }
+
+        return propByRes;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Transactional(readOnly = true)
+    @Override
+    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.setInheritPlainAttrs(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.getRPlainAttrTemplates().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.getMPlainAttrTemplates().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)
+    @Override
+    public RoleTO getRoleTO(final Long key) {
+        return getRoleTO(roleDAO.authFetch(key));
+    }
+}

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/SchemaDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
new file mode 100644
index 0000000..c0adde2
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SchemaDataBinderImpl.java
@@ -0,0 +1,170 @@
+/*
+ * 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.SchemaDataBinder;
+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.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.misc.spring.BeanUtils;
+import org.apache.syncope.core.misc.jexl.JexlUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SchemaDataBinderImpl implements 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);
+    }
+
+    @Override
+    public <T extends PlainSchema> void create(final PlainSchemaTO schemaTO, final T schema) {
+        fill(schema, schemaTO);
+    }
+
+    @Override
+    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.InvalidPlainSchema);
+                e.getElements().add("Cannot change type since " + schema.getKey() + " has attributes");
+
+                scce.addException(e);
+            }
+            if (schema.isUniqueConstraint() != schemaTO.isUniqueConstraint()) {
+                SyncopeClientException e = SyncopeClientException.build(ClientExceptionType.InvalidPlainSchema);
+                e.getElements().add("Cannot alter unique contraint since " + schema.getKey() + " has attributes");
+
+                scce.addException(e);
+            }
+        }
+
+        if (scce.hasExceptions()) {
+            throw scce;
+        }
+
+        fill(schema, schemaTO);
+    }
+
+    @Override
+    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 e = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+            e.getElements().add(derSchemaTO.getExpression());
+
+            scce.addException(e);
+        }
+
+        if (scce.hasExceptions()) {
+            throw scce;
+        }
+
+        BeanUtils.copyProperties(derSchemaTO, derSchema);
+
+        return derSchema;
+    }
+
+    @Override
+    public <T extends DerSchema> T create(final DerSchemaTO derSchemaTO, final T derSchema) {
+        return populate(derSchema, derSchemaTO);
+    }
+
+    @Override
+    public <T extends DerSchema> T update(final DerSchemaTO derSchemaTO, final T derSchema) {
+        return populate(derSchema, derSchemaTO);
+    }
+
+    @Override
+    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;
+    }
+
+    @Override
+    public <T extends VirSchema> T create(final VirSchemaTO virSchemaTO, final T virSchema) {
+        return fill(virSchema, virSchemaTO);
+    }
+
+    @Override
+    public <T extends VirSchema> T update(final VirSchemaTO virSchemaTO, final T virSchema) {
+        return fill(virSchema, virSchemaTO);
+    }
+
+    @Override
+    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/d30c8526/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SecurityQuestionDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SecurityQuestionDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SecurityQuestionDataBinderImpl.java
new file mode 100644
index 0000000..34523f2
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SecurityQuestionDataBinderImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.SecurityQuestionDataBinder;
+import org.apache.syncope.common.lib.to.SecurityQuestionTO;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.core.misc.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SecurityQuestionDataBinderImpl implements SecurityQuestionDataBinder {
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    @Override
+    public SecurityQuestionTO getSecurityQuestionTO(final SecurityQuestion securityQuestion) {
+        SecurityQuestionTO securityQuestionTO = new SecurityQuestionTO();
+
+        BeanUtils.copyProperties(securityQuestion, securityQuestionTO);
+
+        return securityQuestionTO;
+    }
+
+    @Override
+    public SecurityQuestion create(final SecurityQuestionTO securityQuestionTO) {
+        SecurityQuestion result = entityFactory.newEntity(SecurityQuestion.class);
+        update(result, securityQuestionTO);
+        return result;
+    }
+
+    @Override
+    public void update(final SecurityQuestion securityQuestion, final SecurityQuestionTO securityQuestionTO) {
+        BeanUtils.copyProperties(securityQuestionTO, securityQuestion, "key");
+    }
+}

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/TaskDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
new file mode 100644
index 0000000..091c108
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
@@ -0,0 +1,343 @@
+/*
+ * 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.TaskDataBinder;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractProvisioningTaskTO;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.to.TaskExecTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.TaskExecDAO;
+import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
+import org.apache.syncope.core.persistence.api.entity.task.PushTask;
+import org.apache.syncope.core.persistence.api.entity.task.SchedTask;
+import org.apache.syncope.core.persistence.api.entity.task.SyncTask;
+import org.apache.syncope.core.persistence.api.entity.task.Task;
+import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.core.persistence.api.entity.task.TaskUtil;
+import org.apache.syncope.core.provisioning.api.job.JobNamer;
+import org.apache.syncope.core.misc.spring.BeanUtils;
+import org.apache.syncope.core.misc.jexl.JexlUtil;
+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;
+
+@Component
+public class TaskDataBinderImpl implements TaskDataBinder {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(TaskDataBinder.class);
+
+    private static final String[] IGNORE_TASK_PROPERTIES = {
+        "executions", "resource", "matchingRule", "unmatchingRule" };
+
+    private static final String[] IGNORE_TASK_EXECUTION_PROPERTIES = { "key", "task" };
+
+    @Autowired
+    private ExternalResourceDAO resourceDAO;
+
+    @Autowired
+    private TaskExecDAO taskExecDAO;
+
+    @Autowired
+    private SchedulerFactoryBean scheduler;
+
+    private void checkJexl(final AbstractAttributableTO attributableTO, final SyncopeClientException sce) {
+        for (AttrTO attrTO : attributableTO.getPlainAttrs()) {
+            if (!attrTO.getValues().isEmpty() && !JexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
+                sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
+            }
+        }
+
+        for (AttrTO attrTO : attributableTO.getVirAttrs()) {
+            if (!attrTO.getValues().isEmpty() && !JexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
+                sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
+            }
+        }
+    }
+
+    private void fill(final ProvisioningTask task, final AbstractProvisioningTaskTO taskTO) {
+        SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSyncTask);
+
+        if (task instanceof PushTask && taskTO instanceof PushTaskTO) {
+            final PushTask pushTask = (PushTask) task;
+            final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
+
+            pushTask.setUserFilter(pushTaskTO.getUserFilter());
+            pushTask.setRoleFilter(pushTaskTO.getRoleFilter());
+
+            pushTask.setMatchingRule(pushTaskTO.getMatchingRule() == null
+                    ? MatchingRule.LINK : pushTaskTO.getMatchingRule());
+
+            pushTask.setUnmatchingRule(pushTaskTO.getUnmatchingRule() == null
+                    ? UnmatchingRule.ASSIGN : pushTaskTO.getUnmatchingRule());
+
+        } else if (task instanceof SyncTask && taskTO instanceof SyncTaskTO) {
+            final SyncTask syncTask = (SyncTask) task;
+            final SyncTaskTO syncTaskTO = (SyncTaskTO) taskTO;
+
+            syncTask.setMatchingRule(syncTaskTO.getMatchingRule() == null
+                    ? MatchingRule.UPDATE : syncTaskTO.getMatchingRule());
+
+            syncTask.setUnmatchingRule(syncTaskTO.getUnmatchingRule() == null
+                    ? UnmatchingRule.PROVISION : syncTaskTO.getUnmatchingRule());
+
+            // 1. validate JEXL expressions in user and role templates
+            if (syncTaskTO.getUserTemplate() != null) {
+                UserTO template = syncTaskTO.getUserTemplate();
+
+                if (StringUtils.isNotBlank(template.getUsername())
+                        && !JexlUtil.isExpressionValid(template.getUsername())) {
+
+                    sce.getElements().add("Invalid JEXL: " + template.getUsername());
+                }
+                if (StringUtils.isNotBlank(template.getPassword())
+                        && !JexlUtil.isExpressionValid(template.getPassword())) {
+
+                    sce.getElements().add("Invalid JEXL: " + template.getPassword());
+                }
+
+                checkJexl(template, sce);
+
+                for (MembershipTO memb : template.getMemberships()) {
+                    checkJexl(memb, sce);
+                }
+            }
+            if (syncTaskTO.getRoleTemplate() != null) {
+                RoleTO template = syncTaskTO.getRoleTemplate();
+
+                if (StringUtils.isNotBlank(template.getName()) && !JexlUtil.isExpressionValid(template.getName())) {
+                    sce.getElements().add("Invalid JEXL: " + template.getName());
+                }
+
+                checkJexl(template, sce);
+            }
+            if (!sce.isEmpty()) {
+                throw sce;
+            }
+
+            // 2. all JEXL expressions are valid: accept user and role templates
+            syncTask.setUserTemplate(syncTaskTO.getUserTemplate());
+            syncTask.setRoleTemplate(syncTaskTO.getRoleTemplate());
+
+            syncTask.setFullReconciliation(syncTaskTO.isFullReconciliation());
+        }
+
+        // 3. fill the remaining fields
+        task.setPerformCreate(taskTO.isPerformCreate());
+        task.setPerformUpdate(taskTO.isPerformUpdate());
+        task.setPerformDelete(taskTO.isPerformDelete());
+        task.setSyncStatus(taskTO.isSyncStatus());
+        task.getActionsClassNames().clear();
+        task.getActionsClassNames().addAll(taskTO.getActionsClassNames());
+    }
+
+    @Override
+    public SchedTask createSchedTask(final SchedTaskTO taskTO, final TaskUtil taskUtil) {
+        final Class<? extends AbstractTaskTO> taskTOClass = taskUtil.taskTOClass();
+
+        if (taskTOClass == null || !taskTOClass.equals(taskTO.getClass())) {
+            throw new IllegalArgumentException(
+                    String.format("taskUtil is type %s but task is not: %s", taskTOClass, taskTO.getClass()));
+        }
+
+        SchedTask task = taskUtil.newTask();
+        task.setCronExpression(taskTO.getCronExpression());
+        task.setName(taskTO.getName());
+        task.setDescription(taskTO.getDescription());
+
+        if (taskUtil.getType() == TaskType.SCHEDULED) {
+            task.setJobClassName(taskTO.getJobClassName());
+        } else if (taskTO instanceof AbstractProvisioningTaskTO) {
+            final AbstractProvisioningTaskTO provisioningTaskTO = (AbstractProvisioningTaskTO) taskTO;
+
+            ExternalResource resource = resourceDAO.find(provisioningTaskTO.getResource());
+            if (resource == null) {
+                throw new NotFoundException("Resource " + provisioningTaskTO.getResource());
+            }
+            ((ProvisioningTask) task).setResource(resource);
+
+            fill((ProvisioningTask) task, provisioningTaskTO);
+        }
+
+        return task;
+    }
+
+    @Override
+    public void updateSchedTask(final SchedTask task, final SchedTaskTO taskTO, final TaskUtil taskUtil) {
+        Class<? extends Task> taskClass = taskUtil.taskClass();
+        Class<? extends AbstractTaskTO> taskTOClass = taskUtil.taskTOClass();
+
+        if (taskClass == null || !taskClass.isAssignableFrom(task.getClass())) {
+            throw new IllegalArgumentException(
+                    String.format("taskUtil is type %s but task is not: %s", taskClass, task.getClass()));
+        }
+
+        if (taskTOClass == null || !taskTOClass.equals(taskTO.getClass())) {
+            throw new IllegalArgumentException(
+                    String.format("taskUtil is type %s but task is not: %s", taskTOClass, taskTO.getClass()));
+        }
+
+        task.setCronExpression(taskTO.getCronExpression());
+        if (StringUtils.isNotBlank(taskTO.getName())) {
+            task.setName(taskTO.getName());
+        }
+        if (StringUtils.isNotBlank(taskTO.getDescription())) {
+            task.setDescription(taskTO.getDescription());
+        }
+
+        if (task instanceof ProvisioningTask) {
+            fill((ProvisioningTask) task, (AbstractProvisioningTaskTO) taskTO);
+        }
+    }
+
+    @Override
+    public TaskExecTO getTaskExecTO(final TaskExec execution) {
+        TaskExecTO executionTO = new TaskExecTO();
+        BeanUtils.copyProperties(execution, executionTO, IGNORE_TASK_EXECUTION_PROPERTIES);
+
+        if (execution.getKey() != null) {
+            executionTO.setKey(execution.getKey());
+        }
+
+        if (execution.getTask() != null && execution.getTask().getKey() != null) {
+            executionTO.setTask(execution.getTask().getKey());
+        }
+
+        return executionTO;
+    }
+
+    private void setExecTime(final SchedTaskTO taskTO, final Task task) {
+        String triggerName = JobNamer.getTriggerName(JobNamer.getJobName(task));
+
+        Trigger trigger = null;
+        try {
+            trigger = scheduler.getScheduler().getTrigger(new TriggerKey(triggerName, Scheduler.DEFAULT_GROUP));
+        } catch (SchedulerException e) {
+            LOG.warn("While trying to get to " + triggerName, e);
+        }
+
+        if (trigger != null) {
+            taskTO.setLastExec(trigger.getPreviousFireTime());
+            taskTO.setNextExec(trigger.getNextFireTime());
+        }
+    }
+
+    @Override
+    public <T extends AbstractTaskTO> T getTaskTO(final Task task, final TaskUtil taskUtil) {
+        T taskTO = taskUtil.newTaskTO();
+        BeanUtils.copyProperties(task, taskTO, IGNORE_TASK_PROPERTIES);
+
+        TaskExec latestExec = taskExecDAO.findLatestStarted(task);
+        taskTO.setLatestExecStatus(latestExec == null ? "" : latestExec.getStatus());
+        taskTO.setStartDate(latestExec == null ? null : latestExec.getStartDate());
+        taskTO.setEndDate(latestExec == null ? null : latestExec.getEndDate());
+
+        for (TaskExec execution : task.getExecs()) {
+            taskTO.getExecutions().add(getTaskExecTO(execution));
+        }
+
+        switch (taskUtil.getType()) {
+            case PROPAGATION:
+                if (!(task instanceof PropagationTask)) {
+                    throw new IllegalArgumentException("taskUtil is type Propagation but task is not PropagationTask: "
+                            + task.getClass().getName());
+                }
+                ((PropagationTaskTO) taskTO).setResource(((PropagationTask) task).getResource().getKey());
+                break;
+
+            case SCHEDULED:
+                if (!(task instanceof SchedTask)) {
+                    throw new IllegalArgumentException("taskUtil is type Sched but task is not SchedTask: "
+                            + task.getClass().getName());
+                }
+                setExecTime((SchedTaskTO) taskTO, task);
+                ((SchedTaskTO) taskTO).setName(((SchedTask) task).getName());
+                ((SchedTaskTO) taskTO).setDescription(((SchedTask) task).getDescription());
+                break;
+
+            case SYNCHRONIZATION:
+                if (!(task instanceof SyncTask)) {
+                    throw new IllegalArgumentException("taskUtil is type Sync but task is not SyncTask: "
+                            + task.getClass().getName());
+                }
+                setExecTime((SchedTaskTO) taskTO, task);
+                ((SyncTaskTO) taskTO).setName(((SyncTask) task).getName());
+                ((SyncTaskTO) taskTO).setDescription(((SyncTask) task).getDescription());
+                ((SyncTaskTO) taskTO).setResource(((SyncTask) task).getResource().getKey());
+                ((SyncTaskTO) taskTO).setMatchingRule(((SyncTask) task).getMatchingRule() == null
+                        ? MatchingRule.UPDATE : ((SyncTask) task).getMatchingRule());
+                ((SyncTaskTO) taskTO).setUnmatchingRule(((SyncTask) task).getUnmatchingRule() == null
+                        ? UnmatchingRule.PROVISION : ((SyncTask) task).getUnmatchingRule());
+                break;
+
+            case PUSH:
+                if (!(task instanceof PushTask)) {
+                    throw new IllegalArgumentException("taskUtil is type Push but task is not PushTask: "
+                            + task.getClass().getName());
+                }
+                setExecTime((SchedTaskTO) taskTO, task);
+                ((PushTaskTO) taskTO).setName(((PushTask) task).getName());
+                ((PushTaskTO) taskTO).setDescription(((PushTask) task).getDescription());
+                ((PushTaskTO) taskTO).setResource(((PushTask) task).getResource().getKey());
+                ((PushTaskTO) taskTO).setMatchingRule(((PushTask) task).getMatchingRule() == null
+                        ? MatchingRule.LINK : ((PushTask) task).getMatchingRule());
+                ((PushTaskTO) taskTO).setUnmatchingRule(((PushTask) task).getUnmatchingRule() == null
+                        ? UnmatchingRule.ASSIGN : ((PushTask) task).getUnmatchingRule());
+                break;
+
+            case NOTIFICATION:
+                if (((NotificationTask) task).isExecuted() && StringUtils.isBlank(taskTO.getLatestExecStatus())) {
+                    taskTO.setLatestExecStatus("[EXECUTED]");
+                }
+                break;
+
+            default:
+        }
+
+        return taskTO;
+    }
+}

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/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
new file mode 100644
index 0000000..af6dbb6
--- /dev/null
+++ b/syncope620/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -0,0 +1,411 @@
+/*
+ * 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.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Resource;
+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.MembershipMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.CipherAlgorithm;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.persistence.api.dao.ConfDAO;
+import org.apache.syncope.core.persistence.api.dao.SecurityQuestionDAO;
+import org.apache.syncope.core.persistence.api.entity.DerAttr;
+import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.membership.MDerAttr;
+import org.apache.syncope.core.persistence.api.entity.membership.MPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.membership.MVirAttr;
+import org.apache.syncope.core.persistence.api.entity.membership.Membership;
+import org.apache.syncope.core.persistence.api.entity.role.Role;
+import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
+import org.apache.syncope.core.misc.security.AuthContextUtil;
+import org.apache.syncope.core.misc.security.Encryptor;
+import org.apache.syncope.core.misc.spring.BeanUtils;
+import org.apache.syncope.core.misc.ConnObjectUtil;
+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 UserDataBinderImpl extends AbstractAttributableDataBinder implements UserDataBinder {
+
+    private static final String[] IGNORE_USER_PROPERTIES = {
+        "memberships", "plainAttrs", "derAttrs", "virAttrs", "resources", "securityQuestion", "securityAnswer"
+    };
+
+    @Autowired
+    private ConfDAO confDAO;
+
+    @Autowired
+    private ConnObjectUtil connObjectUtil;
+
+    @Autowired
+    private SecurityQuestionDAO securityQuestionDAO;
+
+    @Resource(name = "adminUser")
+    private String adminUser;
+
+    @Resource(name = "anonymousUser")
+    private String anonymousUser;
+
+    private final Encryptor encryptor = Encryptor.getInstance();
+
+    @Transactional(readOnly = true)
+    @Override
+    public UserTO getAuthenticatedUserTO() {
+        final UserTO authUserTO;
+
+        final String authUsername = AuthContextUtil.getAuthenticatedUsername();
+        if (anonymousUser.equals(authUsername)) {
+            authUserTO = new UserTO();
+            authUserTO.setKey(-2);
+            authUserTO.setUsername(anonymousUser);
+        } else if (adminUser.equals(authUsername)) {
+            authUserTO = new UserTO();
+            authUserTO.setKey(-1);
+            authUserTO.setUsername(adminUser);
+        } else {
+            User authUser = userDAO.find(authUsername);
+            authUserTO = getUserTO(authUser);
+        }
+
+        return authUserTO;
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public boolean verifyPassword(final String username, final String password) {
+        return verifyPassword(userDAO.authFetch(username), password);
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public boolean verifyPassword(final User user, final String password) {
+        return encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword());
+    }
+
+    private void setPassword(final User user, final String password,
+            final SyncopeClientCompositeException scce) {
+
+        try {
+            final String algorithm = confDAO.find(
+                    "password.cipher.algorithm", CipherAlgorithm.AES.name()).getValues().get(0).getStringValue();
+            CipherAlgorithm predefined = CipherAlgorithm.valueOf(algorithm);
+            user.setPassword(password, predefined);
+        } catch (IllegalArgumentException e) {
+            final SyncopeClientException invalidCiperAlgorithm =
+                    SyncopeClientException.build(ClientExceptionType.NotFound);
+            invalidCiperAlgorithm.getElements().add(e.getMessage());
+            scce.addException(invalidCiperAlgorithm);
+
+            throw scce;
+        }
+    }
+
+    @Override
+    public void create(final User user, final UserTO userTO, final boolean storePassword) {
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        // memberships
+        Role role;
+        for (MembershipTO membershipTO : userTO.getMemberships()) {
+            role = roleDAO.find(membershipTO.getRoleId());
+
+            if (role == null) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Ignoring invalid role " + membershipTO.getRoleName());
+                }
+            } else {
+                Membership membership = null;
+                if (user.getKey() != null) {
+                    membership = user.getMembership(role.getKey()) == null
+                            ? membershipDAO.find(user, role)
+                            : user.getMembership(role.getKey());
+                }
+                if (membership == null) {
+                    membership = entityFactory.newEntity(Membership.class);
+                    membership.setRole(role);
+                    membership.setUser(user);
+
+                    user.addMembership(membership);
+                }
+
+                fill(membership, membershipTO, attrUtilFactory.getInstance(AttributableType.MEMBERSHIP), scce);
+            }
+        }
+
+        // attributes, derived attributes, virtual attributes and resources
+        fill(user, userTO, attrUtilFactory.getInstance(AttributableType.USER), scce);
+
+        // set password
+        if (StringUtils.isBlank(userTO.getPassword()) || !storePassword) {
+            LOG.debug("Password was not provided or not required to be stored");
+        } else {
+            setPassword(user, userTO.getPassword(), scce);
+        }
+
+        // set username
+        user.setUsername(userTO.getUsername());
+
+        // security question / answer
+        if (userTO.getSecurityQuestion() != null) {
+            SecurityQuestion securityQuestion = securityQuestionDAO.find(userTO.getSecurityQuestion());
+            if (securityQuestion != null) {
+                user.setSecurityQuestion(securityQuestion);
+            }
+        }
+        user.setSecurityAnswer(userTO.getSecurityAnswer());
+    }
+
+    /**
+     * Update user, given UserMod.
+     *
+     * @param toBeUpdated user to be updated
+     * @param userMod bean containing update request
+     * @return updated user + propagation by resource
+     * @see PropagationByResource
+     */
+    @Override
+    public PropagationByResource update(final User toBeUpdated, final UserMod userMod) {
+        // Re-merge any pending change from workflow tasks
+        User user = userDAO.save(toBeUpdated);
+
+        PropagationByResource propByRes = new PropagationByResource();
+
+        SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+        Set<String> currentResources = user.getResourceNames();
+
+        // fetch account ids before update
+        Map<String, String> oldAccountIds = getAccountIds(user, AttributableType.USER);
+
+        // password
+        if (StringUtils.isNotBlank(userMod.getPassword())) {
+            setPassword(user, userMod.getPassword(), scce);
+            user.setChangePwdDate(new Date());
+            propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+        }
+
+        // username
+        if (userMod.getUsername() != null && !userMod.getUsername().equals(user.getUsername())) {
+            propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+
+            user.setUsername(userMod.getUsername());
+        }
+
+        // security question / answer:
+        // userMod.getSecurityQuestion() is null => remove user security question and answer
+        // userMod.getSecurityQuestion() == 0 => don't change anything
+        // userMod.getSecurityQuestion() > 0 => update user security question and answer
+        if (userMod.getSecurityQuestion() == null) {
+            user.setSecurityQuestion(null);
+            user.setSecurityAnswer(null);
+        } else if (userMod.getSecurityQuestion() > 0) {
+            SecurityQuestion securityQuestion = securityQuestionDAO.find(userMod.getSecurityQuestion());
+            if (securityQuestion != null) {
+                user.setSecurityQuestion(securityQuestion);
+                user.setSecurityAnswer(userMod.getSecurityAnswer());
+            }
+        }
+
+        // attributes, derived attributes, virtual attributes and resources
+        propByRes.merge(fill(user, userMod, attrUtilFactory.getInstance(AttributableType.USER), scce));
+
+        // store the role ids of membership required to be added
+        Set<Long> membershipToBeAddedRoleIds = new HashSet<>();
+        for (MembershipMod membToBeAdded : userMod.getMembershipsToAdd()) {
+            membershipToBeAddedRoleIds.add(membToBeAdded.getRole());
+        }
+
+        final Set<String> toBeDeprovisioned = new HashSet<>();
+        final Set<String> toBeProvisioned = new HashSet<>();
+
+        // memberships to be removed
+        for (Long membershipId : userMod.getMembershipsToRemove()) {
+            LOG.debug("Membership to be removed: {}", membershipId);
+
+            Membership membership = membershipDAO.find(membershipId);
+            if (membership == null) {
+                LOG.debug("Invalid membership id specified to be removed: {}", membershipId);
+            } else {
+                if (!membershipToBeAddedRoleIds.contains(membership.getRole().getKey())) {
+                    toBeDeprovisioned.addAll(membership.getRole().getResourceNames());
+                }
+
+                // In order to make the removeMembership() below to work,
+                // we need to be sure to take exactly the same membership
+                // of the user object currently in memory (which has potentially
+                // some modifications compared to the one stored in the DB
+                membership = user.getMembership(membership.getRole().getKey());
+                if (membershipToBeAddedRoleIds.contains(membership.getRole().getKey())) {
+                    Set<Long> attributeIds = new HashSet<>(membership.getPlainAttrs().size());
+                    for (PlainAttr attribute : membership.getPlainAttrs()) {
+                        attributeIds.add(attribute.getKey());
+                    }
+                    for (Long attributeId : attributeIds) {
+                        plainAttrDAO.delete(attributeId, MPlainAttr.class);
+                    }
+                    attributeIds.clear();
+
+                    // remove derived attributes
+                    for (DerAttr derAttr : membership.getDerAttrs()) {
+                        attributeIds.add(derAttr.getKey());
+                    }
+                    for (Long derAttrId : attributeIds) {
+                        derAttrDAO.delete(derAttrId, MDerAttr.class);
+                    }
+                    attributeIds.clear();
+
+                    // remove virtual attributes
+                    for (VirAttr virAttr : membership.getVirAttrs()) {
+                        attributeIds.add(virAttr.getKey());
+                    }
+                    for (Long virAttrId : attributeIds) {
+                        virAttrDAO.delete(virAttrId, MVirAttr.class);
+                    }
+                    attributeIds.clear();
+                } else {
+                    user.removeMembership(membership);
+
+                    membershipDAO.delete(membershipId);
+                }
+            }
+        }
+
+        // memberships to be added
+        for (MembershipMod membershipMod : userMod.getMembershipsToAdd()) {
+            LOG.debug("Membership to be added: role({})", membershipMod.getRole());
+
+            Role role = roleDAO.find(membershipMod.getRole());
+            if (role == null) {
+                LOG.debug("Ignoring invalid role {}", membershipMod.getRole());
+            } else {
+                Membership membership = user.getMembership(role.getKey());
+                if (membership == null) {
+                    membership = entityFactory.newEntity(Membership.class);
+                    membership.setRole(role);
+                    membership.setUser(user);
+
+                    user.addMembership(membership);
+
+                    toBeProvisioned.addAll(role.getResourceNames());
+                }
+
+                propByRes.merge(fill(membership, membershipMod,
+                        attrUtilFactory.getInstance(AttributableType.MEMBERSHIP), scce));
+            }
+        }
+
+        propByRes.addAll(ResourceOperation.DELETE, toBeDeprovisioned);
+        propByRes.addAll(ResourceOperation.UPDATE, toBeProvisioned);
+
+        /**
+         * In case of new memberships all the current resources have to be updated in order to propagate new role and
+         * membership attribute values.
+         */
+        if (!toBeDeprovisioned.isEmpty() || !toBeProvisioned.isEmpty()) {
+            currentResources.removeAll(toBeDeprovisioned);
+            propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+        }
+
+        // check if some account id was changed by the update above
+        Map<String, String> newAccountIds = getAccountIds(user, AttributableType.USER);
+        for (Map.Entry<String, String> entry : oldAccountIds.entrySet()) {
+            if (newAccountIds.containsKey(entry.getKey())
+                    && !entry.getValue().equals(newAccountIds.get(entry.getKey()))) {
+
+                propByRes.addOldAccountId(entry.getKey(), entry.getValue());
+                propByRes.add(ResourceOperation.UPDATE, entry.getKey());
+            }
+        }
+
+        return propByRes;
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public UserTO getUserTO(final User user) {
+        UserTO userTO = new UserTO();
+
+        BeanUtils.copyProperties(user, userTO, IGNORE_USER_PROPERTIES);
+
+        if (user.getSecurityQuestion() != null) {
+            userTO.setSecurityQuestion(user.getSecurityQuestion().getKey());
+        }
+
+        connObjectUtil.retrieveVirAttrValues(user, attrUtilFactory.getInstance(AttributableType.USER));
+        fillTO(userTO, user.getPlainAttrs(), user.getDerAttrs(), user.getVirAttrs(), user.getResources());
+
+        MembershipTO membershipTO;
+        for (Membership membership : user.getMemberships()) {
+            membershipTO = new MembershipTO();
+
+            // set sys info
+            membershipTO.setCreator(membership.getCreator());
+            membershipTO.setCreationDate(membership.getCreationDate());
+            membershipTO.setLastModifier(membership.getLastModifier());
+            membershipTO.setLastChangeDate(membership.getLastChangeDate());
+
+            membershipTO.setKey(membership.getKey());
+            membershipTO.setRoleId(membership.getRole().getKey());
+            membershipTO.setRoleName(membership.getRole().getName());
+
+            // SYNCOPE-458 retrieve also membership virtual attributes
+            connObjectUtil.retrieveVirAttrValues(membership, attrUtilFactory.getInstance(AttributableType.MEMBERSHIP));
+
+            fillTO(membershipTO,
+                    membership.getPlainAttrs(), membership.getDerAttrs(), membership.getVirAttrs(),
+                    Collections.<ExternalResource>emptyList());
+
+            userTO.getMemberships().add(membershipTO);
+        }
+
+        return userTO;
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public UserTO getUserTO(final String username) {
+        return getUserTO(userDAO.authFetch(username));
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public UserTO getUserTO(final Long key) {
+        return getUserTO(userDAO.authFetch(key));
+    }
+
+}