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 2016/06/14 15:58:31 UTC

[15/17] syncope git commit: [SYNCOPE-862] Features complete

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index e2f793a..7d38624 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -21,24 +21,21 @@ package org.apache.syncope.core.provisioning.java;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import org.apache.commons.collections4.ListUtils;
-import org.apache.commons.jexl3.JexlContext;
-import org.apache.commons.jexl3.MapContext;
-import org.apache.commons.lang3.ClassUtils;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 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.MembershipTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
-import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.provisioning.api.utils.policy.InvalidPasswordRuleConf;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
@@ -48,53 +45,46 @@ import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 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.spring.security.Encryptor;
-import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
 import org.apache.syncope.core.spring.security.PasswordGenerator;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 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.VirSchema;
-import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
 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.DerAttrHandler;
-import org.apache.syncope.core.provisioning.api.IntAttrNameParser;
-import org.apache.syncope.core.provisioning.api.IntAttrNameParser.IntAttrName;
+import org.apache.syncope.core.provisioning.api.IntAttrName;
 import org.apache.syncope.core.provisioning.api.MappingManager;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
-import org.apache.syncope.core.provisioning.java.data.JEXLMappingItemTransformer;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.identityconnectors.framework.common.FrameworkUtil;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeBuilder;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
-import org.identityconnectors.framework.common.objects.Name;
-import org.identityconnectors.framework.common.objects.OperationOptions;
-import org.identityconnectors.framework.common.objects.OperationOptionsBuilder;
 import org.identityconnectors.framework.common.objects.OperationalAttributes;
-import org.identityconnectors.framework.common.objects.Uid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 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;
+import org.apache.syncope.common.lib.to.GroupableRelatableTO;
 
 @Component
 public class MappingManagerImpl implements MappingManager {
@@ -116,10 +106,10 @@ public class MappingManagerImpl implements MappingManager {
     private VirSchemaDAO virSchemaDAO;
 
     @Autowired
-    private UserDAO userDAO;
+    private AnyObjectDAO anyObjectDAO;
 
     @Autowired
-    private AnyObjectDAO anyObjectDAO;
+    private GroupDAO groupDAO;
 
     @Autowired
     private DerAttrHandler derAttrHandler;
@@ -139,201 +129,9 @@ public class MappingManagerImpl implements MappingManager {
     @Autowired
     private AnyUtilsFactory anyUtilsFactory;
 
-    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 PULL:
-                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.PULL != 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> getPullMappingItems(final Provision provision) {
-        return getMappingItems(provision, MappingPurpose.PULL);
-    }
-
-    /**
-     * 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, 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<>();
-
-        // First consider the JEXL transformation expressions
-        JEXLMappingItemTransformer jexlTransformer = null;
-        if (StringUtils.isNotBlank(mappingItem.getPropagationJEXLTransformer())
-                || StringUtils.isNotBlank(mappingItem.getPullJEXLTransformer())) {
-
-            try {
-                jexlTransformer = (JEXLMappingItemTransformer) ApplicationContextProvider.getBeanFactory().
-                        createBean(JEXLMappingItemTransformer.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
-
-                jexlTransformer.setPropagationJEXL(mappingItem.getPropagationJEXLTransformer());
-                jexlTransformer.setPullJEXL(mappingItem.getPullJEXLTransformer());
-            } catch (Exception e) {
-                LOG.error("Could not instantiate {}, ignoring...", JEXLMappingItemTransformer.class.getName(), e);
-            }
-        }
-        if (jexlTransformer != null) {
-            result.add(jexlTransformer);
-        }
-
-        // Then other custom tranaformers
-        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;
-    }
-
-    /**
-     * Build options for requesting all mapped connector attributes.
-     *
-     * @param mapItems mapping items
-     * @return options for requesting all mapped connector attributes
-     * @see OperationOptions
-     */
-    public static OperationOptions buildOperationOptions(final Iterator<? extends MappingItem> mapItems) {
-        OperationOptionsBuilder builder = new OperationOptionsBuilder();
-
-        Set<String> attrsToGet = new HashSet<>();
-        attrsToGet.add(Name.NAME);
-        attrsToGet.add(Uid.NAME);
-        attrsToGet.add(OperationalAttributes.ENABLE_NAME);
-
-        while (mapItems.hasNext()) {
-            MappingItem mapItem = mapItems.next();
-            if (mapItem.getPurpose() != MappingPurpose.NONE) {
-                attrsToGet.add(mapItem.getExtAttrName());
-            }
-        }
-
-        builder.setAttributesToGet(attrsToGet);
-        // -------------------------------------
-
-        return builder.build();
-    }
+    @Autowired
+    private IntAttrNameParser intAttrNameParser;
 
-    /**
-     * Prepare attributes for sending to a connector instance.
-     *
-     * @param any given any object
-     * @param password clear-text password
-     * @param changePwd whether password should be included for propagation attributes or not
-     * @param enable whether any object must be enabled or not
-     * @param provision provision information
-     * @return connObjectLink + prepared attributes
-     */
     @Transactional(readOnly = true)
     @Override
     public Pair<String, Set<Attribute>> prepareAttrs(
@@ -349,42 +147,44 @@ public class MappingManagerImpl implements MappingManager {
         Set<Attribute> attributes = new HashSet<>();
         String connObjectKey = null;
 
-        for (MappingItem mappingItem : getMappingItems(provision, MappingPurpose.PROPAGATION)) {
-            LOG.debug("Processing expression '{}'", mappingItem.getIntAttrName());
+        for (MappingItem mapItem : MappingUtils.getPropagationMappingItems(provision)) {
+            LOG.debug("Processing expression '{}'", mapItem.getIntAttrName());
 
             try {
-                Pair<String, Attribute> preparedAttr = prepareAttr(provision, mappingItem, any, password);
-
-                if (preparedAttr != null && preparedAttr.getKey() != null) {
-                    connObjectKey = preparedAttr.getKey();
-                }
+                Pair<String, Attribute> preparedAttr = prepareAttr(provision, mapItem, any, password);
+                if (preparedAttr != null) {
+                    if (preparedAttr.getKey() != null) {
+                        connObjectKey = preparedAttr.getKey();
+                    }
 
-                if (preparedAttr != null && preparedAttr.getValue() != null) {
-                    Attribute alreadyAdded = AttributeUtil.find(preparedAttr.getValue().getName(), attributes);
+                    if (preparedAttr.getValue() != null) {
+                        Attribute alreadyAdded = AttributeUtil.find(preparedAttr.getValue().getName(), attributes);
 
-                    if (alreadyAdded == null) {
-                        attributes.add(preparedAttr.getValue());
-                    } else {
-                        attributes.remove(alreadyAdded);
+                        if (alreadyAdded == null) {
+                            attributes.add(preparedAttr.getValue());
+                        } else {
+                            attributes.remove(alreadyAdded);
 
-                        Set<Object> values = new HashSet<>(alreadyAdded.getValue());
-                        values.addAll(preparedAttr.getValue().getValue());
+                            Set<Object> values = new HashSet<>(alreadyAdded.getValue());
+                            values.addAll(preparedAttr.getValue().getValue());
 
-                        attributes.add(AttributeBuilder.build(preparedAttr.getValue().getName(), values));
+                            attributes.add(AttributeBuilder.build(preparedAttr.getValue().getName(), values));
+                        }
                     }
                 }
             } catch (Exception e) {
-                LOG.debug("Expression '{}' processing failed", mappingItem.getIntAttrName(), e);
+                LOG.error("Expression '{}' processing failed", mapItem.getIntAttrName(), e);
             }
         }
 
         Attribute connObjectKeyExtAttr =
-                AttributeUtil.find(getConnObjectKeyItem(provision).getExtAttrName(), attributes);
+                AttributeUtil.find(MappingUtils.getConnObjectKeyItem(provision).getExtAttrName(), attributes);
         if (connObjectKeyExtAttr != null) {
             attributes.remove(connObjectKeyExtAttr);
-            attributes.add(AttributeBuilder.build(getConnObjectKeyItem(provision).getExtAttrName(), connObjectKey));
+            attributes.add(AttributeBuilder.build(
+                    MappingUtils.getConnObjectKeyItem(provision).getExtAttrName(), connObjectKey));
         }
-        attributes.add(evaluateNAME(any, provision, connObjectKey));
+        attributes.add(MappingUtils.evaluateNAME(any, provision, connObjectKey));
 
         if (enable != null) {
             attributes.add(AttributeBuilder.buildEnabled(enable));
@@ -404,7 +204,7 @@ public class MappingManagerImpl implements MappingManager {
      *
      * @param provision external resource
      * @param mapItem mapping item for the given attribute
-     * @param any any object
+     * @param any given any object
      * @param password clear-text password
      * @return connObjectKey + prepared attribute
      */
@@ -412,63 +212,33 @@ public class MappingManagerImpl implements MappingManager {
             final Provision provision, final MappingItem mapItem, final Any<?> any, final String password) {
 
         IntAttrName intAttrName =
-                IntAttrNameParser.parse(mapItem.getIntAttrName(), anyUtilsFactory, provision.getAnyType().getKind());
-
-        List<Any<?>> anys = new ArrayList<>();
-
-        switch (intAttrName.getAnyTypeKind()) {
-            case USER:
-                if (any instanceof User) {
-                    anys.add(any);
-                }
-                break;
-
-            case GROUP:
-                if (any instanceof User) {
-                    anys.addAll(userDAO.findAllGroups((User) any));
-                } else if (any instanceof AnyObject) {
-                    anys.addAll(anyObjectDAO.findAllGroups((AnyObject) any));
-                } else if (any instanceof Group) {
-                    anys.add(any);
-                }
-                break;
+                intAttrNameParser.parse(mapItem.getIntAttrName(), provision.getAnyType().getKind());
 
-            case ANY_OBJECT:
-                if (any instanceof AnyObject) {
-                    anys.add(any);
-                }
-                break;
-
-            default:
-        }
-
-        Schema schema = null;
         boolean readOnlyVirSchema = false;
-        AttrSchemaType schemaType;
-        Pair<String, Attribute> result;
-
-        switch (intAttrName.getSchemaType()) {
-            case PLAIN:
-                schema = plainSchemaDAO.find(intAttrName.getSchemaName());
-                schemaType = schema == null ? AttrSchemaType.String : schema.getType();
-                break;
+        Schema schema = null;
+        AttrSchemaType schemaType = AttrSchemaType.String;
+        if (intAttrName.getSchemaType() != null) {
+            switch (intAttrName.getSchemaType()) {
+                case PLAIN:
+                    schema = plainSchemaDAO.find(intAttrName.getSchemaName());
+                    if (schema != null) {
+                        schemaType = schema.getType();
+                    }
+                    break;
 
-            case VIRTUAL:
-                schema = virSchemaDAO.find(intAttrName.getSchemaName());
-                readOnlyVirSchema = (schema != null && schema.isReadonly());
-                schemaType = AttrSchemaType.String;
-                break;
+                case VIRTUAL:
+                    schema = virSchemaDAO.find(intAttrName.getSchemaName());
+                    readOnlyVirSchema = (schema != null && schema.isReadonly());
+                    break;
 
-            default:
-                schemaType = AttrSchemaType.String;
+                default:
+            }
         }
 
-        String extAttrName = mapItem.getExtAttrName();
-
-        List<PlainAttrValue> values = getIntValues(provision, mapItem, anys);
+        List<PlainAttrValue> values = getIntValues(provision, mapItem, intAttrName, any);
 
         LOG.debug("Define mapping for: "
-                + "\n* ExtAttrName " + extAttrName
+                + "\n* ExtAttrName " + mapItem.getExtAttrName()
                 + "\n* is connObjectKey " + mapItem.isConnObjectKey()
                 + "\n* is password " + mapItem.isPassword()
                 + "\n* mandatory condition " + mapItem.getMandatoryCondition()
@@ -476,6 +246,7 @@ public class MappingManagerImpl implements MappingManager {
                 + "\n* ClassType " + schemaType.getType().getName()
                 + "\n* Values " + values);
 
+        Pair<String, Attribute> result;
         if (readOnlyVirSchema) {
             result = null;
         } else {
@@ -516,78 +287,103 @@ public class MappingManagerImpl implements MappingManager {
                     result = new ImmutablePair<>(
                             null, AttributeBuilder.buildPassword(passwordAttrValue.toCharArray()));
                 }
-            } else if ((schema != null && schema.isMultivalue())
-                    || anyUtilsFactory.getInstance(any).getAnyTypeKind() != intAttrName.getAnyTypeKind()) {
-
+            } else if (schema != null && schema.isMultivalue()) {
                 result = new ImmutablePair<>(
-                        null, AttributeBuilder.build(extAttrName, objValues));
+                        null, AttributeBuilder.build(mapItem.getExtAttrName(), objValues));
             } else {
                 result = new ImmutablePair<>(
                         null, objValues.isEmpty()
-                                ? AttributeBuilder.build(extAttrName)
-                                : AttributeBuilder.build(extAttrName, objValues.iterator().next()));
+                                ? AttributeBuilder.build(mapItem.getExtAttrName())
+                                : AttributeBuilder.build(mapItem.getExtAttrName(), objValues.iterator().next()));
             }
         }
 
         return result;
     }
 
-    private String getGroupOwnerValue(final Provision provision, final Any<?> any) {
-        Pair<String, Attribute> preparedAttr = prepareAttr(provision, getConnObjectKeyItem(provision), any, null);
-        String connObjectKey = preparedAttr.getKey();
-
-        return evaluateNAME(any, provision, connObjectKey).getNameValue();
-    }
-
     @Transactional(readOnly = true)
     @Override
     public List<PlainAttrValue> getIntValues(
-            final Provision provision, final MappingItem mapItem, final List<Any<?>> anys) {
+            final Provision provision,
+            final MappingItem mapItem,
+            final IntAttrName intAttrName,
+            final Any<?> any) {
 
-        LOG.debug("Get attributes for '{}' and intAttrName '{}'", anys, mapItem.getIntAttrName());
+        LOG.debug("Get internal values for {} as '{}' on {}", any, mapItem.getIntAttrName(), provision.getResource());
 
-        IntAttrName intAttrName =
-                IntAttrNameParser.parse(mapItem.getIntAttrName(), anyUtilsFactory, provision.getAnyType().getKind());
+        Any<?> reference = null;
+        Membership<?> membership = null;
+        if (intAttrName.getEnclosingGroup() == null && intAttrName.getRelatedAnyObject() == null) {
+            reference = any;
+        }
+        if (any instanceof GroupableRelatable) {
+            GroupableRelatable<?, ?, ?, ?, ?> groupableRelatable = (GroupableRelatable<?, ?, ?, ?, ?>) any;
+
+            if (intAttrName.getEnclosingGroup() != null) {
+                Group group = groupDAO.findByName(intAttrName.getEnclosingGroup());
+                if (group == null || groupableRelatable.getMembership(group.getKey()) == null) {
+                    LOG.warn("No membership for {} in {}, ignoring",
+                            intAttrName.getEnclosingGroup(), groupableRelatable);
+                } else {
+                    reference = group;
+                }
+            } else if (intAttrName.getRelatedAnyObject() != null) {
+                AnyObject anyObject = anyObjectDAO.findByName(intAttrName.getRelatedAnyObject());
+                if (anyObject == null || groupableRelatable.getRelationships(anyObject.getKey()).isEmpty()) {
+                    LOG.warn("No relationship for {} in {}, ignoring",
+                            intAttrName.getRelatedAnyObject(), groupableRelatable);
+                } else {
+                    reference = anyObject;
+                }
+            } else if (intAttrName.getMembershipOfGroup() != null) {
+                Group group = groupDAO.findByName(intAttrName.getMembershipOfGroup());
+                membership = groupableRelatable.getMembership(group.getKey());
+            }
+        }
+        if (reference == null) {
+            LOG.warn("Could not determine the reference instance for {}", mapItem.getIntAttrName());
+            return Collections.emptyList();
+        }
 
         List<PlainAttrValue> values = new ArrayList<>();
         boolean transform = true;
 
         if (intAttrName.getField() != null) {
+            AnyUtils anyUtils = anyUtilsFactory.getInstance(reference);
+            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+
             switch (intAttrName.getField()) {
                 case "key":
-                    for (Any<?> any : anys) {
-                        AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-                        PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                        attrValue.setStringValue(any.getKey());
-                        values.add(attrValue);
-                    }
+                    attrValue.setStringValue(reference.getKey());
+                    values.add(attrValue);
+                    break;
+
+                case "password":
+                    // ignore
                     break;
 
                 case "username":
-                    for (Any<?> any : anys) {
-                        if (any instanceof User) {
-                            UPlainAttrValue attrValue = entityFactory.newEntity(UPlainAttrValue.class);
-                            attrValue.setStringValue(((User) any).getUsername());
-                            values.add(attrValue);
-                        }
+                    if (reference instanceof User) {
+                        attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+                        attrValue.setStringValue(((User) reference).getUsername());
+                        values.add(attrValue);
                     }
                     break;
 
                 case "name":
-                    for (Any<?> any : anys) {
-                        if (any instanceof Group) {
-                            GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
-                            attrValue.setStringValue(((Group) any).getName());
-                            values.add(attrValue);
-                        } else if (any instanceof AnyObject) {
-                            APlainAttrValue attrValue = entityFactory.newEntity(APlainAttrValue.class);
-                            attrValue.setStringValue(((AnyObject) any).getName());
-                            values.add(attrValue);
-                        }
+                    if (reference instanceof Group) {
+                        attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+                        attrValue.setStringValue(((Group) reference).getName());
+                        values.add(attrValue);
+                    } else if (reference instanceof AnyObject) {
+                        attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+                        attrValue.setStringValue(((AnyObject) reference).getName());
+                        values.add(attrValue);
                     }
                     break;
 
-                case "owner":
+                case "userOwner":
+                case "groupOwner":
                     Mapping uMapping = provision.getAnyType().equals(anyTypeDAO.findUser())
                             ? provision.getMapping()
                             : null;
@@ -595,44 +391,53 @@ public class MappingManagerImpl implements MappingManager {
                             ? provision.getMapping()
                             : null;
 
-                    for (Any<?> any : anys) {
-                        if (any instanceof Group) {
-                            Group group = (Group) any;
-                            String groupOwnerValue = null;
-                            if (group.getUserOwner() != null && uMapping != null) {
-                                groupOwnerValue = getGroupOwnerValue(provision, group.getUserOwner());
-                            }
-                            if (group.getGroupOwner() != null && gMapping != null) {
-                                groupOwnerValue = getGroupOwnerValue(provision, group.getGroupOwner());
-                            }
+                    if (reference instanceof Group) {
+                        Group group = (Group) reference;
+                        String groupOwnerValue = null;
+                        if (group.getUserOwner() != null && uMapping != null) {
+                            groupOwnerValue = getGroupOwnerValue(provision, group.getUserOwner());
+                        }
+                        if (group.getGroupOwner() != null && gMapping != null) {
+                            groupOwnerValue = getGroupOwnerValue(provision, group.getGroupOwner());
+                        }
 
-                            if (StringUtils.isNotBlank(groupOwnerValue)) {
-                                GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
-                                attrValue.setStringValue(groupOwnerValue);
-                                values.add(attrValue);
-                            }
+                        if (StringUtils.isNotBlank(groupOwnerValue)) {
+                            attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+                            attrValue.setStringValue(groupOwnerValue);
+                            values.add(attrValue);
                         }
                     }
                     break;
 
                 default:
+                    try {
+                        attrValue.setStringValue(FieldUtils.readField(
+                                reference, intAttrName.getField(), true).toString());
+                        values.add(attrValue);
+                    } catch (IllegalAccessException e) {
+                        LOG.error("Could not read value of '{}' from {}", intAttrName.getField(), reference, e);
+                    }
             }
         } else if (intAttrName.getSchemaType() != null) {
             switch (intAttrName.getSchemaType()) {
                 case PLAIN:
-                    for (Any<?> any : anys) {
-                        PlainAttr<?> attr = any.getPlainAttr(intAttrName.getSchemaName());
-                        if (attr != null) {
-                            if (attr.getUniqueValue() != null) {
-                                PlainAttrUniqueValue value = SerializationUtils.clone(attr.getUniqueValue());
-                                value.setAttr(null);
-                                values.add(value);
-                            } else if (attr.getValues() != null) {
-                                for (PlainAttrValue value : attr.getValues()) {
-                                    PlainAttrValue shadow = SerializationUtils.clone(value);
-                                    shadow.setAttr(null);
-                                    values.add(shadow);
-                                }
+                    PlainAttr<?> attr;
+                    if (membership == null) {
+                        attr = reference.getPlainAttr(intAttrName.getSchemaName());
+                    } else {
+                        attr = ((GroupableRelatable<?, ?, ?, ?, ?>) reference).getPlainAttr(
+                                intAttrName.getSchemaName(), membership);
+                    }
+                    if (attr != null) {
+                        if (attr.getUniqueValue() != null) {
+                            PlainAttrUniqueValue value = SerializationUtils.clone(attr.getUniqueValue());
+                            value.setAttr(null);
+                            values.add(value);
+                        } else if (attr.getValues() != null) {
+                            for (PlainAttrValue value : attr.getValues()) {
+                                PlainAttrValue shadow = SerializationUtils.clone(value);
+                                shadow.setAttr(null);
+                                values.add(shadow);
                             }
                         }
                     }
@@ -641,14 +446,14 @@ public class MappingManagerImpl implements MappingManager {
                 case DERIVED:
                     DerSchema derSchema = derSchemaDAO.find(intAttrName.getSchemaName());
                     if (derSchema != null) {
-                        for (Any<?> any : anys) {
-                            String value = derAttrHandler.getValue(any, derSchema);
-                            if (value != null) {
-                                AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-                                PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                                attrValue.setStringValue(value);
-                                values.add(attrValue);
-                            }
+                        String value = membership == null
+                                ? derAttrHandler.getValue(reference, derSchema)
+                                : derAttrHandler.getValue(reference, membership, derSchema);
+                        if (value != null) {
+                            AnyUtils anyUtils = anyUtilsFactory.getInstance(reference);
+                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                            attrValue.setStringValue(value);
+                            values.add(attrValue);
                         }
                     }
                     break;
@@ -659,16 +464,18 @@ public class MappingManagerImpl implements MappingManager {
 
                     VirSchema virSchema = virSchemaDAO.find(intAttrName.getSchemaName());
                     if (virSchema != null) {
-                        for (Any<?> any : anys) {
-                            LOG.debug("Expire entry cache {}-{}", any.getKey(), intAttrName.getSchemaName());
-                            virAttrCache.expire(any.getType().getKey(), any.getKey(), intAttrName.getSchemaName());
-
-                            AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-                            for (String value : virAttrHandler.getValues(any, virSchema)) {
-                                PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
-                                attrValue.setStringValue(value);
-                                values.add(attrValue);
-                            }
+                        LOG.debug("Expire entry cache {}-{}", reference, intAttrName.getSchemaName());
+                        virAttrCache.expire(
+                                reference.getType().getKey(), reference.getKey(), intAttrName.getSchemaName());
+
+                        AnyUtils anyUtils = anyUtilsFactory.getInstance(reference);
+                        List<String> virValues = membership == null
+                                ? virAttrHandler.getValues(reference, virSchema)
+                                : virAttrHandler.getValues(reference, membership, virSchema);
+                        for (String value : virValues) {
+                            PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+                            attrValue.setStringValue(value);
+                            values.add(attrValue);
                         }
                     }
                     break;
@@ -677,14 +484,14 @@ public class MappingManagerImpl implements MappingManager {
             }
         }
 
-        LOG.debug("Values for propagation: {}", values);
+        LOG.debug("Internal values: {}", values);
 
         List<PlainAttrValue> transformed = values;
         if (transform) {
-            for (MappingItemTransformer transformer : getMappingItemTransformers(mapItem)) {
-                transformed = transformer.beforePropagation(mapItem, anys, transformed);
+            for (MappingItemTransformer transformer : MappingUtils.getMappingItemTransformers(mapItem)) {
+                transformed = transformer.beforePropagation(mapItem, any, transformed);
             }
-            LOG.debug("Transformed values for propagation: {}", values);
+            LOG.debug("Transformed values: {}", values);
         } else {
             LOG.debug("No transformation occurred");
         }
@@ -692,12 +499,24 @@ public class MappingManagerImpl implements MappingManager {
         return transformed;
     }
 
+    private String getGroupOwnerValue(final Provision provision, final Any<?> any) {
+        Pair<String, Attribute> preparedAttr =
+                prepareAttr(provision, MappingUtils.getConnObjectKeyItem(provision), any, null);
+        String connObjectKey = preparedAttr.getKey();
+
+        return MappingUtils.evaluateNAME(any, provision, connObjectKey).getNameValue();
+    }
+
     @Transactional(readOnly = true)
     @Override
     public String getConnObjectKeyValue(final Any<?> any, final Provision provision) {
-        List<PlainAttrValue> values = getIntValues(provision, provision.getMapping().getConnObjectKeyItem(),
-                Collections.<Any<?>>singletonList(any));
-        return values == null || values.isEmpty()
+        MappingItem mapItem = provision.getMapping().getConnObjectKeyItem();
+        List<PlainAttrValue> values = getIntValues(
+                provision,
+                mapItem,
+                intAttrNameParser.parse(mapItem.getIntAttrName(), provision.getAnyType().getKind()),
+                any);
+        return values.isEmpty()
                 ? null
                 : values.get(0).getValueAsString();
     }
@@ -710,20 +529,17 @@ public class MappingManagerImpl implements MappingManager {
         List<Object> values = null;
         if (attr != null) {
             values = attr.getValue();
-            for (MappingItemTransformer transformer : getMappingItemTransformers(mapItem)) {
+            for (MappingItemTransformer transformer : MappingUtils.getMappingItemTransformers(mapItem)) {
                 values = transformer.beforePull(mapItem, anyTO, values);
             }
         }
         values = ListUtils.emptyIfNull(values);
 
         IntAttrName intAttrName =
-                IntAttrNameParser.parse(mapItem.getIntAttrName(), anyUtilsFactory, anyUtils.getAnyTypeKind());
+                intAttrNameParser.parse(mapItem.getIntAttrName(), anyUtils.getAnyTypeKind());
 
         if (intAttrName.getField() != null) {
             switch (intAttrName.getField()) {
-                case "key":
-                    break;
-
                 case "password":
                     if (anyTO instanceof UserTO && !values.isEmpty()) {
                         ((UserTO) anyTO).setPassword(ConnObjectUtils.getPassword(values.get(0)));
@@ -750,7 +566,8 @@ public class MappingManagerImpl implements MappingManager {
                     }
                     break;
 
-                case "owner":
+                case "userOwner":
+                case "groupOwner":
                     if (anyTO instanceof GroupTO && attr != null) {
                         // using a special attribute (with schema "", that will be ignored) for carrying the
                         // GroupOwnerSchema value
@@ -769,6 +586,13 @@ public class MappingManagerImpl implements MappingManager {
                 default:
             }
         } else if (intAttrName.getSchemaType() != null) {
+            GroupableRelatableTO groupableTO = null;
+            Group group = null;
+            if (anyTO instanceof GroupableRelatableTO && intAttrName.getMembershipOfGroup() != null) {
+                groupableTO = (GroupableRelatableTO) anyTO;
+                group = groupDAO.findByName(intAttrName.getMembershipOfGroup());
+            }
+
             switch (intAttrName.getSchemaType()) {
                 case PLAIN:
                     AttrTO attrTO = new AttrTO();
@@ -803,13 +627,31 @@ public class MappingManagerImpl implements MappingManager {
                         }
                     }
 
-                    anyTO.getPlainAttrs().add(attrTO);
+                    if (groupableTO == null || group == null) {
+                        anyTO.getPlainAttrs().add(attrTO);
+                    } else {
+                        MembershipTO membership = groupableTO.getMembershipMap().get(group.getKey());
+                        if (membership == null) {
+                            membership = new MembershipTO.Builder().group(group.getKey(), group.getName()).build();
+                            groupableTO.getMemberships().add(membership);
+                        }
+                        membership.getPlainAttrs().add(attrTO);
+                    }
                     break;
 
                 case DERIVED:
                     attrTO = new AttrTO();
                     attrTO.setSchema(intAttrName.getSchemaName());
-                    anyTO.getDerAttrs().add(attrTO);
+                    if (groupableTO == null || group == null) {
+                        anyTO.getDerAttrs().add(attrTO);
+                    } else {
+                        MembershipTO membership = groupableTO.getMembershipMap().get(group.getKey());
+                        if (membership == null) {
+                            membership = new MembershipTO.Builder().group(group.getKey(), group.getName()).build();
+                            groupableTO.getMemberships().add(membership);
+                        }
+                        membership.getDerAttrs().add(attrTO);
+                    }
                     break;
 
                 case VIRTUAL:
@@ -825,7 +667,16 @@ public class MappingManagerImpl implements MappingManager {
                         }
                     }
 
-                    anyTO.getVirAttrs().add(attrTO);
+                    if (groupableTO == null || group == null) {
+                        anyTO.getVirAttrs().add(attrTO);
+                    } else {
+                        MembershipTO membership = groupableTO.getMembershipMap().get(group.getKey());
+                        if (membership == null) {
+                            membership = new MembershipTO.Builder().group(group.getKey(), group.getName()).build();
+                            groupableTO.getMemberships().add(membership);
+                        }
+                        membership.getVirAttrs().add(attrTO);
+                    }
                     break;
 
                 default:

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/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 67a821c..85e6522 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
@@ -40,6 +40,7 @@ import org.apache.syncope.core.provisioning.api.MappingManager;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
 import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
 import org.identityconnectors.framework.common.objects.Uid;
@@ -99,7 +100,7 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
         for (Map.Entry<Provision, Set<VirSchema>> entry : toRead.entrySet()) {
             LOG.debug("About to read from {}: {}", entry.getKey(), entry.getValue());
 
-            String connObjectKey = MappingManagerImpl.getConnObjectKeyItem(entry.getKey()) == null
+            String connObjectKey = MappingUtils.getConnObjectKeyItem(entry.getKey()) == null
                     ? null
                     : mappingManager.getConnObjectKeyValue(any, entry.getKey());
             if (StringUtils.isBlank(connObjectKey)) {
@@ -114,7 +115,7 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
                 try {
                     ConnectorObject connectorObject = connector.getObject(entry.getKey().getObjectClass(),
                             new Uid(connObjectKey),
-                            MappingManagerImpl.buildOperationOptions(linkingMappingItems.iterator()));
+                            MappingUtils.buildOperationOptions(linkingMappingItems.iterator()));
 
                     if (connectorObject == null) {
                         LOG.debug("No read from {} about {}", entry.getKey(), connObjectKey);

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index ca94e16..b826b63 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -37,7 +37,6 @@ import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.MembershipTO;
 import org.apache.syncope.common.lib.to.RelationshipTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
@@ -59,7 +58,6 @@ import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.common.lib.types.PropagationByResource;
 import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
-import org.apache.syncope.core.provisioning.java.MappingManagerImpl;
 import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
 import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -89,6 +87,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
+import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
+import org.apache.syncope.core.provisioning.api.IntAttrName;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 
 abstract class AbstractAnyDataBinder {
 
@@ -154,6 +155,9 @@ abstract class AbstractAnyDataBinder {
     @Autowired
     protected MappingManager mappingManager;
 
+    @Autowired
+    protected IntAttrNameParser intAttrNameParser;
+
     protected void setRealm(final Any<?> any, final AnyPatch anyPatch) {
         if (anyPatch.getRealm() != null && StringUtils.isNotBlank(anyPatch.getRealm().getValue())) {
             Realm newRealm = realmDAO.findByFullPath(anyPatch.getRealm().getValue());
@@ -215,14 +219,13 @@ abstract class AbstractAnyDataBinder {
     private List<String> evaluateMandatoryCondition(final Provision provision, final Any<?> any) {
         List<String> missingAttrNames = new ArrayList<>();
 
-        if (provision != null) {
-            for (MappingItem item : provision.getMapping().getItems()) {
-                if ((item.getPurpose() == MappingPurpose.PROPAGATION || item.getPurpose() == MappingPurpose.BOTH)) {
-                    List<PlainAttrValue> values = mappingManager.getIntValues(
-                            provision, item, Collections.<Any<?>>singletonList(any));
-                    if (values.isEmpty() && JexlUtils.evaluateMandatoryCondition(item.getMandatoryCondition(), any)) {
-                        missingAttrNames.add(item.getIntAttrName());
-                    }
+        for (MappingItem mapItem : MappingUtils.getPropagationMappingItems(provision)) {
+            IntAttrName intAttrName =
+                    intAttrNameParser.parse(mapItem.getIntAttrName(), provision.getAnyType().getKind());
+            if (intAttrName.getSchemaType() != null) {
+                List<PlainAttrValue> values = mappingManager.getIntValues(provision, mapItem, intAttrName, any);
+                if (values.isEmpty() && JexlUtils.evaluateMandatoryCondition(mapItem.getMandatoryCondition(), any)) {
+                    missingAttrNames.add(mapItem.getIntAttrName());
                 }
             }
         }
@@ -230,9 +233,7 @@ abstract class AbstractAnyDataBinder {
         return missingAttrNames;
     }
 
-    private SyncopeClientException checkMandatoryOnResources(
-            final Any<?> any, final Set<ExternalResource> resources) {
-
+    private SyncopeClientException checkMandatoryOnResources(final Any<?> any, final Set<ExternalResource> resources) {
         SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
 
         for (ExternalResource resource : resources) {
@@ -338,13 +339,11 @@ abstract class AbstractAnyDataBinder {
         }
 
         for (ExternalResource resource : resources) {
-            for (MappingItem mapItem
-                    : MappingManagerImpl.getPropagationMappingItems(resource.getProvision(any.getType()))) {
-
-                if (schema.getKey().equals(mapItem.getIntAttrName())) {
+            for (MappingItem item : MappingUtils.getPropagationMappingItems(resource.getProvision(any.getType()))) {
+                if (schema.getKey().equals(item.getIntAttrName())) {
                     propByRes.add(ResourceOperation.UPDATE, resource.getKey());
 
-                    if (mapItem.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) {
+                    if (item.isConnObjectKey() && !attr.getValuesAsStrings().isEmpty()) {
                         propByRes.addOldConnObjectKey(resource.getKey(), attr.getValuesAsStrings().get(0));
                     }
                 }
@@ -646,7 +645,7 @@ abstract class AbstractAnyDataBinder {
         for (ExternalResource resource : iterable) {
             Provision provision = resource.getProvision(any.getType());
             if (provision != null && provision.getMapping() != null) {
-                MappingItem connObjectKeyItem = MappingManagerImpl.getConnObjectKeyItem(provision);
+                MappingItem connObjectKeyItem = MappingUtils.getConnObjectKeyItem(provision);
                 if (connObjectKeyItem == null) {
                     throw new NotFoundException(
                             "ConnObjectKey mapping for " + any.getType().getKey() + " " + any.getKey()

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
index 7ed913d..37a471c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
@@ -35,7 +35,7 @@ public class DefaultMappingItemTransformer implements MappingItemTransformer {
     @Override
     public List<PlainAttrValue> beforePropagation(
             final MappingItem mappingItem,
-            final List<Any<?>> anys,
+            final Any<?> any,
             final List<PlainAttrValue> values) {
 
         return values;

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java
index e4e155a..6fef0bb 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java
@@ -20,18 +20,13 @@ package org.apache.syncope.core.provisioning.java.data;
 
 import java.util.ArrayList;
 import java.util.List;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.MapContext;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
-import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
-import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
 
 /**
@@ -55,47 +50,10 @@ public class JEXLMappingItemTransformer extends DefaultMappingItemTransformer {
     @Override
     public List<PlainAttrValue> beforePropagation(
             final MappingItem mappingItem,
-            final List<Any<?>> anys,
+            final Any<?> any,
             final List<PlainAttrValue> values) {
 
         if (StringUtils.isNotBlank(propagationJEXL) && values != null) {
-            Any<?> any = null;
-            if (!anys.isEmpty()) {
-                switch (mappingItem.getMapping().getProvision().getAnyType().getKind()) {
-                    case USER:
-                        any = IterableUtils.find(anys, new Predicate<Any<?>>() {
-
-                            @Override
-                            public boolean evaluate(final Any<?> object) {
-                                return object instanceof User;
-                            }
-                        });
-                        break;
-
-                    case GROUP:
-                        any = IterableUtils.find(anys, new Predicate<Any<?>>() {
-
-                            @Override
-                            public boolean evaluate(final Any<?> object) {
-                                return object instanceof Group;
-                            }
-                        });
-                        break;
-
-                    case ANY_OBJECT:
-                        any = IterableUtils.find(anys, new Predicate<Any<?>>() {
-
-                            @Override
-                            public boolean evaluate(final Any<?> object) {
-                                return object instanceof AnyObject;
-                            }
-                        });
-                        break;
-
-                    default:
-                }
-            }
-
             for (PlainAttrValue value : values) {
                 JexlContext jexlContext = new MapContext();
                 if (any != null) {
@@ -111,7 +69,7 @@ public class JEXLMappingItemTransformer extends DefaultMappingItemTransformer {
             return values;
         }
 
-        return super.beforePropagation(mappingItem, anys, values);
+        return super.beforePropagation(mappingItem, any, values);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
index a9de5bd..11b4cb0 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
@@ -34,9 +34,8 @@ import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.MailTemplateDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyAbout;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.MailTemplate;
-import org.apache.syncope.core.provisioning.api.IntAttrNameParser;
+import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -59,7 +58,7 @@ public class NotificationDataBinderImpl implements NotificationDataBinder {
     private EntityFactory entityFactory;
 
     @Autowired
-    private AnyUtilsFactory anyUtilsFactory;
+    private IntAttrNameParser intAttrNameParser;
 
     @Override
     public NotificationTO getNotificationTO(final Notification notification) {
@@ -126,6 +125,6 @@ public class NotificationDataBinderImpl implements NotificationDataBinder {
         });
 
         // 3. verify recipientAttrName
-        IntAttrNameParser.parse(notification.getRecipientAttrName(), anyUtilsFactory, AnyTypeKind.USER);
+        intAttrNameParser.parse(notification.getRecipientAttrName(), AnyTypeKind.USER);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index ddf5a14..7eea744 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -31,6 +31,7 @@ import org.apache.syncope.common.lib.to.MappingTO;
 import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
 import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO;
@@ -48,14 +49,13 @@ import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
-import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.provisioning.api.IntAttrNameParser;
-import org.apache.syncope.core.provisioning.api.IntAttrNameParser.IntAttrName;
+import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
+import org.apache.syncope.core.provisioning.api.IntAttrName;
 import org.apache.syncope.core.provisioning.api.data.ResourceDataBinder;
 import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
 import org.identityconnectors.framework.common.objects.ObjectClass;
@@ -90,7 +90,7 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
     private EntityFactory entityFactory;
 
     @Autowired
-    private AnyUtilsFactory anyUtilsFactory;
+    private IntAttrNameParser intAttrNameParser;
 
     @Override
     public ExternalResource create(final ResourceTO resourceTO) {
@@ -268,30 +268,29 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
             if (itemTO == null) {
                 LOG.error("Null {}", MappingItemTO.class.getSimpleName());
                 invalidMapping.getElements().add("Null " + MappingItemTO.class.getSimpleName());
+            } else if (itemTO.getIntAttrName() == null) {
+                requiredValuesMissing.getElements().add("intAttrName");
+                scce.addException(requiredValuesMissing);
             } else {
-                if (itemTO.getIntAttrName() == null) {
-                    requiredValuesMissing.getElements().add("intAttrName");
-                    scce.addException(requiredValuesMissing);
-                }
-
-                IntAttrName intAttrName = IntAttrNameParser.parse(
+                IntAttrName intAttrName = intAttrNameParser.parse(
                         itemTO.getIntAttrName(),
-                        anyUtilsFactory,
                         mapping.getProvision().getAnyType().getKind());
 
                 boolean allowed = true;
-                if (intAttrName.getSchemaType() != null) {
+                if (intAttrName.getSchemaType() != null
+                        && intAttrName.getEnclosingGroup() == null && intAttrName.getRelatedAnyObject() == null) {
+
                     switch (intAttrName.getSchemaType()) {
                         case PLAIN:
-                            allowed = allowedSchemas.getPlainSchemas().contains(itemTO.getIntAttrName());
+                            allowed = allowedSchemas.getPlainSchemas().contains(intAttrName.getSchemaName());
                             break;
 
                         case DERIVED:
-                            allowed = allowedSchemas.getDerSchemas().contains(itemTO.getIntAttrName());
+                            allowed = allowedSchemas.getDerSchemas().contains(intAttrName.getSchemaName());
                             break;
 
                         case VIRTUAL:
-                            allowed = allowedSchemas.getVirSchemas().contains(itemTO.getIntAttrName());
+                            allowed = allowedSchemas.getVirSchemas().contains(intAttrName.getSchemaName());
                             break;
 
                         default:
@@ -324,6 +323,37 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
                     } else {
                         mapping.add(item);
                     }
+
+                    if (intAttrName.getEnclosingGroup() != null
+                            && item.getPurpose() != MappingPurpose.PROPAGATION) {
+
+                        invalidMapping.getElements().add(
+                                "Only " + MappingPurpose.PROPAGATION.name() + " allowed when referring to groups");
+                    }
+                    if (intAttrName.getRelatedAnyObject() != null
+                            && item.getPurpose() != MappingPurpose.PROPAGATION) {
+
+                        invalidMapping.getElements().add(
+                                "Only " + MappingPurpose.PROPAGATION.name() + " allowed when referring to any objects");
+                    }
+                    if (intAttrName.getSchemaType() == SchemaType.DERIVED
+                            && item.getPurpose() != MappingPurpose.PROPAGATION) {
+
+                        invalidMapping.getElements().add(
+                                "Only " + MappingPurpose.PROPAGATION.name() + " allowed for derived");
+                    }
+                    if (intAttrName.getSchemaType() == SchemaType.VIRTUAL) {
+                        if (item.getPurpose() != MappingPurpose.PROPAGATION) {
+                            invalidMapping.getElements().add(
+                                    "Only " + MappingPurpose.PROPAGATION.name() + " allowed for virtual");
+                        }
+
+                        VirSchema schema = virSchemaDAO.find(item.getIntAttrName());
+                        if (schema != null && schema.getProvision().equals(item.getMapping().getProvision())) {
+                            invalidMapping.getElements().add(
+                                    "No need to map virtual schema on linking resource");
+                        }
+                    }
                 } else {
                     LOG.error("{} not allowed", itemTO.getIntAttrName());
                     invalidMapping.getElements().add(itemTO.getIntAttrName() + " not allowed");

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index 1581463..5a532d7 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -159,8 +159,7 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             CipherAlgorithm predefined = CipherAlgorithm.valueOf(algorithm);
             user.setPassword(password, predefined);
         } catch (IllegalArgumentException e) {
-            final SyncopeClientException invalidCiperAlgorithm =
-                    SyncopeClientException.build(ClientExceptionType.NotFound);
+            SyncopeClientException invalidCiperAlgorithm = SyncopeClientException.build(ClientExceptionType.NotFound);
             invalidCiperAlgorithm.getElements().add(e.getMessage());
             scce.addException(invalidCiperAlgorithm);
 
@@ -305,7 +304,7 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
     @Override
     public PropagationByResource update(final User toBeUpdated, final UserPatch userPatch) {
         // Re-merge any pending change from workflow tasks
-        final User user = userDAO.save(toBeUpdated);
+        User user = userDAO.save(toBeUpdated);
 
         PropagationByResource propByRes = new PropagationByResource();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
index d0229f9..3509bfe 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
@@ -62,13 +62,13 @@ import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyAbout;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.provisioning.api.DerAttrHandler;
-import org.apache.syncope.core.provisioning.api.IntAttrNameParser;
-import org.apache.syncope.core.provisioning.api.IntAttrNameParser.IntAttrName;
+import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
+import org.apache.syncope.core.provisioning.api.IntAttrName;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
 import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
@@ -153,7 +153,7 @@ public class NotificationManagerImpl implements NotificationManager {
     private EntityFactory entityFactory;
 
     @Autowired
-    private AnyUtilsFactory anyUtilsFactory;
+    private IntAttrNameParser intAttrNameParser;
 
     @Transactional(readOnly = true)
     @Override
@@ -346,14 +346,24 @@ public class NotificationManagerImpl implements NotificationManager {
     private String getRecipientEmail(final String recipientAttrName, final User user) {
         String email = null;
 
-        IntAttrName intAttrName = IntAttrNameParser.parse(recipientAttrName, anyUtilsFactory, AnyTypeKind.USER);
+        IntAttrName intAttrName = intAttrNameParser.parse(recipientAttrName, AnyTypeKind.USER);
 
         if ("username".equals(intAttrName.getField())) {
             email = user.getUsername();
         } else if (intAttrName.getSchemaType() != null) {
+            UMembership membership = null;
+            if (intAttrName.getMembershipOfGroup() != null) {
+                Group group = groupDAO.findByName(intAttrName.getMembershipOfGroup());
+                if (group != null) {
+                    membership = user.getMembership(group.getKey());
+                }
+            }
+
             switch (intAttrName.getSchemaType()) {
                 case PLAIN:
-                    UPlainAttr attr = user.getPlainAttr(recipientAttrName);
+                    UPlainAttr attr = membership == null
+                            ? user.getPlainAttr(recipientAttrName)
+                            : user.getPlainAttr(recipientAttrName, membership);
                     if (attr != null) {
                         email = attr.getValuesAsStrings().isEmpty() ? null : attr.getValuesAsStrings().get(0);
                     }
@@ -364,7 +374,9 @@ public class NotificationManagerImpl implements NotificationManager {
                     if (schema == null) {
                         LOG.warn("Ignoring non existing {} {}", DerSchema.class.getSimpleName(), recipientAttrName);
                     } else {
-                        email = derAttrHander.getValue(user, schema);
+                        email = membership == null
+                                ? derAttrHander.getValue(user, schema)
+                                : derAttrHander.getValue(user, membership, schema);
                     }
                     break;
 
@@ -373,7 +385,9 @@ public class NotificationManagerImpl implements NotificationManager {
                     if (virSchema == null) {
                         LOG.warn("Ignoring non existing {} {}", VirSchema.class.getSimpleName(), recipientAttrName);
                     } else {
-                        List<String> virAttrValues = virAttrHander.getValues(user, virSchema);
+                        List<String> virAttrValues = membership == null
+                                ? virAttrHander.getValues(user, virSchema)
+                                : virAttrHander.getValues(user, membership, virSchema);
                         email = virAttrValues.isEmpty() ? null : virAttrValues.get(0);
                     }
                     break;

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index 9069b7a..a1b5434 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -47,7 +47,6 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecu
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
 import org.apache.syncope.core.provisioning.api.utils.ExceptionUtils2;
-import org.apache.syncope.core.provisioning.java.MappingManagerImpl;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
@@ -63,6 +62,7 @@ import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
 import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
 import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.identityconnectors.framework.common.exceptions.ConnectorException;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
@@ -599,8 +599,8 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
         try {
             obj = connector.getObject(new ObjectClass(task.getObjectClassName()),
                     new Uid(connObjectKey),
-                    MappingManagerImpl.buildOperationOptions(IteratorUtils.chainedIterator(
-                            MappingManagerImpl.getPropagationMappingItems(provision).iterator(),
+                    MappingUtils.buildOperationOptions(IteratorUtils.chainedIterator(
+                            MappingUtils.getPropagationMappingItems(provision).iterator(),
                             linkingMappingItems.iterator())));
 
             for (MappingItem item : linkingMappingItems) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
index 96b37c7..a0007f1 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
@@ -44,7 +44,6 @@ import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
-import org.apache.syncope.core.provisioning.java.MappingManagerImpl;
 import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -59,6 +58,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.MappingManager;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeBuilder;
 import org.identityconnectors.framework.common.objects.AttributeUtil;
@@ -375,7 +375,7 @@ public class PropagationManagerImpl implements PropagationManager {
             Provision provision = resource == null ? null : resource.getProvision(any.getType());
             List<MappingItem> mappingItems = provision == null
                     ? Collections.<MappingItem>emptyList()
-                    : MappingManagerImpl.getPropagationMappingItems(provision);
+                    : MappingUtils.getPropagationMappingItems(provision);
 
             if (resource == null) {
                 LOG.error("Invalid resource name specified: {}, ignoring...", entry.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
index 41edc94..31732fd 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPushResultHandler.java
@@ -37,7 +37,6 @@ import org.apache.syncope.core.persistence.api.entity.task.PushTask;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
 import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
-import org.apache.syncope.core.provisioning.java.MappingManagerImpl;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
@@ -48,6 +47,7 @@ import org.apache.syncope.core.provisioning.api.MappingManager;
 import org.apache.syncope.core.provisioning.api.TimeoutException;
 import org.apache.syncope.core.provisioning.api.pushpull.IgnoreProvisionException;
 import org.apache.syncope.core.provisioning.api.pushpull.SyncopePushResultHandler;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.identityconnectors.framework.common.objects.Uid;
@@ -134,7 +134,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
 
             obj = profile.getConnector().getObject(objectClass,
                     uid,
-                    MappingManagerImpl.buildOperationOptions(IteratorUtils.<MappingItem>emptyIterator()));
+                    MappingUtils.buildOperationOptions(IteratorUtils.<MappingItem>emptyIterator()));
         } catch (TimeoutException toe) {
             LOG.debug("Request timeout", toe);
             throw toe;

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
index 990127a..e5a1c88 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
@@ -22,7 +22,6 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import org.apache.syncope.core.provisioning.java.MappingManagerImpl;
 import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
 import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
@@ -32,6 +31,7 @@ import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
 import org.apache.syncope.core.provisioning.api.pushpull.PullCorrelationRule;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 
 public class PlainAttrsPullCorrelationRule implements PullCorrelationRule {
 
@@ -47,7 +47,7 @@ public class PlainAttrsPullCorrelationRule implements PullCorrelationRule {
     @Override
     public SearchCond getSearchCond(final ConnectorObject connObj) {
         Map<String, MappingItem> mappingItems = new HashMap<>();
-        for (MappingItem item : MappingManagerImpl.getPullMappingItems(provision)) {
+        for (MappingItem item : MappingUtils.getPullMappingItems(provision)) {
             mappingItems.put(item.getIntAttrName(), item);
         }
 
@@ -65,7 +65,7 @@ public class PlainAttrsPullCorrelationRule implements PullCorrelationRule {
             }
 
             List<Object> values = attr.getValue();
-            for (MappingItemTransformer transformer : MappingManagerImpl.getMappingItemTransformers(mappingItem)) {
+            for (MappingItemTransformer transformer : MappingUtils.getMappingItemTransformers(mappingItem)) {
                 values = transformer.beforePull(mappingItem, null, values);
             }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/394f8c98/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
index 4c1b3cb..b5a7dfe 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
@@ -28,7 +28,6 @@ import java.util.Set;
 import org.apache.commons.collections4.IteratorUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.policy.PullPolicySpec;
-import org.apache.syncope.core.provisioning.java.MappingManagerImpl;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
@@ -52,6 +51,7 @@ import org.apache.syncope.core.provisioning.api.pushpull.GroupPullResultHandler;
 import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullExecutor;
 import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandler;
 import org.apache.syncope.core.provisioning.api.pushpull.UserPullResultHandler;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.identityconnectors.framework.common.objects.SyncToken;
 
@@ -157,7 +157,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
         ghandler.setPullExecutor(this);
 
         latestSyncTokens.clear();
-        
+
         if (!profile.isDryRun()) {
             for (PullActions action : actions) {
                 action.beforeAll(profile);
@@ -196,7 +196,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
                                     provision.getObjectClass(),
                                     provision.getSyncToken(),
                                     handler,
-                                    MappingManagerImpl.buildOperationOptions(mapItems));
+                                    MappingUtils.buildOperationOptions(mapItems));
                             if (!dryRun) {
                                 provision.setSyncToken(latestSyncTokens.get(provision.getObjectClass()));
                                 resourceDAO.save(provision.getResource());
@@ -211,14 +211,14 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
                             connector.filteredReconciliation(provision.getObjectClass(),
                                     filterBuilder,
                                     handler,
-                                    MappingManagerImpl.buildOperationOptions(mapItems));
+                                    MappingUtils.buildOperationOptions(mapItems));
                             break;
 
                         case FULL_RECONCILIATION:
                         default:
                             connector.fullReconciliation(provision.getObjectClass(),
                                     handler,
-                                    MappingManagerImpl.buildOperationOptions(mapItems));
+                                    MappingUtils.buildOperationOptions(mapItems));
                             break;
                     }
                 } catch (Throwable t) {