syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [2/2] syncope git commit: [SYNCOPE-698] Implementation completed
Date Fri, 25 Sep 2015 14:43:34 GMT
[SYNCOPE-698] Implementation completed


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/72e6ceb0
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/72e6ceb0
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/72e6ceb0

Branch: refs/heads/master
Commit: 72e6ceb0624a90a9b63bafce37c04104c7391d79
Parents: 5537d29
Author: Francesco Chicchiriccò <ilgrosso@apache.org>
Authored: Fri Sep 25 16:43:23 2015 +0200
Committer: Francesco Chicchiriccò <ilgrosso@apache.org>
Committed: Fri Sep 25 16:43:23 2015 +0200

----------------------------------------------------------------------
 .../syncope/common/lib/to/MappingItemTO.java    |  11 +-
 .../apache/syncope/common/lib/to/SyncopeTO.java |   9 +
 .../syncope/core/logic/ResourceLogic.java       |   8 +-
 .../apache/syncope/core/logic/SyncopeLogic.java |  25 +-
 .../init/ClassPathScanImplementationLookup.java |   6 +
 .../syncope/core/misc/ConnObjectUtils.java      | 232 ++-------
 .../apache/syncope/core/misc/MappingUtils.java  | 501 +++++++++++++------
 .../core/misc/security/AuthDataAccessor.java    |   9 +-
 .../serialization/GuardedStringSerializer.java  |   4 +-
 .../persistence/api/ImplementationLookup.java   |   1 +
 .../api/entity/resource/MappingItem.java        |   3 +
 .../jpa/entity/resource/JPAMappingItem.java     |  22 +
 .../entity/ExternalResourceValidator.java       |  22 +
 .../api/data/MappingItemTransformer.java        |  47 ++
 .../provisioning/java/AsyncConnectorFacade.java |  14 +-
 .../provisioning/java/VirAttrHandlerImpl.java   |  44 +-
 .../java/data/AbstractAnyDataBinder.java        |  19 +-
 .../data/DefaultMappingItemTransformer.java     |  40 ++
 .../AbstractPropagationTaskExecutor.java        |  33 +-
 .../propagation/DefaultPropagationActions.java  |   2 +-
 .../propagation/DefaultPropagationReporter.java |   2 +-
 .../propagation/PropagationManagerImpl.java     |  10 +-
 .../java/sync/AbstractPushResultHandler.java    |   6 +-
 .../java/sync/AbstractSyncResultHandler.java    |   2 +-
 .../sync/PlainAttrsSyncCorrelationRule.java     |  41 +-
 .../core/provisioning/java/sync/SyncUtils.java  |  37 +-
 .../reference/PrefixMappingItemTransformer.java |  55 ++
 .../fit/core/reference/SyncTaskITCase.java      | 101 ++--
 28 files changed, 824 insertions(+), 482 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
index f252fbb..b838f6e 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
@@ -18,6 +18,8 @@
  */
 package org.apache.syncope.common.lib.to;
 
+import java.util.ArrayList;
+import java.util.List;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 import org.apache.syncope.common.lib.AbstractBaseBean;
@@ -64,10 +66,12 @@ public class MappingItemTO extends AbstractBaseBean {
     private String mandatoryCondition = "false";
 
     /**
-     * Mapping purposes: SYNCHRONIZATION, PROPAGATION, BOTH, NONE.
+     * Mapping purposes.
      */
     private MappingPurpose purpose;
 
+    private final List<String> mappingItemTransformerClassNames = new ArrayList<>();
+
     public boolean isConnObjectKey() {
         return connObjectKey;
     }
@@ -131,4 +135,9 @@ public class MappingItemTO extends AbstractBaseBean {
     public void setPurpose(final MappingPurpose purpose) {
         this.purpose = purpose;
     }
+
+    public List<String> getMappingItemTransformerClassNames() {
+        return mappingItemTransformerClassNames;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java
index 638f32f..f65badc 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncopeTO.java
@@ -65,6 +65,8 @@ public class SyncopeTO extends AbstractBaseBean {
 
     private final List<String> passwordRules = new ArrayList<>();
 
+    private final List<String> mappingItemTransformers = new ArrayList<>();
+
     private final List<String> taskJobs = new ArrayList<>();
 
     private final List<String> logicActions = new ArrayList<>();
@@ -163,6 +165,13 @@ public class SyncopeTO extends AbstractBaseBean {
         return passwordRules;
     }
 
+    @XmlElementWrapper(name = "mappingItemTransformers")
+    @XmlElement(name = "mappingItemTransformer")
+    @JsonProperty("mappingItemTransformers")
+    public List<String> getMappingItemTransformers() {
+        return mappingItemTransformers;
+    }
+
     @XmlElementWrapper(name = "taskJobs")
     @XmlElement(name = "taskJob")
     @JsonProperty("taskJobs")

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index 7defb27..c3ce0c6 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -36,7 +36,6 @@ import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.Entitlement;
-import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.persistence.api.dao.DuplicateException;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
@@ -93,6 +92,9 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
     private ConnObjectUtils connObjectUtils;
 
     @Autowired
+    private MappingUtils mappingUtils;
+
+    @Autowired
     private ConnectorFactory connFactory;
 
     @PreAuthorize("hasRole('" + Entitlement.RESOURCE_CREATE + "')")
@@ -216,13 +218,13 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
             throw new NotFoundException(
                     "ConnObjectKey mapping for " + init.getMiddle() + " " + anyKey + " on resource '" + key + "'");
         }
-        String connObjectKeyValue = MappingUtils.getConnObjectKeyValue(any, init.getRight());
+        String connObjectKeyValue = mappingUtils.getConnObjectKeyValue(any, init.getRight());
 
         Connector connector = connFactory.getConnector(init.getLeft());
         ConnectorObject connectorObject = connector.getObject(
                 init.getRight().getObjectClass(),
                 new Uid(connObjectKeyValue),
-                connector.getOperationOptions(MappingUtils.getMappingItems(init.getRight(), MappingPurpose.BOTH)));
+                connector.getOperationOptions(MappingUtils.getBothMappingItems(init.getRight())));
         if (connectorObject == null) {
             throw new NotFoundException(
                     "Object " + connObjectKeyValue + " with class " + init.getRight().getObjectClass()

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
index 7f9b7c9..480efc1 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/SyncopeLogic.java
@@ -82,7 +82,7 @@ public class SyncopeLogic extends AbstractLogic<SyncopeTO> {
     private PasswordGenerator passwordGenerator;
 
     @Autowired
-    private ImplementationLookup implementationLookup;
+    private ImplementationLookup implLookup;
 
     @Resource(name = "velocityResourceLoader")
     private ResourceWithFallbackLoader resourceLoader;
@@ -128,17 +128,18 @@ public class SyncopeLogic extends AbstractLogic<SyncopeTO> {
         syncopeTO.setVirAttrCache(virAttrCache.getClass().getName());
         syncopeTO.setPasswordGenerator(passwordGenerator.getClass().getName());
 
-        syncopeTO.getReportlets().addAll(implementationLookup.getClassNames(Type.REPORTLET));
-        syncopeTO.getAccountRules().addAll(implementationLookup.getClassNames(Type.ACCOUNT_RULE));
-        syncopeTO.getPasswordRules().addAll(implementationLookup.getClassNames(Type.PASSWORD_RULE));
-        syncopeTO.getTaskJobs().addAll(implementationLookup.getClassNames(Type.TASKJOBDELEGATE));
-        syncopeTO.getLogicActions().addAll(implementationLookup.getClassNames(Type.LOGIC_ACTIONS));
-        syncopeTO.getPropagationActions().addAll(implementationLookup.getClassNames(Type.PROPAGATION_ACTIONS));
-        syncopeTO.getSyncActions().addAll(implementationLookup.getClassNames(Type.SYNC_ACTIONS));
-        syncopeTO.getPushActions().addAll(implementationLookup.getClassNames(Type.PUSH_ACTIONS));
-        syncopeTO.getSyncCorrelationRules().addAll(implementationLookup.getClassNames(Type.SYNC_CORRELATION_RULE));
-        syncopeTO.getPushCorrelationRules().addAll(implementationLookup.getClassNames(Type.PUSH_CORRELATION_RULE));
-        syncopeTO.getValidators().addAll(implementationLookup.getClassNames(Type.VALIDATOR));
+        syncopeTO.getReportlets().addAll(implLookup.getClassNames(Type.REPORTLET));
+        syncopeTO.getAccountRules().addAll(implLookup.getClassNames(Type.ACCOUNT_RULE));
+        syncopeTO.getPasswordRules().addAll(implLookup.getClassNames(Type.PASSWORD_RULE));
+        syncopeTO.getMappingItemTransformers().addAll(implLookup.getClassNames(Type.MAPPING_ITEM_TRANSFORMER));
+        syncopeTO.getTaskJobs().addAll(implLookup.getClassNames(Type.TASKJOBDELEGATE));
+        syncopeTO.getLogicActions().addAll(implLookup.getClassNames(Type.LOGIC_ACTIONS));
+        syncopeTO.getPropagationActions().addAll(implLookup.getClassNames(Type.PROPAGATION_ACTIONS));
+        syncopeTO.getSyncActions().addAll(implLookup.getClassNames(Type.SYNC_ACTIONS));
+        syncopeTO.getPushActions().addAll(implLookup.getClassNames(Type.PUSH_ACTIONS));
+        syncopeTO.getSyncCorrelationRules().addAll(implLookup.getClassNames(Type.SYNC_CORRELATION_RULE));
+        syncopeTO.getPushCorrelationRules().addAll(implLookup.getClassNames(Type.PUSH_CORRELATION_RULE));
+        syncopeTO.getValidators().addAll(implLookup.getClassNames(Type.VALIDATOR));
 
         Set<String> htmlTemplates = new HashSet<>();
         Set<String> textTemplates = new HashSet<>();

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
index d68df96..5147a39 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
@@ -38,6 +38,7 @@ import org.apache.syncope.core.persistence.api.dao.AccountRuleConfClass;
 import org.apache.syncope.core.persistence.api.dao.PasswordRule;
 import org.apache.syncope.core.persistence.api.dao.PasswordRuleConfClass;
 import org.apache.syncope.core.provisioning.api.LogicActions;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
 import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
 import org.apache.syncope.core.provisioning.api.sync.PushActions;
@@ -90,6 +91,7 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
         scanner.addIncludeFilter(new AssignableTypeFilter(Reportlet.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(AccountRule.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(PasswordRule.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(MappingItemTransformer.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(SchedTaskJobDelegate.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(LogicActions.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(PropagationActions.class));
@@ -131,6 +133,10 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
                     }
                 }
 
+                if (MappingItemTransformer.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                    classNames.get(Type.MAPPING_ITEM_TRANSFORMER).add(clazz.getName());
+                }
+
                 if (SchedTaskJobDelegate.class.isAssignableFrom(clazz) && !isAbsractClazz
                         && !SyncJobDelegate.class.isAssignableFrom(clazz)
                         && !PushJobDelegate.class.isAssignableFrom(clazz)) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
index 7c39bb7..f78cc31 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
@@ -21,11 +21,7 @@ package org.apache.syncope.core.misc;
 import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
 import org.apache.syncope.core.misc.security.SecureRandomUtils;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.AnyOperations;
 import org.apache.syncope.common.lib.patch.AnyPatch;
@@ -37,17 +33,11 @@ import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.AttrSchemaType;
-import org.apache.syncope.common.lib.types.MappingPurpose;
-import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.task.SyncTask;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.misc.security.Encryptor;
@@ -71,6 +61,8 @@ public class ConnObjectUtils {
 
     private static final Logger LOG = LoggerFactory.getLogger(ConnObjectUtils.class);
 
+    private static final Encryptor ENCRYPTOR = Encryptor.getInstance();
+
     @Autowired
     private TemplateUtils templateUtils;
 
@@ -84,12 +76,44 @@ public class ConnObjectUtils {
     private ExternalResourceDAO resourceDAO;
 
     @Autowired
-    private PlainSchemaDAO plainSchemaDAO;
+    private PasswordGenerator passwordGenerator;
 
     @Autowired
-    private PasswordGenerator pwdGen;
+    private MappingUtils mappingUtils;
+
+    /**
+     * Extract password value from passed value (if instance of GuardedString or GuardedByteArray).
+     *
+     * @param pwd received from the underlying connector
+     * @return password value
+     */
+    public static String getPassword(final Object pwd) {
+        final StringBuilder result = new StringBuilder();
+
+        if (pwd instanceof GuardedString) {
+            ((GuardedString) pwd).access(new GuardedString.Accessor() {
+
+                @Override
+                public void access(final char[] clearChars) {
+                    result.append(clearChars);
+                }
+            });
+        } else if (pwd instanceof GuardedByteArray) {
+            ((GuardedByteArray) pwd).access(new GuardedByteArray.Accessor() {
+
+                @Override
+                public void access(final byte[] clearBytes) {
+                    result.append(new String(clearBytes));
+                }
+            });
+        } else if (pwd instanceof String) {
+            result.append((String) pwd);
+        } else {
+            result.append(pwd.toString());
+        }
 
-    private final Encryptor encryptor = Encryptor.getInstance();
+        return result.toString();
+    }
 
     /**
      * Build a UserTO / GroupTO / AnyObjectTO out of connector object attributes and schema mapping.
@@ -131,7 +155,7 @@ public class ConnObjectUtils {
 
             String password;
             try {
-                password = pwdGen.generate(ruleConfs);
+                password = passwordGenerator.generate(ruleConfs);
             } catch (InvalidPasswordRuleConf e) {
                 LOG.error("Could not generate policy-compliant random password for {}", userTO, e);
 
@@ -167,7 +191,7 @@ public class ConnObjectUtils {
             // update password if and only if password is really changed
             User user = userDAO.authFind(key);
             if (StringUtils.isBlank(((UserTO) updated).getPassword())
-                    || encryptor.verify(((UserTO) updated).getPassword(),
+                    || ENCRYPTOR.verify(((UserTO) updated).getPassword(),
                             user.getCipherAlgorithm(), user.getPassword())) {
 
                 ((UserTO) updated).setPassword(null);
@@ -190,127 +214,8 @@ public class ConnObjectUtils {
 
         // 1. fill with data from connector object
         anyTO.setRealm(syncTask.getDestinatioRealm().getFullPath());
-        for (MappingItem item : MappingUtils.getMappingItems(provision, MappingPurpose.SYNCHRONIZATION)) {
-            Attribute attr = obj.getAttributeByName(item.getExtAttrName());
-
-            AttrTO attrTO;
-            switch (item.getIntMappingType()) {
-                case UserKey:
-                case GroupKey:
-                case AnyObjectKey:
-                    break;
-
-                case Password:
-                    if (anyTO instanceof UserTO && attr != null && attr.getValue() != null
-                            && !attr.getValue().isEmpty()) {
-
-                        ((UserTO) anyTO).setPassword(getPassword(attr.getValue().get(0)));
-                    }
-                    break;
-
-                case Username:
-                    if (anyTO instanceof UserTO) {
-                        ((UserTO) anyTO).setUsername(attr == null || attr.getValue().isEmpty()
-                                || attr.getValue().get(0) == null
-                                        ? null
-                                        : attr.getValue().get(0).toString());
-                    }
-                    break;
-
-                case GroupName:
-                    if (anyTO instanceof GroupTO) {
-                        ((GroupTO) anyTO).setName(attr == null || attr.getValue().isEmpty()
-                                || attr.getValue().get(0) == null
-                                        ? null
-                                        : attr.getValue().get(0).toString());
-                    }
-                    break;
-
-                case GroupOwnerSchema:
-                    if (anyTO instanceof GroupTO && attr != null) {
-                        // using a special attribute (with schema "", that will be ignored) for carrying the
-                        // GroupOwnerSchema value
-                        attrTO = new AttrTO();
-                        attrTO.setSchema(StringUtils.EMPTY);
-                        if (attr.getValue().isEmpty() || attr.getValue().get(0) == null) {
-                            attrTO.getValues().add(StringUtils.EMPTY);
-                        } else {
-                            attrTO.getValues().add(attr.getValue().get(0).toString());
-                        }
-
-                        ((GroupTO) anyTO).getPlainAttrs().add(attrTO);
-                    }
-                    break;
-
-                case UserPlainSchema:
-                case GroupPlainSchema:
-                case AnyObjectPlainSchema:
-                    attrTO = new AttrTO();
-                    attrTO.setSchema(item.getIntAttrName());
-
-                    PlainSchema schema = plainSchemaDAO.find(item.getIntAttrName());
-
-                    for (Object value : attr == null || attr.getValue() == null
-                            ? Collections.emptyList()
-                            : attr.getValue()) {
-
-                        AttrSchemaType schemaType = schema == null ? AttrSchemaType.String : schema.getType();
-                        if (value != null) {
-                            final PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                            switch (schemaType) {
-                                case String:
-                                    attrValue.setStringValue(value.toString());
-                                    break;
-
-                                case Binary:
-                                    attrValue.setBinaryValue((byte[]) value);
-                                    break;
-
-                                default:
-                                    try {
-                                        attrValue.parseValue(schema, value.toString());
-                                    } catch (ParsingValidationException e) {
-                                        LOG.error("While parsing provided value {}", value, e);
-                                        attrValue.setStringValue(value.toString());
-                                        schemaType = AttrSchemaType.String;
-                                    }
-                                    break;
-                            }
-                            attrTO.getValues().add(attrValue.getValueAsString(schemaType));
-                        }
-                    }
-
-                    anyTO.getPlainAttrs().add(attrTO);
-                    break;
-
-                case UserDerivedSchema:
-                case GroupDerivedSchema:
-                case AnyObjectDerivedSchema:
-                    attrTO = new AttrTO();
-                    attrTO.setSchema(item.getIntAttrName());
-                    anyTO.getDerAttrs().add(attrTO);
-                    break;
-
-                case UserVirtualSchema:
-                case GroupVirtualSchema:
-                case AnyObjectVirtualSchema:
-                    attrTO = new AttrTO();
-                    attrTO.setSchema(item.getIntAttrName());
-
-                    for (Object value : attr == null || attr.getValue() == null
-                            ? Collections.emptyList()
-                            : attr.getValue()) {
-
-                        if (value != null) {
-                            attrTO.getValues().add(value.toString());
-                        }
-                    }
-
-                    anyTO.getVirAttrs().add(attrTO);
-                    break;
-
-                default:
-            }
+        for (MappingItem item : MappingUtils.getSyncMappingItems(provision)) {
+            mappingUtils.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), anyTO, anyUtils);
         }
 
         // 2. add data from defined template (if any)
@@ -320,40 +225,6 @@ public class ConnObjectUtils {
     }
 
     /**
-     * Extract password value from passed value (if instance of GuardedString or GuardedByteArray).
-     *
-     * @param pwd received from the underlying connector
-     * @return password value
-     */
-    public String getPassword(final Object pwd) {
-        final StringBuilder result = new StringBuilder();
-
-        if (pwd instanceof GuardedString) {
-            ((GuardedString) pwd).access(new GuardedString.Accessor() {
-
-                @Override
-                public void access(final char[] clearChars) {
-                    result.append(clearChars);
-                }
-            });
-        } else if (pwd instanceof GuardedByteArray) {
-            ((GuardedByteArray) pwd).access(new GuardedByteArray.Accessor() {
-
-                @Override
-                public void access(final byte[] clearBytes) {
-                    result.append(new String(clearBytes));
-                }
-            });
-        } else if (pwd instanceof String) {
-            result.append((String) pwd);
-        } else {
-            result.append(pwd.toString());
-        }
-
-        return result.toString();
-    }
-
-    /**
      * Get connector object TO from a connector object.
      *
      * @param connObject connector object.
@@ -385,25 +256,4 @@ public class ConnObjectUtils {
 
         return connObjectTO;
     }
-
-    /**
-     * Transform a
-     * <code>Collection</code> of {@link Attribute} instances into a {@link Map}. The key to each element in the map is
-     * the <i>name</i> of an
-     * <code>Attribute</code>. The value of each element in the map is the
-     * <code>Attribute</code> instance with that name. <br/> Different from the original because: <ul> <li>map keys are
-     * transformed toUpperCase()</li> <li>returned map is mutable</li> </ul>
-     *
-     * @param attributes set of attribute to transform to a map.
-     * @return a map of string and attribute.
-     *
-     * @see org.identityconnectors.framework.common.objects.AttributeUtil#toMap(java.util.Collection)
-     */
-    public Map<String, Attribute> toMap(final Collection<? extends Attribute> attributes) {
-        final Map<String, Attribute> map = new HashMap<>();
-        for (Attribute attr : attributes) {
-            map.put(attr.getName().toUpperCase(), attr);
-        }
-        return map;
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
index 2f0a0c5..085f07d 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.core.misc;
 
-import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -27,16 +26,24 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.ListUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.jexl2.JexlContext;
 import org.apache.commons.jexl2.MapContext;
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -53,17 +60,21 @@ import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
 import org.apache.syncope.core.misc.security.Encryptor;
-import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.core.misc.jexl.JexlUtils;
 import org.apache.syncope.core.misc.security.PasswordGenerator;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
 import org.identityconnectors.framework.common.FrameworkUtil;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeBuilder;
@@ -72,14 +83,45 @@ import org.identityconnectors.framework.common.objects.Name;
 import org.identityconnectors.framework.common.objects.OperationalAttributes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
-public final class MappingUtils {
+@Component
+public class MappingUtils {
 
     private static final Logger LOG = LoggerFactory.getLogger(MappingUtils.class);
 
     private static final Encryptor ENCRYPTOR = Encryptor.getInstance();
 
+    @Autowired
+    private UserDAO userDAO;
+
+    @Autowired
+    private AnyTypeDAO anyTypeDAO;
+
+    @Autowired
+    private PlainSchemaDAO plainSchemaDAO;
+
+    @Autowired
+    private VirSchemaDAO virSchemaDAO;
+
+    @Autowired
+    private VirAttrHandler virAttrHandler;
+
+    @Autowired
+    private VirAttrCache virAttrCache;
+
+    @Autowired
+    private PasswordGenerator passwordGenerator;
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    @Autowired
+    private AnyUtilsFactory anyUtilsFactory;
+
     public static <T extends MappingItem> Collection<T> getMatchingMappingItems(
             final Collection<T> items, final IntMappingType type) {
 
@@ -116,6 +158,144 @@ public final class MappingUtils {
         });
     }
 
+    public static MappingItem getConnObjectKeyItem(final Provision provision) {
+        Mapping mapping = null;
+        if (provision != null) {
+            mapping = provision.getMapping();
+        }
+
+        return mapping == null
+                ? null
+                : mapping.getConnObjectKeyItem();
+    }
+
+    private static List<MappingItem> getMappingItems(final Provision provision, final MappingPurpose purpose) {
+        List<? extends MappingItem> items = Collections.<MappingItem>emptyList();
+        if (provision != null) {
+            items = provision.getMapping().getItems();
+        }
+
+        List<MappingItem> result = new ArrayList<>();
+
+        switch (purpose) {
+            case SYNCHRONIZATION:
+                for (MappingItem item : items) {
+                    if (MappingPurpose.PROPAGATION != item.getPurpose()
+                            && MappingPurpose.NONE != item.getPurpose()) {
+
+                        result.add(item);
+                    }
+                }
+                break;
+
+            case PROPAGATION:
+                for (MappingItem item : items) {
+                    if (MappingPurpose.SYNCHRONIZATION != item.getPurpose()
+                            && MappingPurpose.NONE != item.getPurpose()) {
+
+                        result.add(item);
+                    }
+                }
+                break;
+
+            case BOTH:
+                for (MappingItem item : items) {
+                    if (MappingPurpose.NONE != item.getPurpose()) {
+                        result.add(item);
+                    }
+                }
+                break;
+
+            case NONE:
+                for (MappingItem item : items) {
+                    if (MappingPurpose.NONE == item.getPurpose()) {
+                        result.add(item);
+                    }
+                }
+                break;
+
+            default:
+        }
+
+        return result;
+    }
+
+    public static List<MappingItem> getBothMappingItems(final Provision provision) {
+        return getMappingItems(provision, MappingPurpose.BOTH);
+    }
+
+    public static List<MappingItem> getPropagationMappingItems(final Provision provision) {
+        return getMappingItems(provision, MappingPurpose.PROPAGATION);
+    }
+
+    public static List<MappingItem> getSyncMappingItems(final Provision provision) {
+        return getMappingItems(provision, MappingPurpose.SYNCHRONIZATION);
+    }
+
+    /**
+     * Build __NAME__ for propagation. First look if there ia a defined connObjectLink for the given resource (and in
+     * this case evaluate as JEXL); otherwise, take given connObjectKey.
+     *
+     * @param any given any object
+     * @param provision external resource
+     * @param connObjectKey connector object key
+     * @return the value to be propagated as __NAME__
+     */
+    public static Name evaluateNAME(final Any<?, ?, ?> any, final Provision provision, final String connObjectKey) {
+        if (StringUtils.isBlank(connObjectKey)) {
+            // LOG error but avoid to throw exception: leave it to the external resource
+            LOG.error("Missing ConnObjectKey for '{}': ", provision.getResource());
+        }
+
+        // Evaluate connObjectKey expression
+        String connObjectLink = provision == null || provision.getMapping() == null
+                ? null
+                : provision.getMapping().getConnObjectLink();
+        String evalConnObjectLink = null;
+        if (StringUtils.isNotBlank(connObjectLink)) {
+            JexlContext jexlContext = new MapContext();
+            JexlUtils.addFieldsToContext(any, jexlContext);
+            JexlUtils.addPlainAttrsToContext(any.getPlainAttrs(), jexlContext);
+            JexlUtils.addDerAttrsToContext(any.getDerAttrs(), any.getPlainAttrs(), jexlContext);
+            evalConnObjectLink = JexlUtils.evaluate(connObjectLink, jexlContext);
+        }
+
+        // If connObjectLink evaluates to an empty string, just use the provided connObjectKey as Name(),
+        // otherwise evaluated connObjectLink expression is taken as Name().
+        Name name;
+        if (StringUtils.isBlank(evalConnObjectLink)) {
+            // add connObjectKey as __NAME__ attribute ...
+            LOG.debug("Add connObjectKey [{}] as __NAME__", connObjectKey);
+            name = new Name(connObjectKey);
+        } else {
+            LOG.debug("Add connObjectLink [{}] as __NAME__", evalConnObjectLink);
+            name = new Name(evalConnObjectLink);
+
+            // connObjectKey not propagated: it will be used to set the value for __UID__ attribute
+            LOG.debug("connObjectKey will be used just as __UID__ attribute");
+        }
+
+        return name;
+    }
+
+    public static List<MappingItemTransformer> getMappingItemTransformers(final MappingItem mappingItem) {
+        List<MappingItemTransformer> result = new ArrayList<>();
+
+        for (String className : mappingItem.getMappingItemTransformerClassNames()) {
+            try {
+                Class<?> transformerClass = ClassUtils.getClass(className);
+
+                result.add((MappingItemTransformer) ApplicationContextProvider.
+                        getBeanFactory().
+                        createBean(transformerClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false));
+            } catch (Exception e) {
+                LOG.error("Could not instantiate {}, ignoring...", className, e);
+            }
+        }
+
+        return result;
+    }
+
     /**
      * Prepare attributes for sending to a connector instance.
      *
@@ -127,7 +307,8 @@ public final class MappingUtils {
      * @param provision provision information
      * @return connObjectLink + prepared attributes
      */
-    public static Pair<String, Set<Attribute>> prepareAttrs(
+    @Transactional(readOnly = true)
+    public Pair<String, Set<Attribute>> prepareAttrs(
             final Any<?, ?, ?> any,
             final String password,
             final boolean changePwd,
@@ -138,10 +319,6 @@ public final class MappingUtils {
         LOG.debug("Preparing resource attributes for {} with provision {} for attributes {}",
                 any, provision, any.getPlainAttrs());
 
-        DefaultListableBeanFactory beanFactory = ApplicationContextProvider.getBeanFactory();
-        VirAttrCache virAttrCache = beanFactory.getBean(VirAttrCache.class);
-        PasswordGenerator passwordGenerator = beanFactory.getBean(PasswordGenerator.class);
-
         Set<Attribute> attributes = new HashSet<>();
         String connObjectKey = null;
 
@@ -157,8 +334,7 @@ public final class MappingUtils {
                     virAttrCache.expire(any.getType().getKey(), any.getKey(), mapping.getIntAttrName());
                 }
 
-                Pair<String, Attribute> preparedAttr = prepareAttr(
-                        provision, mapping, any, password, passwordGenerator, vAttrs);
+                Pair<String, Attribute> preparedAttr = prepareAttr(provision, mapping, any, password, vAttrs);
 
                 if (preparedAttr != null && preparedAttr.getKey() != null) {
                     connObjectKey = preparedAttr.getKey();
@@ -211,22 +387,16 @@ public final class MappingUtils {
      * @param mapItem mapping item for the given attribute
      * @param any any object
      * @param password clear-text password
-     * @param passwordGenerator password generator
      * @param vAttrs virtual attributes to be managed
      * @return connObjectLink + prepared attribute
      */
-    @SuppressWarnings("unchecked")
-    private static Pair<String, Attribute> prepareAttr(
+    private Pair<String, Attribute> prepareAttr(
             final Provision provision, final MappingItem mapItem,
-            final Any<?, ?, ?> any, final String password, final PasswordGenerator passwordGenerator,
+            final Any<?, ?, ?> any, final String password,
             final Map<String, AttrPatch> vAttrs) {
 
         List<Any<?, ?, ?>> anys = new ArrayList<>();
 
-        DefaultListableBeanFactory beanFactory = ApplicationContextProvider.getBeanFactory();
-        AnyUtilsFactory anyUtilsFactory = beanFactory.getBean(AnyUtilsFactory.class);
-        VirAttrHandler virAttrHandler = beanFactory.getBean(VirAttrHandler.class);
-
         switch (mapItem.getIntMappingType().getAnyTypeKind()) {
             case USER:
                 if (any instanceof User) {
@@ -236,7 +406,6 @@ public final class MappingUtils {
 
             case GROUP:
                 if (any instanceof User) {
-                    UserDAO userDAO = beanFactory.getBean(UserDAO.class);
                     for (Group group : userDAO.findAllGroups((User) any)) {
                         virAttrHandler.retrieveVirAttrValues(group);
                         anys.add(group);
@@ -266,7 +435,6 @@ public final class MappingUtils {
             case UserPlainSchema:
             case GroupPlainSchema:
             case AnyObjectPlainSchema:
-                PlainSchemaDAO plainSchemaDAO = beanFactory.getBean(PlainSchemaDAO.class);
                 schema = plainSchemaDAO.find(mapItem.getIntAttrName());
                 schemaType = schema == null ? AttrSchemaType.String : schema.getType();
                 break;
@@ -274,7 +442,6 @@ public final class MappingUtils {
             case UserVirtualSchema:
             case GroupVirtualSchema:
             case AnyObjectVirtualSchema:
-                VirSchemaDAO virSchemaDAO = beanFactory.getBean(VirSchemaDAO.class);
                 schema = virSchemaDAO.find(mapItem.getIntAttrName());
                 readOnlyVirSchema = (schema != null && schema.isReadonly());
                 schemaType = AttrSchemaType.String;
@@ -357,63 +524,16 @@ public final class MappingUtils {
         return result;
     }
 
-    /**
-     * Build __NAME__ for propagation. First look if there ia a defined connObjectLink for the given resource (and in
-     * this case evaluate as JEXL); otherwise, take given connObjectKey.
-     *
-     * @param any given any object
-     * @param provision external resource
-     * @param connObjectKey connector object key
-     * @return the value to be propagated as __NAME__
-     */
-    public static Name evaluateNAME(final Any<?, ?, ?> any, final Provision provision, final String connObjectKey) {
-        if (StringUtils.isBlank(connObjectKey)) {
-            // LOG error but avoid to throw exception: leave it to the external resource
-            LOG.error("Missing ConnObjectKey for '{}': ", provision.getResource());
-        }
-
-        // Evaluate connObjectKey expression
-        String connObjectLink = provision == null || provision.getMapping() == null
-                ? null
-                : provision.getMapping().getConnObjectLink();
-        String evalConnObjectLink = null;
-        if (StringUtils.isNotBlank(connObjectLink)) {
-            JexlContext jexlContext = new MapContext();
-            JexlUtils.addFieldsToContext(any, jexlContext);
-            JexlUtils.addPlainAttrsToContext(any.getPlainAttrs(), jexlContext);
-            JexlUtils.addDerAttrsToContext(any.getDerAttrs(), any.getPlainAttrs(), jexlContext);
-            evalConnObjectLink = JexlUtils.evaluate(connObjectLink, jexlContext);
-        }
-
-        // If connObjectLink evaluates to an empty string, just use the provided connObjectKey as Name(),
-        // otherwise evaluated connObjectLink expression is taken as Name().
-        Name name;
-        if (StringUtils.isBlank(evalConnObjectLink)) {
-            // add connObjectKey as __NAME__ attribute ...
-            LOG.debug("Add connObjectKey [{}] as __NAME__", connObjectKey);
-            name = new Name(connObjectKey);
-        } else {
-            LOG.debug("Add connObjectLink [{}] as __NAME__", evalConnObjectLink);
-            name = new Name(evalConnObjectLink);
-
-            // connObjectKey not propagated: it will be used to set the value for __UID__ attribute
-            LOG.debug("connObjectKey will be used just as __UID__ attribute");
-        }
-
-        return name;
-    }
-
-    private static String getGroupOwnerValue(final Provision provision, final Any<?, ?, ?> any) {
-        Pair<String, Attribute> preparedAttr = prepareAttr(provision, getConnObjectKeyItem(provision),
-                any, null, null, Collections.<String, AttrPatch>emptyMap());
+    private String getGroupOwnerValue(final Provision provision, final Any<?, ?, ?> any) {
+        Pair<String, Attribute> preparedAttr = prepareAttr(
+                provision, getConnObjectKeyItem(provision), any, null, Collections.<String, AttrPatch>emptyMap());
         String connObjectKey = preparedAttr.getKey();
 
-        final Name groupOwnerName = evaluateNAME(any, provision, connObjectKey);
-        return groupOwnerName.getNameValue();
+        return evaluateNAME(any, provision, connObjectKey).getNameValue();
     }
 
     /**
-     * Get attribute values.
+     * Get attribute values for the given {@link MappingItem} and any objects.
      *
      * @param provision provision information
      * @param mappingItem mapping item
@@ -421,17 +541,15 @@ public final class MappingUtils {
      * @param vAttrs virtual attributes to be managed
      * @return attribute values.
      */
-    public static List<PlainAttrValue> getIntValues(final Provision provision,
+    @Transactional(readOnly = true)
+    public List<PlainAttrValue> getIntValues(final Provision provision,
             final MappingItem mappingItem, final List<Any<?, ?, ?>> anys, final Map<String, AttrPatch> vAttrs) {
 
         LOG.debug("Get attributes for '{}' and mapping type '{}'", anys, mappingItem.getIntMappingType());
 
-        EntityFactory entityFactory =
-                ApplicationContextProvider.getBeanFactory().getBean(EntityFactory.class);
-        AnyUtilsFactory anyUtilsFactory =
-                ApplicationContextProvider.getBeanFactory().getBean(AnyUtilsFactory.class);
+        boolean transform = true;
+
         List<PlainAttrValue> values = new ArrayList<>();
-        PlainAttrValue attrValue;
         switch (mappingItem.getIntMappingType()) {
             case UserPlainSchema:
             case GroupPlainSchema:
@@ -440,9 +558,15 @@ public final class MappingUtils {
                     PlainAttr<?> attr = any.getPlainAttr(mappingItem.getIntAttrName());
                     if (attr != null) {
                         if (attr.getUniqueValue() != null) {
-                            values.add(attr.getUniqueValue());
+                            PlainAttrUniqueValue value = SerializationUtils.clone(attr.getUniqueValue());
+                            value.setAttr(null);
+                            values.add(value);
                         } else if (attr.getValues() != null) {
-                            values.addAll(attr.getValues());
+                            for (PlainAttrValue value : attr.getValues()) {
+                                PlainAttrValue shadow = SerializationUtils.clone(value);
+                                shadow.setAttr(null);
+                                values.add(shadow);
+                            }
                         }
                     }
 
@@ -458,26 +582,27 @@ public final class MappingUtils {
             case UserVirtualSchema:
             case GroupVirtualSchema:
             case AnyObjectVirtualSchema:
+                // virtual attributes don't get transformed
+                transform = false;
+
                 for (Any<?, ?, ?> any : anys) {
                     AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-                    VirAttr<?> virAttr = any.getVirAttr(mappingItem.getIntAttrName());
-                    if (virAttr != null) {
+                    VirAttr<?> attr = any.getVirAttr(mappingItem.getIntAttrName());
+                    if (attr != null) {
                         if (vAttrs != null) {
                             if (vAttrs.containsKey(mappingItem.getIntAttrName())) {
-                                virAttr.getValues().clear();
-                                virAttr.getValues().addAll(
+                                attr.getValues().clear();
+                                attr.getValues().addAll(
                                         vAttrs.get(mappingItem.getIntAttrName()).getAttrTO().getValues());
                             } else {
                                 throw new IllegalArgumentException("Don't need to update virtual attribute '"
                                         + mappingItem.getIntAttrName() + "'");
                             }
                         }
-                        if (virAttr.getValues() != null) {
-                            for (String value : virAttr.getValues()) {
-                                attrValue = anyUtils.newPlainAttrValue();
-                                attrValue.setStringValue(value);
-                                values.add(attrValue);
-                            }
+                        for (String value : attr.getValues()) {
+                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                            attrValue.setStringValue(value);
+                            values.add(attrValue);
                         }
                     }
 
@@ -486,7 +611,7 @@ public final class MappingUtils {
                             + "\n* IntMappingType {}"
                             + "\n* Attribute values {}",
                             any.getClass().getSimpleName(),
-                            virAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+                            attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
                 }
                 break;
 
@@ -495,10 +620,10 @@ public final class MappingUtils {
             case AnyObjectDerivedSchema:
                 for (Any<?, ?, ?> any : anys) {
                     AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-                    DerAttr<?> derAttr = any.getDerAttr(mappingItem.getIntAttrName());
-                    if (derAttr != null) {
-                        attrValue = anyUtils.newPlainAttrValue();
-                        attrValue.setStringValue(derAttr.getValue(any.getPlainAttrs()));
+                    DerAttr<?> attr = any.getDerAttr(mappingItem.getIntAttrName());
+                    if (attr != null) {
+                        PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                        attrValue.setStringValue(attr.getValue(any.getPlainAttrs()));
                         values.add(attrValue);
                     }
 
@@ -506,7 +631,7 @@ public final class MappingUtils {
                             + "\n* IntAttrName {}"
                             + "\n* IntMappingType {}"
                             + "\n* Attribute values {}",
-                            derAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+                            attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
                 }
                 break;
 
@@ -515,7 +640,7 @@ public final class MappingUtils {
             case AnyObjectKey:
                 for (Any<?, ?, ?> any : anys) {
                     AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-                    attrValue = anyUtils.newPlainAttrValue();
+                    PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
                     attrValue.setStringValue(any.getKey().toString());
                     values.add(attrValue);
                 }
@@ -524,7 +649,7 @@ public final class MappingUtils {
             case Username:
                 for (Any<?, ?, ?> any : anys) {
                     if (any instanceof User) {
-                        attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+                        UPlainAttrValue attrValue = entityFactory.newEntity(UPlainAttrValue.class);
                         attrValue.setStringValue(((User) any).getUsername());
                         values.add(attrValue);
                     }
@@ -534,7 +659,7 @@ public final class MappingUtils {
             case GroupName:
                 for (Any<?, ?, ?> any : anys) {
                     if (any instanceof Group) {
-                        attrValue = entityFactory.newEntity(GPlainAttrValue.class);
+                        GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
                         attrValue.setStringValue(((Group) any).getName());
                         values.add(attrValue);
                     }
@@ -542,7 +667,6 @@ public final class MappingUtils {
                 break;
 
             case GroupOwnerSchema:
-                AnyTypeDAO anyTypeDAO = ApplicationContextProvider.getBeanFactory().getBean(AnyTypeDAO.class);
                 Mapping uMapping = provision.getAnyType().equals(anyTypeDAO.findUser())
                         ? null
                         : provision.getMapping();
@@ -562,7 +686,7 @@ public final class MappingUtils {
                         }
 
                         if (StringUtils.isNotBlank(groupOwnerValue)) {
-                            attrValue = entityFactory.newEntity(GPlainAttrValue.class);
+                            GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
                             attrValue.setStringValue(groupOwnerValue);
                             values.add(attrValue);
                         }
@@ -573,9 +697,19 @@ public final class MappingUtils {
             default:
         }
 
-        LOG.debug("Retrieved values '{}'", values);
+        LOG.debug("Values for propagation: {}", values);
 
-        return values;
+        List<PlainAttrValue> transformed = values;
+        if (transform) {
+            for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItem)) {
+                transformed = transformer.beforePropagation(transformed);
+            }
+            LOG.debug("Transformed values for propagation: {}", values);
+        } else {
+            LOG.debug("No transformation occurred");
+        }
+
+        return transformed;
     }
 
     /**
@@ -585,7 +719,8 @@ public final class MappingUtils {
      * @param provision provision information
      * @return connObjectKey internal value
      */
-    public static String getConnObjectKeyValue(final Any<?, ?, ?> any, final Provision provision) {
+    @Transactional(readOnly = true)
+    public String getConnObjectKeyValue(final Any<?, ?, ?> any, final Provision provision) {
         List<PlainAttrValue> values = getIntValues(provision, provision.getMapping().getConnObjectKeyItem(),
                 Collections.<Any<?, ?, ?>>singletonList(any), null);
         return values == null || values.isEmpty()
@@ -593,71 +728,139 @@ public final class MappingUtils {
                 : values.get(0).getValueAsString();
     }
 
-    public static MappingItem getConnObjectKeyItem(final Provision provision) {
-        Mapping mapping = null;
-        if (provision != null) {
-            mapping = provision.getMapping();
-        }
-
-        return mapping == null
-                ? null
-                : mapping.getConnObjectKeyItem();
-    }
-
-    public static List<MappingItem> getMappingItems(final Provision provision, final MappingPurpose purpose) {
-        List<? extends MappingItem> items = Collections.<MappingItem>emptyList();
-        if (provision != null) {
-            items = provision.getMapping().getItems();
+    /**
+     * Set attribute values, according to the given {@link MappingItem}, to any object from attribute received from
+     * connector.
+     *
+     * @param <T> any object
+     * @param mappingItem mapping item
+     * @param attr attribute received from connector
+     * @param anyTO any object
+     * @param anyUtils any utils
+     */
+    @Transactional(readOnly = true)
+    public <T extends AnyTO> void setIntValues(
+            final MappingItem mappingItem, final Attribute attr, final T anyTO, final AnyUtils anyUtils) {
+
+        List<Object> values = null;
+        if (attr != null) {
+            values = attr.getValue();
+            for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItem)) {
+                values = transformer.beforeSync(values);
+            }
         }
+        values = ListUtils.emptyIfNull(values);
 
-        List<MappingItem> result = new ArrayList<>();
+        switch (mappingItem.getIntMappingType()) {
+            case UserKey:
+            case GroupKey:
+            case AnyObjectKey:
+                break;
 
-        switch (purpose) {
-            case SYNCHRONIZATION:
-                for (MappingItem item : items) {
-                    if (MappingPurpose.PROPAGATION != item.getPurpose()
-                            && MappingPurpose.NONE != item.getPurpose()) {
+            case Password:
+                if (anyTO instanceof UserTO && !values.isEmpty()) {
+                    ((UserTO) anyTO).setPassword(ConnObjectUtils.getPassword(values.get(0)));
+                }
+                break;
 
-                        result.add(item);
-                    }
+            case Username:
+                if (anyTO instanceof UserTO) {
+                    ((UserTO) anyTO).setUsername(values.isEmpty() || values.get(0) == null
+                            ? null
+                            : values.get(0).toString());
                 }
                 break;
 
-            case PROPAGATION:
-                for (MappingItem item : items) {
-                    if (MappingPurpose.SYNCHRONIZATION != item.getPurpose()
-                            && MappingPurpose.NONE != item.getPurpose()) {
+            case GroupName:
+                if (anyTO instanceof GroupTO) {
+                    ((GroupTO) anyTO).setName(values.isEmpty() || values.get(0) == null
+                            ? null
+                            : values.get(0).toString());
+                }
+                break;
 
-                        result.add(item);
+            case GroupOwnerSchema:
+                if (anyTO instanceof GroupTO && attr != null) {
+                    // using a special attribute (with schema "", that will be ignored) for carrying the
+                    // GroupOwnerSchema value
+                    AttrTO attrTO = new AttrTO();
+                    attrTO.setSchema(StringUtils.EMPTY);
+                    if (values.isEmpty() || values.get(0) == null) {
+                        attrTO.getValues().add(StringUtils.EMPTY);
+                    } else {
+                        attrTO.getValues().add(values.get(0).toString());
                     }
+
+                    ((GroupTO) anyTO).getPlainAttrs().add(attrTO);
                 }
                 break;
 
-            case BOTH:
-                for (MappingItem item : items) {
-                    if (MappingPurpose.NONE != item.getPurpose()) {
-                        result.add(item);
+            case UserPlainSchema:
+            case GroupPlainSchema:
+            case AnyObjectPlainSchema:
+                AttrTO attrTO = new AttrTO();
+                attrTO.setSchema(mappingItem.getIntAttrName());
+
+                PlainSchema schema = plainSchemaDAO.find(mappingItem.getIntAttrName());
+
+                for (Object value : values) {
+                    AttrSchemaType schemaType = schema == null ? AttrSchemaType.String : schema.getType();
+                    if (value != null) {
+                        PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                        switch (schemaType) {
+                            case String:
+                                attrValue.setStringValue(value.toString());
+                                break;
+
+                            case Binary:
+                                attrValue.setBinaryValue((byte[]) value);
+                                break;
+
+                            default:
+                                try {
+                                    attrValue.parseValue(schema, value.toString());
+                                } catch (ParsingValidationException e) {
+                                    LOG.error("While parsing provided value {}", value, e);
+                                    attrValue.setStringValue(value.toString());
+                                    schemaType = AttrSchemaType.String;
+                                }
+                                break;
+                        }
+                        attrTO.getValues().add(attrValue.getValueAsString(schemaType));
                     }
                 }
+
+                anyTO.getPlainAttrs().add(attrTO);
                 break;
 
-            case NONE:
-                for (MappingItem item : items) {
-                    if (MappingPurpose.NONE == item.getPurpose()) {
-                        result.add(item);
+            case UserDerivedSchema:
+            case GroupDerivedSchema:
+            case AnyObjectDerivedSchema:
+                attrTO = new AttrTO();
+                attrTO.setSchema(mappingItem.getIntAttrName());
+                anyTO.getDerAttrs().add(attrTO);
+                break;
+
+            case UserVirtualSchema:
+            case GroupVirtualSchema:
+            case AnyObjectVirtualSchema:
+                attrTO = new AttrTO();
+                attrTO.setSchema(mappingItem.getIntAttrName());
+
+                // virtual attributes don't get transformed, iterate over original attr.getValue()
+                for (Object value : (attr == null || attr.getValue() == null)
+                        ? Collections.emptyList() : attr.getValue()) {
+
+                    if (value != null) {
+                        attrTO.getValues().add(value.toString());
                     }
                 }
+
+                anyTO.getVirAttrs().add(attrTO);
                 break;
 
             default:
         }
-
-        return result;
     }
 
-    /**
-     * Private default constructor, for static-only classes.
-     */
-    private MappingUtils() {
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java
index ff9e646..10eb235 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java
@@ -72,6 +72,8 @@ public class AuthDataAccessor {
 
     protected static final Logger LOG = LoggerFactory.getLogger(AuthDataAccessor.class);
 
+    protected static final Encryptor ENCRYPTOR = Encryptor.getInstance();
+
     @Resource(name = "adminUser")
     protected String adminUser;
 
@@ -102,7 +104,8 @@ public class AuthDataAccessor {
     @Autowired
     protected AuditManager auditManager;
 
-    protected final Encryptor encryptor = Encryptor.getInstance();
+    @Autowired
+    protected MappingUtils mappingUtils;
 
     @Transactional(readOnly = true)
     public Domain findDomain(final String key) {
@@ -158,7 +161,7 @@ public class AuthDataAccessor {
     }
 
     protected boolean authenticate(final User user, final String password) {
-        boolean authenticated = encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword());
+        boolean authenticated = ENCRYPTOR.verify(password, user.getCipherAlgorithm(), user.getPassword());
         LOG.debug("{} authenticated on internal storage: {}", user.getUsername(), authenticated);
 
         for (Iterator<? extends ExternalResource> itor = getPassthroughResources(user).iterator();
@@ -167,7 +170,7 @@ public class AuthDataAccessor {
             ExternalResource resource = itor.next();
             String connObjectKey = null;
             try {
-                connObjectKey = MappingUtils.getConnObjectKeyValue(user, resource.getProvision(anyTypeDAO.findUser()));
+                connObjectKey = mappingUtils.getConnObjectKeyValue(user, resource.getProvision(anyTypeDAO.findUser()));
                 Uid uid = connFactory.getConnector(resource).authenticate(connObjectKey, password, null);
                 if (uid != null) {
                     authenticated = true;

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java b/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java
index c86fb2e..5c780f0 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/serialization/GuardedStringSerializer.java
@@ -60,14 +60,14 @@ class GuardedStringSerializer extends JsonSerializer<GuardedString> {
         jgen.writeBooleanField("disposed", disposed);
 
         final StringBuilder cleartext = new StringBuilder();
-        ((GuardedString) source).access(new GuardedString.Accessor() {
+        source.access(new GuardedString.Accessor() {
 
             @Override
             public void access(final char[] clearChars) {
                 cleartext.append(clearChars);
             }
         });
-        final byte[] encryptedBytes =
+        byte[] encryptedBytes =
                 EncryptorFactory.getInstance().getDefaultEncryptor().encrypt(cleartext.toString().getBytes());
         jgen.writeStringField("encryptedBytes", Base64.encode(encryptedBytes));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
index 530b406..fd349a9 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
@@ -33,6 +33,7 @@ public interface ImplementationLookup extends SyncopeLoader {
         REPORTLET,
         ACCOUNT_RULE,
         PASSWORD_RULE,
+        MAPPING_ITEM_TRANSFORMER,
         TASKJOBDELEGATE,
         LOGIC_ACTIONS,
         PROPAGATION_ACTIONS,

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
index 1a5380f..9f515ed 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.persistence.api.entity.resource;
 
+import java.util.List;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.persistence.api.entity.Entity;
@@ -56,4 +57,6 @@ public interface MappingItem extends Entity<Long> {
 
     void setPassword(boolean password);
 
+    List<String> getMappingItemTransformerClassNames();
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
index ae9a117..8dba286 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
@@ -18,13 +18,19 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity.resource;
 
+import java.util.ArrayList;
+import java.util.List;
 import javax.persistence.Basic;
 import javax.persistence.Cacheable;
+import javax.persistence.CollectionTable;
 import javax.persistence.Column;
+import javax.persistence.ElementCollection;
 import javax.persistence.Entity;
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
 import javax.persistence.Id;
+import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
 import javax.validation.constraints.Max;
@@ -91,6 +97,16 @@ public class JPAMappingItem extends AbstractEntity<Long> implements MappingItem
     @Enumerated(EnumType.STRING)
     private MappingPurpose purpose;
 
+    /**
+     * (Optional) classes for MappingItem transformation.
+     */
+    @ElementCollection(fetch = FetchType.EAGER)
+    @Column(name = "transformerClassName")
+    @CollectionTable(name = "MappingItem_Transformer",
+            joinColumns =
+            @JoinColumn(name = "mappingItem_id", referencedColumnName = "id"))
+    private List<String> mappingItemTransformerClassNames = new ArrayList<>();
+
     public JPAMappingItem() {
         super();
 
@@ -214,4 +230,10 @@ public class JPAMappingItem extends AbstractEntity<Long> implements MappingItem
     public void setPurpose(final MappingPurpose purpose) {
         this.purpose = purpose;
     }
+
+    @Override
+    public List<String> getMappingItemTransformerClassNames() {
+        return mappingItemTransformerClassNames;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
index 9ad2082..7879661 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java
@@ -30,6 +30,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
 
 public class ExternalResourceValidator extends AbstractValidator<ExternalResourceCheck, ExternalResource> {
@@ -106,6 +107,27 @@ public class ExternalResourceValidator extends AbstractValidator<ExternalResourc
             isValid = false;
         }
 
+        for (MappingItem item : mapping.getItems()) {
+            for (String className : item.getMappingItemTransformerClassNames()) {
+                Class<?> actionsClass = null;
+                boolean isAssignable = false;
+                try {
+                    actionsClass = Class.forName(className);
+                    isAssignable = MappingItemTransformer.class.isAssignableFrom(actionsClass);
+                } catch (Exception e) {
+                    LOG.error("Invalid MappingItemTransformer specified: {}", className, e);
+                }
+
+                if (actionsClass == null || !isAssignable) {
+                    context.buildConstraintViolationWithTemplate(
+                            getTemplate(EntityViolationType.InvalidMapping,
+                                    "Invalid mapping item trasformer class name")).
+                            addPropertyNode("mappingItemTransformerClassName").addConstraintViolation();
+                    isValid = false;
+                }
+            }
+        }
+
         return isValid;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
new file mode 100644
index 0000000..ae11199
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
@@ -0,0 +1,47 @@
+/*
+ * 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.api.data;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+
+/**
+ * Transforms values to be propagated to (or synchronizing from) external resources right before they leave (or enter)
+ * the Syncope internal storage.
+ *
+ * These transformations are not applied to virtual attribute values.
+ */
+public interface MappingItemTransformer {
+
+    /**
+     * Invoked while preparing attribute values to be sent out to external resource during propagation.
+     *
+     * @param values original values
+     * @return transformed values
+     */
+    List<PlainAttrValue> beforePropagation(List<PlainAttrValue> values);
+
+    /**
+     * Invoked while reading attribute values from external resource during synchronization.
+     *
+     * @param values original values
+     * @return transformed values
+     */
+    List<Object> beforeSync(List<Object> values);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java
index ae2d297..0b4340e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/AsyncConnectorFacade.java
@@ -120,7 +120,7 @@ public class AsyncConnectorFacade {
 
         Attribute attribute = null;
 
-        final ConnectorObject object = connector.getObject(objectClass, uid, options);
+        ConnectorObject object = connector.getObject(objectClass, uid, options);
         if (object == null) {
             LOG.debug("Object for '{}' not found", uid.getUidValue());
         } else {
@@ -137,9 +137,9 @@ public class AsyncConnectorFacade {
             final Uid uid,
             final OperationOptions options) {
 
-        final Set<Attribute> attributes = new HashSet<>();
+        Set<Attribute> attributes = new HashSet<>();
 
-        final ConnectorObject object = connector.getObject(objectClass, uid, options);
+        ConnectorObject object = connector.getObject(objectClass, uid, options);
 
         if (object == null) {
             LOG.debug("Object for '{}' not found", uid.getUidValue());
@@ -154,10 +154,10 @@ public class AsyncConnectorFacade {
 
     @Async
     public Future<Set<String>> getSchemaNames(final ConnectorFacade connector, final boolean includeSpecial) {
-        final Set<String> schemaNames = new HashSet<>();
+        Set<String> schemaNames = new HashSet<>();
 
         try {
-            final Schema schema = connector.schema();
+            Schema schema = connector.schema();
             for (ObjectClassInfo info : schema.getObjectClassInfo()) {
                 for (AttributeInfo attrInfo : info.getAttributeInfo()) {
                     if (includeSpecial || !AttributeUtil.isSpecialName(attrInfo.getName())) {
@@ -175,10 +175,10 @@ public class AsyncConnectorFacade {
 
     @Async
     public Future<Set<ObjectClass>> getSupportedObjectClasses(final ConnectorFacade connector) {
-        final Set<ObjectClass> objectClasses = new HashSet<>();
+        Set<ObjectClass> objectClasses = new HashSet<>();
 
         try {
-            final Schema schema = connector.schema();
+            Schema schema = connector.schema();
             for (ObjectClassInfo info : schema.getObjectClassInfo()) {
                 objectClasses.add(new ObjectClass(info.getType()));
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/72e6ceb0/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
index 3907700..3d60089 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
@@ -34,7 +34,6 @@ import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.IntMappingType;
-import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.misc.MappingUtils;
@@ -61,7 +60,6 @@ import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
 import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.identityconnectors.framework.common.objects.OperationOptions;
 import org.identityconnectors.framework.common.objects.Uid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -102,6 +100,9 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
     @Autowired
     private VirAttrCache virAttrCache;
 
+    @Autowired
+    private MappingUtils mappingUtils;
+
     @Override
     public VirSchema getVirSchema(final String virSchemaName) {
         VirSchema virtualSchema = null;
@@ -122,8 +123,8 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
             final PropagationByResource propByRes) {
 
         for (ExternalResource resource : resources) {
-            for (MappingItem mapItem : MappingUtils.getMappingItems(
-                    resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) {
+            for (MappingItem mapItem
+                    : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
 
                 if (schemaKey.equals(mapItem.getIntAttrName()) && mapItem.getIntMappingType() == mappingType) {
                     propByRes.add(ResourceOperation.UPDATE, resource.getKey());
@@ -232,8 +233,8 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
                         }
 
                         for (ExternalResource resource : externalResources) {
-                            for (MappingItem mapItem : MappingUtils.getMappingItems(
-                                    resource.getProvision(any.getType()), MappingPurpose.PROPAGATION)) {
+                            for (MappingItem mapItem
+                                    : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
 
                                 if (virSchema.getKey().equals(mapItem.getIntAttrName())
                                         && mapItem.getIntMappingType() == anyUtils.virIntMappingType()) {
@@ -314,7 +315,7 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
                 LOG.debug("Search values into {},{}", resource, provision);
 
                 try {
-                    List<MappingItem> mappings = MappingUtils.getMappingItems(provision, MappingPurpose.BOTH);
+                    List<MappingItem> mapItems = MappingUtils.getBothMappingItems(provision);
 
                     ConnectorObject connectorObject;
                     if (externalResources.containsKey(resource.getKey())) {
@@ -323,33 +324,26 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
                         LOG.debug("Perform connection to {}", resource.getKey());
                         String connObjectKey = MappingUtils.getConnObjectKeyItem(provision) == null
                                 ? null
-                                : MappingUtils.getConnObjectKeyValue(any, provision);
+                                : mappingUtils.getConnObjectKeyValue(any, provision);
 
                         if (StringUtils.isBlank(connObjectKey)) {
                             throw new IllegalArgumentException("No ConnObjectKey found for " + resource.getKey());
                         }
 
                         Connector connector = connFactory.getConnector(resource);
-
-                        OperationOptions oo =
-                                connector.getOperationOptions(MappingUtils.getMatchingMappingItems(mappings, type));
-
-                        connectorObject =
-                                connector.getObject(provision.getObjectClass(), new Uid(connObjectKey), oo);
+                        connectorObject = connector.getObject(
+                                provision.getObjectClass(),
+                                new Uid(connObjectKey),
+                                connector.getOperationOptions(MappingUtils.getMatchingMappingItems(mapItems, type)));
                         externalResources.put(resource.getKey(), connectorObject);
                     }
 
                     if (connectorObject != null) {
-                        // ask for searched virtual attribute value
-                        Collection<MappingItem> virAttrMappings =
-                                MappingUtils.getMatchingMappingItems(mappings, schemaName, type);
-
-                        // the same virtual attribute could be mapped with one or more external attribute 
-                        for (MappingItem mapping : virAttrMappings) {
-                            Attribute attribute = connectorObject.getAttributeByName(mapping.getExtAttrName());
-
-                            if (attribute != null && attribute.getValue() != null) {
-                                for (Object obj : attribute.getValue()) {
+                        // the same virtual attribute could be mapped with one or more external attributes
+                        for (MappingItem mapItem : MappingUtils.getMatchingMappingItems(mapItems, schemaName, type)) {
+                            Attribute attr = connectorObject.getAttributeByName(mapItem.getExtAttrName());
+                            if (attr != null && attr.getValue() != null) {
+                                for (Object obj : attr.getValue()) {
                                     if (obj != null) {
                                         virAttr.getValues().add(obj.toString());
                                     }
@@ -390,7 +384,7 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
             public boolean evaluate(final ExternalResource resource) {
                 return resource.getProvision(anyType) != null
                         && !MappingUtils.getMatchingMappingItems(
-                                MappingUtils.getMappingItems(resource.getProvision(anyType), MappingPurpose.BOTH),
+                                MappingUtils.getBothMappingItems(resource.getProvision(anyType)),
                                 attr.getSchema().getKey(), type).isEmpty();
             }
         });


Mime
View raw message