syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [3/5] syncope git commit: [SYNCOPE-874] Most of work done on core; console implementation is missing
Date Wed, 22 Jun 2016 06:43:58 GMT
http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/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 31732fd..0766bd5 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
@@ -94,7 +94,6 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                 noPropResources));
     }
 
-    @SuppressWarnings("unchecked")
     protected void link(final Any<?> any, final Boolean unlink) {
         AnyPatch patch = newPatch(any.getKey());
         patch.getResources().add(new StringPatchItem.Builder().
@@ -104,7 +103,6 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         update(patch);
     }
 
-    @SuppressWarnings("unchecked")
     protected void unassign(final Any<?> any) {
         AnyPatch patch = newPatch(any.getKey());
         patch.getResources().add(new StringPatchItem.Builder().
@@ -169,7 +167,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         }
     }
 
-    protected final void doHandle(final Any<?> any) throws JobExecutionException {
+    private void doHandle(final Any<?> any) throws JobExecutionException {
         AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
 
         ProvisioningReport result = new ProvisioningReport();
@@ -370,9 +368,8 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                         profile.getTask().getResource().getKey(),
                         operation,
                         resultStatus,
-                        connObjectUtils.getConnObjectTO(beforeObj),
-                        output instanceof ConnectorObject
-                                ? connObjectUtils.getConnObjectTO((ConnectorObject) output) : output,
+                        beforeObj,
+                        output,
                         any);
             }
         }
@@ -400,21 +397,21 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         }
     }
 
-    protected Any<?> update(final Any<?> any, final Boolean enabled) {
+    private Any<?> update(final Any<?> any, final Boolean enabled) {
         boolean changepwd;
-        Collection<String> resourceNames;
+        Collection<String> resourceKeys;
         if (any instanceof User) {
             changepwd = true;
-            resourceNames = userDAO.findAllResourceNames((User) any);
+            resourceKeys = userDAO.findAllResourceNames((User) any);
         } else if (any instanceof AnyObject) {
             changepwd = false;
-            resourceNames = anyObjectDAO.findAllResourceNames((AnyObject) any);
+            resourceKeys = anyObjectDAO.findAllResourceNames((AnyObject) any);
         } else {
             changepwd = false;
-            resourceNames = ((Group) any).getResourceNames();
+            resourceKeys = ((Group) any).getResourceKeys();
         }
 
-        List<String> noPropResources = new ArrayList<>(resourceNames);
+        List<String> noPropResources = new ArrayList<>(resourceKeys);
         noPropResources.remove(profile.getTask().getResource().getKey());
 
         PropagationByResource propByRes = new PropagationByResource();

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractRealmResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractRealmResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractRealmResultHandler.java
new file mode 100644
index 0000000..0df7f49
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractRealmResultHandler.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java.pushpull;
+
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
+import org.apache.syncope.core.provisioning.api.AuditManager;
+import org.apache.syncope.core.provisioning.api.data.RealmDataBinder;
+import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningActions;
+import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopeResultHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public abstract class AbstractRealmResultHandler<T extends ProvisioningTask, A extends ProvisioningActions>
+        implements SyncopeResultHandler<T, A> {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(SyncopeResultHandler.class);
+
+    protected static final String REALM_TYPE = "REALM";
+    
+    @Autowired
+    protected RealmDAO realmDAO;
+
+    @Autowired
+    protected RealmDataBinder binder;
+
+    /**
+     * Notification Manager.
+     */
+    @Autowired
+    protected NotificationManager notificationManager;
+
+    /**
+     * Audit Manager.
+     */
+    @Autowired
+    protected AuditManager auditManager;
+
+    /**
+     * Propagation manager.
+     */
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    /**
+     * Task executor.
+     */
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    /**
+     * Provisioning profile.
+     */
+    protected ProvisioningProfile<T, A> profile;
+
+    @Override
+    public void setProfile(final ProvisioningProfile<T, A> profile) {
+        this.profile = profile;
+    }
+
+    @Override
+    public ProvisioningProfile<T, A> getProfile() {
+        return profile;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java
index f41b912..8f3224c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractSyncopeResultHandler.java
@@ -129,7 +129,7 @@ public abstract class AbstractSyncopeResultHandler<T extends ProvisioningTask, A
     protected AnyUtilsFactory anyUtilsFactory;
 
     /**
-     * Sync profile.
+     * Provisioning profile.
      */
     protected ProvisioningProfile<T, A> profile;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AnyObjectPullResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AnyObjectPullResultHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AnyObjectPullResultHandlerImpl.java
index 888779d..2fd67c5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AnyObjectPullResultHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AnyObjectPullResultHandlerImpl.java
@@ -21,7 +21,6 @@ package org.apache.syncope.core.provisioning.java.pushpull;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 import org.apache.syncope.common.lib.patch.AnyPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
@@ -45,7 +44,7 @@ public class AnyObjectPullResultHandlerImpl extends AbstractPullResultHandler im
 
     @Override
     protected String getName(final AnyTO anyTO) {
-        return StringUtils.EMPTY;
+        return AnyObjectTO.class.cast(anyTO).getName();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DBPasswordPullActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DBPasswordPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DBPasswordPullActions.java
index 5562d3c..cd2aaf3 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DBPasswordPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DBPasswordPullActions.java
@@ -24,6 +24,7 @@ import org.apache.syncope.common.lib.patch.AnyPatch;
 import org.apache.syncope.common.lib.patch.PasswordPatch;
 import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
@@ -60,10 +61,10 @@ public class DBPasswordPullActions extends DefaultPullActions {
 
     @Transactional(readOnly = true)
     @Override
-    public <A extends AnyTO> SyncDelta beforeProvision(
+    public SyncDelta beforeProvision(
             final ProvisioningProfile<?, ?> profile,
             final SyncDelta delta,
-            final A any) throws JobExecutionException {
+            final EntityTO any) throws JobExecutionException {
 
         if (any instanceof UserTO) {
             String password = ((UserTO) any).getPassword();
@@ -124,10 +125,10 @@ public class DBPasswordPullActions extends DefaultPullActions {
 
     @Transactional
     @Override
-    public <A extends AnyTO> void after(
+    public void after(
             final ProvisioningProfile<?, ?> profile,
             final SyncDelta delta,
-            final A any,
+            final EntityTO any,
             final ProvisioningReport result) throws JobExecutionException {
 
         if (any instanceof UserTO && encodedPassword != null && cipher != null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPullActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPullActions.java
index a1d5878..a75ff8b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPullActions.java
@@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.java.pushpull;
 
 import org.apache.syncope.common.lib.patch.AnyPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.core.provisioning.api.pushpull.IgnoreProvisionException;
 import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
 import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
@@ -47,64 +48,64 @@ public abstract class DefaultPullActions implements PullActions {
     }
 
     @Override
-    public <A extends AnyTO> SyncDelta beforeDelete(
-            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final A any)
+    public SyncDelta beforeDelete(
+            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final EntityTO entity)
             throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <A extends AnyTO> SyncDelta beforeAssign(
-            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final A any)
+    public SyncDelta beforeAssign(
+            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final EntityTO entity)
             throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <A extends AnyTO> SyncDelta beforeProvision(
-            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final A any)
+    public SyncDelta beforeProvision(
+            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final EntityTO entity)
             throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <A extends AnyTO> SyncDelta beforeLink(
-            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final A any)
+    public SyncDelta beforeLink(
+            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final EntityTO entity)
             throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <A extends AnyTO> SyncDelta beforeUnassign(
-            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final A any)
+    public SyncDelta beforeUnassign(
+            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final EntityTO entity)
             throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <A extends AnyTO> SyncDelta beforeDeprovision(
-            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final A any)
+    public SyncDelta beforeDeprovision(
+            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final EntityTO entity)
             throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <A extends AnyTO> SyncDelta beforeUnlink(
-            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final A any)
+    public SyncDelta beforeUnlink(
+            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final EntityTO entity)
             throws JobExecutionException {
 
         return delta;
     }
 
     @Override
-    public <A extends AnyTO> void after(
-            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final A any,
+    public void after(
+            final ProvisioningProfile<?, ?> profile, final SyncDelta delta, final EntityTO entity,
             final ProvisioningReport result)
             throws JobExecutionException {
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPushActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPushActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPushActions.java
index 2e75870..eea4980 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPushActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultPushActions.java
@@ -18,7 +18,7 @@
  */
 package org.apache.syncope.core.provisioning.java.pushpull;
 
-import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
 import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
 import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
@@ -34,58 +34,58 @@ public abstract class DefaultPushActions implements PushActions {
     }
 
     @Override
-    public <A extends Any<?>> A beforeAssign(final ProvisioningProfile<?, ?> profile, final A any)
+    public Entity beforeAssign(final ProvisioningProfile<?, ?> profile, final Entity entity)
             throws JobExecutionException {
 
-        return any;
+        return entity;
     }
 
     @Override
-    public <A extends Any<?>> A beforeProvision(final ProvisioningProfile<?, ?> profile, final A any)
+    public Entity beforeProvision(final ProvisioningProfile<?, ?> profile, final Entity entity)
             throws JobExecutionException {
 
-        return any;
+        return entity;
     }
 
     @Override
-    public <A extends Any<?>> A beforeLink(final ProvisioningProfile<?, ?> profile, final A any)
+    public Entity beforeLink(final ProvisioningProfile<?, ?> profile, final Entity entity)
             throws JobExecutionException {
 
-        return any;
+        return entity;
     }
 
     @Override
-    public <A extends Any<?>> A beforeUnassign(final ProvisioningProfile<?, ?> profile, final A any)
+    public Entity beforeUnassign(final ProvisioningProfile<?, ?> profile, final Entity entity)
             throws JobExecutionException {
 
-        return any;
+        return entity;
     }
 
     @Override
-    public <A extends Any<?>> A beforeDeprovision(final ProvisioningProfile<?, ?> profile, final A any)
+    public Entity beforeDeprovision(final ProvisioningProfile<?, ?> profile, final Entity entity)
             throws JobExecutionException {
 
-        return any;
+        return entity;
     }
 
     @Override
-    public <A extends Any<?>> A beforeUnlink(final ProvisioningProfile<?, ?> profile, final A any)
+    public Entity beforeUnlink(final ProvisioningProfile<?, ?> profile, final Entity entity)
             throws JobExecutionException {
 
-        return any;
+        return entity;
     }
 
     @Override
-    public <A extends Any<?>> void onError(
-            final ProvisioningProfile<?, ?> profile, final A any, final ProvisioningReport result,
+    public void onError(
+            final ProvisioningProfile<?, ?> profile, final Entity entity, final ProvisioningReport result,
             final Exception error) throws JobExecutionException {
 
         // do nothing
     }
 
     @Override
-    public <A extends Any<?>> void after(
-            final ProvisioningProfile<?, ?> profile, final A any, final ProvisioningReport result)
+    public void after(
+            final ProvisioningProfile<?, ?> profile, final Entity entity, final ProvisioningReport result)
             throws JobExecutionException {
 
         // do nothing

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
index cac2f85..98ce3b9 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPMembershipPullActions.java
@@ -26,7 +26,7 @@ import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
-import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
@@ -154,23 +154,23 @@ public class LDAPMembershipPullActions extends SchedulingPullActions {
      * {@inheritDoc}
      */
     @Override
-    public <A extends AnyTO> void after(
+    public void after(
             final ProvisioningProfile<?, ?> profile,
             final SyncDelta delta,
-            final A any,
+            final EntityTO entity,
             final ProvisioningReport result) throws JobExecutionException {
 
         if (!(profile.getTask() instanceof PullTask)) {
             return;
         }
 
-        if (!(any instanceof GroupTO)
+        if (!(entity instanceof GroupTO)
                 || profile.getTask().getResource().getProvision(anyTypeDAO.findUser()) == null
                 || profile.getTask().getResource().getProvision(anyTypeDAO.findUser()).getMapping() == null) {
 
-            super.after(profile, delta, any, result);
+            super.after(profile, delta, entity, result);
         } else {
-            populateMemberships(profile, delta, (GroupTO) any);
+            populateMemberships(profile, delta, (GroupTO) entity);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java
index 9ffbcb5..967b27c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/LDAPPasswordPullActions.java
@@ -22,6 +22,7 @@ import org.apache.syncope.common.lib.patch.AnyPatch;
 import org.apache.syncope.common.lib.patch.PasswordPatch;
 import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -54,13 +55,13 @@ public class LDAPPasswordPullActions extends DefaultPullActions {
 
     @Transactional(readOnly = true)
     @Override
-    public <A extends AnyTO> SyncDelta beforeProvision(
+    public SyncDelta beforeProvision(
             final ProvisioningProfile<?, ?> profile,
             final SyncDelta delta,
-            final A any) throws JobExecutionException {
+            final EntityTO entity) throws JobExecutionException {
 
-        if (any instanceof UserTO) {
-            String password = ((UserTO) any).getPassword();
+        if (entity instanceof UserTO) {
+            String password = ((UserTO) entity).getPassword();
             parseEncodedPassword(password);
         }
 
@@ -102,14 +103,14 @@ public class LDAPPasswordPullActions extends DefaultPullActions {
 
     @Transactional
     @Override
-    public <A extends AnyTO> void after(
+    public void after(
             final ProvisioningProfile<?, ?> profile,
             final SyncDelta delta,
-            final A any,
+            final EntityTO entity,
             final ProvisioningReport result) throws JobExecutionException {
 
-        if (any instanceof UserTO && encodedPassword != null && cipher != null) {
-            User user = userDAO.find(any.getKey());
+        if (entity instanceof UserTO && encodedPassword != null && cipher != null) {
+            User user = userDAO.find(entity.getKey());
             if (user != null) {
                 byte[] encodedPasswordBytes = Base64.decode(encodedPassword.getBytes());
                 char[] encodedHex = Hex.encode(encodedPasswordBytes);

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/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 b5a7dfe..5655385 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
@@ -36,6 +36,7 @@ import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 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.resource.OrgUnit;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
 import org.apache.syncope.core.provisioning.api.Connector;
@@ -52,8 +53,12 @@ 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.Name;
 import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.identityconnectors.framework.common.objects.OperationOptions;
+import org.identityconnectors.framework.common.objects.OperationOptionsBuilder;
 import org.identityconnectors.framework.common.objects.SyncToken;
+import org.identityconnectors.framework.common.objects.Uid;
 
 public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> implements SyncopePullExecutor {
 
@@ -76,7 +81,7 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
         latestSyncTokens.put(objectClass, latestSyncToken);
     }
 
-    protected void setGroupOwners(final GroupPullResultHandler ghandler) {
+    private void setGroupOwners(final GroupPullResultHandler ghandler) {
         for (Map.Entry<String, String> entry : ghandler.getGroupOwnerMap().entrySet()) {
             Group group = groupDAO.find(entry.getKey());
             if (group == null) {
@@ -226,13 +231,59 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
                 }
             }
         }
-
         try {
             setGroupOwners(ghandler);
         } catch (Exception e) {
             LOG.error("While setting group owners", e);
         }
 
+        if (pullTask.getResource().getOrgUnit() != null) {
+            OrgUnit orgUnit = pullTask.getResource().getOrgUnit();
+            OperationOptions options = new OperationOptionsBuilder().setAttributesToGet(Name.NAME, Uid.NAME).build();
+
+            SyncopePullResultHandler handler =
+                    (SyncopePullResultHandler) ApplicationContextProvider.getBeanFactory().
+                    createBean(RealmPullResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+            ahandler.setProfile(profile);
+            ahandler.setPullExecutor(this);
+
+            try {
+                switch (pullTask.getPullMode()) {
+                    case INCREMENTAL:
+                        connector.sync(
+                                orgUnit.getObjectClass(),
+                                orgUnit.getSyncToken(),
+                                handler,
+                                options);
+                        if (!dryRun) {
+                            orgUnit.setSyncToken(latestSyncTokens.get(orgUnit.getObjectClass()));
+                            resourceDAO.save(orgUnit.getResource());
+                        }
+                        break;
+
+                    case FILTERED_RECONCILIATION:
+                        ReconciliationFilterBuilder filterBuilder =
+                                (ReconciliationFilterBuilder) ApplicationContextProvider.getBeanFactory().
+                                createBean(Class.forName(pullTask.getReconciliationFilterBuilderClassName()),
+                                        AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+                        connector.filteredReconciliation(orgUnit.getObjectClass(),
+                                filterBuilder,
+                                handler,
+                                options);
+                        break;
+
+                    case FULL_RECONCILIATION:
+                    default:
+                        connector.fullReconciliation(orgUnit.getObjectClass(),
+                                handler,
+                                options);
+                        break;
+                }
+            } catch (Throwable t) {
+                throw new JobExecutionException("While pulling from connector", t);
+            }
+        }
+
         if (!profile.isDryRun()) {
             for (PullActions action : actions) {
                 action.afterAll(profile);

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
index 563c64a..00be8a1 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
@@ -30,9 +30,11 @@ import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 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.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.task.PushTask;
@@ -72,6 +74,9 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
     @Autowired
     private AnyObjectDAO anyObjectDAO;
 
+    @Autowired
+    private RealmDAO realmDAO;
+
     private AnyDAO<?> getAnyDAO(final AnyTypeKind anyTypeKind) {
         AnyDAO<?> result;
         switch (anyTypeKind) {
@@ -91,7 +96,7 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
         return result;
     }
 
-    protected void handle(
+    private void doHandle(
             final List<? extends Any<?>> anys,
             final SyncopePushResultHandler handler,
             final ExternalResource resource)
@@ -176,7 +181,7 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
                         ? null
                         : pushTask.getFilter(provision.getAnyType()).getFIQLCond();
                 if (StringUtils.isBlank(filter)) {
-                    handle(anyDAO.findAll(), handler, pushTask.getResource());
+                    doHandle(anyDAO.findAll(), handler, pushTask.getResource());
                 } else {
                     int count = anyDAO.count(SyncopeConstants.FULL_ADMIN_REALMS);
                     for (int page = 1; page <= (count / PAGE_SIZE) + 1; page++) {
@@ -187,12 +192,28 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
                                 PAGE_SIZE,
                                 Collections.<OrderByClause>emptyList(),
                                 provision.getAnyType().getKind());
-                        handle(anys, handler, pushTask.getResource());
+                        doHandle(anys, handler, pushTask.getResource());
                     }
                 }
             }
         }
 
+        if (pushTask.getResource().getOrgUnit() != null) {
+            SyncopePushResultHandler handler =
+                    (SyncopePushResultHandler) ApplicationContextProvider.getBeanFactory().
+                    createBean(RealmPullResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+            handler.setProfile(profile);
+
+            for (Realm realm : realmDAO.findAll()) {
+                try {
+                    handler.handle(realm.getKey());
+                } catch (Exception e) {
+                    LOG.warn("Failure pushing '{}' on '{}'", realm, pushTask.getResource(), e);
+                    throw new JobExecutionException("While pushing " + realm + " on " + pushTask.getResource(), e);
+                }
+            }
+        }
+
         if (!profile.isDryRun()) {
             for (PushActions action : actions) {
                 action.afterAll(profile);

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/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
new file mode 100644
index 0000000..c97ffb9
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPullResultHandlerImpl.java
@@ -0,0 +1,693 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java.pushpull;
+
+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.SyncopeConstants;
+import org.apache.syncope.common.lib.to.RealmTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.lib.types.AuditElements.Result;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.common.lib.types.PullMode;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+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;
+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.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.apache.syncope.core.spring.ApplicationContextProvider;
+import org.identityconnectors.framework.common.objects.SyncDelta;
+import org.identityconnectors.framework.common.objects.SyncDeltaType;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional(rollbackFor = Throwable.class)
+public class RealmPullResultHandlerImpl
+        extends AbstractRealmResultHandler<PullTask, PullActions>
+        implements SyncopePullResultHandler {
+
+    @Autowired
+    private AnySearchDAO searchDAO;
+
+    private SyncopePullExecutor executor;
+
+    private Result latestResult = null;
+
+    @Override
+    public void setPullExecutor(final SyncopePullExecutor executor) {
+        this.executor = executor;
+    }
+
+    @Override
+    public boolean handle(final SyncDelta delta) {
+        try {
+            OrgUnit orgUnit = profile.getTask().getResource().getOrgUnit();
+            if (orgUnit == null) {
+                throw new JobExecutionException("No orgUnit found on " + profile.getTask().getResource() + " for "
+                        + delta.getObject().getObjectClass());
+            }
+
+            doHandle(delta, orgUnit);
+
+            LOG.debug("Successfully handled {}", delta);
+
+            if (profile.getTask().getPullMode() != PullMode.INCREMENTAL) {
+                return true;
+            }
+
+            boolean shouldContinue;
+            synchronized (this) {
+                shouldContinue = latestResult == Result.SUCCESS;
+                this.latestResult = null;
+            }
+            if (shouldContinue) {
+                executor.setLatestSyncToken(delta.getObjectClass(), delta.getToken());
+            }
+            return shouldContinue;
+        } catch (IgnoreProvisionException e) {
+            ProvisioningReport ignoreResult = new ProvisioningReport();
+            ignoreResult.setOperation(ResourceOperation.NONE);
+            ignoreResult.setStatus(ProvisioningReport.Status.IGNORE);
+            ignoreResult.setAnyType(REALM_TYPE);
+            ignoreResult.setKey(null);
+            ignoreResult.setName(delta.getObject().getName().getNameValue());
+            profile.getResults().add(ignoreResult);
+
+            LOG.warn("Ignoring during pull", e);
+
+            executor.setLatestSyncToken(delta.getObjectClass(), delta.getToken());
+
+            return true;
+        } catch (JobExecutionException e) {
+            LOG.error("Pull failed", e);
+
+            return false;
+        }
+    }
+
+    private ProvisioningReport assign(final SyncDelta delta, final String name) throws JobExecutionException {
+        if (!profile.getTask().isPerformCreate()) {
+            LOG.debug("PullTask not configured for create");
+            return null;
+        }
+
+        RealmTO realmTO = new RealmTO();
+        realmTO.setName(name);
+        realmTO.setParent(SyncopeConstants.ROOT_REALM);
+        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(SyncopeConstants.ROOT_REALM + name);
+
+        if (profile.isDryRun()) {
+            result.setKey(null);
+        } else {
+            SyncDelta actionedDelta = delta;
+            for (PullActions action : profile.getActions()) {
+                actionedDelta = action.beforeAssign(profile, actionedDelta, realmTO);
+            }
+
+            create(realmTO, actionedDelta, UnmatchingRule.toEventName(UnmatchingRule.ASSIGN), result);
+        }
+
+        return result;
+    }
+
+    private ProvisioningReport provision(final SyncDelta delta, final String name) throws JobExecutionException {
+        if (!profile.getTask().isPerformCreate()) {
+            LOG.debug("PullTask not configured for create");
+            return null;
+        }
+
+        RealmTO realmTO = new RealmTO();
+        realmTO.setName(name);
+        realmTO.setParent(SyncopeConstants.ROOT_REALM);
+        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(SyncopeConstants.ROOT_REALM + name);
+
+        if (profile.isDryRun()) {
+            result.setKey(null);
+        } else {
+            SyncDelta actionedDelta = delta;
+            for (PullActions action : profile.getActions()) {
+                actionedDelta = action.beforeProvision(profile, actionedDelta, realmTO);
+            }
+
+            create(realmTO, actionedDelta, UnmatchingRule.toEventName(UnmatchingRule.PROVISION), result);
+        }
+
+        return result;
+    }
+
+    private void throwIgnoreProvisionException(final SyncDelta delta, final Exception exception)
+            throws JobExecutionException {
+
+        if (exception instanceof IgnoreProvisionException) {
+            throw IgnoreProvisionException.class.cast(exception);
+        }
+
+        IgnoreProvisionException ipe = null;
+        for (PullActions action : profile.getActions()) {
+            if (ipe == null) {
+                ipe = action.onError(profile, delta, exception);
+            }
+        }
+        if (ipe != null) {
+            throw ipe;
+        }
+    }
+
+    private void create(
+            final RealmTO realmTO,
+            final SyncDelta delta,
+            final String operation,
+            final ProvisioningReport result)
+            throws JobExecutionException {
+
+        Object output;
+        Result resultStatus;
+
+        try {
+            Realm realm = realmDAO.save(binder.create(SyncopeConstants.ROOT_REALM, realmTO));
+
+            PropagationByResource propByRes = new PropagationByResource();
+            for (String resource : realm.getResourceKeys()) {
+                propByRes.add(ResourceOperation.CREATE, resource);
+            }
+            List<PropagationTask> tasks = propagationManager.createTasks(realm, propByRes, null);
+            PropagationReporter propagationReporter =
+                    ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+            taskExecutor.execute(tasks, propagationReporter, false);
+
+            RealmTO actual = binder.getRealmTO(realm);
+            result.setName(SyncopeConstants.ROOT_REALM + realmTO.getName());
+            output = actual;
+            resultStatus = Result.SUCCESS;
+
+            for (PullActions action : profile.getActions()) {
+                action.after(profile, delta, actual, result);
+            }
+
+            LOG.debug("Realm {} successfully created", actual.getKey());
+        } 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 create Realm {} ", delta.getUid().getUidValue(), e);
+            output = e;
+            resultStatus = Result.FAILURE;
+        }
+
+        finalize(operation, resultStatus, null, output, delta);
+    }
+
+    private ProvisioningReport update(final SyncDelta delta, final Realm realm, final String name)
+            throws JobExecutionException {
+
+        if (!profile.getTask().isPerformUpdate()) {
+            LOG.debug("PullTask not configured for update");
+            return null;
+        }
+
+        LOG.debug("About to update {}", realm);
+
+        RealmTO before = binder.getRealmTO(realm);
+
+        ProvisioningReport result = new ProvisioningReport();
+        result.setOperation(ResourceOperation.UPDATE);
+        result.setAnyType(REALM_TYPE);
+        result.setStatus(ProvisioningReport.Status.SUCCESS);
+        result.setKey(realm.getKey());
+
+        Result resultStatus;
+        Object output;
+        if (!profile.isDryRun()) {
+            try {
+                before.setName(name);
+
+                PropagationByResource propByRes = binder.update(realm, before);
+                Realm updated = realmDAO.save(realm);
+
+                List<PropagationTask> tasks = propagationManager.createTasks(updated, propByRes, null);
+                PropagationReporter propagationReporter =
+                        ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+                taskExecutor.execute(tasks, propagationReporter, false);
+
+                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 {}", 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(MatchingRule.toEventName(MatchingRule.UPDATE), resultStatus, before, output, delta);
+        }
+
+        return result;
+    }
+
+    private ProvisioningReport deprovision(final SyncDelta delta, final Realm realm, final boolean unlink)
+            throws JobExecutionException {
+
+        if (!profile.getTask().isPerformUpdate()) {
+            LOG.debug("PullTask not configured for update");
+            return null;
+        }
+
+        LOG.debug("About to deprovision {}", realm);
+
+        ProvisioningReport result = new ProvisioningReport();
+        result.setOperation(ResourceOperation.DELETE);
+        result.setAnyType(REALM_TYPE);
+        result.setStatus(ProvisioningReport.Status.SUCCESS);
+        result.setKey(realm.getKey());
+
+        RealmTO before = binder.getRealmTO(realm);
+
+        Object output;
+        Result resultStatus;
+        if (!profile.isDryRun()) {
+            result.setName(realm.getFullPath());
+
+            try {
+                if (unlink) {
+                    for (PullActions action : profile.getActions()) {
+                        action.beforeUnassign(profile, delta, before);
+                    }
+                } else {
+                    for (PullActions action : profile.getActions()) {
+                        action.beforeDeprovision(profile, delta, before);
+                    }
+                }
+
+                PropagationByResource propByRes = new PropagationByResource();
+                propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey());
+                taskExecutor.execute(propagationManager.createTasks(realm, propByRes, null));
+
+                if (unlink) {
+                    realm.getResources().remove(profile.getTask().getResource());
+                    output = binder.getRealmTO(realmDAO.save(realm));
+                } else {
+                    output = binder.getRealmTO(realm);
+                }
+
+                for (PullActions action : profile.getActions()) {
+                    action.after(profile, delta, 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 {}", 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);
+        }
+
+        return result;
+    }
+
+    private ProvisioningReport link(final SyncDelta delta, final Realm realm, final boolean unlink)
+            throws JobExecutionException {
+
+        if (!profile.getTask().isPerformUpdate()) {
+            LOG.debug("PullTask not configured for update");
+            return null;
+        }
+
+        LOG.debug("About to link {}", realm);
+
+        ProvisioningReport result = new ProvisioningReport();
+        result.setOperation(ResourceOperation.NONE);
+        result.setAnyType(REALM_TYPE);
+        result.setStatus(ProvisioningReport.Status.SUCCESS);
+        result.setKey(realm.getKey());
+
+        RealmTO before = binder.getRealmTO(realm);
+
+        Object output;
+        Result resultStatus;
+        if (!profile.isDryRun()) {
+            result.setName(realm.getFullPath());
+
+            try {
+                if (unlink) {
+                    for (PullActions action : profile.getActions()) {
+                        action.beforeUnlink(profile, delta, before);
+                    }
+                } else {
+                    for (PullActions action : profile.getActions()) {
+                        action.beforeLink(profile, delta, before);
+                    }
+                }
+
+                if (unlink) {
+                    realm.getResources().remove(profile.getTask().getResource());
+                } 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);
+                }
+
+                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, delta);
+        }
+
+        return result;
+    }
+
+    private ProvisioningReport delete(final SyncDelta delta, final Realm realm)
+            throws JobExecutionException {
+
+        if (!profile.getTask().isPerformDelete()) {
+            LOG.debug("PullTask not configured for delete");
+            return null;
+        }
+
+        LOG.debug("About to delete {}", realm);
+
+        SyncDelta workingDelta = delta;
+        Object output;
+        Result resultStatus = Result.FAILURE;
+
+        ProvisioningReport result = new ProvisioningReport();
+
+        try {
+            RealmTO before = binder.getRealmTO(realm);
+
+            result.setKey(realm.getKey());
+            result.setName(realm.getFullPath());
+            result.setOperation(ResourceOperation.DELETE);
+            result.setAnyType(REALM_TYPE);
+            result.setStatus(ProvisioningReport.Status.SUCCESS);
+
+            if (!profile.isDryRun()) {
+                for (PullActions action : profile.getActions()) {
+                    workingDelta = action.beforeDelete(profile, workingDelta, before);
+                }
+
+                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);
+                    PropagationReporter propagationReporter =
+                            ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+                    taskExecutor.execute(tasks, propagationReporter, 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);
+            }
+        } catch (Exception e) {
+            LOG.error("Could not delete {}", realm, e);
+        }
+
+        return result;
+    }
+
+    private ProvisioningReport ignore(
+            final SyncDelta delta,
+            final boolean matching)
+            throws JobExecutionException {
+
+        LOG.debug("Any to ignore {}", delta.getObject().getUid().getUidValue());
+
+        ProvisioningReport result = new ProvisioningReport();
+
+        result.setKey(null);
+        result.setName(delta.getObject().getUid().getUidValue());
+        result.setOperation(ResourceOperation.NONE);
+        result.setAnyType(REALM_TYPE);
+        result.setStatus(ProvisioningReport.Status.SUCCESS);
+
+        if (!profile.isDryRun()) {
+            finalize(matching
+                    ? MatchingRule.toEventName(MatchingRule.IGNORE)
+                    : UnmatchingRule.toEventName(UnmatchingRule.IGNORE), Result.SUCCESS, null, null, delta);
+        }
+
+        return result;
+    }
+
+    private void doHandle(final SyncDelta delta, final OrgUnit orgUnit) throws JobExecutionException {
+        LOG.debug("Process {} for {} as {}",
+                delta.getDeltaType(), delta.getUid().getUidValue(), delta.getObject().getObjectClass());
+
+        Realm realm = IterableUtils.find(realmDAO.findAll(), new Predicate<Realm>() {
+
+            @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);
+            }
+        });
+        LOG.debug("Match found for {} as {}: {}",
+                delta.getObject().getName().getNameValue(), delta.getObject().getObjectClass(), realm);
+
+        try {
+            if (SyncDeltaType.CREATE_OR_UPDATE == delta.getDeltaType()) {
+                if (realm == null) {
+                    switch (profile.getTask().getUnmatchingRule()) {
+                        case ASSIGN:
+                            CollectionUtils.addIgnoreNull(
+                                    profile.getResults(), assign(delta, delta.getUid().getUidValue()));
+                            break;
+
+                        case PROVISION:
+                            CollectionUtils.addIgnoreNull(
+                                    profile.getResults(), provision(delta, delta.getUid().getUidValue()));
+                            break;
+
+                        case IGNORE:
+                            CollectionUtils.addIgnoreNull(
+                                    profile.getResults(), ignore(delta, false));
+                            break;
+
+                        default:
+                        // do nothing
+                    }
+                } else {
+                    switch (profile.getTask().getMatchingRule()) {
+                        case UPDATE:
+                            CollectionUtils.addIgnoreNull(
+                                    profile.getResults(), update(delta, realm, delta.getUid().getUidValue()));
+                            break;
+
+                        case DEPROVISION:
+                            CollectionUtils.addIgnoreNull(
+                                    profile.getResults(), deprovision(delta, realm, false));
+                            break;
+
+                        case UNASSIGN:
+                            CollectionUtils.addIgnoreNull(
+                                    profile.getResults(), deprovision(delta, realm, true));
+                            break;
+
+                        case LINK:
+                            CollectionUtils.addIgnoreNull(
+                                    profile.getResults(), link(delta, realm, false));
+                            break;
+
+                        case UNLINK:
+                            CollectionUtils.addIgnoreNull(
+                                    profile.getResults(), link(delta, realm, true));
+                            break;
+
+                        case IGNORE:
+                            CollectionUtils.addIgnoreNull(profile.getResults(), ignore(delta, true));
+                            break;
+
+                        default:
+                        // do nothing
+                    }
+                }
+            } else if (SyncDeltaType.DELETE == delta.getDeltaType()) {
+                if (realm == null) {
+                    LOG.debug("No match found for deletion");
+                } else {
+                    CollectionUtils.addIgnoreNull(profile.getResults(), delete(delta, realm));
+                }
+            }
+        } catch (IllegalStateException | IllegalArgumentException e) {
+            LOG.warn(e.getMessage());
+        }
+    }
+
+    private void finalize(
+            final String event,
+            final Result result,
+            final Object before,
+            final Object output,
+            final SyncDelta delta) {
+
+        synchronized (this) {
+            this.latestResult = result;
+        }
+
+        notificationManager.createTasks(AuditElements.EventCategoryType.PULL,
+                REALM_TYPE.toLowerCase(),
+                profile.getTask().getResource().getKey(),
+                event,
+                result,
+                before,
+                output,
+                delta);
+
+        auditManager.audit(AuditElements.EventCategoryType.PULL,
+                REALM_TYPE.toLowerCase(),
+                profile.getTask().getResource().getKey(),
+                event,
+                result,
+                before,
+                output,
+                delta);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/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
new file mode 100644
index 0000000..eb24796
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/RealmPushResultHandlerImpl.java
@@ -0,0 +1,374 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java.pushpull;
+
+import java.util.ArrayList;
+import java.util.List;
+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;
+import org.apache.syncope.common.lib.types.AuditElements.Result;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.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.task.PropagationTask;
+import org.apache.syncope.core.persistence.api.entity.task.PushTask;
+import org.apache.syncope.core.provisioning.api.TimeoutException;
+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.PushActions;
+import org.apache.syncope.core.provisioning.api.pushpull.SyncopePushResultHandler;
+import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.identityconnectors.framework.common.objects.Uid;
+import org.quartz.JobExecutionException;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+public class RealmPushResultHandlerImpl
+        extends AbstractRealmResultHandler<PushTask, PushActions>
+        implements SyncopePushResultHandler {
+
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    @Override
+    public boolean handle(final String realmKey) {
+        Realm realm = null;
+        try {
+            realm = realmDAO.find(realmKey);
+            doHandle(realm);
+            return true;
+        } catch (IgnoreProvisionException e) {
+            ProvisioningReport result = new ProvisioningReport();
+            result.setOperation(ResourceOperation.NONE);
+            result.setAnyType(realm == null ? null : REALM_TYPE);
+            result.setStatus(ProvisioningReport.Status.IGNORE);
+            result.setKey(realmKey);
+            profile.getResults().add(result);
+
+            LOG.warn("Ignoring during push", e);
+            return true;
+        } catch (JobExecutionException e) {
+            LOG.error("Push failed", e);
+            return false;
+        }
+    }
+
+    private ConnectorObject getRemoteObject(final String connObjectKey, final ObjectClass objectClass) {
+        ConnectorObject obj = null;
+        try {
+            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 {}", connObjectKey, ignore);
+        }
+
+        return obj;
+    }
+
+    private Realm update(final RealmTO realmTO) {
+        Realm realm = realmDAO.findByFullPath(realmTO.getFullPath());
+        PropagationByResource propByRes = binder.update(realm, realmTO);
+        realm = realmDAO.save(realm);
+
+        List<PropagationTask> tasks = propagationManager.createTasks(realm, propByRes, null);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getBeanFactory().getBean(PropagationReporter.class);
+        taskExecutor.execute(tasks, propagationReporter, false);
+
+        return realm;
+    }
+
+    private void deprovision(final Realm realm) {
+        List<String> noPropResources = new ArrayList<>(realm.getResourceKeys());
+        noPropResources.remove(profile.getTask().getResource().getKey());
+
+        PropagationByResource propByRes = new PropagationByResource();
+        propByRes.addAll(ResourceOperation.DELETE, realm.getResourceKeys());
+
+        taskExecutor.execute(propagationManager.createTasks(realm, propByRes, noPropResources));
+    }
+
+    private void provision(final Realm realm) {
+        List<String> noPropResources = new ArrayList<>(realm.getResourceKeys());
+        noPropResources.remove(profile.getTask().getResource().getKey());
+
+        PropagationByResource propByRes = new PropagationByResource();
+        propByRes.add(ResourceOperation.CREATE, profile.getTask().getResource().getKey());
+
+        taskExecutor.execute(propagationManager.createTasks(realm, propByRes, noPropResources));
+    }
+
+    private void link(final Realm realm, final Boolean unlink) {
+        RealmTO realmTO = binder.getRealmTO(realm);
+        if (unlink) {
+            realmTO.getResources().remove(profile.getTask().getResource().getKey());
+        } else {
+            realmTO.getResources().add(profile.getTask().getResource().getKey());
+        }
+
+        update(realmTO);
+    }
+
+    private void unassign(final Realm realm) {
+        RealmTO realmTO = binder.getRealmTO(realm);
+        realmTO.getResources().remove(profile.getTask().getResource().getKey());
+
+        deprovision(update(realmTO));
+    }
+
+    private void assign(final Realm realm) {
+        RealmTO realmTO = binder.getRealmTO(realm);
+        realmTO.getResources().add(profile.getTask().getResource().getKey());
+
+        provision(update(realmTO));
+    }
+
+    private void doHandle(final Realm realm) throws JobExecutionException {
+        ProvisioningReport result = new ProvisioningReport();
+        profile.getResults().add(result);
+
+        result.setKey(realm.getKey());
+        result.setAnyType(REALM_TYPE);
+        result.setName(realm.getFullPath());
+
+        LOG.debug("Propagating Realm with key {} towards {}", realm.getKey(), profile.getTask().getResource());
+
+        Object output = null;
+        Result resultStatus = null;
+        String operation = null;
+
+        // Try to read remote object BEFORE any actual operation
+        ConnectorObject beforeObj = getRemoteObject(
+                realm.getName(), profile.getTask().getResource().getOrgUnit().getObjectClass());
+
+        if (profile.isDryRun()) {
+            if (beforeObj == null) {
+                result.setOperation(getResourceOperation(profile.getTask().getUnmatchingRule()));
+            } else {
+                result.setOperation(getResourceOperation(profile.getTask().getMatchingRule()));
+            }
+            result.setStatus(ProvisioningReport.Status.SUCCESS);
+        } else {
+            try {
+                if (beforeObj == null) {
+                    operation = UnmatchingRule.toEventName(profile.getTask().getUnmatchingRule());
+                    result.setOperation(getResourceOperation(profile.getTask().getUnmatchingRule()));
+
+                    switch (profile.getTask().getUnmatchingRule()) {
+                        case ASSIGN:
+                            for (PushActions action : profile.getActions()) {
+                                action.beforeAssign(this.getProfile(), realm);
+                            }
+
+                            if (!profile.getTask().isPerformCreate()) {
+                                LOG.debug("PushTask not configured for create");
+                            } else {
+                                assign(realm);
+                            }
+
+                            break;
+
+                        case PROVISION:
+                            for (PushActions action : profile.getActions()) {
+                                action.beforeProvision(this.getProfile(), realm);
+                            }
+
+                            if (!profile.getTask().isPerformCreate()) {
+                                LOG.debug("PushTask not configured for create");
+                            } else {
+                                provision(realm);
+                            }
+
+                            break;
+
+                        case UNLINK:
+                            for (PushActions action : profile.getActions()) {
+                                action.beforeUnlink(this.getProfile(), realm);
+                            }
+
+                            if (!profile.getTask().isPerformUpdate()) {
+                                LOG.debug("PushTask not configured for update");
+                            } else {
+                                link(realm, true);
+                            }
+
+                            break;
+
+                        case IGNORE:
+                            LOG.debug("Ignored any: {}", realm);
+                            break;
+                        default:
+                        // do nothing
+                    }
+                } else {
+                    operation = MatchingRule.toEventName(profile.getTask().getMatchingRule());
+                    result.setOperation(getResourceOperation(profile.getTask().getMatchingRule()));
+
+                    switch (profile.getTask().getMatchingRule()) {
+                        case UPDATE:
+                            for (PushActions action : profile.getActions()) {
+                                action.beforeUpdate(this.getProfile(), realm);
+                            }
+                            if (!profile.getTask().isPerformUpdate()) {
+                                LOG.debug("PushTask not configured for update");
+                            } else {
+                                update(binder.getRealmTO(realm));
+                            }
+
+                            break;
+
+                        case DEPROVISION:
+                            for (PushActions action : profile.getActions()) {
+                                action.beforeDeprovision(this.getProfile(), realm);
+                            }
+
+                            if (!profile.getTask().isPerformDelete()) {
+                                LOG.debug("PushTask not configured for delete");
+                            } else {
+                                deprovision(realm);
+                            }
+
+                            break;
+
+                        case UNASSIGN:
+                            for (PushActions action : profile.getActions()) {
+                                action.beforeUnassign(this.getProfile(), realm);
+                            }
+
+                            if (!profile.getTask().isPerformDelete()) {
+                                LOG.debug("PushTask not configured for delete");
+                            } else {
+                                unassign(realm);
+                            }
+
+                            break;
+
+                        case LINK:
+                            for (PushActions action : profile.getActions()) {
+                                action.beforeLink(this.getProfile(), realm);
+                            }
+
+                            if (!profile.getTask().isPerformUpdate()) {
+                                LOG.debug("PushTask not configured for update");
+                            } else {
+                                link(realm, false);
+                            }
+
+                            break;
+
+                        case UNLINK:
+                            for (PushActions action : profile.getActions()) {
+                                action.beforeUnlink(this.getProfile(), realm);
+                            }
+
+                            if (!profile.getTask().isPerformUpdate()) {
+                                LOG.debug("PushTask not configured for update");
+                            } else {
+                                link(realm, true);
+                            }
+
+                            break;
+
+                        case IGNORE:
+                            LOG.debug("Ignored any: {}", realm);
+                            break;
+                        default:
+                        // do nothing
+                    }
+                }
+
+                for (PushActions action : profile.getActions()) {
+                    action.after(this.getProfile(), realm, result);
+                }
+
+                result.setStatus(ProvisioningReport.Status.SUCCESS);
+                resultStatus = AuditElements.Result.SUCCESS;
+                output = getRemoteObject(
+                        realm.getName(), profile.getTask().getResource().getOrgUnit().getObjectClass());
+            } catch (IgnoreProvisionException e) {
+                throw e;
+            } catch (Exception e) {
+                result.setStatus(ProvisioningReport.Status.FAILURE);
+                result.setMessage(ExceptionUtils.getRootCauseMessage(e));
+                resultStatus = AuditElements.Result.FAILURE;
+                output = e;
+
+                LOG.warn("Error pushing {} towards {}", realm, profile.getTask().getResource(), e);
+
+                for (PushActions action : profile.getActions()) {
+                    action.onError(this.getProfile(), realm, result, e);
+                }
+
+                throw new JobExecutionException(e);
+            } finally {
+                notificationManager.createTasks(AuditElements.EventCategoryType.PUSH,
+                        REALM_TYPE.toLowerCase(),
+                        profile.getTask().getResource().getKey(),
+                        operation,
+                        resultStatus,
+                        beforeObj,
+                        output,
+                        realm);
+                auditManager.audit(AuditElements.EventCategoryType.PUSH,
+                        REALM_TYPE.toLowerCase(),
+                        profile.getTask().getResource().getKey(),
+                        operation,
+                        resultStatus,
+                        beforeObj,
+                        output,
+                        realm);
+            }
+        }
+    }
+
+    private ResourceOperation getResourceOperation(final UnmatchingRule rule) {
+        switch (rule) {
+            case ASSIGN:
+            case PROVISION:
+                return ResourceOperation.CREATE;
+            default:
+                return ResourceOperation.NONE;
+        }
+    }
+
+    private ResourceOperation getResourceOperation(final MatchingRule rule) {
+        switch (rule) {
+            case UPDATE:
+                return ResourceOperation.UPDATE;
+            case DEPROVISION:
+            case UNASSIGN:
+                return ResourceOperation.DELETE;
+            default:
+                return ResourceOperation.NONE;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java
index 1558267..dc6f0e6 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AddETagFilter.java
@@ -27,6 +27,7 @@ import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.ext.Provider;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.to.AbstractAnnotatedBean;
+import org.apache.syncope.common.lib.to.EntityTO;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 
 /**
@@ -43,7 +44,10 @@ public class AddETagFilter implements ContainerResponseFilter {
             if (resCtx.getEntity() instanceof AbstractAnnotatedBean) {
                 annotated = (AbstractAnnotatedBean) resCtx.getEntity();
             } else if (resCtx.getEntity() instanceof ProvisioningResult) {
-                annotated = ((ProvisioningResult<?>) resCtx.getEntity()).getAny();
+                EntityTO entity = ((ProvisioningResult<?>) resCtx.getEntity()).getEntity();
+                if (entity instanceof AbstractAnnotatedBean) {
+                    annotated = (AbstractAnnotatedBean) entity;
+                }
             }
             if (annotated != null) {
                 String etagValue = annotated.getETagValue();

http://git-wip-us.apache.org/repos/asf/syncope/blob/62f56963/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
index d24f522..8548fbb 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
@@ -227,7 +227,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
         switch (patch.getAction()) {
             case UNLINK:
                 updated = new ProvisioningResult<>();
-                updated.setAny(getAnyLogic().unlink(patch.getKey(), patch.getResources()));
+                updated.setEntity(getAnyLogic().unlink(patch.getKey(), patch.getResources()));
                 break;
 
             case UNASSIGN:
@@ -240,7 +240,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
 
             default:
                 updated = new ProvisioningResult<>();
-                updated.setAny(getAnyLogic().read(patch.getKey()));
+                updated.setEntity(getAnyLogic().read(patch.getKey()));
         }
 
         BulkActionResult result = new BulkActionResult();
@@ -248,7 +248,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
         if (patch.getAction() == ResourceDeassociationAction.UNLINK) {
             for (String resource : patch.getResources()) {
                 result.getResults().put(resource,
-                        updated.getAny().getResources().contains(resource)
+                        updated.getEntity().getResources().contains(resource)
                         ? BulkActionResult.Status.FAILURE
                         : BulkActionResult.Status.SUCCESS);
             }
@@ -272,7 +272,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
         switch (patch.getAction()) {
             case LINK:
                 updated = new ProvisioningResult<>();
-                updated.setAny(getAnyLogic().link(
+                updated.setEntity(getAnyLogic().link(
                         patch.getKey(),
                         patch.getResources()));
                 break;
@@ -297,7 +297,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
 
             default:
                 updated = new ProvisioningResult<>();
-                updated.setAny(getAnyLogic().read(patch.getKey()));
+                updated.setEntity(getAnyLogic().read(patch.getKey()));
         }
 
         BulkActionResult result = new BulkActionResult();
@@ -305,7 +305,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
         if (patch.getAction() == ResourceAssociationAction.LINK) {
             for (String resource : patch.getResources()) {
                 result.getResults().put(resource,
-                        updated.getAny().getResources().contains(resource)
+                        updated.getEntity().getResources().contains(resource)
                         ? BulkActionResult.Status.SUCCESS
                         : BulkActionResult.Status.FAILURE);
             }
@@ -335,7 +335,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
                             userPatch.setMustChangePassword(new BooleanReplacePatchItem.Builder().value(true).build());
 
                             result.getResults().put(
-                                    ((UserLogic) logic).update(userPatch, false).getAny().getKey(),
+                                    ((UserLogic) logic).update(userPatch, false).getEntity().getKey(),
                                     BulkActionResult.Status.SUCCESS);
                         } catch (Exception e) {
                             LOG.error("Error performing delete for user {}", key, e);
@@ -351,7 +351,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
                 for (String key : bulkAction.getTargets()) {
                     try {
                         result.getResults().put(
-                                logic.delete(key, isNullPriorityAsync()).getAny().getKey(),
+                                logic.delete(key, isNullPriorityAsync()).getEntity().getKey(),
                                 BulkActionResult.Status.SUCCESS);
                     } catch (Exception e) {
                         LOG.error("Error performing delete for user {}", key, e);
@@ -369,7 +369,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
                         try {
                             result.getResults().put(
                                     ((UserLogic) logic).
-                                    status(statusPatch, isNullPriorityAsync()).getAny().getKey(),
+                                    status(statusPatch, isNullPriorityAsync()).getEntity().getKey(),
                                     BulkActionResult.Status.SUCCESS);
                         } catch (Exception e) {
                             LOG.error("Error performing suspend for user {}", key, e);
@@ -390,7 +390,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
                         try {
                             result.getResults().put(
                                     ((UserLogic) logic).
-                                    status(statusPatch, isNullPriorityAsync()).getAny().getKey(),
+                                    status(statusPatch, isNullPriorityAsync()).getEntity().getKey(),
                                     BulkActionResult.Status.SUCCESS);
                         } catch (Exception e) {
                             LOG.error("Error performing reactivate for user {}", key, e);


Mime
View raw message