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 2017/07/18 10:22:45 UTC

[02/12] syncope git commit: [SYNCOPE-1164] Realm provisioning now features complete mapping, as Anys

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPullResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPullResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPullResultHandlerImpl.java
index fc711ca..c4be4e2 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPullResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPullResultHandlerImpl.java
@@ -18,14 +18,10 @@
  */
 package org.apache.syncope.core.provisioning.java.pushpull;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-import org.apache.commons.collections4.CollectionUtils;
-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.exception.ExceptionUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.RealmTO;
@@ -47,14 +43,13 @@ import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
 import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
-import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 import org.apache.syncope.core.provisioning.api.pushpull.IgnoreProvisionException;
 import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
 import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
 import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullExecutor;
 import org.apache.syncope.core.provisioning.api.pushpull.SyncopePullResultHandler;
-import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
-import org.identityconnectors.framework.common.objects.Attribute;
+import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
+import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.identityconnectors.framework.common.objects.SyncDelta;
 import org.identityconnectors.framework.common.objects.SyncDeltaType;
 import org.quartz.JobExecutionException;
@@ -67,6 +62,12 @@ public class RealmPullResultHandlerImpl
         implements SyncopePullResultHandler {
 
     @Autowired
+    private PullUtils pullUtils;
+
+    @Autowired
+    private ConnObjectUtils connObjectUtils;
+
+    @Autowired
     private AnySearchDAO searchDAO;
 
     private SyncopePullExecutor executor;
@@ -125,24 +126,32 @@ public class RealmPullResultHandlerImpl
         }
     }
 
-    private ProvisioningReport assign(final SyncDelta delta, final String name) throws JobExecutionException {
+    private List<ProvisioningReport> assign(final SyncDelta delta, final OrgUnit orgUnit) throws JobExecutionException {
         if (!profile.getTask().isPerformCreate()) {
             LOG.debug("PullTask not configured for create");
-            return null;
+            finalize(UnmatchingRule.toEventName(UnmatchingRule.ASSIGN), Result.SUCCESS, null, null, delta);
+            return Collections.<ProvisioningReport>emptyList();
         }
 
-        RealmTO realmTO = new RealmTO();
-        realmTO.setName(name);
+        RealmTO realmTO = connObjectUtils.getRealmTO(delta.getObject(), profile.getTask(), orgUnit);
+        if (realmTO.getFullPath() == null) {
+            if (realmTO.getParent() == null) {
+                realmTO.setParent(profile.getTask().getDestinatioRealm().getFullPath());
+            }
+
+            realmTO.setFullPath(realmTO.getParent() + "/" + realmTO.getName());
+        }
         realmTO.getResources().add(profile.getTask().getResource().getKey());
 
         ProvisioningReport result = new ProvisioningReport();
         result.setOperation(ResourceOperation.CREATE);
         result.setAnyType(REALM_TYPE);
         result.setStatus(ProvisioningReport.Status.SUCCESS);
-        result.setName(profile.getTask().getDestinatioRealm().getFullPath() + "/" + name);
+        result.setName(realmTO.getFullPath());
 
         if (profile.isDryRun()) {
             result.setKey(null);
+            finalize(UnmatchingRule.toEventName(UnmatchingRule.ASSIGN), Result.SUCCESS, null, null, delta);
         } else {
             SyncDelta actionedDelta = delta;
             for (PullActions action : profile.getActions()) {
@@ -152,27 +161,36 @@ public class RealmPullResultHandlerImpl
             create(realmTO, actionedDelta, UnmatchingRule.toEventName(UnmatchingRule.ASSIGN), result);
         }
 
-        return result;
+        return Collections.singletonList(result);
     }
 
-    private ProvisioningReport provision(final SyncDelta delta, final String name) throws JobExecutionException {
+    private List<ProvisioningReport> provision(final SyncDelta delta, final OrgUnit orgUnit)
+            throws JobExecutionException {
+
         if (!profile.getTask().isPerformCreate()) {
             LOG.debug("PullTask not configured for create");
-            return null;
+            finalize(UnmatchingRule.toEventName(UnmatchingRule.PROVISION), Result.SUCCESS, null, null, delta);
+            return Collections.<ProvisioningReport>emptyList();
         }
 
-        RealmTO realmTO = new RealmTO();
-        realmTO.setName(name);
-        realmTO.getResources().add(profile.getTask().getResource().getKey());
+        RealmTO realmTO = connObjectUtils.getRealmTO(delta.getObject(), profile.getTask(), orgUnit);
+        if (realmTO.getFullPath() == null) {
+            if (realmTO.getParent() == null) {
+                realmTO.setParent(profile.getTask().getDestinatioRealm().getFullPath());
+            }
+
+            realmTO.setFullPath(realmTO.getParent() + "/" + realmTO.getName());
+        }
 
         ProvisioningReport result = new ProvisioningReport();
         result.setOperation(ResourceOperation.CREATE);
         result.setAnyType(REALM_TYPE);
         result.setStatus(ProvisioningReport.Status.SUCCESS);
-        result.setName(profile.getTask().getDestinatioRealm().getFullPath() + "/" + name);
+        result.setName(realmTO.getFullPath());
 
         if (profile.isDryRun()) {
             result.setKey(null);
+            finalize(UnmatchingRule.toEventName(UnmatchingRule.PROVISION), Result.SUCCESS, null, null, delta);
         } else {
             SyncDelta actionedDelta = delta;
             for (PullActions action : profile.getActions()) {
@@ -182,7 +200,7 @@ public class RealmPullResultHandlerImpl
             create(realmTO, actionedDelta, UnmatchingRule.toEventName(UnmatchingRule.PROVISION), result);
         }
 
-        return result;
+        return Collections.singletonList(result);
     }
 
     private void throwIgnoreProvisionException(final SyncDelta delta, final Exception exception)
@@ -255,293 +273,378 @@ public class RealmPullResultHandlerImpl
         finalize(operation, resultStatus, null, output, delta);
     }
 
-    private ProvisioningReport update(final SyncDelta delta, final Realm realm, final String name)
+    private List<ProvisioningReport> update(final SyncDelta delta, final List<String> keys)
             throws JobExecutionException {
 
         if (!profile.getTask().isPerformUpdate()) {
             LOG.debug("PullTask not configured for update");
-            return null;
+            finalize(MatchingRule.toEventName(MatchingRule.UPDATE), Result.SUCCESS, null, null, delta);
+            return Collections.<ProvisioningReport>emptyList();
         }
 
-        LOG.debug("About to update {}", realm);
-
-        RealmTO before = binder.getRealmTO(realm, true);
-
-        ProvisioningReport result = new ProvisioningReport();
-        result.setOperation(ResourceOperation.UPDATE);
-        result.setAnyType(REALM_TYPE);
-        result.setStatus(ProvisioningReport.Status.SUCCESS);
-        result.setKey(realm.getKey());
+        LOG.debug("About to update {}", keys);
 
-        Result resultStatus;
-        Object output;
-        if (!profile.isDryRun()) {
-            try {
-                before.setName(name);
+        List<ProvisioningReport> results = new ArrayList<>();
 
-                PropagationByResource propByRes = binder.update(realm, before);
-                Realm updated = realmDAO.save(realm);
+        SyncDelta workingDelta = delta;
+        for (String key : keys) {
+            LOG.debug("About to update {}", key);
 
-                List<PropagationTask> tasks = propagationManager.createTasks(updated, propByRes, null);
-                PropagationReporter propagationReporter = taskExecutor.execute(tasks, false);
+            ProvisioningReport result = new ProvisioningReport();
+            result.setOperation(ResourceOperation.UPDATE);
+            result.setAnyType(REALM_TYPE);
+            result.setStatus(ProvisioningReport.Status.SUCCESS);
+            result.setKey(key);
 
-                output = updated;
-                resultStatus = Result.SUCCESS;
-                result.setName(updated.getFullPath());
+            Realm realm = realmDAO.find(key);
+            RealmTO before = binder.getRealmTO(realm, true);
+            if (before == null) {
+                result.setStatus(ProvisioningReport.Status.FAILURE);
+                result.setMessage(String.format("Realm '%s' not found", key));
+            } else {
+                result.setName(before.getFullPath());
+            }
 
-                LOG.debug("{} successfully updated", updated);
-            } catch (PropagationException e) {
-                // A propagation failure doesn't imply a pull failure.
-                // The propagation exception status will be reported into the propagation task execution.
-                LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
-            } catch (Exception e) {
-                throwIgnoreProvisionException(delta, e);
+            if (!profile.isDryRun()) {
+                Result resultStatus;
+                Object output;
 
-                result.setStatus(ProvisioningReport.Status.FAILURE);
-                result.setMessage(ExceptionUtils.getRootCauseMessage(e));
-                LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
+                if (before == null) {
+                    resultStatus = Result.FAILURE;
+                    output = null;
+                } else {
+                    try {
+                        for (PullActions action : profile.getActions()) {
+                            workingDelta = action.beforeUpdate(profile, workingDelta, before, null);
+                        }
+
+                        PropagationByResource propByRes = binder.update(realm, before);
+                        realm = realmDAO.save(realm);
+                        RealmTO updated = binder.getRealmTO(realm, true);
+
+                        List<PropagationTask> tasks = propagationManager.createTasks(realm, propByRes, null);
+                        taskExecutor.execute(tasks, false);
+
+                        for (PullActions action : profile.getActions()) {
+                            action.after(profile, workingDelta, updated, result);
+                        }
+
+                        output = updated;
+                        resultStatus = Result.SUCCESS;
+                        result.setName(updated.getFullPath());
+
+                        LOG.debug("{} successfully updated", updated);
+                    } catch (PropagationException e) {
+                        // A propagation failure doesn't imply a pull failure.
+                        // The propagation exception status will be reported into the propagation task execution.
+                        LOG.error("Could not propagate Realm {}", workingDelta.getUid().getUidValue(), e);
+                        output = e;
+                        resultStatus = Result.FAILURE;
+                    } catch (Exception e) {
+                        throwIgnoreProvisionException(workingDelta, e);
+
+                        result.setStatus(ProvisioningReport.Status.FAILURE);
+                        result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+                        LOG.error("Could not update Realm {}", workingDelta.getUid().getUidValue(), e);
+                        output = e;
+                        resultStatus = Result.FAILURE;
+                    }
+                }
+                finalize(MatchingRule.toEventName(MatchingRule.UPDATE), resultStatus, before, output, workingDelta);
             }
-            finalize(MatchingRule.toEventName(MatchingRule.UPDATE), resultStatus, before, output, delta);
+            results.add(result);
         }
 
-        return result;
+        return results;
     }
 
-    private ProvisioningReport deprovision(final SyncDelta delta, final Realm realm, final boolean unlink)
+    private List<ProvisioningReport> deprovision(final SyncDelta delta, final List<String> keys, final boolean unlink)
             throws JobExecutionException {
 
         if (!profile.getTask().isPerformUpdate()) {
             LOG.debug("PullTask not configured for update");
-            return null;
+            finalize(unlink
+                    ? MatchingRule.toEventName(MatchingRule.UNASSIGN)
+                    : MatchingRule.toEventName(MatchingRule.DEPROVISION), Result.SUCCESS, null, null, delta);
+            return Collections.<ProvisioningReport>emptyList();
         }
 
-        LOG.debug("About to deprovision {}", realm);
+        LOG.debug("About to deprovision {}", keys);
 
-        ProvisioningReport result = new ProvisioningReport();
-        result.setOperation(ResourceOperation.DELETE);
-        result.setAnyType(REALM_TYPE);
-        result.setStatus(ProvisioningReport.Status.SUCCESS);
-        result.setKey(realm.getKey());
+        final List<ProvisioningReport> results = new ArrayList<>();
 
-        RealmTO before = binder.getRealmTO(realm, true);
+        SyncDelta workingDelta = delta;
+        for (String key : keys) {
+            LOG.debug("About to unassign resource {}", key);
 
-        Object output;
-        Result resultStatus;
-        if (!profile.isDryRun()) {
-            result.setName(realm.getFullPath());
+            ProvisioningReport result = new ProvisioningReport();
+            result.setOperation(ResourceOperation.DELETE);
+            result.setAnyType(REALM_TYPE);
+            result.setStatus(ProvisioningReport.Status.SUCCESS);
+            result.setKey(key);
 
-            try {
-                if (unlink) {
-                    for (PullActions action : profile.getActions()) {
-                        action.beforeUnassign(profile, delta, before);
-                    }
-                } else {
-                    for (PullActions action : profile.getActions()) {
-                        action.beforeDeprovision(profile, delta, before);
-                    }
-                }
+            Realm realm = realmDAO.find(key);
+            RealmTO before = binder.getRealmTO(realm, true);
+            if (before == null) {
+                result.setStatus(ProvisioningReport.Status.FAILURE);
+                result.setMessage(String.format("Realm '%s' not found", key));
+            } else {
+                result.setName(before.getFullPath());
+            }
 
-                PropagationByResource propByRes = new PropagationByResource();
-                propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey());
-                taskExecutor.execute(propagationManager.createTasks(realm, propByRes, null), false);
+            if (!profile.isDryRun()) {
+                Object output;
+                Result resultStatus;
 
-                if (unlink) {
-                    realm.getResources().remove(profile.getTask().getResource());
-                    output = binder.getRealmTO(realmDAO.save(realm), true);
+                if (before == null) {
+                    resultStatus = Result.FAILURE;
+                    output = null;
                 } else {
-                    output = binder.getRealmTO(realm, true);
-                }
-
-                for (PullActions action : profile.getActions()) {
-                    action.after(profile, delta, RealmTO.class.cast(output), result);
+                    try {
+                        if (unlink) {
+                            for (PullActions action : profile.getActions()) {
+                                workingDelta = action.beforeUnassign(profile, workingDelta, before);
+                            }
+                        } else {
+                            for (PullActions action : profile.getActions()) {
+                                workingDelta = action.beforeDeprovision(profile, workingDelta, before);
+                            }
+                        }
+
+                        PropagationByResource propByRes = new PropagationByResource();
+                        propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey());
+                        taskExecutor.execute(propagationManager.createTasks(realm, propByRes, null), false);
+
+                        if (unlink) {
+                            realm.getResources().remove(profile.getTask().getResource());
+                            output = binder.getRealmTO(realmDAO.save(realm), true);
+                        } else {
+                            output = binder.getRealmTO(realm, true);
+                        }
+
+                        for (PullActions action : profile.getActions()) {
+                            action.after(profile, workingDelta, RealmTO.class.cast(output), result);
+                        }
+
+                        resultStatus = Result.SUCCESS;
+
+                        LOG.debug("{} successfully updated", realm);
+                    } catch (PropagationException e) {
+                        // A propagation failure doesn't imply a pull failure.
+                        // The propagation exception status will be reported into the propagation task execution.
+                        LOG.error("Could not propagate Realm {}", workingDelta.getUid().getUidValue(), e);
+                        output = e;
+                        resultStatus = Result.FAILURE;
+                    } catch (Exception e) {
+                        throwIgnoreProvisionException(workingDelta, e);
+
+                        result.setStatus(ProvisioningReport.Status.FAILURE);
+                        result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+                        LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
+                        output = e;
+                        resultStatus = Result.FAILURE;
+                    }
                 }
-
-                resultStatus = Result.SUCCESS;
-
-                LOG.debug("{} successfully updated", realm);
-            } catch (PropagationException e) {
-                // A propagation failure doesn't imply a pull failure.
-                // The propagation exception status will be reported into the propagation task execution.
-                LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
-            } catch (Exception e) {
-                throwIgnoreProvisionException(delta, e);
-
-                result.setStatus(ProvisioningReport.Status.FAILURE);
-                result.setMessage(ExceptionUtils.getRootCauseMessage(e));
-                LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
+                finalize(unlink
+                        ? MatchingRule.toEventName(MatchingRule.UNASSIGN)
+                        : MatchingRule.toEventName(MatchingRule.DEPROVISION), resultStatus, before, output, delta);
             }
-
-            finalize(unlink
-                    ? MatchingRule.toEventName(MatchingRule.UNASSIGN)
-                    : MatchingRule.toEventName(MatchingRule.DEPROVISION), resultStatus, before, output, delta);
+            results.add(result);
         }
 
-        return result;
+        return results;
     }
 
-    private ProvisioningReport link(final SyncDelta delta, final Realm realm, final boolean unlink)
+    private List<ProvisioningReport> link(final SyncDelta delta, final List<String> keys, final boolean unlink)
             throws JobExecutionException {
 
         if (!profile.getTask().isPerformUpdate()) {
             LOG.debug("PullTask not configured for update");
-            return null;
+            finalize(unlink
+                    ? MatchingRule.toEventName(MatchingRule.UNLINK)
+                    : MatchingRule.toEventName(MatchingRule.LINK), Result.SUCCESS, null, null, delta);
+            return Collections.<ProvisioningReport>emptyList();
         }
 
-        LOG.debug("About to link {}", realm);
+        LOG.debug("About to link {}", keys);
 
-        ProvisioningReport result = new ProvisioningReport();
-        result.setOperation(ResourceOperation.NONE);
-        result.setAnyType(REALM_TYPE);
-        result.setStatus(ProvisioningReport.Status.SUCCESS);
-        result.setKey(realm.getKey());
+        final List<ProvisioningReport> results = new ArrayList<>();
 
-        RealmTO before = binder.getRealmTO(realm, true);
+        SyncDelta workingDelta = delta;
+        for (String key : keys) {
+            LOG.debug("About to unassign resource {}", key);
 
-        Object output;
-        Result resultStatus;
-        if (!profile.isDryRun()) {
-            result.setName(realm.getFullPath());
+            ProvisioningReport result = new ProvisioningReport();
+            result.setOperation(ResourceOperation.NONE);
+            result.setAnyType(REALM_TYPE);
+            result.setStatus(ProvisioningReport.Status.SUCCESS);
+            result.setKey(key);
 
-            try {
-                if (unlink) {
-                    for (PullActions action : profile.getActions()) {
-                        action.beforeUnlink(profile, delta, before);
-                    }
-                } else {
-                    for (PullActions action : profile.getActions()) {
-                        action.beforeLink(profile, delta, before);
-                    }
-                }
+            Realm realm = realmDAO.find(key);
+            RealmTO before = binder.getRealmTO(realm, true);
+            if (before == null) {
+                result.setStatus(ProvisioningReport.Status.FAILURE);
+                result.setMessage(String.format("Realm '%s' not found", key));
+            } else {
+                result.setName(before.getFullPath());
+            }
 
-                if (unlink) {
-                    realm.getResources().remove(profile.getTask().getResource());
+            Object output;
+            Result resultStatus;
+            if (!profile.isDryRun()) {
+                if (before == null) {
+                    resultStatus = Result.FAILURE;
+                    output = null;
                 } else {
-                    realm.add(profile.getTask().getResource());
-                }
-                output = update(delta, realm, realm.getName());
-
-                for (PullActions action : profile.getActions()) {
-                    action.after(profile, delta, RealmTO.class.cast(output), result);
+                    try {
+                        if (unlink) {
+                            for (PullActions action : profile.getActions()) {
+                                workingDelta = action.beforeUnlink(profile, workingDelta, before);
+                            }
+                        } else {
+                            for (PullActions action : profile.getActions()) {
+                                workingDelta = action.beforeLink(profile, workingDelta, before);
+                            }
+                        }
+
+                        if (unlink) {
+                            realm.getResources().remove(profile.getTask().getResource());
+                        } else {
+                            realm.add(profile.getTask().getResource());
+                        }
+                        output = update(workingDelta, Collections.singletonList(key));
+
+                        for (PullActions action : profile.getActions()) {
+                            action.after(profile, workingDelta, RealmTO.class.cast(output), result);
+                        }
+
+                        resultStatus = Result.SUCCESS;
+
+                        LOG.debug("{} successfully updated", realm);
+                    } catch (PropagationException e) {
+                        // A propagation failure doesn't imply a pull failure.
+                        // The propagation exception status will be reported into the propagation task execution.
+                        LOG.error("Could not propagate Realm {}", workingDelta.getUid().getUidValue(), e);
+                        output = e;
+                        resultStatus = Result.FAILURE;
+                    } catch (Exception e) {
+                        throwIgnoreProvisionException(workingDelta, e);
+
+                        result.setStatus(ProvisioningReport.Status.FAILURE);
+                        result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+                        LOG.error("Could not update Realm {}", workingDelta.getUid().getUidValue(), e);
+                        output = e;
+                        resultStatus = Result.FAILURE;
+                    }
                 }
-
-                resultStatus = Result.SUCCESS;
-
-                LOG.debug("{} successfully updated", realm);
-            } catch (PropagationException e) {
-                // A propagation failure doesn't imply a pull failure.
-                // The propagation exception status will be reported into the propagation task execution.
-                LOG.error("Could not propagate Realm {}", delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
-            } catch (Exception e) {
-                throwIgnoreProvisionException(delta, e);
-
-                result.setStatus(ProvisioningReport.Status.FAILURE);
-                result.setMessage(ExceptionUtils.getRootCauseMessage(e));
-                LOG.error("Could not update Realm {}", delta.getUid().getUidValue(), e);
-                output = e;
-                resultStatus = Result.FAILURE;
+                finalize(unlink
+                        ? MatchingRule.toEventName(MatchingRule.UNLINK)
+                        : MatchingRule.toEventName(MatchingRule.LINK), resultStatus, before, output, workingDelta);
             }
-
-            finalize(unlink
-                    ? MatchingRule.toEventName(MatchingRule.UNLINK)
-                    : MatchingRule.toEventName(MatchingRule.LINK), resultStatus, before, output, delta);
+            results.add(result);
         }
 
-        return result;
+        return results;
     }
 
-    private ProvisioningReport delete(final SyncDelta delta, final Realm realm)
+    private List<ProvisioningReport> delete(final SyncDelta delta, final List<String> keys)
             throws JobExecutionException {
 
         if (!profile.getTask().isPerformDelete()) {
             LOG.debug("PullTask not configured for delete");
-            return null;
+            finalize(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta);
+            return Collections.<ProvisioningReport>emptyList();
         }
 
-        LOG.debug("About to delete {}", realm);
+        LOG.debug("About to delete {}", keys);
 
-        SyncDelta workingDelta = delta;
-        Object output;
-        Result resultStatus = Result.FAILURE;
+        List<ProvisioningReport> results = new ArrayList<>();
 
-        ProvisioningReport result = new ProvisioningReport();
-
-        try {
-            RealmTO before = binder.getRealmTO(realm, true);
+        SyncDelta workingDelta = delta;
+        for (String key : keys) {
+            Object output;
+            Result resultStatus = Result.FAILURE;
 
-            result.setKey(realm.getKey());
-            result.setName(realm.getFullPath());
-            result.setOperation(ResourceOperation.DELETE);
-            result.setAnyType(REALM_TYPE);
-            result.setStatus(ProvisioningReport.Status.SUCCESS);
+            ProvisioningReport result = new ProvisioningReport();
 
-            if (!profile.isDryRun()) {
-                for (PullActions action : profile.getActions()) {
-                    workingDelta = action.beforeDelete(profile, workingDelta, before);
+            try {
+                result.setKey(key);
+                result.setOperation(ResourceOperation.DELETE);
+                result.setAnyType(REALM_TYPE);
+                result.setStatus(ProvisioningReport.Status.SUCCESS);
+
+                Realm realm = realmDAO.find(key);
+                RealmTO before = binder.getRealmTO(realm, true);
+                if (before == null) {
+                    result.setStatus(ProvisioningReport.Status.FAILURE);
+                    result.setMessage(String.format("Realm '%s' not found", key));
+                } else {
+                    result.setName(before.getFullPath());
                 }
 
-                try {
-                    if (!realmDAO.findChildren(realm).isEmpty()) {
-                        throw SyncopeClientException.build(ClientExceptionType.HasChildren);
-                    }
-
-                    Set<String> adminRealms = Collections.singleton(realm.getFullPath());
-                    AnyCond keyCond = new AnyCond(AttributeCond.Type.ISNOTNULL);
-                    keyCond.setSchema("key");
-                    SearchCond allMatchingCond = SearchCond.getLeafCond(keyCond);
-                    int users = searchDAO.count(adminRealms, allMatchingCond, AnyTypeKind.USER);
-                    int groups = searchDAO.count(adminRealms, allMatchingCond, AnyTypeKind.GROUP);
-                    int anyObjects = searchDAO.count(adminRealms, allMatchingCond, AnyTypeKind.ANY_OBJECT);
-
-                    if (users + groups + anyObjects > 0) {
-                        SyncopeClientException containedAnys = SyncopeClientException.build(
-                                ClientExceptionType.AssociatedAnys);
-                        containedAnys.getElements().add(users + " user(s)");
-                        containedAnys.getElements().add(groups + " group(s)");
-                        containedAnys.getElements().add(anyObjects + " anyObject(s)");
-                        throw containedAnys;
+                if (!profile.isDryRun()) {
+                    for (PullActions action : profile.getActions()) {
+                        workingDelta = action.beforeDelete(profile, workingDelta, before);
                     }
 
-                    PropagationByResource propByRes = new PropagationByResource();
-                    for (String resource : realm.getResourceKeys()) {
-                        propByRes.add(ResourceOperation.DELETE, resource);
+                    try {
+                        if (!realmDAO.findChildren(realm).isEmpty()) {
+                            throw SyncopeClientException.build(ClientExceptionType.HasChildren);
+                        }
+
+                        Set<String> adminRealms = Collections.singleton(realm.getFullPath());
+                        AnyCond keyCond = new AnyCond(AttributeCond.Type.ISNOTNULL);
+                        keyCond.setSchema("key");
+                        SearchCond allMatchingCond = SearchCond.getLeafCond(keyCond);
+                        int users = searchDAO.count(adminRealms, allMatchingCond, AnyTypeKind.USER);
+                        int groups = searchDAO.count(adminRealms, allMatchingCond, AnyTypeKind.GROUP);
+                        int anyObjects = searchDAO.count(adminRealms, allMatchingCond, AnyTypeKind.ANY_OBJECT);
+
+                        if (users + groups + anyObjects > 0) {
+                            SyncopeClientException containedAnys = SyncopeClientException.build(
+                                    ClientExceptionType.AssociatedAnys);
+                            containedAnys.getElements().add(users + " user(s)");
+                            containedAnys.getElements().add(groups + " group(s)");
+                            containedAnys.getElements().add(anyObjects + " anyObject(s)");
+                            throw containedAnys;
+                        }
+
+                        PropagationByResource propByRes = new PropagationByResource();
+                        for (String resource : realm.getResourceKeys()) {
+                            propByRes.add(ResourceOperation.DELETE, resource);
+                        }
+                        List<PropagationTask> tasks = propagationManager.createTasks(realm, propByRes, null);
+                        taskExecutor.execute(tasks, false);
+
+                        realmDAO.delete(realm);
+
+                        output = null;
+                        resultStatus = Result.SUCCESS;
+
+                        for (PullActions action : profile.getActions()) {
+                            action.after(profile, workingDelta, before, result);
+                        }
+                    } catch (Exception e) {
+                        throwIgnoreProvisionException(workingDelta, e);
+
+                        result.setStatus(ProvisioningReport.Status.FAILURE);
+                        result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+                        LOG.error("Could not delete {}", realm, e);
+                        output = e;
                     }
-                    List<PropagationTask> tasks = propagationManager.createTasks(realm, propByRes, null);
-                    PropagationReporter propagationReporter = taskExecutor.execute(tasks, false);
-
-                    realmDAO.delete(realm);
 
-                    output = null;
-                    resultStatus = Result.SUCCESS;
-
-                    for (PullActions action : profile.getActions()) {
-                        action.after(profile, workingDelta, before, result);
-                    }
-                } catch (Exception e) {
-                    throwIgnoreProvisionException(delta, e);
-
-                    result.setStatus(ProvisioningReport.Status.FAILURE);
-                    result.setMessage(ExceptionUtils.getRootCauseMessage(e));
-                    LOG.error("Could not delete {}", realm, e);
-                    output = e;
+                    finalize(ResourceOperation.DELETE.name().toLowerCase(), resultStatus, before, output, workingDelta);
                 }
 
-                finalize(ResourceOperation.DELETE.name().toLowerCase(), resultStatus, before, output, workingDelta);
+                results.add(result);
+            } catch (DelegatedAdministrationException e) {
+                LOG.error("Not allowed to read Realm {}", key, e);
+            } catch (Exception e) {
+                LOG.error("Could not delete Realm {}", key, e);
             }
-        } catch (Exception e) {
-            LOG.error("Could not delete {}", realm, e);
         }
 
-        return result;
+        return results;
     }
 
     private ProvisioningReport ignore(
@@ -572,43 +675,46 @@ public class RealmPullResultHandlerImpl
         LOG.debug("Process {} for {} as {}",
                 delta.getDeltaType(), delta.getUid().getUidValue(), delta.getObject().getObjectClass());
 
-        Realm realm = IterableUtils.find(realmDAO.findAll(), new Predicate<Realm>() {
+        String uid = delta.getPreviousUid() == null
+                ? delta.getUid().getUidValue()
+                : delta.getPreviousUid().getUidValue();
 
-            @Override
-            public boolean evaluate(final Realm realm) {
-                JexlContext jexlContext = new MapContext();
-                JexlUtils.addFieldsToContext(realm, jexlContext);
-                String evalConnObjectLink = JexlUtils.evaluate(orgUnit.getConnObjectLink(), jexlContext);
-
-                return delta.getObject().getName().getNameValue().equals(evalConnObjectLink);
-            }
-        });
+        List<String> keys = pullUtils.findExisting(uid, delta.getObject(), orgUnit);
         LOG.debug("Match found for {} as {}: {}",
-                delta.getObject().getName().getNameValue(), delta.getObject().getObjectClass(), realm);
+                delta.getUid().getUidValue(), delta.getObject().getObjectClass(), keys);
 
-        String realmName = delta.getUid().getUidValue();
-        Attribute nameAttr = delta.getObject().getAttributeByName(orgUnit.getExtAttrName());
-        if (nameAttr != null && nameAttr.getValue() != null && !nameAttr.getValue().isEmpty()) {
-            realmName = nameAttr.getValue().get(0).toString();
+        if (keys.size() > 1) {
+            switch (profile.getResAct()) {
+                case IGNORE:
+                    throw new IllegalStateException("More than one match " + keys);
+
+                case FIRSTMATCH:
+                    keys = keys.subList(0, 1);
+                    break;
+
+                case LASTMATCH:
+                    keys = keys.subList(keys.size() - 1, keys.size());
+                    break;
+
+                default:
+                // keep keys unmodified
+                }
         }
 
         try {
             if (SyncDeltaType.CREATE_OR_UPDATE == delta.getDeltaType()) {
-                if (realm == null) {
+                if (keys.isEmpty()) {
                     switch (profile.getTask().getUnmatchingRule()) {
                         case ASSIGN:
-                            CollectionUtils.addIgnoreNull(
-                                    profile.getResults(), assign(delta, realmName));
+                            profile.getResults().addAll(assign(delta, orgUnit));
                             break;
 
                         case PROVISION:
-                            CollectionUtils.addIgnoreNull(
-                                    profile.getResults(), provision(delta, realmName));
+                            profile.getResults().addAll(provision(delta, orgUnit));
                             break;
 
                         case IGNORE:
-                            CollectionUtils.addIgnoreNull(
-                                    profile.getResults(), ignore(delta, false));
+                            profile.getResults().add(ignore(delta, false));
                             break;
 
                         default:
@@ -617,32 +723,27 @@ public class RealmPullResultHandlerImpl
                 } else {
                     switch (profile.getTask().getMatchingRule()) {
                         case UPDATE:
-                            CollectionUtils.addIgnoreNull(
-                                    profile.getResults(), update(delta, realm, realmName));
+                            profile.getResults().addAll(update(delta, keys));
                             break;
 
                         case DEPROVISION:
-                            CollectionUtils.addIgnoreNull(
-                                    profile.getResults(), deprovision(delta, realm, false));
+                            profile.getResults().addAll(deprovision(delta, keys, false));
                             break;
 
                         case UNASSIGN:
-                            CollectionUtils.addIgnoreNull(
-                                    profile.getResults(), deprovision(delta, realm, true));
+                            profile.getResults().addAll(deprovision(delta, keys, true));
                             break;
 
                         case LINK:
-                            CollectionUtils.addIgnoreNull(
-                                    profile.getResults(), link(delta, realm, false));
+                            profile.getResults().addAll(link(delta, keys, false));
                             break;
 
                         case UNLINK:
-                            CollectionUtils.addIgnoreNull(
-                                    profile.getResults(), link(delta, realm, true));
+                            profile.getResults().addAll(link(delta, keys, true));
                             break;
 
                         case IGNORE:
-                            CollectionUtils.addIgnoreNull(profile.getResults(), ignore(delta, true));
+                            profile.getResults().add(ignore(delta, true));
                             break;
 
                         default:
@@ -650,10 +751,11 @@ public class RealmPullResultHandlerImpl
                     }
                 }
             } else if (SyncDeltaType.DELETE == delta.getDeltaType()) {
-                if (realm == null) {
+                if (keys.isEmpty()) {
+                    finalize(ResourceOperation.DELETE.name().toLowerCase(), Result.SUCCESS, null, null, delta);
                     LOG.debug("No match found for deletion");
                 } else {
-                    CollectionUtils.addIgnoreNull(profile.getResults(), delete(delta, realm));
+                    profile.getResults().addAll(delete(delta, keys));
                 }
             }
         } catch (IllegalStateException | IllegalArgumentException e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPushResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPushResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPushResultHandlerImpl.java
index f028b38..104276e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPushResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPushResultHandlerImpl.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.apache.commons.collections4.IteratorUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.common.lib.types.AuditElements;
@@ -32,9 +33,10 @@ import org.apache.syncope.core.provisioning.api.PropagationByResource;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.common.lib.types.UnmatchingRule;
 import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
 import org.apache.syncope.core.persistence.api.entity.task.PushTask;
-import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.MappingManager;
 import org.apache.syncope.core.provisioning.api.TimeoutException;
 import org.apache.syncope.core.provisioning.api.event.AfterHandlingEvent;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
@@ -44,10 +46,9 @@ import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
 import org.apache.syncope.core.provisioning.api.pushpull.SyncopePushResultHandler;
 import org.apache.syncope.core.provisioning.java.job.AfterHandlingJob;
 import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.identityconnectors.framework.common.objects.AttributeBuilder;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.identityconnectors.framework.common.objects.ResultsHandler;
-import org.identityconnectors.framework.common.objects.filter.EqualsFilter;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.identityconnectors.framework.common.objects.Uid;
 import org.quartz.JobExecutionException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@@ -59,7 +60,10 @@ public class RealmPushResultHandlerImpl
         implements SyncopePushResultHandler {
 
     @Autowired
-    protected SchedulerFactoryBean scheduler;
+    private MappingManager mappingManager;
+
+    @Autowired
+    private SchedulerFactoryBean scheduler;
 
     @Transactional(propagation = Propagation.REQUIRES_NEW)
     @Override
@@ -153,39 +157,22 @@ public class RealmPushResultHandlerImpl
         provision(update(realmTO, result), result);
     }
 
-    /**
-     * Get remote object for given realm .
-     *
-     * @param connector connector facade proxy.
-     * @param task current propagation task.
-     * @param orgUnit orgUnit
-     * @return remote connector object.
-     */
-    private ConnectorObject getRemoteObject(
-            final String realmName,
-            final Connector connector,
-            final OrgUnit orgUnit) {
-
-        final ConnectorObject[] obj = new ConnectorObject[1];
+    protected ConnectorObject getRemoteObject(final String connObjectKey, final ObjectClass objectClass) {
+        ConnectorObject obj = null;
         try {
-            connector.search(orgUnit.getObjectClass(),
-                    new EqualsFilter(AttributeBuilder.build(orgUnit.getExtAttrName(), realmName)),
-                    new ResultsHandler() {
-
-                @Override
-                public boolean handle(final ConnectorObject connectorObject) {
-                    obj[0] = connectorObject;
-                    return false;
-                }
-            }, MappingUtils.buildOperationOptions(orgUnit));
+            Uid uid = new Uid(connObjectKey);
+
+            obj = profile.getConnector().getObject(objectClass,
+                    uid,
+                    MappingUtils.buildOperationOptions(IteratorUtils.<MappingItem>emptyIterator()));
         } catch (TimeoutException toe) {
             LOG.debug("Request timeout", toe);
             throw toe;
         } catch (RuntimeException ignore) {
-            LOG.debug("While resolving {}", realmName, ignore);
+            LOG.debug("While resolving {}", connObjectKey, ignore);
         }
 
-        return obj[0];
+        return obj;
     }
 
     private void doHandle(final Realm realm) throws JobExecutionException {
@@ -202,10 +189,10 @@ public class RealmPushResultHandlerImpl
         Result resultStatus = null;
 
         // Try to read remote object BEFORE any actual operation
-        ConnectorObject beforeObj = getRemoteObject(
-                realm.getName(),
-                profile.getConnector(),
-                profile.getTask().getResource().getOrgUnit());
+        OrgUnit orgUnit = profile.getTask().getResource().getOrgUnit();
+        String connObjecKey = mappingManager.getConnObjectKeyValue(realm, orgUnit);
+
+        ConnectorObject beforeObj = getRemoteObject(connObjecKey, orgUnit.getObjectClass());
 
         if (profile.isDryRun()) {
             if (beforeObj == null) {
@@ -375,10 +362,7 @@ public class RealmPushResultHandlerImpl
                     result.setStatus(ProvisioningReport.Status.SUCCESS);
                 }
                 resultStatus = AuditElements.Result.SUCCESS;
-                output = getRemoteObject(
-                        realm.getName(),
-                        profile.getConnector(),
-                        profile.getTask().getResource().getOrgUnit());
+                output = getRemoteObject(connObjecKey, orgUnit.getObjectClass());
             } catch (IgnoreProvisionException e) {
                 throw e;
             } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index be35d61..249e488 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -29,6 +29,7 @@ import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -41,6 +42,8 @@ import org.apache.syncope.core.spring.security.PasswordGenerator;
 import org.apache.syncope.core.spring.security.SecureRandomUtils;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
+import org.apache.syncope.core.persistence.api.entity.resource.OrgUnitItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
 import org.apache.syncope.core.provisioning.api.MappingManager;
@@ -159,6 +162,16 @@ public class ConnObjectUtils {
         return anyTO;
     }
 
+    public RealmTO getRealmTO(final ConnectorObject obj, final PullTask task, final OrgUnit orgUnit) {
+        RealmTO realmTO = new RealmTO();
+
+        for (OrgUnitItem item : MappingUtils.getPullItems(orgUnit)) {
+            mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), realmTO);
+        }
+
+        return realmTO;
+    }
+
     /**
      * Build {@link AnyPatch} out of connector object attributes and schema mapping.
      *
@@ -255,7 +268,7 @@ public class ConnObjectUtils {
 
         // 1. fill with data from connector object
         anyTO.setRealm(pullTask.getDestinatioRealm().getFullPath());
-        for (MappingItem item : MappingUtils.getPullMappingItems(provision)) {
+        for (MappingItem item : MappingUtils.getPullItems(provision)) {
             mappingManager.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), anyTO, anyUtils);
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
index e719a38..2c71f37 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
@@ -19,25 +19,27 @@
 package org.apache.syncope.core.provisioning.java.utils;
 
 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.collections4.Predicate;
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.MapContext;
 import org.apache.commons.lang3.ClassUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.resource.Item;
 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.OrgUnit;
+import org.apache.syncope.core.persistence.api.entity.resource.OrgUnitItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.provisioning.api.data.JEXLMappingItemTransformer;
-import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
-import org.apache.syncope.core.provisioning.java.data.JEXLMappingItemTransformerImpl;
+import org.apache.syncope.core.provisioning.java.data.JEXLItemTransformerImpl;
 import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.identityconnectors.framework.common.objects.Name;
@@ -48,6 +50,8 @@ import org.identityconnectors.framework.common.objects.Uid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
+import org.apache.syncope.core.provisioning.api.data.JEXLItemTransformer;
 
 public final class MappingUtils {
 
@@ -64,67 +68,68 @@ public final class MappingUtils {
                 : 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();
-        }
+    public static List<? extends MappingItem> getPropagationItems(final Provision provision) {
+        return ListUtils.select(provision.getMapping().getItems(), new Predicate<MappingItem>() {
 
-        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:
-        }
+            @Override
+            public boolean evaluate(final MappingItem item) {
+                return item.getPurpose() == MappingPurpose.PROPAGATION || item.getPurpose() == MappingPurpose.BOTH;
+            }
+        });
+    }
 
-        return result;
+    public static List<? extends MappingItem> getPullItems(final Provision provision) {
+        return ListUtils.select(provision.getMapping().getItems(), new Predicate<MappingItem>() {
+
+            @Override
+            public boolean evaluate(final MappingItem item) {
+                return item.getPurpose() == MappingPurpose.PULL || item.getPurpose() == MappingPurpose.BOTH;
+            }
+        });
     }
 
-    public static List<MappingItem> getPropagationMappingItems(final Provision provision) {
-        return getMappingItems(provision, MappingPurpose.PROPAGATION);
+    public static List<? extends OrgUnitItem> getPropagationItems(final OrgUnit orgUnit) {
+        return ListUtils.select(orgUnit.getItems(), new Predicate<OrgUnitItem>() {
+
+            @Override
+            public boolean evaluate(final OrgUnitItem item) {
+                return item.getPurpose() == MappingPurpose.PROPAGATION || item.getPurpose() == MappingPurpose.BOTH;
+            }
+        });
     }
 
-    public static List<MappingItem> getPullMappingItems(final Provision provision) {
-        return getMappingItems(provision, MappingPurpose.PULL);
+    public static List<? extends OrgUnitItem> getPullItems(final OrgUnit orgUnit) {
+        return ListUtils.select(orgUnit.getItems(), new Predicate<OrgUnitItem>() {
+
+            @Override
+            public boolean evaluate(final OrgUnitItem item) {
+                return item.getPurpose() == MappingPurpose.PULL || item.getPurpose() == MappingPurpose.BOTH;
+            }
+        });
+    }
+
+    private static Name evaluateNAME(final String evalConnObjectLink, final String connObjectKey) {
+        // 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;
     }
 
     /**
-     * Build __NAME__ for propagation. First look if there ia a defined connObjectLink for the given resource (and in
+     * Build __NAME__ for propagation.
+     * First look if there is a defined connObjectLink for the given resource (and in
      * this case evaluate as JEXL); otherwise, take given connObjectKey.
      *
      * @param any given any object
@@ -151,36 +156,51 @@ public final class MappingUtils {
             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);
+        return evaluateNAME(evalConnObjectLink, connObjectKey);
+    }
 
-            // connObjectKey not propagated: it will be used to set the value for __UID__ attribute
-            LOG.debug("connObjectKey will be used just as __UID__ attribute");
+    /**
+     * Build __NAME__ for propagation.
+     * First look if there is a defined connObjectLink for the given resource (and in
+     * this case evaluate as JEXL); otherwise, take given connObjectKey.
+     *
+     * @param realm given any object
+     * @param orgUnit external resource
+     * @param connObjectKey connector object key
+     * @return the value to be propagated as __NAME__
+     */
+    public static Name evaluateNAME(final Realm realm, final OrgUnit orgUnit, 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 '{}': ", orgUnit.getResource());
         }
 
-        return name;
+        // Evaluate connObjectKey expression
+        String connObjectLink = orgUnit == null
+                ? null
+                : orgUnit.getConnObjectLink();
+        String evalConnObjectLink = null;
+        if (StringUtils.isNotBlank(connObjectLink)) {
+            JexlContext jexlContext = new MapContext();
+            JexlUtils.addFieldsToContext(realm, jexlContext);
+            evalConnObjectLink = JexlUtils.evaluate(connObjectLink, jexlContext);
+        }
+
+        return evaluateNAME(evalConnObjectLink, connObjectKey);
     }
 
-    private static List<MappingItemTransformer> getMappingItemTransformers(
+    private static List<ItemTransformer> getMappingItemTransformers(
             final String propagationJEXLTransformer,
             final String pullJEXLTransformer,
             final List<String> mappingItemTransformerClassNames) {
 
-        List<MappingItemTransformer> result = new ArrayList<>();
+        List<ItemTransformer> result = new ArrayList<>();
 
         // First consider the JEXL transformation expressions
         if (StringUtils.isNotBlank(propagationJEXLTransformer) || StringUtils.isNotBlank(pullJEXLTransformer)) {
-            JEXLMappingItemTransformer jexlTransformer =
-                    (JEXLMappingItemTransformer) ApplicationContextProvider.getBeanFactory().
-                            createBean(JEXLMappingItemTransformerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME,
+            JEXLItemTransformer jexlTransformer =
+                    (JEXLItemTransformer) ApplicationContextProvider.getBeanFactory().
+                            createBean(JEXLItemTransformerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME,
                                     false);
 
             jexlTransformer.setPropagationJEXL(propagationJEXLTransformer);
@@ -193,7 +213,7 @@ public final class MappingUtils {
             try {
                 Class<?> transformerClass = ClassUtils.getClass(className);
 
-                result.add((MappingItemTransformer) ApplicationContextProvider.getBeanFactory().
+                result.add((ItemTransformer) ApplicationContextProvider.getBeanFactory().
                         createBean(transformerClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false));
             } catch (Exception e) {
                 LOG.error("Could not instantiate {}, ignoring...", className, e);
@@ -203,28 +223,28 @@ public final class MappingUtils {
         return result;
     }
 
-    public static List<MappingItemTransformer> getMappingItemTransformers(final MappingItemTO mappingItem) {
+    public static List<ItemTransformer> getItemTransformers(final ItemTO item) {
         return getMappingItemTransformers(
-                mappingItem.getPropagationJEXLTransformer(),
-                mappingItem.getPullJEXLTransformer(),
-                mappingItem.getMappingItemTransformerClassNames());
+                item.getPropagationJEXLTransformer(),
+                item.getPullJEXLTransformer(),
+                item.getTransformerClassNames());
     }
 
-    public static List<MappingItemTransformer> getMappingItemTransformers(final MappingItem mappingItem) {
+    public static List<ItemTransformer> getItemTransformers(final Item item) {
         return getMappingItemTransformers(
-                mappingItem.getPropagationJEXLTransformer(),
-                mappingItem.getPullJEXLTransformer(),
-                mappingItem.getMappingItemTransformerClassNames());
+                item.getPropagationJEXLTransformer(),
+                item.getPullJEXLTransformer(),
+                item.getTransformerClassNames());
     }
 
     /**
      * Build options for requesting all mapped connector attributes.
      *
-     * @param mapItems mapping items
+     * @param iterator items
      * @return options for requesting all mapped connector attributes
      * @see OperationOptions
      */
-    public static OperationOptions buildOperationOptions(final Iterator<? extends MappingItem> mapItems) {
+    public static OperationOptions buildOperationOptions(final Iterator<? extends Item> iterator) {
         OperationOptionsBuilder builder = new OperationOptionsBuilder();
 
         Set<String> attrsToGet = new HashSet<>();
@@ -232,10 +252,10 @@ public final class MappingUtils {
         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());
+        while (iterator.hasNext()) {
+            Item item = iterator.next();
+            if (item.getPurpose() != MappingPurpose.NONE) {
+                attrsToGet.add(item.getExtAttrName());
             }
         }
 
@@ -246,17 +266,6 @@ public final class MappingUtils {
     }
 
     /**
-     * Build options for requesting connector attributes for the given orgUnit.
-     *
-     * @param orgUnit orgUnit
-     * @return options for requesting connector attributes for the given orgUnit
-     * @see OperationOptions
-     */
-    public static OperationOptions buildOperationOptions(final OrgUnit orgUnit) {
-        return new OperationOptionsBuilder().setAttributesToGet(Name.NAME, Uid.NAME, orgUnit.getExtAttrName()).build();
-    }
-
-    /**
      * Private default constructor, for static-only classes.
      */
     private MappingUtils() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/ResourceDataBinderTest.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/ResourceDataBinderTest.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/ResourceDataBinderTest.java
index 714dcff..bc7329a 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/ResourceDataBinderTest.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/ResourceDataBinderTest.java
@@ -28,7 +28,7 @@ import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.to.MappingTO;
 import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
@@ -122,7 +122,7 @@ public class ResourceDataBinderTest extends AbstractTest {
         MappingTO mapping = new MappingTO();
         provisionTO.setMapping(mapping);
 
-        MappingItemTO item = new MappingItemTO();
+        ItemTO item = new ItemTO();
         item.setIntAttrName("userId");
         item.setExtAttrName("campo1");
         item.setConnObjectKey(true);

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
index 2597f42..8ea1671 100644
--- a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
+++ b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPMappingPanel.java
@@ -23,9 +23,9 @@ import java.util.Collections;
 import java.util.List;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
-import org.apache.syncope.client.console.wizards.resources.MappingItemTransformersTogglePanel;
+import org.apache.syncope.client.console.wizards.resources.ItemTransformersTogglePanel;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.to.SAML2IdPTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.MappingPurpose;
@@ -40,13 +40,13 @@ public class SAML2IdPMappingPanel extends AbstractMappingPanel {
     public SAML2IdPMappingPanel(
             final String id,
             final SAML2IdPTO idpTO,
-            final MappingItemTransformersTogglePanel mapItemTransformers,
+            final ItemTransformersTogglePanel mapItemTransformers,
             final JEXLTransformersTogglePanel jexlTransformers) {
 
         super(id,
                 mapItemTransformers,
                 jexlTransformers,
-                new ListModel<MappingItemTO>(idpTO.getMappingItems()),
+                new ListModel<ItemTO>(idpTO.getMappingItems()),
                 true,
                 true,
                 MappingPurpose.NONE);

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPWizardBuilder.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPWizardBuilder.java b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPWizardBuilder.java
index d824807..aa9ea0f 100644
--- a/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPWizardBuilder.java
+++ b/ext/saml2sp/client-console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPWizardBuilder.java
@@ -32,8 +32,8 @@ import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownCho
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel;
 import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
-import org.apache.syncope.client.console.wizards.resources.MappingItemTransformersTogglePanel;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.client.console.wizards.resources.ItemTransformersTogglePanel;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.to.SAML2IdPTO;
 import org.apache.syncope.common.lib.types.SAML2BindingType;
 import org.apache.wicket.Component;
@@ -68,8 +68,8 @@ public class SAML2IdPWizardBuilder extends AjaxWizardBuilder<SAML2IdPTO> {
         Mapping mapping = new Mapping(modelObject);
         mapping.setOutputMarkupId(true);
 
-        MappingItemTransformersTogglePanel mapItemTransformers =
-                new MappingItemTransformersTogglePanel(mapping, pageRef);
+        ItemTransformersTogglePanel mapItemTransformers =
+                new ItemTransformersTogglePanel(mapping, pageRef);
         addOuterObject(mapItemTransformers);
         JEXLTransformersTogglePanel jexlTransformers = new JEXLTransformersTogglePanel(mapping, pageRef);
         addOuterObject(jexlTransformers);
@@ -133,10 +133,10 @@ public class SAML2IdPWizardBuilder extends AjaxWizardBuilder<SAML2IdPTO> {
     @Override
     protected Serializable onApplyInternal(final SAML2IdPTO modelObject) {
         long connObjectKeyCount = IterableUtils.countMatches(
-                modelObject.getMappingItems(), new Predicate<MappingItemTO>() {
+                modelObject.getMappingItems(), new Predicate<ItemTO>() {
 
             @Override
-            public boolean evaluate(final MappingItemTO item) {
+            public boolean evaluate(final ItemTO item) {
                 return item.isConnObjectKey();
             }
         });

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
index 109af15..089908e 100644
--- a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
+++ b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
@@ -51,7 +51,7 @@ public class SAML2IdPTO extends AbstractBaseBean implements EntityTO {
 
     private boolean logoutSupported;
 
-    private final List<MappingItemTO> mappingItems = new ArrayList<>();
+    private final List<ItemTO> mappingItems = new ArrayList<>();
 
     @Override
     public String getKey() {
@@ -112,24 +112,24 @@ public class SAML2IdPTO extends AbstractBaseBean implements EntityTO {
         this.logoutSupported = logoutSupported;
     }
 
-    public MappingItemTO getConnObjectKeyItem() {
-        return IterableUtils.find(getMappingItems(), new Predicate<MappingItemTO>() {
+    public ItemTO getConnObjectKeyItem() {
+        return IterableUtils.find(getMappingItems(), new Predicate<ItemTO>() {
 
             @Override
-            public boolean evaluate(final MappingItemTO item) {
+            public boolean evaluate(final ItemTO item) {
                 return item.isConnObjectKey();
             }
         });
     }
 
-    protected boolean addConnObjectKeyItem(final MappingItemTO connObjectItem) {
+    protected boolean addConnObjectKeyItem(final ItemTO connObjectItem) {
         connObjectItem.setMandatoryCondition("true");
         connObjectItem.setConnObjectKey(true);
 
         return this.add(connObjectItem);
     }
 
-    public boolean setConnObjectKeyItem(final MappingItemTO connObjectKeyItem) {
+    public boolean setConnObjectKeyItem(final ItemTO connObjectKeyItem) {
         return connObjectKeyItem == null
                 ? remove(getConnObjectKeyItem())
                 : addConnObjectKeyItem(connObjectKeyItem);
@@ -138,15 +138,15 @@ public class SAML2IdPTO extends AbstractBaseBean implements EntityTO {
     @XmlElementWrapper(name = "mappingItems")
     @XmlElement(name = "mappingItem")
     @JsonProperty("mappingItems")
-    public List<MappingItemTO> getMappingItems() {
+    public List<ItemTO> getMappingItems() {
         return mappingItems;
     }
 
-    public boolean add(final MappingItemTO item) {
+    public boolean add(final ItemTO item) {
         return item == null ? false : this.mappingItems.contains(item) || this.mappingItems.add(item);
     }
 
-    public boolean remove(final MappingItemTO item) {
+    public boolean remove(final ItemTO item) {
         return this.mappingItems.remove(item);
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
index 95094e9..bb26b34 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2IdPLogic.java
@@ -30,7 +30,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.to.SAML2IdPTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.SAML2BindingType;
@@ -154,7 +154,7 @@ public class SAML2IdPLogic extends AbstractSAML2Logic<SAML2IdPTO> {
                 idpTO.setMetadata(Base64.encodeBase64String(baos.toByteArray()));
             }
 
-            MappingItemTO connObjectKeyItem = new MappingItemTO();
+            ItemTO connObjectKeyItem = new ItemTO();
             connObjectKeyItem.setIntAttrName("username");
             connObjectKeyItem.setExtAttrName("NameID");
             idpTO.setConnObjectKeyItem(connObjectKeyItem);

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
index 91e9ff0..59d6c2c 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/SAML2SPLogic.java
@@ -43,7 +43,7 @@ import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.SAML2RequestTO;
 import org.apache.syncope.common.lib.to.SAML2LoginResponseTO;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.to.SAML2ReceivedResponseTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
@@ -66,7 +66,6 @@ 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.IntAttrName;
 import org.apache.syncope.core.provisioning.api.data.AccessTokenDataBinder;
-import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
 import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
 import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
 import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
@@ -119,6 +118,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.stereotype.Component;
+import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
 
 @Component
 public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
@@ -340,11 +340,11 @@ public class SAML2SPLogic extends AbstractSAML2Logic<AbstractBaseBean> {
         return requestTO;
     }
 
-    private List<String> findMatchingUser(final String keyValue, final MappingItemTO connObjectKeyItem) {
+    private List<String> findMatchingUser(final String keyValue, final ItemTO connObjectKeyItem) {
         List<String> result = new ArrayList<>();
 
         String transformed = keyValue;
-        for (MappingItemTransformer transformer : MappingUtils.getMappingItemTransformers(connObjectKeyItem)) {
+        for (ItemTransformer transformer : MappingUtils.getItemTransformers(connObjectKeyItem)) {
             List<Object> output = transformer.beforePull(
                     null,
                     null,

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPCache.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPCache.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPCache.java
index a5ab6c3..ed244d0 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPCache.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPCache.java
@@ -28,7 +28,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import net.shibboleth.utilities.java.support.xml.XMLParserException;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.types.SAML2BindingType;
 import org.apache.syncope.core.logic.init.SAML2SPLoader;
 import org.apache.syncope.core.persistence.api.entity.SAML2IdP;
@@ -66,7 +66,7 @@ public class SAML2IdPCache {
 
     public SAML2IdPEntity put(
             final EntityDescriptor entityDescriptor,
-            final MappingItemTO connObjectKeyItem,
+            final ItemTO connObjectKeyItem,
             final boolean useDeflateEncoding,
             final SAML2BindingType bindingType)
             throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException {

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPEntity.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPEntity.java b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPEntity.java
index dd07cdd..b747c32 100644
--- a/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPEntity.java
+++ b/ext/saml2sp/logic/src/main/java/org/apache/syncope/core/logic/saml2/SAML2IdPEntity.java
@@ -31,7 +31,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.apache.commons.codec.binary.Base64;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.types.SAML2BindingType;
 import org.opensaml.saml.common.xml.SAMLConstants;
 import org.opensaml.saml.saml2.metadata.Endpoint;
@@ -55,7 +55,7 @@ public class SAML2IdPEntity {
 
     private SAML2BindingType bindingType;
 
-    private MappingItemTO connObjectKeyItem;
+    private ItemTO connObjectKeyItem;
 
     private final Map<String, Endpoint> ssoBindings = new HashMap<>();
 
@@ -67,7 +67,7 @@ public class SAML2IdPEntity {
 
     public SAML2IdPEntity(
             final EntityDescriptor entityDescriptor,
-            final MappingItemTO connObjectKeyItem,
+            final ItemTO connObjectKeyItem,
             final boolean useDeflateEncoding,
             final SAML2BindingType bindingType,
             final String keyPass)
@@ -141,11 +141,11 @@ public class SAML2IdPEntity {
         this.bindingType = bindingType;
     }
 
-    public MappingItemTO getConnObjectKeyItem() {
+    public ItemTO getConnObjectKeyItem() {
         return connObjectKeyItem;
     }
 
-    public void setConnObjectKeyItem(final MappingItemTO connObjectKeyItem) {
+    public void setConnObjectKeyItem(final ItemTO connObjectKeyItem) {
         this.connObjectKeyItem = connObjectKeyItem;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/SAML2IdPValidator.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/SAML2IdPValidator.java b/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/SAML2IdPValidator.java
index 9869500..3e80bed 100644
--- a/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/SAML2IdPValidator.java
+++ b/ext/saml2sp/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/SAML2IdPValidator.java
@@ -24,7 +24,7 @@ import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.common.lib.types.EntityViolationType;
 import org.apache.syncope.core.persistence.api.entity.SAML2IdP;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
-import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
+import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
 
 public class SAML2IdPValidator extends AbstractValidator<SAML2IdPCheck, SAML2IdP> {
 
@@ -61,12 +61,12 @@ public class SAML2IdPValidator extends AbstractValidator<SAML2IdPCheck, SAML2IdP
         }
 
         for (MappingItem item : value.getMappingItems()) {
-            for (String className : item.getMappingItemTransformerClassNames()) {
+            for (String className : item.getTransformerClassNames()) {
                 Class<?> actionsClass = null;
                 boolean isAssignable = false;
                 try {
                     actionsClass = Class.forName(className);
-                    isAssignable = MappingItemTransformer.class.isAssignableFrom(actionsClass);
+                    isAssignable = ItemTransformer.class.isAssignableFrom(actionsClass);
                 } catch (Exception e) {
                     LOG.error("Invalid MappingItemTransformer specified: {}", className, e);
                 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/e21971bf/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
index 5eba217..f9f16ab 100644
--- a/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
+++ b/ext/saml2sp/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/SAML2IdPDataBinderImpl.java
@@ -22,7 +22,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
-import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.to.SAML2IdPTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
@@ -87,10 +87,10 @@ public class SAML2IdPDataBinderImpl implements SAML2IdPDataBinder {
         SyncopeClientException requiredValuesMissing = SyncopeClientException.build(
                 ClientExceptionType.RequiredValuesMissing);
 
-        for (MappingItemTO itemTO : idpTO.getMappingItems()) {
+        for (ItemTO itemTO : idpTO.getMappingItems()) {
             if (itemTO == null) {
-                LOG.error("Null {}", MappingItemTO.class.getSimpleName());
-                invalidMapping.getElements().add("Null " + MappingItemTO.class.getSimpleName());
+                LOG.error("Null {}", ItemTO.class.getSimpleName());
+                invalidMapping.getElements().add("Null " + ItemTO.class.getSimpleName());
             } else if (itemTO.getIntAttrName() == null) {
                 requiredValuesMissing.getElements().add("intAttrName");
                 scce.addException(requiredValuesMissing);
@@ -194,7 +194,7 @@ public class SAML2IdPDataBinderImpl implements SAML2IdPDataBinder {
 
     private void populateMappingTO(final SAML2IdP idp, final SAML2IdPTO idpTO) {
         for (MappingItem item : idp.getMappingItems()) {
-            MappingItemTO itemTO = new MappingItemTO();
+            ItemTO itemTO = new ItemTO();
             itemTO.setKey(item.getKey());
             BeanUtils.copyProperties(item, itemTO, MAPPINGITEM_IGNORE_PROPERTIES);
             itemTO.setPurpose(MappingPurpose.NONE);