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 2018/06/15 15:34:27 UTC

[2/4] syncope git commit: [SYNCOPE-470] Implementation and documentation provided

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPACorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPACorrelationRule.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPACorrelationRule.java
deleted file mode 100644
index 7b4bb1c..0000000
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPACorrelationRule.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.persistence.jpa.entity.policy;
-
-import javax.persistence.Entity;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
-import javax.persistence.UniqueConstraint;
-import org.apache.syncope.common.lib.types.ImplementationType;
-import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.Implementation;
-import org.apache.syncope.core.persistence.api.entity.policy.CorrelationRule;
-import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
-import org.apache.syncope.core.persistence.jpa.entity.JPAAnyType;
-import org.apache.syncope.core.persistence.jpa.entity.JPAImplementation;
-
-@Entity
-@Table(name = JPACorrelationRule.TABLE, uniqueConstraints =
-        @UniqueConstraint(columnNames = { "pullPolicy_id", "anyType_id" }))
-public class JPACorrelationRule extends AbstractGeneratedKeyEntity implements CorrelationRule {
-
-    private static final long serialVersionUID = 4276417265524083919L;
-
-    public static final String TABLE = "CorrelationRule";
-
-    @ManyToOne(optional = false)
-    private JPAPullPolicy pullPolicy;
-
-    @ManyToOne(optional = false)
-    private JPAAnyType anyType;
-
-    @ManyToOne(optional = false)
-    private JPAImplementation implementation;
-
-    @Override
-    public PullPolicy getPullPolicy() {
-        return pullPolicy;
-    }
-
-    @Override
-    public void setPullPolicy(final PullPolicy pullPolicy) {
-        checkType(pullPolicy, JPAPullPolicy.class);
-        this.pullPolicy = (JPAPullPolicy) pullPolicy;
-    }
-
-    @Override
-    public AnyType getAnyType() {
-        return anyType;
-    }
-
-    @Override
-    public void setAnyType(final AnyType anyType) {
-        checkType(anyType, JPAAnyType.class);
-        this.anyType = (JPAAnyType) anyType;
-    }
-
-    @Override
-    public Implementation getImplementation() {
-        return implementation;
-    }
-
-    @Override
-    public void setImplementation(final Implementation implementation) {
-        checkType(implementation, JPAImplementation.class);
-        checkImplementationType(implementation, ImplementationType.PULL_CORRELATION_RULE);
-        this.implementation = (JPAImplementation) implementation;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPolicyUtilsFactory.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPolicyUtilsFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPolicyUtilsFactory.java
index 6ecd1d0..2a616c2 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPolicyUtilsFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPolicyUtilsFactory.java
@@ -22,6 +22,7 @@ import org.apache.syncope.common.lib.policy.AccountPolicyTO;
 import org.apache.syncope.common.lib.policy.PasswordPolicyTO;
 import org.apache.syncope.common.lib.policy.PolicyTO;
 import org.apache.syncope.common.lib.policy.PullPolicyTO;
+import org.apache.syncope.common.lib.policy.PushPolicyTO;
 import org.apache.syncope.common.lib.types.PolicyType;
 import org.apache.syncope.core.persistence.api.entity.policy.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
@@ -67,6 +68,8 @@ public class JPAPolicyUtilsFactory implements PolicyUtilsFactory {
             type = PolicyType.PASSWORD;
         } else if (policyClass == PullPolicyTO.class) {
             type = PolicyType.PULL;
+        } else if (policyClass == PushPolicyTO.class) {
+            type = PolicyType.PUSH;
         } else {
             throw new IllegalArgumentException("Invalid PolicyTO class: " + policyClass.getName());
         }
@@ -78,5 +81,4 @@ public class JPAPolicyUtilsFactory implements PolicyUtilsFactory {
     public PolicyUtils getInstance(final PolicyTO policyTO) {
         return getInstance(policyTO.getClass());
     }
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullCorrelationRuleEntity.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullCorrelationRuleEntity.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullCorrelationRuleEntity.java
new file mode 100644
index 0000000..394ad08
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullCorrelationRuleEntity.java
@@ -0,0 +1,56 @@
+/*
+ * 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.persistence.jpa.entity.policy;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
+import org.apache.syncope.core.persistence.api.entity.policy.PullCorrelationRuleEntity;
+
+@Entity
+@Table(name = JPAPullCorrelationRuleEntity.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "pullPolicy_id", "anyType_id" }))
+public class JPAPullCorrelationRuleEntity extends AbstractCorrelationRuleEntity implements PullCorrelationRuleEntity {
+
+    private static final long serialVersionUID = 4276417265524083919L;
+
+    public static final String TABLE = "PullCorrelationRuleEntity";
+
+    @ManyToOne(optional = false)
+    private JPAPullPolicy pullPolicy;
+
+    @Override
+    protected ImplementationType getImplementationType() {
+        return ImplementationType.PULL_CORRELATION_RULE;
+    }
+
+    @Override
+    public PullPolicy getPullPolicy() {
+        return pullPolicy;
+    }
+
+    @Override
+    public void setPullPolicy(final PullPolicy pullPolicy) {
+        checkType(pullPolicy, JPAPullPolicy.class);
+        this.pullPolicy = (JPAPullPolicy) pullPolicy;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullPolicy.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullPolicy.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullPolicy.java
index b7d0720..076695a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullPolicy.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPullPolicy.java
@@ -23,56 +23,38 @@ import java.util.List;
 import java.util.Optional;
 import javax.persistence.CascadeType;
 import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
 import javax.persistence.FetchType;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
-import javax.validation.constraints.NotNull;
-import org.apache.syncope.common.lib.types.ConflictResolutionAction;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.policy.CorrelationRule;
 import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
+import org.apache.syncope.core.persistence.api.entity.policy.PullCorrelationRuleEntity;
 
 @Entity
 @Table(name = JPAPullPolicy.TABLE)
-public class JPAPullPolicy extends AbstractPolicy implements PullPolicy {
+public class JPAPullPolicy extends AbstractProvisioningPolicy implements PullPolicy {
 
     private static final long serialVersionUID = -6090413855809521279L;
 
     public static final String TABLE = "PullPolicy";
 
-    @Enumerated(EnumType.STRING)
-    @NotNull
-    private ConflictResolutionAction conflictResolutionAction;
-
     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "pullPolicy")
-    private List<JPACorrelationRule> correlationRules = new ArrayList<>();
-
-    @Override
-    public ConflictResolutionAction getConflictResolutionAction() {
-        return conflictResolutionAction;
-    }
-
-    @Override
-    public void setConflictResolutionAction(final ConflictResolutionAction conflictResolutionAction) {
-        this.conflictResolutionAction = conflictResolutionAction;
-    }
+    private List<JPAPullCorrelationRuleEntity> correlationRules = new ArrayList<>();
 
     @Override
-    public boolean add(final CorrelationRule filter) {
-        checkType(filter, JPACorrelationRule.class);
-        return this.correlationRules.add((JPACorrelationRule) filter);
+    public boolean add(final PullCorrelationRuleEntity filter) {
+        checkType(filter, JPAPullCorrelationRuleEntity.class);
+        return this.correlationRules.add((JPAPullCorrelationRuleEntity) filter);
     }
 
     @Override
-    public Optional<? extends CorrelationRule> getCorrelationRule(final AnyType anyType) {
+    public Optional<? extends PullCorrelationRuleEntity> getCorrelationRule(final AnyType anyType) {
         return correlationRules.stream().
                 filter(rule -> anyType != null && anyType.equals(rule.getAnyType())).findFirst();
     }
 
     @Override
-    public List<? extends CorrelationRule> getCorrelationRules() {
+    public List<? extends PullCorrelationRuleEntity> getCorrelationRules() {
         return correlationRules;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushCorrelationRuleEntity.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushCorrelationRuleEntity.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushCorrelationRuleEntity.java
new file mode 100644
index 0000000..bdf05a7
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushCorrelationRuleEntity.java
@@ -0,0 +1,56 @@
+/*
+ * 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.persistence.jpa.entity.policy;
+
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.core.persistence.api.entity.policy.PushPolicy;
+import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
+
+@Entity
+@Table(name = JPAPushCorrelationRuleEntity.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "pushPolicy_id", "anyType_id" }))
+public class JPAPushCorrelationRuleEntity extends AbstractCorrelationRuleEntity implements PushCorrelationRuleEntity {
+
+    private static final long serialVersionUID = 4276417265524083919L;
+
+    public static final String TABLE = "PushCorrelationRuleEntity";
+
+    @ManyToOne(optional = false)
+    private JPAPushPolicy pushPolicy;
+
+    @Override
+    protected ImplementationType getImplementationType() {
+        return ImplementationType.PUSH_CORRELATION_RULE;
+    }
+
+    @Override
+    public PushPolicy getPushPolicy() {
+        return pushPolicy;
+    }
+
+    @Override
+    public void setPushPolicy(final PushPolicy pushPolicy) {
+        checkType(pushPolicy, JPAPushPolicy.class);
+        this.pushPolicy = (JPAPushPolicy) pushPolicy;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushPolicy.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushPolicy.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushPolicy.java
index dcdfc1d..5103647 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushPolicy.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/policy/JPAPushPolicy.java
@@ -18,32 +18,43 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity.policy;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.persistence.CascadeType;
 import javax.persistence.Entity;
-import javax.persistence.Lob;
+import javax.persistence.FetchType;
+import javax.persistence.OneToMany;
 import javax.persistence.Table;
-import org.apache.syncope.common.lib.policy.PushPolicySpec;
-import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.policy.PushPolicy;
+import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
 
 @Entity
 @Table(name = JPAPushPolicy.TABLE)
-public class JPAPushPolicy extends AbstractPolicy implements PushPolicy {
+public class JPAPushPolicy extends AbstractProvisioningPolicy implements PushPolicy {
 
     private static final long serialVersionUID = -5875589156893921113L;
 
     public static final String TABLE = "PushPolicy";
 
-    @Lob
-    private String specification;
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "pushPolicy")
+    private List<JPAPushCorrelationRuleEntity> correlationRules = new ArrayList<>();
 
     @Override
-    public PushPolicySpec getSpecification() {
-        return POJOHelper.deserialize(specification, PushPolicySpec.class);
+    public boolean add(final PushCorrelationRuleEntity filter) {
+        checkType(filter, JPAPushCorrelationRuleEntity.class);
+        return this.correlationRules.add((JPAPushCorrelationRuleEntity) filter);
     }
 
     @Override
-    public void setSpecification(final PushPolicySpec policy) {
-        this.specification = POJOHelper.serialize(policy);
+    public Optional<? extends PushCorrelationRuleEntity> getCorrelationRule(final AnyType anyType) {
+        return correlationRules.stream().
+                filter(rule -> anyType != null && anyType.equals(rule.getAnyType())).findFirst();
     }
 
+    @Override
+    public List<? extends PushCorrelationRuleEntity> getCorrelationRules() {
+        return correlationRules;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
index 6335bcf..b8e218f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAExternalResource.java
@@ -64,9 +64,11 @@ import org.apache.syncope.core.persistence.jpa.entity.JPAConnInstance;
 import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPasswordPolicy;
 import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPullPolicy;
 import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
+import org.apache.syncope.core.persistence.api.entity.policy.PushPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractProvidedKeyEntity;
 import org.apache.syncope.core.persistence.jpa.entity.JPAImplementation;
+import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPushPolicy;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 
 /**
@@ -141,6 +143,9 @@ public class JPAExternalResource extends AbstractProvidedKeyEntity implements Ex
     @ManyToOne(fetch = FetchType.EAGER)
     private JPAPullPolicy pullPolicy;
 
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAPushPolicy pushPolicy;
+
     /**
      * Configuration properties that are overridden from the connector instance.
      */
@@ -338,6 +343,17 @@ public class JPAExternalResource extends AbstractProvidedKeyEntity implements Ex
     }
 
     @Override
+    public PushPolicy getPushPolicy() {
+        return pushPolicy;
+    }
+
+    @Override
+    public void setPushPolicy(final PushPolicy pushPolicy) {
+        checkType(pushPolicy, JPAPushPolicy.class);
+        this.pushPolicy = (JPAPushPolicy) pushPolicy;
+    }
+
+    @Override
     public Set<ConnConfProperty> getConfOverride() {
         Set<ConnConfProperty> confOverride = new HashSet<>();
         if (!StringUtils.isBlank(jsonConf)) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java
index 5b47a75..376534c 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/DummyImplementationLookup.java
@@ -23,16 +23,19 @@ import java.util.Set;
 import org.apache.syncope.common.lib.policy.AccountRuleConf;
 import org.apache.syncope.common.lib.policy.PasswordRuleConf;
 import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
+import org.apache.syncope.common.lib.policy.PushCorrelationRuleConf;
 import org.apache.syncope.common.lib.report.ReportletConf;
 import org.apache.syncope.common.lib.types.ImplementationType;
 import org.apache.syncope.core.persistence.api.ImplementationLookup;
 import org.apache.syncope.core.persistence.api.dao.AccountRule;
 import org.apache.syncope.core.persistence.api.dao.PasswordRule;
 import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PushCorrelationRule;
 import org.apache.syncope.core.persistence.api.dao.Reportlet;
 import org.apache.syncope.core.persistence.jpa.dao.DefaultAccountRule;
 import org.apache.syncope.core.persistence.jpa.dao.DefaultPasswordRule;
 import org.apache.syncope.core.persistence.jpa.dao.DefaultPullCorrelationRule;
+import org.apache.syncope.core.persistence.jpa.dao.DefaultPushCorrelationRule;
 import org.springframework.stereotype.Component;
 
 @Component
@@ -87,6 +90,13 @@ public class DummyImplementationLookup implements ImplementationLookup {
     }
 
     @Override
+    public Class<? extends PushCorrelationRule> getPushCorrelationRuleClass(
+            final Class<? extends PushCorrelationRuleConf> pushCorrelationRuleConfClass) {
+
+        return DefaultPushCorrelationRule.class;
+    }
+
+    @Override
     public Set<Class<?>> getAuditAppenderClasses() {
         return Collections.emptySet();
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ImplementationTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ImplementationTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ImplementationTest.java
index c0982e6..2f29e17 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ImplementationTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ImplementationTest.java
@@ -43,7 +43,7 @@ public class ImplementationTest extends AbstractTest {
         List<Implementation> implementations = implementationDAO.findAll();
         assertFalse(implementations.isEmpty());
 
-        assertEquals(17, implementations.size());
+        assertEquals(18, implementations.size());
 
         implementations = implementationDAO.find(ImplementationType.PULL_ACTIONS);
         assertEquals(1, implementations.size());
@@ -68,6 +68,9 @@ public class ImplementationTest extends AbstractTest {
 
         implementations = implementationDAO.find(ImplementationType.PULL_CORRELATION_RULE);
         assertEquals(1, implementations.size());
+
+        implementations = implementationDAO.find(ImplementationType.PUSH_CORRELATION_RULE);
+        assertEquals(1, implementations.size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
index 2fa7345..6a6b16c 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PolicyTest.java
@@ -28,6 +28,7 @@ import java.util.List;
 import java.util.UUID;
 import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
 import org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf;
+import org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf;
 import org.apache.syncope.common.lib.types.ConflictResolutionAction;
 import org.apache.syncope.common.lib.types.ImplementationEngine;
 import org.apache.syncope.common.lib.types.ImplementationType;
@@ -37,7 +38,6 @@ import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
 import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
 import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
-import org.apache.syncope.core.persistence.api.entity.policy.CorrelationRule;
 import org.apache.syncope.core.persistence.api.entity.policy.Policy;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
 import org.junit.jupiter.api.Test;
@@ -45,6 +45,9 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
 import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.entity.policy.PullCorrelationRuleEntity;
+import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
+import org.apache.syncope.core.persistence.api.entity.policy.PushPolicy;
 
 @Transactional("Master")
 public class PolicyTest extends AbstractTest {
@@ -67,17 +70,28 @@ public class PolicyTest extends AbstractTest {
 
     @Test
     public void findByKey() {
-        PullPolicy policy = policyDAO.find("880f8553-069b-4aed-9930-2cd53873f544");
-        assertNotNull(policy);
-
-        CorrelationRule rule = policy.getCorrelationRule(anyTypeDAO.findUser()).orElse(null);
-        assertNotNull(rule);
-        DefaultPullCorrelationRuleConf ruleConf =
-                POJOHelper.deserialize(rule.getImplementation().getBody(), DefaultPullCorrelationRuleConf.class);
-        assertNotNull(ruleConf);
-        assertEquals(2, ruleConf.getSchemas().size());
-        assertTrue(ruleConf.getSchemas().contains("username"));
-        assertTrue(ruleConf.getSchemas().contains("firstname"));
+        PullPolicy pullPolicy = policyDAO.find("880f8553-069b-4aed-9930-2cd53873f544");
+        assertNotNull(pullPolicy);
+
+        PullCorrelationRuleEntity pullCR = pullPolicy.getCorrelationRule(anyTypeDAO.findUser()).orElse(null);
+        assertNotNull(pullCR);
+        DefaultPullCorrelationRuleConf pullCRConf =
+                POJOHelper.deserialize(pullCR.getImplementation().getBody(), DefaultPullCorrelationRuleConf.class);
+        assertNotNull(pullCRConf);
+        assertEquals(2, pullCRConf.getSchemas().size());
+        assertTrue(pullCRConf.getSchemas().contains("username"));
+        assertTrue(pullCRConf.getSchemas().contains("firstname"));
+
+        PushPolicy pushPolicy = policyDAO.find("fb6530e5-892d-4f47-a46b-180c5b6c5c83");
+        assertNotNull(pushPolicy);
+
+        PushCorrelationRuleEntity pushCR = pushPolicy.getCorrelationRule(anyTypeDAO.findUser()).orElse(null);
+        assertNotNull(pushCR);
+        DefaultPushCorrelationRuleConf pushCRConf =
+                POJOHelper.deserialize(pushCR.getImplementation().getBody(), DefaultPushCorrelationRuleConf.class);
+        assertNotNull(pushCRConf);
+        assertEquals(1, pushCRConf.getSchemas().size());
+        assertTrue(pushCRConf.getSchemas().contains("email"));
     }
 
     @Test
@@ -103,7 +117,7 @@ public class PolicyTest extends AbstractTest {
         impl1.setBody(PullCorrelationRule.class.getName());
         impl1 = implementationDAO.save(impl1);
 
-        CorrelationRule rule1 = entityFactory.newEntity(CorrelationRule.class);
+        PullCorrelationRuleEntity rule1 = entityFactory.newEntity(PullCorrelationRuleEntity.class);
         rule1.setAnyType(anyTypeDAO.findUser());
         rule1.setPullPolicy(policy);
         rule1.setImplementation(impl1);
@@ -116,7 +130,7 @@ public class PolicyTest extends AbstractTest {
         impl2.setBody(PullCorrelationRule.class.getName());
         impl2 = implementationDAO.save(impl2);
 
-        CorrelationRule rule2 = entityFactory.newEntity(CorrelationRule.class);
+        PullCorrelationRuleEntity rule2 = entityFactory.newEntity(PullCorrelationRuleEntity.class);
         rule2.setAnyType(anyTypeDAO.findGroup());
         rule2.setPullPolicy(policy);
         rule2.setImplementation(impl2);

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 3243cf2..3c33586 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -640,11 +640,18 @@ under the License.
   <PullPolicy id="880f8553-069b-4aed-9930-2cd53873f544" description="another pull policy" conflictResolutionAction="ALL"/>
   <Implementation id="TestPullCorrelationRule" type="PULL_CORRELATION_RULE" engine="JAVA"
                   body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf","name":"org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf","schemas":["username","firstname"]}'/>
-  <CorrelationRule id="10e3d196-7486-4c88-aefd-59e40d93a0c1" pullPolicy_id="880f8553-069b-4aed-9930-2cd53873f544" 
-                   anyType_id="USER" implementation_id="TestPullCorrelationRule"/>
+  <PullCorrelationRuleEntity id="10e3d196-7486-4c88-aefd-59e40d93a0c1" pullPolicy_id="880f8553-069b-4aed-9930-2cd53873f544" 
+                             anyType_id="USER" implementation_id="TestPullCorrelationRule"/>
   <PullPolicy id="4ad10d94-e002-4b3f-b771-16089cc71da9" description="pull policy 1" conflictResolutionAction="IGNORE"/>
   <PullPolicy id="9454b0d7-2610-400a-be82-fc23cf553dd6" description="pull policy for java rule" conflictResolutionAction="IGNORE"/>
 
+  <!-- push policies -->
+  <PushPolicy id="fb6530e5-892d-4f47-a46b-180c5b6c5c83" description="a push policy" conflictResolutionAction="IGNORE"/>
+  <Implementation id="TestPushCorrelationRule" type="PUSH_CORRELATION_RULE" engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf","name":"org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf","schemas":["email"]}'/>
+  <PushCorrelationRuleEntity id="24463935-32a0-4272-bc78-04d6d0adc69e" pushPolicy_id="fb6530e5-892d-4f47-a46b-180c5b6c5c83" 
+                             anyType_id="USER" implementation_id="TestPushCorrelationRule"/>
+  
   <ConnInstance id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" displayName="ConnInstance100"
                 adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
                 location="${connid.location}"

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
index e5d23a9..1cc30c6 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/MappingManager.java
@@ -65,6 +65,17 @@ public interface MappingManager {
     List<PlainAttrValue> getIntValues(Provision provision, Item mapItem, IntAttrName intAttrName, Any<?> any);
 
     /**
+     * Prepare attribute for sending to a connector instance.
+     *
+     * @param provision provision information
+     * @param item mapping item
+     * @param any given any object
+     * @param password clear-text password
+     * @return connObjectLink (if it is the case) + prepared attribute
+     */
+    Pair<String, Attribute> prepareAttr(Provision provision, Item item, Any<?> any, String password);
+
+    /**
      * Prepare attributes for sending to a connector instance.
      *
      * @param any given any object

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java
index 4c02da1..9aa3050 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ProvisioningProfile.java
@@ -34,7 +34,7 @@ public class ProvisioningProfile<T extends ProvisioningTask, A extends Provision
 
     private boolean dryRun;
 
-    private ConflictResolutionAction resAct;
+    private ConflictResolutionAction conflictResolutionAction;
 
     private final List<A> actions = new ArrayList<>();
 
@@ -63,12 +63,12 @@ public class ProvisioningProfile<T extends ProvisioningTask, A extends Provision
         this.dryRun = dryRun;
     }
 
-    public ConflictResolutionAction getResAct() {
-        return resAct;
+    public ConflictResolutionAction getConflictResolutionAction() {
+        return conflictResolutionAction;
     }
 
-    public void setResAct(final ConflictResolutionAction resAct) {
-        this.resAct = resAct;
+    public void setConflictResolutionAction(final ConflictResolutionAction conflictResolutionAction) {
+        this.conflictResolutionAction = conflictResolutionAction;
     }
 
     public List<A> getActions() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index 5186a70..fbaf761 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -304,23 +304,18 @@ public class MappingManagerImpl implements MappingManager {
         return Pair.of(connObjectKey, attributes);
     }
 
-    /**
-     * Prepare an attribute to be sent to a connector instance.
-     *
-     * @param provision external resource
-     * @param mapItem mapping item for the given attribute
-     * @param any given any object
-     * @param password clear-text password
-     * @return connObjectKey + prepared attribute
-     */
-    private Pair<String, Attribute> prepareAttr(
-            final Provision provision, final Item mapItem, final Any<?> any, final String password) {
+    @Override
+    public Pair<String, Attribute> prepareAttr(
+            final Provision provision,
+            final Item item,
+            final Any<?> any,
+            final String password) {
 
         IntAttrName intAttrName;
         try {
-            intAttrName = intAttrNameParser.parse(mapItem.getIntAttrName(), provision.getAnyType().getKind());
+            intAttrName = intAttrNameParser.parse(item.getIntAttrName(), provision.getAnyType().getKind());
         } catch (ParseException e) {
-            LOG.error("Invalid intAttrName '{}' specified, ignoring", mapItem.getIntAttrName(), e);
+            LOG.error("Invalid intAttrName '{}' specified, ignoring", item.getIntAttrName(), e);
             return null;
         }
 
@@ -345,13 +340,13 @@ public class MappingManagerImpl implements MappingManager {
             }
         }
 
-        List<PlainAttrValue> values = getIntValues(provision, mapItem, intAttrName, any);
+        List<PlainAttrValue> values = getIntValues(provision, item, intAttrName, any);
 
         LOG.debug("Define mapping for: "
-                + "\n* ExtAttrName " + mapItem.getExtAttrName()
-                + "\n* is connObjectKey " + mapItem.isConnObjectKey()
-                + "\n* is password " + mapItem.isPassword()
-                + "\n* mandatory condition " + mapItem.getMandatoryCondition()
+                + "\n* ExtAttrName " + item.getExtAttrName()
+                + "\n* is connObjectKey " + item.isConnObjectKey()
+                + "\n* is password " + item.isPassword()
+                + "\n* mandatory condition " + item.getMandatoryCondition()
                 + "\n* Schema " + intAttrName.getSchemaName()
                 + "\n* ClassType " + schemaType.getType().getName()
                 + "\n* Values " + values);
@@ -370,9 +365,9 @@ public class MappingManagerImpl implements MappingManager {
                 }
             }
 
-            if (mapItem.isConnObjectKey()) {
+            if (item.isConnObjectKey()) {
                 result = Pair.of(objValues.isEmpty() ? null : objValues.iterator().next().toString(), null);
-            } else if (mapItem.isPassword() && any instanceof User) {
+            } else if (item.isPassword() && any instanceof User) {
                 String passwordAttrValue = password;
                 if (StringUtils.isBlank(passwordAttrValue)) {
                     User user = (User) any;
@@ -398,8 +393,8 @@ public class MappingManagerImpl implements MappingManager {
                 }
             } else {
                 result = Pair.of(null, objValues.isEmpty()
-                        ? AttributeBuilder.build(mapItem.getExtAttrName())
-                        : AttributeBuilder.build(mapItem.getExtAttrName(), objValues));
+                        ? AttributeBuilder.build(item.getExtAttrName())
+                        : AttributeBuilder.build(item.getExtAttrName(), objValues));
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index 2ced472..a06d54a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -59,6 +59,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
@@ -593,9 +594,7 @@ abstract class AbstractAnyDataBinder {
             anyTO.getVirAttrs().add(attrTOBuilder.build());
         });
 
-        resources.forEach(resource -> {
-            anyTO.getResources().add(resource.getKey());
-        });
+        anyTO.getResources().addAll(resources.stream().map(Entity::getKey).collect(Collectors.toSet()));
     }
 
     protected RelationshipTO getRelationshipTO(final String relationshipType, final Any<?> otherEnd) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index e09ab0e..129d0e4 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -423,10 +423,10 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
         }
 
         // check if some connObjectKey was changed by the update above
-        Map<String, String> newcCnnObjectKeys = getConnObjectKeys(anyObject, anyUtils);
+        Map<String, String> newConnObjectKeys = getConnObjectKeys(anyObject, anyUtils);
         oldConnObjectKeys.entrySet().stream().
-                filter(entry -> newcCnnObjectKeys.containsKey(entry.getKey())
-                && !entry.getValue().equals(newcCnnObjectKeys.get(entry.getKey()))).
+                filter(entry -> newConnObjectKeys.containsKey(entry.getKey())
+                && !entry.getValue().equals(newConnObjectKeys.get(entry.getKey()))).
                 forEach(entry -> {
                     propByRes.addOldConnObjectKey(entry.getKey(), entry.getValue());
                     propByRes.add(ResourceOperation.UPDATE, entry.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
index 73d653e..91df46f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
@@ -40,6 +40,7 @@ import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
 import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
 import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PushCorrelationRule;
 import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
 import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
@@ -128,6 +129,10 @@ public class ImplementationDataBinderImpl implements ImplementationDataBinder {
                     base = PullCorrelationRule.class;
                     break;
 
+                case PUSH_CORRELATION_RULE:
+                    base = PushCorrelationRule.class;
+                    break;
+
                 case VALIDATOR:
                     base = Validator.class;
                     break;
@@ -152,12 +157,13 @@ public class ImplementationDataBinderImpl implements ImplementationDataBinder {
                 }
             } else if (implementation.getType() == ImplementationType.ACCOUNT_RULE
                     || implementation.getType() == ImplementationType.PASSWORD_RULE
-                    || implementation.getType() == ImplementationType.PULL_CORRELATION_RULE) {
+                    || implementation.getType() == ImplementationType.PULL_CORRELATION_RULE
+                    || implementation.getType() == ImplementationType.PUSH_CORRELATION_RULE) {
 
                 RuleConf rule = POJOHelper.deserialize(implementation.getBody(), RuleConf.class);
                 if (rule == null) {
-                    sce.getElements().
-                            add("Could not deserialize as neither Account, Password nor PullCorrelation RuleConf");
+                    sce.getElements().add("Could not deserialize as neither "
+                            + "Account, Password, Pull nor Push Correlation RuleConf");
                     throw sce;
                 }
             } else {
@@ -188,5 +194,4 @@ public class ImplementationDataBinderImpl implements ImplementationDataBinder {
         BeanUtils.copyProperties(implementation, implementationTO);
         return implementationTO;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java
index a1a400c..53122b5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/PolicyDataBinderImpl.java
@@ -24,6 +24,7 @@ import org.apache.syncope.common.lib.policy.PolicyTO;
 import org.apache.syncope.common.lib.policy.AccountPolicyTO;
 import org.apache.syncope.common.lib.policy.PasswordPolicyTO;
 import org.apache.syncope.common.lib.policy.PullPolicyTO;
+import org.apache.syncope.common.lib.policy.PushPolicyTO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
@@ -37,9 +38,11 @@ import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
 import org.apache.syncope.core.persistence.api.entity.Realm;
-import org.apache.syncope.core.persistence.api.entity.policy.CorrelationRule;
 import org.apache.syncope.core.persistence.api.entity.policy.Policy;
+import org.apache.syncope.core.persistence.api.entity.policy.PullCorrelationRuleEntity;
 import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
+import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
+import org.apache.syncope.core.persistence.api.entity.policy.PushPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -138,9 +141,9 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
                 if (anyType == null) {
                     LOG.debug("Invalid AnyType {} specified, ignoring...", type);
                 } else {
-                    CorrelationRule correlationRule = pullPolicy.getCorrelationRule(anyType).orElse(null);
+                    PullCorrelationRuleEntity correlationRule = pullPolicy.getCorrelationRule(anyType).orElse(null);
                     if (correlationRule == null) {
-                        correlationRule = entityFactory.newEntity(CorrelationRule.class);
+                        correlationRule = entityFactory.newEntity(PullCorrelationRuleEntity.class);
                         correlationRule.setAnyType(anyType);
                         correlationRule.setPullPolicy(pullPolicy);
                         pullPolicy.add(correlationRule);
@@ -148,7 +151,7 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
 
                     Implementation rule = implementationDAO.find(impl);
                     if (rule == null) {
-                        throw new NotFoundException("Implementation " + type);
+                        throw new NotFoundException("Implementation " + type + " " + impl);
                     }
                     correlationRule.setImplementation(rule);
                 }
@@ -156,6 +159,39 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
             // remove all rules not contained in the TO
             pullPolicy.getCorrelationRules().removeIf(anyFilter
                     -> !pullPolicyTO.getCorrelationRules().containsKey(anyFilter.getAnyType().getKey()));
+        } else if (policyTO instanceof PushPolicyTO) {
+            if (result == null) {
+                result = (T) entityFactory.newEntity(PushPolicy.class);
+            }
+
+            PushPolicy pushPolicy = PushPolicy.class.cast(result);
+            PushPolicyTO pushPolicyTO = PushPolicyTO.class.cast(policyTO);
+
+            pushPolicy.setConflictResolutionAction(pushPolicyTO.getConflictResolutionAction());
+
+            pushPolicyTO.getCorrelationRules().forEach((type, impl) -> {
+                AnyType anyType = anyTypeDAO.find(type);
+                if (anyType == null) {
+                    LOG.debug("Invalid AnyType {} specified, ignoring...", type);
+                } else {
+                    PushCorrelationRuleEntity correlationRule = pushPolicy.getCorrelationRule(anyType).orElse(null);
+                    if (correlationRule == null) {
+                        correlationRule = entityFactory.newEntity(PushCorrelationRuleEntity.class);
+                        correlationRule.setAnyType(anyType);
+                        correlationRule.setPushPolicy(pushPolicy);
+                        pushPolicy.add(correlationRule);
+                    }
+
+                    Implementation rule = implementationDAO.find(impl);
+                    if (rule == null) {
+                        throw new NotFoundException("Implementation " + type + " " + impl);
+                    }
+                    correlationRule.setImplementation(rule);
+                }
+            });
+            // remove all rules not contained in the TO
+            pushPolicy.getCorrelationRules().removeIf(anyFilter
+                    -> !pushPolicyTO.getCorrelationRules().containsKey(anyFilter.getAnyType().getKey()));
         }
 
         if (result != null) {
@@ -212,6 +248,15 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
             pullPolicy.getCorrelationRules().forEach(rule -> {
                 pullPolicyTO.getCorrelationRules().put(rule.getAnyType().getKey(), rule.getImplementation().getKey());
             });
+        } else if (policy instanceof PushPolicy) {
+            PushPolicy pushPolicy = PushPolicy.class.cast(policy);
+            PushPolicyTO pushPolicyTO = new PushPolicyTO();
+            policyTO = (T) pushPolicyTO;
+
+            pushPolicyTO.setConflictResolutionAction(((PushPolicy) policy).getConflictResolutionAction());
+            pushPolicy.getCorrelationRules().forEach(rule -> {
+                pushPolicyTO.getCorrelationRules().put(rule.getAnyType().getKey(), rule.getImplementation().getKey());
+            });
         }
 
         if (policyTO != null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index fedc288..de0c9ac 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -65,6 +65,7 @@ import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
+import org.apache.syncope.core.persistence.api.entity.policy.PushPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResourceHistoryConf;
 import org.apache.syncope.core.persistence.api.entity.resource.Item;
 import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
@@ -381,6 +382,9 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
         resource.setPullPolicy(resourceTO.getPullPolicy() == null
                 ? null : (PullPolicy) policyDAO.find(resourceTO.getPullPolicy()));
 
+        resource.setPushPolicy(resourceTO.getPushPolicy() == null
+                ? null : (PushPolicy) policyDAO.find(resourceTO.getPushPolicy()));
+
         resource.setConfOverride(new HashSet<>(resourceTO.getConfOverride()));
 
         resource.setOverrideCapabilities(resourceTO.isOverrideCapabilities());
@@ -675,6 +679,9 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
         resourceTO.setPullPolicy(resource.getPullPolicy() == null
                 ? null : resource.getPullPolicy().getKey());
 
+        resourceTO.setPushPolicy(resource.getPushPolicy() == null
+                ? null : resource.getPushPolicy().getKey());
+
         resourceTO.getConfOverride().addAll(resource.getConfOverride());
         Collections.sort(resourceTO.getConfOverride());
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index fa9cb9f..aaec195 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -525,10 +525,10 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
         }
 
         // check if some connObjectKey was changed by the update above
-        Map<String, String> newcCnnObjectKeys = getConnObjectKeys(user, anyUtils);
+        Map<String, String> newConnObjectKeys = getConnObjectKeys(user, anyUtils);
         oldConnObjectKeys.entrySet().stream().
-                filter(entry -> newcCnnObjectKeys.containsKey(entry.getKey())
-                && !entry.getValue().equals(newcCnnObjectKeys.get(entry.getKey()))).
+                filter(entry -> newConnObjectKeys.containsKey(entry.getKey())
+                && !entry.getValue().equals(newConnObjectKeys.get(entry.getKey()))).
                 forEach(entry -> {
                     propByRes.addOldConnObjectKey(entry.getKey(), entry.getValue());
                     propByRes.add(ResourceOperation.UPDATE, entry.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/SyncopeJexlFunctions.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/SyncopeJexlFunctions.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/SyncopeJexlFunctions.java
index 684c021..bf770d1 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/SyncopeJexlFunctions.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/SyncopeJexlFunctions.java
@@ -33,7 +33,7 @@ public class SyncopeJexlFunctions {
     /**
      * Converts realm's full path into the equivalent DN.
      *
-     * Example: {@code}/a/b/c{@code} becomes {@code}ou=c,ou=b,ou=a{@code}.
+     * Example: {@code /a/b/c} becomes {@code ou=c,ou=b,ou=a}.
      *
      * @param fullPath realm's full path
      * @param attr attribute name for DN
@@ -46,8 +46,8 @@ public class SyncopeJexlFunctions {
     /**
      * Converts realm's full path into the equivalent DN.
      *
-     * Example: {@code}/a/b/c{@code} becomes {@code},ou=c,ou=b,ou=a{@code}, when {@code}prefix{@code} is
-     * {@code}&quot;,&quot;{@code}
+     * Example: {@code /a/b/c} becomes {@code ,ou=c,ou=b,ou=a}, when {@code prefix} is
+     * {@code &quot;,&quot;}
      *
      * @param fullPath realm's full path
      * @param attr attribute name for DN

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
index e51690e..6de2eec 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/AbstractPullResultHandler.java
@@ -501,7 +501,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
 
                         AnyPatch anyPatch = null;
                         if (unlink) {
-                            anyPatch = newPatch(key);
+                            anyPatch = getAnyUtils().newAnyPatch(key);
                             anyPatch.getResources().add(new StringPatchItem.Builder().
                                     operation(PatchOperation.DELETE).
                                     value(profile.getTask().getResource().getKey()).build());
@@ -604,7 +604,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
                             }
                         }
 
-                        AnyPatch anyPatch = newPatch(before.getKey());
+                        AnyPatch anyPatch = getAnyUtils().newAnyPatch(before.getKey());
                         anyPatch.getResources().add(new StringPatchItem.Builder().
                                 operation(unlink ? PatchOperation.DELETE : PatchOperation.ADD_REPLACE).
                                 value(profile.getTask().getResource().getKey()).build());
@@ -804,9 +804,9 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
                     processed.getUid().getUidValue(), processed.getObject().getObjectClass(), anyKeys);
 
             if (anyKeys.size() > 1) {
-                switch (profile.getResAct()) {
+                switch (profile.getConflictResolutionAction()) {
                     case IGNORE:
-                        throw new IllegalStateException("More than one match " + anyKeys);
+                        throw new IllegalStateException("More than one match: " + anyKeys);
 
                     case FIRSTMATCH:
                         anyKeys = anyKeys.subList(0, 1);
@@ -915,8 +915,10 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
             this.latestResult = result;
         }
 
+        AnyUtils anyUtils = getAnyUtils();
+
         notificationManager.createTasks(AuditElements.EventCategoryType.PULL,
-                getAnyUtils().anyTypeKind().name().toLowerCase(),
+                anyUtils.anyTypeKind().name().toLowerCase(),
                 profile.getTask().getResource().getKey(),
                 event,
                 result,
@@ -926,7 +928,7 @@ public abstract class AbstractPullResultHandler extends AbstractSyncopeResultHan
                 furtherInput);
 
         auditManager.audit(AuditElements.EventCategoryType.PULL,
-                getAnyUtils().anyTypeKind().name().toLowerCase(),
+                anyUtils.anyTypeKind().name().toLowerCase(),
                 profile.getTask().getResource().getKey(),
                 event,
                 result,

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/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 7a98f90..06f6da9 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
@@ -19,12 +19,10 @@
 package org.apache.syncope.core.provisioning.java.pushpull;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
+import java.util.stream.Collectors;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.syncope.common.lib.patch.AnyPatch;
 import org.apache.syncope.common.lib.patch.StringPatchItem;
@@ -42,24 +40,17 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningReport;
 import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
 import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.AnyUtils;
-import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
-import org.apache.syncope.core.persistence.api.entity.resource.Item;
-import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.provisioning.api.AuditManager;
 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.notification.NotificationManager;
 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.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.ObjectClass;
 import org.quartz.JobExecutionException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.quartz.SchedulerFactoryBean;
@@ -69,6 +60,9 @@ import org.springframework.transaction.annotation.Transactional;
 public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHandler<PushTask, PushActions>
         implements SyncopePushResultHandler {
 
+    @Autowired
+    protected PushUtils pushUtils;
+
     /**
      * Notification Manager.
      */
@@ -96,25 +90,17 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         }
     }
 
-    protected void update(final Any<?> any, final ProvisioningReport result) {
-        boolean changepwd;
-        Collection<String> resourceKeys;
-        if (any instanceof User) {
-            changepwd = true;
-            resourceKeys = userDAO.findAllResourceKeys(any.getKey());
-        } else if (any instanceof AnyObject) {
-            changepwd = false;
-            resourceKeys = anyObjectDAO.findAllResourceKeys(any.getKey());
-        } else {
-            changepwd = false;
-            resourceKeys = groupDAO.findAllResourceKeys(any.getKey());
-        }
+    protected void update(final Any<?> any, final ConnectorObject beforeObj, final ProvisioningReport result) {
+        boolean changepwd = any instanceof User;
+        List<String> ownedResources = getAnyUtils().getAllResources(any).stream().
+                map(Entity::getKey).collect(Collectors.toList());
 
-        List<String> noPropResources = new ArrayList<>(resourceKeys);
+        List<String> noPropResources = new ArrayList<>(ownedResources);
         noPropResources.remove(profile.getTask().getResource().getKey());
 
         PropagationByResource propByRes = new PropagationByResource();
-        propByRes.add(ResourceOperation.CREATE, profile.getTask().getResource().getKey());
+        propByRes.add(ResourceOperation.UPDATE, profile.getTask().getResource().getKey());
+        propByRes.addOldConnObjectKey(profile.getTask().getResource().getKey(), beforeObj.getUid().getUidValue());
 
         PropagationReporter reporter = taskExecutor.execute(propagationManager.getUpdateTasks(
                 any.getType().getKind(),
@@ -128,16 +114,20 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         reportPropagation(result, reporter);
     }
 
-    protected void deprovision(final Any<?> any, final ProvisioningReport result) {
+    protected void deprovision(final Any<?> any, final ConnectorObject beforeObj, final ProvisioningReport result) {
         AnyTO before = getAnyTO(any.getKey());
 
         List<String> noPropResources = new ArrayList<>(before.getResources());
         noPropResources.remove(profile.getTask().getResource().getKey());
 
+        PropagationByResource propByRes = new PropagationByResource();
+        propByRes.add(ResourceOperation.DELETE, profile.getTask().getResource().getKey());
+        propByRes.addOldConnObjectKey(profile.getTask().getResource().getKey(), beforeObj.getUid().getUidValue());
+
         PropagationReporter reporter = taskExecutor.execute(propagationManager.getDeleteTasks(
                 any.getType().getKind(),
                 any.getKey(),
-                null,
+                propByRes,
                 noPropResources),
                 false);
         reportPropagation(result, reporter);
@@ -163,7 +153,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
     }
 
     protected void link(final Any<?> any, final boolean unlink, final ProvisioningReport result) {
-        AnyPatch patch = newPatch(any.getKey());
+        AnyPatch patch = getAnyUtils().newAnyPatch(any.getKey());
         patch.getResources().add(new StringPatchItem.Builder().
                 operation(unlink ? PatchOperation.DELETE : PatchOperation.ADD_REPLACE).
                 value(profile.getTask().getResource().getKey()).build());
@@ -173,19 +163,19 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         result.setStatus(ProvisioningReport.Status.SUCCESS);
     }
 
-    protected void unassign(final Any<?> any, final ProvisioningReport result) {
-        AnyPatch patch = newPatch(any.getKey());
+    protected void unassign(final Any<?> any, final ConnectorObject beforeObj, final ProvisioningReport result) {
+        AnyPatch patch = getAnyUtils().newAnyPatch(any.getKey());
         patch.getResources().add(new StringPatchItem.Builder().
                 operation(PatchOperation.DELETE).
                 value(profile.getTask().getResource().getKey()).build());
 
         update(patch);
 
-        deprovision(any, result);
+        deprovision(any, beforeObj, result);
     }
 
     protected void assign(final Any<?> any, final Boolean enabled, final ProvisioningReport result) {
-        AnyPatch patch = newPatch(any.getKey());
+        AnyPatch patch = getAnyUtils().newAnyPatch(any.getKey());
         patch.getResources().add(new StringPatchItem.Builder().
                 operation(PatchOperation.ADD_REPLACE).
                 value(profile.getTask().getResource().getKey()).build());
@@ -195,37 +185,20 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         provision(any, enabled, result);
     }
 
-    protected ConnectorObject getRemoteObject(
-            final ObjectClass objectClass,
-            final String connObjectKey,
-            final String connObjectKeyValue,
-            final boolean ignoreCaseMatch,
-            final Iterator<? extends Item> iterator) {
-
-        ConnectorObject obj = null;
-        try {
-            obj = profile.getConnector().getObject(
-                    objectClass,
-                    AttributeBuilder.build(connObjectKey, connObjectKeyValue),
-                    ignoreCaseMatch,
-                    MappingUtils.buildOperationOptions(iterator));
-        } catch (TimeoutException toe) {
-            LOG.debug("Request timeout", toe);
-            throw toe;
-        } catch (RuntimeException ignore) {
-            LOG.debug("While resolving {}", connObjectKeyValue, ignore);
-        }
-
-        return obj;
-    }
-
     @Transactional(propagation = Propagation.REQUIRES_NEW)
     @Override
     public boolean handle(final String anyKey) {
         Any<?> any = null;
         try {
-            any = getAny(anyKey);
-            doHandle(any);
+            any = getAnyUtils().dao().authFind(anyKey);
+
+            Provision provision = profile.getTask().getResource().getProvision(any.getType()).orElse(null);
+            if (provision == null) {
+                throw new JobExecutionException("No provision found on " + profile.getTask().getResource() + " for "
+                        + any.getType().getKey());
+            }
+
+            doHandle(any, provision);
             return true;
         } catch (IgnoreProvisionException e) {
             ProvisioningReport result = profile.getResults().stream().
@@ -251,9 +224,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         }
     }
 
-    protected void doHandle(final Any<?> any) throws JobExecutionException {
-        AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
-
+    protected void doHandle(final Any<?> any, final Provision provision) throws JobExecutionException {
         ProvisioningReport result = new ProvisioningReport();
         profile.getResults().add(result);
 
@@ -261,32 +232,39 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
         result.setAnyType(any.getType().getKey());
         result.setName(getName(any));
 
-        Boolean enabled = any instanceof User && profile.getTask().isSyncStatus()
-                ? ((User) any).isSuspended() ? Boolean.FALSE : Boolean.TRUE
-                : null;
-
         LOG.debug("Propagating {} with key {} towards {}",
-                anyUtils.anyTypeKind(), any.getKey(), profile.getTask().getResource());
+                any.getType().getKind(), any.getKey(), profile.getTask().getResource());
+
+        // Try to read remote object BEFORE any actual operation
+        List<ConnectorObject> connObjs = pushUtils.match(profile.getConnector(), any, provision);
+        LOG.debug("Match(es) found for {} as {}: {}", any, provision.getObjectClass(), connObjs);
+
+        if (connObjs.size() > 1) {
+            switch (profile.getConflictResolutionAction()) {
+                case IGNORE:
+                    throw new IllegalStateException("More than one match: " + connObjs);
+
+                case FIRSTMATCH:
+                    connObjs = connObjs.subList(0, 1);
+                    break;
+
+                case LASTMATCH:
+                    connObjs = connObjs.subList(connObjs.size() - 1, connObjs.size());
+                    break;
+
+                default:
+            }
+        }
+        ConnectorObject beforeObj = connObjs.isEmpty() ? null : connObjs.get(0);
 
         Object output = null;
         Result resultStatus = null;
 
-        // Try to read remote object BEFORE any actual operation
-        Optional<? extends Provision> provision = profile.getTask().getResource().getProvision(any.getType());
-        Optional<MappingItem> connObjectKey = MappingUtils.getConnObjectKeyItem(provision.get());
-        Optional<String> connObjecKeyValue = mappingManager.getConnObjectKeyValue(any, provision.get());
-
-        ConnectorObject beforeObj = null;
-        if (connObjectKey.isPresent() && connObjecKeyValue.isPresent()) {
-            beforeObj = getRemoteObject(
-                    provision.get().getObjectClass(),
-                    connObjectKey.get().getExtAttrName(),
-                    connObjecKeyValue.get(),
-                    provision.get().isIgnoreCaseMatch(),
-                    provision.get().getMapping().getItems().iterator());
-        } else {
-            LOG.debug("ConnObjectKeyItem {} or its value {} are null", connObjectKey, connObjecKeyValue);
-        }
+        Boolean enabled = any instanceof User && profile.getTask().isSyncStatus()
+                ? ((User) any).isSuspended()
+                ? Boolean.FALSE
+                : Boolean.TRUE
+                : null;
 
         Boolean status = profile.getTask().isSyncStatus() ? enabled : null;
 
@@ -376,7 +354,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                                 LOG.debug("PushTask not configured for update");
                                 result.setStatus(ProvisioningReport.Status.IGNORE);
                             } else {
-                                update(any, result);
+                                update(any, beforeObj, result);
                             }
                             break;
 
@@ -389,7 +367,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                                 LOG.debug("PushTask not configured for delete");
                                 result.setStatus(ProvisioningReport.Status.IGNORE);
                             } else {
-                                deprovision(any, result);
+                                deprovision(any, beforeObj, result);
                             }
                             break;
 
@@ -402,7 +380,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                                 LOG.debug("PushTask not configured for delete");
                                 result.setStatus(ProvisioningReport.Status.IGNORE);
                             } else {
-                                unassign(any, result);
+                                unassign(any, beforeObj, result);
                             }
                             break;
 
@@ -451,14 +429,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
                     result.setStatus(ProvisioningReport.Status.SUCCESS);
                 }
                 resultStatus = AuditElements.Result.SUCCESS;
-                if (connObjectKey.isPresent() && connObjecKeyValue.isPresent()) {
-                    output = getRemoteObject(
-                            provision.get().getObjectClass(),
-                            connObjectKey.get().getExtAttrName(),
-                            connObjecKeyValue.get(),
-                            provision.get().isIgnoreCaseMatch(),
-                            provision.get().getMapping().getItems().iterator());
-                }
+                output = pushUtils.findByConnObjectKey(profile.getConnector(), any, provision);
             } catch (IgnoreProvisionException e) {
                 throw e;
             } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/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 53c4258..4e0b229 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
@@ -20,8 +20,6 @@ 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.core.persistence.api.dao.GroupDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
 import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
 import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
@@ -29,8 +27,6 @@ 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.ProvisioningProfile;
 import org.apache.syncope.core.provisioning.api.pushpull.SyncopeResultHandler;
-import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
-import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
@@ -48,15 +44,6 @@ public abstract class AbstractSyncopeResultHandler<T extends ProvisioningTask, A
 
     protected static final Logger LOG = LoggerFactory.getLogger(SyncopeResultHandler.class);
 
-    @Autowired
-    protected AnyObjectDAO anyObjectDAO;
-
-    @Autowired
-    protected UserDAO userDAO;
-
-    @Autowired
-    protected GroupDAO groupDAO;
-
     /**
      * Propagation manager.
      */
@@ -105,10 +92,6 @@ public abstract class AbstractSyncopeResultHandler<T extends ProvisioningTask, A
 
     protected abstract AnyTO getAnyTO(String key);
 
-    protected abstract Any<?> getAny(String key);
-
-    protected abstract AnyPatch newPatch(String key);
-
     protected abstract WorkflowResult<? extends AnyPatch> update(AnyPatch patch);
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java
index 8d71a2d..bb6e61e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPullResultHandler.java
@@ -28,7 +28,6 @@ import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
 import org.apache.syncope.core.provisioning.api.ProvisioningManager;
@@ -59,28 +58,11 @@ public class DefaultAnyObjectPullResultHandler extends AbstractPullResultHandler
     }
 
     @Override
-    protected Any<?> getAny(final String key) {
-        try {
-            return anyObjectDAO.authFind(key);
-        } catch (Exception e) {
-            LOG.warn("Error retrieving anyObject {}", key, e);
-            return null;
-        }
-    }
-
-    @Override
     protected AnyTO getAnyTO(final String key) {
         return anyObjectDataBinder.getAnyObjectTO(key);
     }
 
     @Override
-    protected AnyPatch newPatch(final String key) {
-        AnyObjectPatch patch = new AnyObjectPatch();
-        patch.setKey(key);
-        return patch;
-    }
-
-    @Override
     protected WorkflowResult<? extends AnyPatch> update(final AnyPatch patch) {
         return awfAdapter.update((AnyObjectPatch) patch);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java
index 3c401ae..a2b7e35 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultAnyObjectPushResultHandler.java
@@ -18,13 +18,13 @@
  */
 package org.apache.syncope.core.provisioning.java.pushpull;
 
-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;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.provisioning.api.pushpull.AnyObjectPushResultHandler;
 
@@ -37,17 +37,7 @@ public class DefaultAnyObjectPushResultHandler extends AbstractPushResultHandler
 
     @Override
     protected String getName(final Any<?> any) {
-        return StringUtils.EMPTY;
-    }
-
-    @Override
-    protected Any<?> getAny(final String key) {
-        try {
-            return anyObjectDAO.authFind(key);
-        } catch (Exception e) {
-            LOG.warn("Error retrieving anyObject {}", key, e);
-            return null;
-        }
+        return AnyObject.class.cast(any).getName();
     }
 
     @Override
@@ -56,15 +46,7 @@ public class DefaultAnyObjectPushResultHandler extends AbstractPushResultHandler
     }
 
     @Override
-    protected AnyPatch newPatch(final String key) {
-        AnyObjectPatch patch = new AnyObjectPatch();
-        patch.setKey(key);
-        return patch;
-    }
-
-    @Override
     protected WorkflowResult<? extends AnyObjectPatch> update(final AnyPatch patch) {
         return awfAdapter.update((AnyObjectPatch) patch);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java
index 451659b..e377123 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPullResultHandler.java
@@ -31,7 +31,6 @@ import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.PatchOperation;
-import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.provisioning.api.GroupProvisioningManager;
 import org.apache.syncope.core.provisioning.api.ProvisioningManager;
@@ -69,28 +68,11 @@ public class DefaultGroupPullResultHandler extends AbstractPullResultHandler imp
     }
 
     @Override
-    protected Any<?> getAny(final String key) {
-        try {
-            return groupDAO.authFind(key);
-        } catch (Exception e) {
-            LOG.warn("Error retrieving group {}", key, e);
-            return null;
-        }
-    }
-
-    @Override
     protected AnyTO getAnyTO(final String key) {
         return groupDataBinder.getGroupTO(key);
     }
 
     @Override
-    protected AnyPatch newPatch(final String key) {
-        GroupPatch patch = new GroupPatch();
-        patch.setKey(key);
-        return patch;
-    }
-
-    @Override
     protected WorkflowResult<? extends AnyPatch> update(final AnyPatch patch) {
         return gwfAdapter.update((GroupPatch) patch);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/595a8d15/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java
index 993f747..3c5f59b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/DefaultGroupPushResultHandler.java
@@ -41,30 +41,12 @@ public class DefaultGroupPushResultHandler extends AbstractPushResultHandler imp
     }
 
     @Override
-    protected Any<?> getAny(final String key) {
-        try {
-            return groupDAO.authFind(key);
-        } catch (Exception e) {
-            LOG.warn("Error retrieving group {}", key, e);
-            return null;
-        }
-    }
-
-    @Override
     protected AnyTO getAnyTO(final String key) {
         return groupDataBinder.getGroupTO(key);
     }
 
     @Override
-    protected AnyPatch newPatch(final String key) {
-        GroupPatch patch = new GroupPatch();
-        patch.setKey(key);
-        return patch;
-    }
-
-    @Override
     protected WorkflowResult<? extends AnyPatch> update(final AnyPatch patch) {
         return gwfAdapter.update((GroupPatch) patch);
     }
-
 }