You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2017/10/20 15:06:37 UTC

[1/2] syncope git commit: [SYNCOPE-956] PullCorrelationRule as AccountRule and PasswordRule

Repository: syncope
Updated Branches:
  refs/heads/master 3f47e9bde -> 17174c7a3


http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PullCorrelationRuleConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PullCorrelationRuleConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PullCorrelationRuleConf.java
new file mode 100644
index 0000000..6b840fe
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PullCorrelationRuleConf.java
@@ -0,0 +1,23 @@
+/*
+ * 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.common.lib.policy;
+
+public interface PullCorrelationRuleConf extends RuleConf {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java
index 6f3800a..69b2c45 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.common.lib.report;
 
+import org.apache.syncope.common.lib.Schema;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.util.ArrayList;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/report/Schema.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/report/Schema.java b/common/lib/src/main/java/org/apache/syncope/common/lib/report/Schema.java
deleted file mode 100644
index c1771ba..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/report/Schema.java
+++ /dev/null
@@ -1,35 +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.common.lib.report;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.SchemaType;
-
-@Target({ ElementType.FIELD })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Schema {
-
-    SchemaType[] type() default { SchemaType.PLAIN };
-
-    AnyTypeKind anyTypeKind();
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
index 0a5455d..1608563 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlEnum;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.Schema;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.SchemaType;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
index 8aa628f..3b824c5 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
@@ -27,6 +27,7 @@ import java.util.Map;
 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.report.ReportletConf;
 import org.apache.syncope.common.lib.types.ImplementationType;
 import org.apache.syncope.core.logic.audit.AuditAppender;
@@ -44,12 +45,12 @@ import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
 import org.apache.syncope.core.provisioning.api.notification.RecipientsProvider;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
 import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
-import org.apache.syncope.core.provisioning.api.pushpull.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRuleConfClass;
 import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
 import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
 import org.apache.syncope.core.provisioning.java.data.JEXLItemTransformerImpl;
 import org.apache.syncope.core.provisioning.java.job.GroupMemberProvisionTaskJobDelegate;
-import org.apache.syncope.core.provisioning.java.pushpull.PlainAttrsPullCorrelationRule;
 import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate;
 import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate;
 import org.apache.syncope.core.spring.security.JWTSSOProvider;
@@ -78,6 +79,8 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
 
     private Map<Class<? extends PasswordRuleConf>, Class<? extends PasswordRule>> passwordRuleClasses;
 
+    private Map<Class<? extends PullCorrelationRuleConf>, Class<? extends PullCorrelationRule>> correlationRuleClasses;
+
     private Set<Class<?>> auditAppenderClasses;
 
     @Override
@@ -106,6 +109,7 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
         reportletClasses = new HashMap<>();
         accountRuleClasses = new HashMap<>();
         passwordRuleClasses = new HashMap<>();
+        correlationRuleClasses = new HashMap<>();
         auditAppenderClasses = new HashSet<>();
 
         ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
@@ -113,6 +117,7 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
         scanner.addIncludeFilter(new AssignableTypeFilter(Reportlet.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(AccountRule.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(PasswordRule.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(PullCorrelationRule.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(ItemTransformer.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(SchedTaskJobDelegate.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(ReconFilterBuilder.class));
@@ -120,7 +125,6 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
         scanner.addIncludeFilter(new AssignableTypeFilter(PropagationActions.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(PullActions.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(PushActions.class));
-        scanner.addIncludeFilter(new AssignableTypeFilter(PullCorrelationRule.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(Validator.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(RecipientsProvider.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(AuditAppender.class));
@@ -166,6 +170,16 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
                     }
                 }
 
+                if (PullCorrelationRule.class.isAssignableFrom(clazz) && !isAbstractClazz) {
+                    PullCorrelationRuleConfClass annotation = clazz.getAnnotation(PullCorrelationRuleConfClass.class);
+                    if (annotation == null) {
+                        LOG.warn("Found pull correlation rule {} without declared configuration", clazz.getName());
+                    } else {
+                        classNames.get(ImplementationType.ACCOUNT_RULE).add(clazz.getName());
+                        correlationRuleClasses.put(annotation.value(), (Class<? extends PullCorrelationRule>) clazz);
+                    }
+                }
+
                 if (ItemTransformer.class.isAssignableFrom(clazz) && !isAbstractClazz
                         && !clazz.equals(JEXLItemTransformerImpl.class)) {
 
@@ -200,12 +214,6 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
                     classNames.get(ImplementationType.PUSH_ACTIONS).add(bd.getBeanClassName());
                 }
 
-                if (PullCorrelationRule.class.isAssignableFrom(clazz) && !isAbstractClazz
-                        && !PlainAttrsPullCorrelationRule.class.isAssignableFrom(clazz)) {
-
-                    classNames.get(ImplementationType.PULL_CORRELATION_RULE).add(bd.getBeanClassName());
-                }
-
                 if (Validator.class.isAssignableFrom(clazz) && !isAbstractClazz) {
                     classNames.get(ImplementationType.VALIDATOR).add(bd.getBeanClassName());
                 }
@@ -230,6 +238,7 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
         reportletClasses = Collections.unmodifiableMap(reportletClasses);
         accountRuleClasses = Collections.unmodifiableMap(accountRuleClasses);
         passwordRuleClasses = Collections.unmodifiableMap(passwordRuleClasses);
+        correlationRuleClasses = Collections.unmodifiableMap(correlationRuleClasses);
         auditAppenderClasses = Collections.unmodifiableSet(auditAppenderClasses);
     }
 
@@ -265,6 +274,13 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
     }
 
     @Override
+    public Class<? extends PullCorrelationRule> getPullCorrelationRuleClass(
+            final Class<? extends PullCorrelationRuleConf> correlationRuleConfClass) {
+
+        return correlationRuleClasses.get(correlationRuleConfClass);
+    }
+
+    @Override
     public Set<Class<?>> getAuditAppenderClasses() {
         return auditAppenderClasses;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
index 774928d..fce4be4 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/ImplementationLookup.java
@@ -21,10 +21,12 @@ package org.apache.syncope.core.persistence.api;
 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.report.ReportletConf;
 import org.apache.syncope.common.lib.types.ImplementationType;
 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.Reportlet;
 
 public interface ImplementationLookup extends SyncopeLoader {
@@ -33,11 +35,17 @@ public interface ImplementationLookup extends SyncopeLoader {
 
     Set<Class<?>> getJWTSSOProviderClasses();
 
-    Class<? extends Reportlet> getReportletClass(Class<? extends ReportletConf> reportletConfClass);
+    Class<? extends Reportlet> getReportletClass(
+            Class<? extends ReportletConf> reportletConfClass);
 
-    Class<? extends AccountRule> getAccountRuleClass(Class<? extends AccountRuleConf> accountRuleConfClass);
+    Class<? extends AccountRule> getAccountRuleClass(
+            Class<? extends AccountRuleConf> accountRuleConfClass);
 
-    Class<? extends PasswordRule> getPasswordRuleClass(Class<? extends PasswordRuleConf> passwordRuleConfClass);
+    Class<? extends PasswordRule> getPasswordRuleClass(
+            Class<? extends PasswordRuleConf> passwordRuleConfClass);
+
+    Class<? extends PullCorrelationRule> getPullCorrelationRuleClass(
+            Class<? extends PullCorrelationRuleConf> pullCorrelationRuleConfClass);
 
     Set<Class<?>> getAuditAppenderClasses();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRule.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRule.java
new file mode 100644
index 0000000..83a82f7
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRule.java
@@ -0,0 +1,42 @@
+/*
+ * 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.api.dao;
+
+import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+
+/**
+ * Interface for correlation rule to be evaluated during PullJob execution.
+ */
+public interface PullCorrelationRule {
+
+    default void setConf(PullCorrelationRuleConf conf) {
+    }
+
+    /**
+     * Return a search condition.
+     *
+     * @param connObj connector object.
+     * @param provision resource provision
+     * @return search condition.
+     */
+    SearchCond getSearchCond(ConnectorObject connObj, Provision provision);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRuleConfClass.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRuleConfClass.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRuleConfClass.java
new file mode 100644
index 0000000..b96a699
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PullCorrelationRuleConfClass.java
@@ -0,0 +1,33 @@
+/*
+ * 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.api.dao;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
+
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface PullCorrelationRuleConfClass {
+
+    Class<? extends PullCorrelationRuleConf> value();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultAccountRule.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultAccountRule.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultAccountRule.java
index 6faf055..636b788 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultAccountRule.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultAccountRule.java
@@ -43,7 +43,6 @@ public class DefaultAccountRule implements AccountRule {
             throw new IllegalArgumentException(
                     DefaultAccountRuleConf.class.getName() + " expected, got " + conf.getClass().getName());
         }
-
     }
 
     @Transactional(readOnly = true)

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultPullCorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultPullCorrelationRule.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultPullCorrelationRule.java
new file mode 100644
index 0000000..02cc568
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultPullCorrelationRule.java
@@ -0,0 +1,113 @@
+/*
+ * 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.dao;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf;
+import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
+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.resource.Item;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRuleConfClass;
+
+@PullCorrelationRuleConfClass(DefaultPullCorrelationRuleConf.class)
+public class DefaultPullCorrelationRule implements PullCorrelationRule {
+
+    private DefaultPullCorrelationRuleConf conf;
+
+    @Override
+    public void setConf(final PullCorrelationRuleConf conf) {
+        if (conf instanceof DefaultPullCorrelationRuleConf) {
+            this.conf = DefaultPullCorrelationRuleConf.class.cast(conf);
+        } else {
+            throw new IllegalArgumentException(
+                    DefaultPullCorrelationRuleConf.class.getName() + " expected, got " + conf.getClass().getName());
+        }
+    }
+
+    @Override
+    public SearchCond getSearchCond(final ConnectorObject connObj, final Provision provision) {
+        Map<String, Item> mappingItems = provision.getMapping().getItems().stream().
+                collect(Collectors.toMap(Item::getIntAttrName, Function.identity()));
+
+        // search for anys by attribute(s) specified in the policy
+        SearchCond searchCond = null;
+
+        for (String schema : conf.getSchemas()) {
+            Item mappingItem = mappingItems.get(schema);
+            Attribute attr = mappingItem == null
+                    ? null
+                    : connObj.getAttributeByName(mappingItem.getExtAttrName());
+            if (attr == null) {
+                throw new IllegalArgumentException(
+                        "Connector object does not contains the attributes to perform the search: " + schema);
+            }
+
+            AttributeCond.Type type;
+            String expression = null;
+
+            if (attr.getValue() == null || attr.getValue().isEmpty()
+                    || (attr.getValue().size() == 1 && attr.getValue().get(0) == null)) {
+
+                type = AttributeCond.Type.ISNULL;
+            } else {
+                type = AttributeCond.Type.EQ;
+                expression = attr.getValue().size() > 1
+                        ? attr.getValue().toString()
+                        : attr.getValue().get(0).toString();
+            }
+
+            SearchCond nodeCond;
+            // users: just key or username can be selected
+            // groups: just key or name can be selected
+            // any objects: just key or name can be selected
+            if ("key".equalsIgnoreCase(schema)
+                    || "username".equalsIgnoreCase(schema) || "name".equalsIgnoreCase(schema)) {
+
+                AnyCond cond = new AnyCond();
+                cond.setSchema(schema);
+                cond.setType(type);
+                cond.setExpression(expression);
+
+                nodeCond = SearchCond.getLeafCond(cond);
+            } else {
+                AttributeCond cond = new AttributeCond();
+                cond.setSchema(schema);
+                cond.setType(type);
+                cond.setExpression(expression);
+
+                nodeCond = SearchCond.getLeafCond(cond);
+            }
+
+            searchCond = searchCond == null
+                    ? nodeCond
+                    : SearchCond.getAndCond(searchCond, nodeCond);
+        }
+
+        return searchCond;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/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 943a0e3..5b47a75 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
@@ -22,14 +22,17 @@ import java.util.Collections;
 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.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.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.springframework.stereotype.Component;
 
 @Component
@@ -77,6 +80,13 @@ public class DummyImplementationLookup implements ImplementationLookup {
     }
 
     @Override
+    public Class<? extends PullCorrelationRule> getPullCorrelationRuleClass(
+            final Class<? extends PullCorrelationRuleConf> pullCorrelationRuleConfClass) {
+
+        return DefaultPullCorrelationRule.class;
+    }
+
+    @Override
     public Set<Class<?>> getAuditAppenderClasses() {
         return Collections.emptySet();
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/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 abf6ea3..1301395 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
@@ -26,8 +26,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.List;
 import java.util.UUID;
-import org.apache.commons.lang3.ArrayUtils;
 import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
+import org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf;
 import org.apache.syncope.common.lib.types.ConflictResolutionAction;
 import org.apache.syncope.common.lib.types.ImplementationEngine;
 import org.apache.syncope.common.lib.types.ImplementationType;
@@ -44,7 +44,7 @@ import org.junit.jupiter.api.Test;
 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.provisioning.api.pushpull.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
 
 @Transactional("Master")
 public class PolicyTest extends AbstractTest {
@@ -72,11 +72,12 @@ public class PolicyTest extends AbstractTest {
 
         CorrelationRule rule = policy.getCorrelationRule(anyTypeDAO.findUser()).orElse(null);
         assertNotNull(rule);
-        String[] plainSchemas = POJOHelper.deserialize(rule.getImplementation().getBody(), String[].class);
-        assertNotNull(plainSchemas);
-        assertEquals(2, plainSchemas.length);
-        assertTrue(ArrayUtils.contains(plainSchemas, "username"));
-        assertTrue(ArrayUtils.contains(plainSchemas, "firstname"));
+        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"));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/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 fd3c0c4..7c2298d 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -635,7 +635,7 @@ under the License.
   <PullPolicy id="66691e96-285f-4464-bc19-e68384ea4c85" description="a pull policy" conflictResolutionAction="IGNORE"/>
   <PullPolicy id="880f8553-069b-4aed-9930-2cd53873f544" description="another pull policy" conflictResolutionAction="ALL"/>
   <Implementation id="TestPullCorrelationRule" type="PULL_CORRELATION_RULE" engine="JAVA"
-                  body='["username","firstname"]'/>
+                  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"/>
   <PullPolicy id="4ad10d94-e002-4b3f-b771-16089cc71da9" description="pull policy 1" conflictResolutionAction="IGNORE"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/PullCorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/PullCorrelationRule.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/PullCorrelationRule.java
deleted file mode 100644
index 5d6d922..0000000
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/PullCorrelationRule.java
+++ /dev/null
@@ -1,36 +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.provisioning.api.pushpull;
-
-import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
-import org.identityconnectors.framework.common.objects.ConnectorObject;
-
-/**
- * Interface for correlation rule to be evaluated during PullJob execution.
- */
-public interface PullCorrelationRule {
-
-    /**
-     * Return a search condition.
-     *
-     * @param connObj connector object.
-     * @return search condition.
-     */
-    SearchCond getSearchCond(ConnectorObject connObj);
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/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 65aa6f6..73d653e 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
@@ -39,7 +39,7 @@ import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
 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.provisioning.api.pushpull.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
 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;
@@ -151,11 +151,13 @@ public class ImplementationDataBinderImpl implements ImplementationDataBinder {
                     throw sce;
                 }
             } else if (implementation.getType() == ImplementationType.ACCOUNT_RULE
-                    || implementation.getType() == ImplementationType.PASSWORD_RULE) {
+                    || implementation.getType() == ImplementationType.PASSWORD_RULE
+                    || implementation.getType() == ImplementationType.PULL_CORRELATION_RULE) {
 
                 RuleConf rule = POJOHelper.deserialize(implementation.getBody(), RuleConf.class);
                 if (rule == null) {
-                    sce.getElements().add("Could not deserialize as neither Account nor Password RuleConf");
+                    sce.getElements().
+                            add("Could not deserialize as neither Account, Password nor PullCorrelation RuleConf");
                     throw sce;
                 }
             } else {

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/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 fe826f4..e39f329 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
@@ -27,6 +27,7 @@ import org.apache.syncope.common.lib.policy.PullPolicyTO;
 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;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.Entity;
@@ -142,18 +143,16 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
                     CorrelationRule correlationRule = pullPolicy.getCorrelationRule(anyType).orElse(null);
                     if (correlationRule == null) {
                         correlationRule = entityFactory.newEntity(CorrelationRule.class);
-                        correlationRule.setAnyType(anyTypeDAO.find(entry.getKey()));
+                        correlationRule.setAnyType(anyType);
                         correlationRule.setPullPolicy(pullPolicy);
                         pullPolicy.add(correlationRule);
                     }
 
                     Implementation implementation = implementationDAO.find(entry.getValue());
                     if (implementation == null) {
-                        LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
-                                entry.getValue());
-                    } else {
-                        correlationRule.setImplementation(implementation);
+                        throw new NotFoundException("Implementation " + entry.getValue());
                     }
+                    correlationRule.setImplementation(implementation);
                 }
             });
             // remove all rules not contained in the TO

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
deleted file mode 100644
index 030a712..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
+++ /dev/null
@@ -1,113 +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.provisioning.java.pushpull;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-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.resource.Item;
-import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.identityconnectors.framework.common.objects.Attribute;
-import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.apache.syncope.core.provisioning.api.pushpull.PullCorrelationRule;
-import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
-import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
-
-public class PlainAttrsPullCorrelationRule implements PullCorrelationRule {
-
-    private final List<String> plainSchemaNames;
-
-    private final Provision provision;
-
-    public PlainAttrsPullCorrelationRule(final String[] plainSchemaNames, final Provision provision) {
-        this.plainSchemaNames = Arrays.asList(plainSchemaNames);
-        this.provision = provision;
-    }
-
-    @Override
-    public SearchCond getSearchCond(final ConnectorObject connObj) {
-        Map<String, Item> mappingItems = provision.getMapping().getItems().stream().
-                collect(Collectors.toMap(Item::getIntAttrName, Function.identity()));
-
-        // search for anys by attribute(s) specified in the policy
-        SearchCond searchCond = null;
-
-        for (String schema : plainSchemaNames) {
-            Item mappingItem = mappingItems.get(schema);
-            Attribute attr = mappingItem == null
-                    ? null
-                    : connObj.getAttributeByName(mappingItem.getExtAttrName());
-            if (attr == null) {
-                throw new IllegalArgumentException(
-                        "Connector object does not contains the attributes to perform the search: " + schema);
-            }
-
-            List<Object> values = attr.getValue();
-            for (ItemTransformer transformer : MappingUtils.getItemTransformers(mappingItem)) {
-                values = transformer.beforePull(mappingItem, null, values);
-            }
-
-            AttributeCond.Type type;
-            String expression = null;
-
-            if (values == null || values.isEmpty() || (values.size() == 1 && values.get(0) == null)) {
-                type = AttributeCond.Type.ISNULL;
-            } else {
-                type = AttributeCond.Type.EQ;
-                expression = values.size() > 1
-                        ? values.toString()
-                        : values.get(0).toString();
-            }
-
-            SearchCond nodeCond;
-            // users: just key or username can be selected
-            // groups: just key or name can be selected
-            // any objects: just key or name can be selected
-            if ("key".equalsIgnoreCase(schema)
-                    || "username".equalsIgnoreCase(schema) || "name".equalsIgnoreCase(schema)) {
-
-                AnyCond cond = new AnyCond();
-                cond.setSchema(schema);
-                cond.setType(type);
-                cond.setExpression(expression);
-
-                nodeCond = SearchCond.getLeafCond(cond);
-            } else {
-                AttributeCond cond = new AttributeCond();
-                cond.setSchema(schema);
-                cond.setType(type);
-                cond.setExpression(expression);
-
-                nodeCond = SearchCond.getLeafCond(cond);
-            }
-
-            searchCond = searchCond == null
-                    ? nodeCond
-                    : SearchCond.getAndCond(searchCond, nodeCond);
-        }
-
-        return searchCond;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 32e2118..094e88b 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -24,7 +24,6 @@ import java.util.List;
 import java.util.Optional;
 import java.util.stream.Collectors;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -66,7 +65,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
-import org.apache.syncope.core.provisioning.api.pushpull.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
 import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
 import org.apache.syncope.core.spring.ImplementationManager;
@@ -267,9 +266,12 @@ public class PullUtils {
     }
 
     private List<String> findByCorrelationRule(
-            final ConnectorObject connObj, final PullCorrelationRule rule, final AnyTypeKind type) {
+            final ConnectorObject connObj,
+            final Provision provision,
+            final PullCorrelationRule rule,
+            final AnyTypeKind type) {
 
-        return searchDAO.search(rule.getSearchCond(connObj), type).stream().
+        return searchDAO.search(rule.getSearchCond(connObj, provision), type).stream().
                 map(Entity::getKey).collect(Collectors.toList());
     }
 
@@ -292,24 +294,19 @@ public class PullUtils {
                 ? Optional.empty()
                 : provision.getResource().getPullPolicy().getCorrelationRule(provision.getAnyType());
 
-        PullCorrelationRule rule = null;
+        Optional<PullCorrelationRule> rule = Optional.empty();
         if (correlationRule.isPresent()) {
-            if (correlationRule.get().getImplementation().getBody().charAt(0) == '[') {
-                rule = new PlainAttrsPullCorrelationRule(POJOHelper.deserialize(
-                        correlationRule.get().getImplementation().getBody(), String[].class), provision);
-            } else {
-                try {
-                    rule = ImplementationManager.build(correlationRule.get().getImplementation());
-                } catch (Exception e) {
-                    LOG.error("While building {}", correlationRule.get().getImplementation(), e);
-                }
+            try {
+                rule = ImplementationManager.buildPullCorrelationRule(correlationRule.get().getImplementation());
+            } catch (Exception e) {
+                LOG.error("While building {}", correlationRule.get().getImplementation(), e);
             }
         }
 
         try {
-            return rule == null
-                    ? findByConnObjectKeyItem(uid, provision, anyUtils)
-                    : findByCorrelationRule(connObj, rule, anyUtils.getAnyTypeKind());
+            return rule.isPresent()
+                    ? findByCorrelationRule(connObj, provision, rule.get(), anyUtils.getAnyTypeKind())
+                    : findByConnObjectKeyItem(uid, provision, anyUtils);
         } catch (RuntimeException e) {
             return Collections.<String>emptyList();
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java
index 55e2a26..51ac7ad 100644
--- a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java
+++ b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DummyImplementationLookup.java
@@ -22,14 +22,17 @@ import java.util.Collections;
 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.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.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.springframework.stereotype.Component;
 
 @Component
@@ -77,6 +80,13 @@ public class DummyImplementationLookup implements ImplementationLookup {
     }
 
     @Override
+    public Class<? extends PullCorrelationRule> getPullCorrelationRuleClass(
+            final Class<? extends PullCorrelationRuleConf> pullCorrelationRuleConfClass) {
+
+        return DefaultPullCorrelationRule.class;
+    }
+
+    @Override
     public Set<Class<?>> getAuditAppenderClasses() {
         return Collections.emptySet();
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java
----------------------------------------------------------------------
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java b/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java
index 51c9bf6..dfa4ead 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java
@@ -25,12 +25,14 @@ import java.util.Map;
 import java.util.Optional;
 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.report.ReportletConf;
 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.Reportlet;
 import org.apache.syncope.core.persistence.api.entity.Implementation;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -93,7 +95,7 @@ public final class ImplementationManager {
                 Class<? extends AccountRule> ruleClass = ApplicationContextProvider.getApplicationContext().
                         getBean(ImplementationLookup.class).getAccountRuleClass(ruleConf.getClass());
                 if (ruleClass == null) {
-                    LOG.warn("Could not find matching password rule for {}", impl.getClass());
+                    LOG.warn("Could not find matching account rule for {}", impl.getClass());
                 } else {
                     // fetch (or create) rule
                     if (ApplicationContextProvider.getBeanFactory().containsSingleton(ruleClass.getName())) {
@@ -146,6 +148,41 @@ public final class ImplementationManager {
         }
     }
 
+    public static Optional<PullCorrelationRule> buildPullCorrelationRule(final Implementation impl)
+            throws InstantiationException, IllegalAccessException {
+
+        switch (impl.getEngine()) {
+            case GROOVY:
+                return Optional.of(ImplementationManager.<PullCorrelationRule>buildGroovy(impl));
+
+            case JAVA:
+            default:
+                PullCorrelationRule rule = null;
+
+                PullCorrelationRuleConf ruleConf =
+                        POJOHelper.deserialize(impl.getBody(), PullCorrelationRuleConf.class);
+                Class<? extends PullCorrelationRule> ruleClass = ApplicationContextProvider.getApplicationContext().
+                        getBean(ImplementationLookup.class).getPullCorrelationRuleClass(ruleConf.getClass());
+                if (ruleClass == null) {
+                    LOG.warn("Could not find matching pull correlation rule for {}", impl.getClass());
+                } else {
+                    // fetch (or create) rule
+                    if (ApplicationContextProvider.getBeanFactory().containsSingleton(ruleClass.getName())) {
+                        rule = (PullCorrelationRule) ApplicationContextProvider.getBeanFactory().
+                                getSingleton(ruleClass.getName());
+                    } else {
+                        rule = (PullCorrelationRule) ApplicationContextProvider.getBeanFactory().
+                                createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+                        ApplicationContextProvider.getBeanFactory().
+                                registerSingleton(ruleClass.getName(), rule);
+                    }
+                    rule.setConf(ruleConf);
+                }
+
+                return Optional.ofNullable(rule);
+        }
+    }
+
     public static <T> T build(final Implementation impl)
             throws InstantiationException, IllegalAccessException, ClassNotFoundException {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java
index e644645..1f0d383 100644
--- a/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java
@@ -22,11 +22,13 @@ import java.util.Collections;
 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.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.Reportlet;
 
 public class DummyImplementationLookup implements ImplementationLookup {
@@ -73,6 +75,13 @@ public class DummyImplementationLookup implements ImplementationLookup {
     }
 
     @Override
+    public Class<? extends PullCorrelationRule> getPullCorrelationRuleClass(
+            final Class<? extends PullCorrelationRuleConf> pullCorrelationRuleConfClass) {
+
+        return null;
+    }
+
+    @Override
     public Set<Class<?>> getAuditAppenderClasses() {
         return Collections.emptySet();
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DummyPullCorrelationRule.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DummyPullCorrelationRule.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DummyPullCorrelationRule.java
new file mode 100644
index 0000000..2930038
--- /dev/null
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DummyPullCorrelationRule.java
@@ -0,0 +1,35 @@
+/*
+ * 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.fit.core.reference;
+
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule;
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRuleConfClass;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+
+@PullCorrelationRuleConfClass(DummyPullCorrelationRuleConf.class)
+public class DummyPullCorrelationRule implements PullCorrelationRule {
+
+    @Override
+    public SearchCond getSearchCond(final ConnectorObject connObj, final Provision provision) {
+        return new SearchCond();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DummyPullCorrelationRuleConf.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DummyPullCorrelationRuleConf.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DummyPullCorrelationRuleConf.java
new file mode 100644
index 0000000..e544823
--- /dev/null
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/DummyPullCorrelationRuleConf.java
@@ -0,0 +1,29 @@
+/*
+ * 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.fit.core.reference;
+
+import org.apache.syncope.common.lib.policy.AbstractPullCorrelationRuleConf;
+import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
+
+public class DummyPullCorrelationRuleConf
+        extends AbstractPullCorrelationRuleConf implements PullCorrelationRuleConf {
+
+    private static final long serialVersionUID = -2984203196323732531L;
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
index d4467e8..d285ba6 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/ITImplementationLookup.java
@@ -28,7 +28,9 @@ import javax.sql.DataSource;
 import org.apache.syncope.common.lib.policy.AccountRuleConf;
 import org.apache.syncope.common.lib.policy.DefaultAccountRuleConf;
 import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
+import org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf;
 import org.apache.syncope.common.lib.policy.PasswordRuleConf;
+import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf;
 import org.apache.syncope.common.lib.report.AuditReportletConf;
 import org.apache.syncope.common.lib.report.GroupReportletConf;
 import org.apache.syncope.common.lib.report.ReconciliationReportletConf;
@@ -51,6 +53,7 @@ import org.apache.syncope.core.persistence.api.dao.AccountRule;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
 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.Reportlet;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.Implementation;
@@ -59,6 +62,7 @@ import org.apache.syncope.core.persistence.jpa.attrvalue.validation.BasicValidat
 import org.apache.syncope.core.persistence.jpa.attrvalue.validation.EmailAddressValidator;
 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.provisioning.java.propagation.DBPasswordPropagationActions;
 import org.apache.syncope.core.provisioning.java.propagation.LDAPMembershipPropagationActions;
 import org.apache.syncope.core.provisioning.java.propagation.LDAPPasswordPropagationActions;
@@ -116,6 +120,18 @@ public class ITImplementationLookup implements ImplementationLookup {
         }
     };
 
+    private static final Map<
+            Class<? extends PullCorrelationRuleConf>, Class<? extends PullCorrelationRule>> CORRELATION_RULE_CLASSES =
+            new HashMap<Class<? extends PullCorrelationRuleConf>, Class<? extends PullCorrelationRule>>() {
+
+        private static final long serialVersionUID = 3109256773218160485L;
+
+        {
+            put(DummyPullCorrelationRuleConf.class, DummyPullCorrelationRule.class);
+            put(DefaultPullCorrelationRuleConf.class, DefaultPullCorrelationRule.class);
+        }
+    };
+
     private static final Set<Class<?>> AUDITAPPENDER_CLASSES = new HashSet<>(
             Arrays.asList(TestFileAuditAppender.class, TestFileRewriteAuditAppender.class));
 
@@ -176,6 +192,7 @@ public class ITImplementationLookup implements ImplementationLookup {
             put(ImplementationType.PUSH_ACTIONS, classNames);
 
             classNames = new HashSet<>();
+            classNames.add(DummyPullCorrelationRule.class.getName());
             put(ImplementationType.PULL_CORRELATION_RULE, classNames);
 
             classNames = new HashSet<>();
@@ -278,6 +295,13 @@ public class ITImplementationLookup implements ImplementationLookup {
     }
 
     @Override
+    public Class<? extends PullCorrelationRule> getPullCorrelationRuleClass(
+            final Class<? extends PullCorrelationRuleConf> pullCorrelationRuleConfClass) {
+
+        return CORRELATION_RULE_CLASSES.get(pullCorrelationRuleConfClass);
+    }
+
+    @Override
     public Set<Class<?>> getAuditAppenderClasses() {
         return AUDITAPPENDER_CLASSES;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java
index f3be793..ca6f63d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/PoliciesITCase.java
@@ -25,7 +25,6 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.pages.Policies;
 import org.apache.syncope.client.console.pages.Realms;
-import org.apache.syncope.common.lib.types.ConflictResolutionAction;
 import org.apache.wicket.Component;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.form.TextField;
@@ -457,8 +456,7 @@ public class PoliciesITCase extends AbstractConsoleITCase {
         deleteAccountPolicy(description);
     }
 
-    private void composeDefaultAccountPolicy(final String policyDescription, final String ruleName) {
-
+    private void composeDefaultAccountPolicy(final String policyDescription) {
         Component component = findComponentByProp("description", "body:content:tabbedPanel:panel:container:content:"
                 + "searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", policyDescription);
 
@@ -477,27 +475,16 @@ public class PoliciesITCase extends AbstractConsoleITCase {
 
         FormTester formTester = TESTER.newFormTester("body:content:tabbedPanel:panel:outerObjectsRepeater:4:"
                 + "outer:form:content:container:content:wizard:form");
-        formTester.setValue("view:name:textField", ruleName);
-        formTester.setValue("view:configuration:dropDownChoiceField", "0");
+        formTester.setValue("view:rule:dropDownChoiceField", "0");
         formTester.submit("buttons:next");
 
-        TESTER.assertModelValue("body:content:tabbedPanel:panel:outerObjectsRepeater:4:outer:form:content:"
-                + "container:content:wizard:form:view:bean:propView:1:value:spinner", 0);
-
         formTester = TESTER.newFormTester("body:content:tabbedPanel:panel:outerObjectsRepeater:4:"
                 + "outer:form:content:container:content:wizard:form");
-        formTester.setValue("view:bean:propView:1:value:spinner", "6");
         formTester.submit("buttons:finish");
 
         TESTER.assertInfoMessages("Operation executed successfully");
         TESTER.cleanupFeedbackMessages();
 
-        component = findComponentByProp("name", "body:content:tabbedPanel:panel:outerObjectsRepeater:4:outer:form:"
-                + "content:container:content:searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable",
-                ruleName);
-
-        assertNotNull(component);
-
         TESTER.clickLink(
                 "body:content:tabbedPanel:panel:outerObjectsRepeater:4:outer:form:content:container:content:exit");
 
@@ -508,7 +495,7 @@ public class PoliciesITCase extends AbstractConsoleITCase {
     public void createComposeDeleteAccountPolicy() {
         final String description = "Account Policy To Be Composed";
         createAccountPolicy(description);
-        composeDefaultAccountPolicy(description, "myrule");
+        composeDefaultAccountPolicy(description);
         deleteAccountPolicy(description);
     }
 
@@ -585,13 +572,9 @@ public class PoliciesITCase extends AbstractConsoleITCase {
 
         FormTester formTester = TESTER.newFormTester("body:content:tabbedPanel:panel:outerObjectsRepeater:4:"
                 + "outer:form:content:container:content:wizard:form");
-        formTester.setValue("view:name:textField", "myrule");
-        formTester.setValue("view:configuration:dropDownChoiceField", "0");
+        formTester.setValue("view:rule:dropDownChoiceField", "0");
         formTester.submit("buttons:next");
 
-        TESTER.assertModelValue("body:content:tabbedPanel:panel:outerObjectsRepeater:4:outer:form:content:"
-                + "container:content:wizard:form:view:bean:propView:0:value:spinner", 0);
-
         formTester = TESTER.newFormTester("body:content:tabbedPanel:panel:outerObjectsRepeater:4:"
                 + "outer:form:content:container:content:wizard:form");
         formTester.submit("buttons:finish");
@@ -599,12 +582,6 @@ public class PoliciesITCase extends AbstractConsoleITCase {
         TESTER.assertInfoMessages("Operation executed successfully");
         TESTER.cleanupFeedbackMessages();
 
-        component = findComponentByProp("name", "body:content:tabbedPanel:panel:outerObjectsRepeater:4:outer:form:"
-                + "content:container:content:searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable",
-                "myrule");
-
-        assertNotNull(component);
-
         TESTER.clickLink(
                 "body:content:tabbedPanel:panel:outerObjectsRepeater:4:outer:form:content:container:content:exit");
 
@@ -670,8 +647,8 @@ public class PoliciesITCase extends AbstractConsoleITCase {
 
         Component component = findComponentByProp("description", "body:content:tabbedPanel:panel:container:content:"
                 + "searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", description);
-
         assertNotNull(component);
+
         TESTER.executeAjaxEvent(component.getPageRelativePath(), Constants.ON_CLICK);
         TESTER.clickLink("body:content:tabbedPanel:panel:outerObjectsRepeater:1:outer:container:content:"
                 + "togglePanelContainer:container:actions:actions:actionRepeater:2:action:action");
@@ -687,9 +664,15 @@ public class PoliciesITCase extends AbstractConsoleITCase {
         TESTER.executeAjaxEvent("body:content:tabbedPanel:panel:outerObjectsRepeater:5:outer:form:content:"
                 + "correlationRules:multiValueContainer:innerForm:content:panelPlus:add", Constants.ON_CLICK);
 
-        formTester.setValue("content:conflictResolutionAction:dropDownChoiceField", "1");
-        formTester.setValue("content:correlationRules:multiValueContainer:innerForm:content:view:0:panel:"
-                + "jsonRule:paletteField:recorder", "fullname");
+        component = findComponentById(
+                "body:content:tabbedPanel:panel:outerObjectsRepeater:5:outer:form:content:"
+                + "correlationRules:multiValueContainer:innerForm:content:view:0:panel:rule",
+                "dropDownChoiceField");
+        assertNotNull(component);
+
+        formTester.setValue(component, "0");
+        TESTER.executeAjaxEvent(component, Constants.ON_CHANGE);
+        formTester.setValue(component, "0");
 
         TESTER.clickLink(
                 "body:content:tabbedPanel:panel:outerObjectsRepeater:5:outer:dialog:footer:inputs:0:submit");
@@ -699,28 +682,6 @@ public class PoliciesITCase extends AbstractConsoleITCase {
 
         closeCallBack(modal);
 
-        component = findComponentByProp("description", "body:content:tabbedPanel:panel:container:content:"
-                + "searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", description);
-
-        assertNotNull(component);
-        TESTER.executeAjaxEvent(component.getPageRelativePath(), Constants.ON_CLICK);
-        TESTER.clickLink("body:content:tabbedPanel:panel:outerObjectsRepeater:1:outer:container:content:"
-                + "togglePanelContainer:container:actions:actions:actionRepeater:2:action:action");
-
-        TESTER.assertComponent("body:content:tabbedPanel:panel:outerObjectsRepeater:5:outer", Modal.class);
-
-        TESTER.assertModelValue("body:content:tabbedPanel:panel:outerObjectsRepeater:5:outer:form:"
-                + "content:conflictResolutionAction:dropDownChoiceField", ConflictResolutionAction.FIRSTMATCH);
-
-        TESTER.assertModelValue("body:content:tabbedPanel:panel:outerObjectsRepeater:5:outer:form:"
-                + "content:correlationRules:multiValueContainer:innerForm:content:view:0:panel:"
-                + "jsonRule:paletteField:recorder", "fullname");
-
-        TESTER.clickLink(
-                "body:content:tabbedPanel:panel:outerObjectsRepeater:5:outer:dialog:footer:buttons:0:button");
-
-        closeCallBack(modal);
-
         deletePullPolicy(description);
     }
 
@@ -729,7 +690,7 @@ public class PoliciesITCase extends AbstractConsoleITCase {
         final String description = "SYNCOPE-1030";
         // Create account policy
         createAccountPolicy(description);
-        composeDefaultAccountPolicy(description, "issue");
+        composeDefaultAccountPolicy(description);
 
         // goto realms
         TESTER.clickLink("body:realmsLI:realms");

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/ReportsITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/ReportsITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/ReportsITCase.java
index f4bd69b..6d75a0c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/ReportsITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/ReportsITCase.java
@@ -91,41 +91,6 @@ public class ReportsITCase extends AbstractConsoleITCase {
                 + "content:searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", "deleteReport"));
     }
 
-    private void deleteReportlet(final String report, final String reportlet) {
-        TESTER.clickLink("body:reportsLI:reports");
-
-        Component result = findComponentByProp(
-                "name", "body:content:tabbedPanel:panel:firstLevelContainer:first:container:"
-                + "content:searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", report);
-
-        assertNotNull(result);
-
-        TESTER.executeAjaxEvent(result.getPageRelativePath(), Constants.ON_CLICK);
-        TESTER.clickLink("body:content:tabbedPanel:panel:firstLevelContainer:first:outerObjectsRepeater:1:outer:"
-                + "container:content:togglePanelContainer:container:actions:actions:actionRepeater:2:action:action");
-
-        result = findComponentByProp("name", "body:content:tabbedPanel:panel:firstLevelContainer:first:"
-                + "outerObjectsRepeater:0:outer:form:content:container:content:searchContainer:resultTable:tablePanel:"
-                + "groupForm:checkgroup:dataTable", reportlet);
-
-        assertNotNull(result);
-
-        TESTER.executeAjaxEvent(result.getPageRelativePath(), Constants.ON_CLICK);
-        TESTER.getRequest().addParameter("confirm", "true");
-
-        TESTER.clickLink(TESTER.getComponentFromLastRenderedPage(
-                "body:content:tabbedPanel:panel:firstLevelContainer:first:outerObjectsRepeater:0:outer:"
-                + "form:content:outerObjectsRepeater:1:outer:container:content:togglePanelContainer:container:actions:"
-                + "actions:actionRepeater:2:action:action"));
-
-        TESTER.assertInfoMessages("Operation executed successfully");
-        TESTER.cleanupFeedbackMessages();
-
-        assertNull(findComponentByProp("name", "body:content:tabbedPanel:panel:firstLevelContainer:first:"
-                + "outerObjectsRepeater:0:outer:form:content:container:content:searchContainer:resultTable:tablePanel:"
-                + "groupForm:checkgroup:dataTable", reportlet));
-    }
-
     @Test
     public void read() {
         Component result = findComponentByProp(
@@ -162,90 +127,6 @@ public class ReportsITCase extends AbstractConsoleITCase {
     }
 
     @Test
-    public void cloneReportlets() {
-        final String report = "test";
-        final String reportlet = "myClone";
-
-        Component result = findComponentByProp(
-                "name", "body:content:tabbedPanel:panel:firstLevelContainer:first:container:"
-                + "content:searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", report);
-
-        assertNotNull(result);
-
-        TESTER.executeAjaxEvent(result.getPageRelativePath(), Constants.ON_CLICK);
-        TESTER.clickLink("body:content:tabbedPanel:panel:firstLevelContainer:first:outerObjectsRepeater:1:outer:"
-                + "container:content:togglePanelContainer:container:actions:actions:actionRepeater:2:action:action");
-
-        result = findComponentByProp("name", "body:content:tabbedPanel:panel:firstLevelContainer:first:"
-                + "outerObjectsRepeater:0:outer:form:content:container:content:searchContainer:resultTable:tablePanel:"
-                + "groupForm:checkgroup:dataTable", "testUserReportlet");
-
-        assertNotNull(result);
-
-        TESTER.executeAjaxEvent(result.getPageRelativePath(), Constants.ON_CLICK);
-
-        TESTER.clickLink("body:content:tabbedPanel:panel:firstLevelContainer:first:outerObjectsRepeater:0:outer:form:"
-                + "content:outerObjectsRepeater:1:outer:container:content:togglePanelContainer:container:actions:"
-                + "actions:actionRepeater:0:action:action");
-
-        FormTester formTester = TESTER.newFormTester("body:content:tabbedPanel:panel:firstLevelContainer:first:"
-                + "outerObjectsRepeater:0:outer:form:content:container:content:wizard:form");
-
-        formTester.setValue("view:name:textField", reportlet);
-        formTester.submit("buttons:finish");
-
-        TESTER.assertInfoMessages("Operation executed successfully");
-        TESTER.cleanupFeedbackMessages();
-
-        deleteReportlet(report, reportlet);
-
-        TESTER.clickLink("body:content:tabbedPanel:panel:firstLevelContainer:first:outerObjectsRepeater:0:"
-                + "outer:form:content:container:content:exit");
-
-        TESTER.assertRenderedPage(Reports.class);
-    }
-
-    @Test
-    public void createReportlets() {
-        final String report = "test";
-        final String reportlet = "myNewReportlet";
-
-        Component result = findComponentByProp(
-                "name", "body:content:tabbedPanel:panel:firstLevelContainer:first:container:"
-                + "content:searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable", report);
-
-        assertNotNull(result);
-
-        TESTER.executeAjaxEvent(result.getPageRelativePath(), Constants.ON_CLICK);
-        TESTER.clickLink("body:content:tabbedPanel:panel:firstLevelContainer:first:outerObjectsRepeater:1:outer:"
-                + "container:content:togglePanelContainer:container:actions:actions:actionRepeater:2:action:action");
-
-        TESTER.clickLink("body:content:tabbedPanel:panel:firstLevelContainer:first:outerObjectsRepeater:0:"
-                + "outer:form:content:container:content:add");
-
-        FormTester formTester = TESTER.newFormTester("body:content:tabbedPanel:panel:firstLevelContainer:first:"
-                + "outerObjectsRepeater:0:outer:form:content:container:content:wizard:form");
-
-        formTester.setValue("view:name:textField", reportlet);
-        formTester.setValue("view:configuration:dropDownChoiceField", "1");
-        formTester.submit("buttons:next");
-
-        formTester = TESTER.newFormTester("body:content:tabbedPanel:panel:firstLevelContainer:first:"
-                + "outerObjectsRepeater:0:outer:form:content:container:content:wizard:form");
-        formTester.submit("buttons:finish");
-
-        TESTER.assertInfoMessages("Operation executed successfully");
-        TESTER.cleanupFeedbackMessages();
-
-        deleteReportlet(report, reportlet);
-
-        TESTER.clickLink("body:content:tabbedPanel:panel:firstLevelContainer:first:outerObjectsRepeater:0:"
-                + "outer:form:content:container:content:exit");
-
-        TESTER.assertRenderedPage(Reports.class);
-    }
-
-    @Test
     public void update() {
         createReport("updateReport");
         Component result = findComponentByProp(

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
index 0a910b0..ff417f6 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
@@ -443,7 +443,7 @@ public class TopologyITCase extends AbstractConsoleITCase {
                 "body:toggle:outerObjectsRepeater:2:outer:form:content:tasks:firstLevelContainer:first:"
                 + "container:content:wizard:form");
         formTester.setValue("view:name:textField", "test");
-        formTester.select("view:jobDelegateClassName:dropDownChoiceField", 0);
+        formTester.select("view:jobDelegate:dropDownChoiceField", 0);
 
         formTester.submit("buttons:next");
         TESTER.cleanupFeedbackMessages();

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java
index fe7bc12..d1c07ba 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java
@@ -152,7 +152,6 @@ public class UsersITCase extends AbstractConsoleITCase {
         formTester.setValue("view:relationships:specification:type:dropDownChoiceField", "1");
         TESTER.executeAjaxEvent(TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:view:relationships:"
                 + "specification:type:dropDownChoiceField", Constants.ON_CHANGE);
-
         // The ON_CHANGE above should enable this component, but it doesn't; doing it by hand
         Component otherType = findComponentById(
                 TAB_PANEL + "outerObjectsRepeater:0:outer:form:content:form:view:relationships:specification",

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java
index a077358..3afec6d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PolicyITCase.java
@@ -29,6 +29,7 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
 import javax.ws.rs.core.Response;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.SerializationUtils;
@@ -47,6 +48,7 @@ import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.service.ImplementationService;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.apache.syncope.fit.AbstractITCase;
+import org.apache.syncope.fit.core.reference.DummyPullCorrelationRule;
 import org.junit.jupiter.api.Test;
 
 public class PolicyITCase extends AbstractITCase {
@@ -166,8 +168,10 @@ public class PolicyITCase extends AbstractITCase {
 
     @Test
     public void getPullCorrelationRuleJavaClasses() {
-        assertTrue(syncopeService.platform().
-                getJavaImplInfo(ImplementationType.PULL_CORRELATION_RULE).get().getClasses().isEmpty());
+        Set<String> classes = syncopeService.platform().
+                getJavaImplInfo(ImplementationType.PULL_CORRELATION_RULE).get().getClasses();
+        assertEquals(1, classes.size());
+        assertEquals(DummyPullCorrelationRule.class.getName(), classes.iterator().next());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/test/resources/TestPullRule.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/TestPullRule.groovy b/fit/core-reference/src/test/resources/TestPullRule.groovy
index 3203c7b..04b1d9e 100644
--- a/fit/core-reference/src/test/resources/TestPullRule.groovy
+++ b/fit/core-reference/src/test/resources/TestPullRule.groovy
@@ -1,3 +1,4 @@
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -17,10 +18,11 @@
  * under the License.
  */
 import groovy.transform.CompileStatic
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule
 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.resource.Provision
 import org.identityconnectors.framework.common.objects.ConnectorObject;
-import org.apache.syncope.core.provisioning.api.pushpull.PullCorrelationRule;
 
 /**
  * Test pull rule relying on <tt>email</tt> attribute value.
@@ -29,7 +31,7 @@ import org.apache.syncope.core.provisioning.api.pushpull.PullCorrelationRule;
 class TestPullRule implements PullCorrelationRule {
 
   @Override
-  SearchCond getSearchCond(final ConnectorObject connObj) {
+  SearchCond getSearchCond(final ConnectorObject connObj, final Provision provision) {
     AttributeCond cond = new AttributeCond();
     cond.setSchema("email");
     cond.setType(AttributeCond.Type.EQ);

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/fit/core-reference/src/test/resources/log4j2.xml
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/log4j2.xml b/fit/core-reference/src/test/resources/log4j2.xml
index a3fe0d6..385f3ef 100644
--- a/fit/core-reference/src/test/resources/log4j2.xml
+++ b/fit/core-reference/src/test/resources/log4j2.xml
@@ -41,6 +41,10 @@ under the License.
       <appender-ref ref="main"/>
     </asyncLogger>
 
+    <asyncLogger name="org.apache.wicket" additivity="false" level="ERROR">
+      <appender-ref ref="main"/>
+    </asyncLogger>
+
     <asyncLogger name="org.apache.syncope.fit" additivity="false" level="DEBUG">
       <appender-ref ref="main"/>
     </asyncLogger>


[2/2] syncope git commit: [SYNCOPE-956] PullCorrelationRule as AccountRule and PasswordRule

Posted by il...@apache.org.
[SYNCOPE-956] PullCorrelationRule as AccountRule and PasswordRule


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

Branch: refs/heads/master
Commit: 17174c7a3f2288a598cc6b1e216fdb811f18659d
Parents: 3f47e9b
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Oct 19 16:00:42 2017 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Fri Oct 20 16:57:48 2017 +0200

----------------------------------------------------------------------
 .../init/ClassPathScanImplementationLookup.java |  13 +
 .../client/console/panels/BeanPanel.java        |   2 +-
 .../panels/ImplementationModalPanel.java        |  10 +
 .../policies/PolicyModalPanelBuilder.java       |  15 +-
 .../policies/PolicyRuleDirectoryPanel.java      |  14 -
 .../console/policies/PolicySpecModalPanel.java  | 344 -------------------
 .../policies/PullPolicyDirectoryPanel.java      |  11 +-
 .../console/policies/PullPolicyModalPanel.java  | 338 ++++++++++++++++++
 .../reports/ReportletDirectoryPanel.java        |  15 -
 .../console/wizards/any/Relationships.java      |   2 +-
 .../MyPullCorrelationRule.groovy                |   5 +-
 .../policies/PolicyDirectoryPanel.properties    |   1 +
 .../policies/PolicyDirectoryPanel_it.properties |   1 +
 .../PolicyDirectoryPanel_pt_BR.properties       |   1 +
 .../policies/PolicyDirectoryPanel_ru.properties |   1 +
 ...licySpecModalPanel$CorrelationRulePanel.html |  32 --
 .../console/policies/PolicySpecModalPanel.html  |  28 --
 .../policies/PolicySpecModalPanel.properties    |  22 --
 .../policies/PolicySpecModalPanel_it.properties |  22 --
 .../PolicySpecModalPanel_pt_BR.properties       |  22 --
 .../policies/PolicySpecModalPanel_ru.properties |  23 --
 ...llPolicyModalPanel$CorrelationRulePanel.html |  31 ++
 .../console/policies/PullPolicyModalPanel.html  |  25 ++
 .../policies/PullPolicyModalPanel.properties    |  19 +
 .../policies/PullPolicyModalPanel_it.properties |  20 ++
 .../PullPolicyModalPanel_pt_BR.properties       |  20 ++
 .../policies/PullPolicyModalPanel_ru.properties |  20 ++
 .../org/apache/syncope/common/lib/Schema.java   |  37 ++
 .../policy/AbstractPullCorrelationRuleConf.java |  52 +++
 .../lib/policy/DefaultAccountRuleConf.java      |   2 +-
 .../lib/policy/DefaultPasswordRuleConf.java     |   2 +-
 .../policy/DefaultPullCorrelationRuleConf.java  |  47 +++
 .../lib/policy/PullCorrelationRuleConf.java     |  23 ++
 .../common/lib/report/GroupReportletConf.java   |   1 +
 .../syncope/common/lib/report/Schema.java       |  35 --
 .../common/lib/report/UserReportletConf.java    |   1 +
 .../init/ClassPathScanImplementationLookup.java |  34 +-
 .../persistence/api/ImplementationLookup.java   |  14 +-
 .../api/dao/PullCorrelationRule.java            |  42 +++
 .../api/dao/PullCorrelationRuleConfClass.java   |  33 ++
 .../persistence/jpa/dao/DefaultAccountRule.java |   1 -
 .../jpa/dao/DefaultPullCorrelationRule.java     | 113 ++++++
 .../jpa/DummyImplementationLookup.java          |  10 +
 .../core/persistence/jpa/inner/PolicyTest.java  |  15 +-
 .../test/resources/domains/MasterContent.xml    |   2 +-
 .../api/pushpull/PullCorrelationRule.java       |  36 --
 .../java/data/ImplementationDataBinderImpl.java |   8 +-
 .../java/data/PolicyDataBinderImpl.java         |   9 +-
 .../pushpull/PlainAttrsPullCorrelationRule.java | 113 ------
 .../provisioning/java/pushpull/PullUtils.java   |  31 +-
 .../java/DummyImplementationLookup.java         |  10 +
 .../core/spring/ImplementationManager.java      |  39 ++-
 .../security/DummyImplementationLookup.java     |   9 +
 .../reference/DummyPullCorrelationRule.java     |  35 ++
 .../reference/DummyPullCorrelationRuleConf.java |  29 ++
 .../core/reference/ITImplementationLookup.java  |  24 ++
 .../syncope/fit/console/PoliciesITCase.java     |  69 +---
 .../syncope/fit/console/ReportsITCase.java      | 119 -------
 .../syncope/fit/console/TopologyITCase.java     |   2 +-
 .../apache/syncope/fit/console/UsersITCase.java |   1 -
 .../apache/syncope/fit/core/PolicyITCase.java   |   8 +-
 .../src/test/resources/TestPullRule.groovy      |   6 +-
 .../src/test/resources/log4j2.xml               |   4 +
 63 files changed, 1131 insertions(+), 942 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java b/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
index ed60e6c..415e7c4 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/init/ClassPathScanImplementationLookup.java
@@ -36,6 +36,7 @@ import org.apache.syncope.client.console.wicket.markup.html.form.preview.Abstrac
 import org.apache.syncope.client.console.widgets.BaseExtWidget;
 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.report.ReportletConf;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -65,6 +66,8 @@ public class ClassPathScanImplementationLookup {
 
     private Map<String, Class<? extends PasswordRuleConf>> passwordRuleConfs;
 
+    private Map<String, Class<? extends PullCorrelationRuleConf>> pullCorrelationRuleConfs;
+
     /**
      * This method can be overridden by subclasses to customize classpath scan.
      *
@@ -84,6 +87,7 @@ public class ClassPathScanImplementationLookup {
         reportletConfs = new HashMap<>();
         accountRuleConfs = new HashMap<>();
         passwordRuleConfs = new HashMap<>();
+        pullCorrelationRuleConfs = new HashMap<>();
 
         ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
         scanner.addIncludeFilter(new AssignableTypeFilter(BasePage.class));
@@ -94,6 +98,7 @@ public class ClassPathScanImplementationLookup {
         scanner.addIncludeFilter(new AssignableTypeFilter(ReportletConf.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(AccountRuleConf.class));
         scanner.addIncludeFilter(new AssignableTypeFilter(PasswordRuleConf.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(PullCorrelationRuleConf.class));
 
         scanner.findCandidateComponents(getBasePackage()).forEach(bd -> {
             try {
@@ -128,6 +133,8 @@ public class ClassPathScanImplementationLookup {
                         accountRuleConfs.put(clazz.getName(), (Class<? extends AccountRuleConf>) clazz);
                     } else if (PasswordRuleConf.class.isAssignableFrom(clazz)) {
                         passwordRuleConfs.put(clazz.getName(), (Class<? extends PasswordRuleConf>) clazz);
+                    } else if (PullCorrelationRuleConf.class.isAssignableFrom(clazz)) {
+                        pullCorrelationRuleConfs.put(clazz.getName(), (Class<? extends PullCorrelationRuleConf>) clazz);
                     }
                 }
             } catch (Throwable t) {
@@ -154,6 +161,7 @@ public class ClassPathScanImplementationLookup {
         reportletConfs = Collections.unmodifiableMap(reportletConfs);
         accountRuleConfs = Collections.unmodifiableMap(accountRuleConfs);
         passwordRuleConfs = Collections.unmodifiableMap(passwordRuleConfs);
+        pullCorrelationRuleConfs = Collections.unmodifiableMap(pullCorrelationRuleConfs);
 
         LOG.debug("Binary previewers found: {}", previewers);
         LOG.debug("Extension pages found: {}", extPages);
@@ -162,6 +170,7 @@ public class ClassPathScanImplementationLookup {
         LOG.debug("Reportlet configurations found: {}", reportletConfs);
         LOG.debug("Account Rule configurations found: {}", accountRuleConfs);
         LOG.debug("Password Rule configurations found: {}", passwordRuleConfs);
+        LOG.debug("Pull Correlation Rule configurations found: {}", pullCorrelationRuleConfs);
     }
 
     public Class<? extends AbstractBinaryPreviewer> getPreviewerClass(final String mimeType) {
@@ -206,4 +215,8 @@ public class ClassPathScanImplementationLookup {
         return passwordRuleConfs;
     }
 
+    public Map<String, Class<? extends PullCorrelationRuleConf>> getPullCorrelationRuleConfs() {
+        return pullCorrelationRuleConfs;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java
index d30bdbe..96ee931 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java
@@ -45,7 +45,7 @@ import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.report.Schema;
+import org.apache.syncope.common.lib.Schema;
 import org.apache.syncope.common.lib.report.SearchCondition;
 import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
 import org.apache.syncope.common.lib.to.AbstractSchemaTO;

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/panels/ImplementationModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ImplementationModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ImplementationModalPanel.java
index a2d4690..0e23e1b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ImplementationModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ImplementationModalPanel.java
@@ -86,6 +86,7 @@ public class ImplementationModalPanel extends AbstractModalPanel<ImplementationT
                 : implementation.getType() == ImplementationType.REPORTLET
                 || implementation.getType() == ImplementationType.ACCOUNT_RULE
                 || implementation.getType() == ImplementationType.PASSWORD_RULE
+                || implementation.getType() == ImplementationType.PULL_CORRELATION_RULE
                 ? ViewMode.JSON_BODY
                 : ViewMode.JAVA_CLASS;
         this.create = implementation.getKey() == null;
@@ -122,6 +123,11 @@ public class ImplementationModalPanel extends AbstractModalPanel<ImplementationT
                             collect(Collectors.toList());
                     break;
 
+                case PULL_CORRELATION_RULE:
+                    classes = implementationLookup.getPullCorrelationRuleConfs().keySet().stream().
+                            collect(Collectors.toList());
+                    break;
+
                 default:
             }
         }
@@ -266,6 +272,10 @@ public class ImplementationModalPanel extends AbstractModalPanel<ImplementationT
                         clazz = implementationLookup.getPasswordRuleConfs().get(jsonClass.getModelObject());
                         break;
 
+                    case PULL_CORRELATION_RULE:
+                        clazz = implementationLookup.getPullCorrelationRuleConfs().get(jsonClass.getModelObject());
+                        break;
+
                     default:
                 }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java
index 91b24d0..3fcb08e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyModalPanelBuilder.java
@@ -18,7 +18,9 @@
  */
 package org.apache.syncope.client.console.policies;
 
+import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
@@ -31,6 +33,7 @@ import org.apache.syncope.client.console.rest.PolicyRestClient;
 import org.apache.syncope.client.console.rest.ResourceRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSpinnerFieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
@@ -40,7 +43,9 @@ import org.apache.syncope.client.console.wizards.AjaxWizard;
 import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
 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.to.EntityTO;
+import org.apache.syncope.common.lib.types.ConflictResolutionAction;
 import org.apache.wicket.Component;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -115,9 +120,7 @@ public class PolicyModalPanelBuilder<T extends AbstractPolicyTO> extends Abstrac
                         "field",
                         new PropertyModel<List<String>>(policyTO, "passthroughResources"),
                         new ListModel<String>(resources.getObject())));
-            }
-
-            if (policyTO instanceof PasswordPolicyTO) {
+            } else if (policyTO instanceof PasswordPolicyTO) {
                 fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().build(
                         "field",
                         "historyLength",
@@ -129,6 +132,12 @@ public class PolicyModalPanelBuilder<T extends AbstractPolicyTO> extends Abstrac
                         "allowNullPassword",
                         new PropertyModel<>(policyTO, "allowNullPassword"),
                         false));
+            } else if (policyTO instanceof PullPolicyTO) {
+                fields.add(new AjaxDropDownChoicePanel<>(
+                        "field",
+                        "conflictResolutionAction",
+                        new PropertyModel<>(policyTO, "conflictResolutionAction")).
+                        setChoices(Arrays.asList((Serializable[]) ConflictResolutionAction.values())));
             }
 
             add(new ListView<Component>("fields", fields) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java
index 2b5f8d4..1cddad3 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleDirectoryPanel.java
@@ -26,7 +26,6 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.stream.Collectors;
-import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.Constants;
@@ -140,19 +139,6 @@ public class PolicyRuleDirectoryPanel<T extends AbstractPolicyTO> extends Direct
 
             @Override
             public void onClick(final AjaxRequestTarget target, final PolicyRuleWrapper ignore) {
-                RuleConf clone = SerializationUtils.clone(model.getObject().getConf());
-
-                PolicyRuleDirectoryPanel.this.getTogglePanel().close(target);
-                send(PolicyRuleDirectoryPanel.this, Broadcast.EXACT,
-                        new AjaxWizard.EditItemActionEvent<>(new PolicyRuleWrapper(true).setConf(clone), target));
-            }
-        }, ActionLink.ActionType.CLONE, StandardEntitlement.POLICY_CREATE);
-        panel.add(new ActionLink<PolicyRuleWrapper>() {
-
-            private static final long serialVersionUID = -3722207913631435501L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target, final PolicyRuleWrapper ignore) {
                 PolicyRuleDirectoryPanel.this.getTogglePanel().close(target);
                 if (model.getObject().getConf() == null) {
                     SyncopeConsoleSession.get().info(getString("noConf"));

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicySpecModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicySpecModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicySpecModalPanel.java
deleted file mode 100644
index 4280996..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicySpecModalPanel.java
+++ /dev/null
@@ -1,344 +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.client.console.policies;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.panels.AbstractModalPanel;
-import org.apache.syncope.client.console.rest.AnyTypeRestClient;
-import org.apache.syncope.client.console.rest.ImplementationRestClient;
-import org.apache.syncope.client.console.rest.PolicyRestClient;
-import org.apache.syncope.client.console.rest.SchemaRestClient;
-import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.MultiPanel;
-import org.apache.syncope.common.lib.policy.PullPolicyTO;
-import org.apache.syncope.common.lib.to.EntityTO;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.ConflictResolutionAction;
-import org.apache.syncope.common.lib.types.ImplementationType;
-import org.apache.syncope.common.lib.types.SchemaType;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.markup.html.list.ListItem;
-import org.apache.wicket.markup.html.panel.Panel;
-import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.model.PropertyModel;
-
-public class PolicySpecModalPanel extends AbstractModalPanel<PullPolicyTO> {
-
-    private static final long serialVersionUID = 5945391813567245081L;
-
-    private enum CorrelationRuleType {
-        PLAIN_ATTRIBUTES,
-        CUSTOM;
-
-    }
-
-    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
-
-    private final IModel<List<CorrelationRule>> model;
-
-    private final PolicyRestClient restClient = new PolicyRestClient();
-
-    public PolicySpecModalPanel(
-            final PullPolicyTO policyTO, final BaseModal<PullPolicyTO> modal, final PageReference pageRef) {
-
-        super(modal, pageRef);
-        modal.setFormModel(policyTO);
-
-        add(new AjaxDropDownChoicePanel<>(
-                "conflictResolutionAction",
-                "conflictResolutionAction",
-                new PropertyModel<>(policyTO, "conflictResolutionAction")).
-                setChoices(Arrays.asList((Serializable[]) ConflictResolutionAction.values())));
-
-        model = new PropertyModel<List<CorrelationRule>>(policyTO, "correlationRules") {
-
-            private static final long serialVersionUID = -8168676563540297301L;
-
-            private List<CorrelationRule> rules = policyTO.getCorrelationRules().keySet().stream().
-                    map(rule -> new CorrelationRule(rule, policyTO.getCorrelationRules().get(rule))).
-                    collect(Collectors.toList());
-
-            @Override
-            public List<CorrelationRule> getObject() {
-                return rules;
-            }
-
-            @Override
-            public void setObject(final List<CorrelationRule> object) {
-                policyTO.getCorrelationRules().clear();
-                rules.forEach(rule -> {
-                    policyTO.getCorrelationRules().put(rule.getAny(), rule.getRule());
-                });
-            }
-        };
-
-        add(new MultiPanel<CorrelationRule>("correlationRules", "correlationRules", model) {
-
-            private static final long serialVersionUID = -2481579077338205547L;
-
-            @Override
-            protected CorrelationRule newModelObject() {
-                return new CorrelationRule();
-            }
-
-            @Override
-            protected CorrelationRulePanel getItemPanel(final ListItem<CorrelationRule> item) {
-                return new CorrelationRulePanel("panel", Model.of(item.getModelObject()));
-            }
-        });
-    }
-
-    @Override
-    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
-        try {
-            getItem().getCorrelationRules().clear();
-            model.getObject().forEach(rule -> {
-                getItem().getCorrelationRules().put(rule.getAny(), rule.getRule());
-            });
-            restClient.updatePolicy(getItem());
-            SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
-            this.modal.close(target);
-        } catch (Exception e) {
-            LOG.error("While creating/updating policy", e);
-            SyncopeConsoleSession.get().error(
-                    StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
-        }
-        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
-    }
-
-    public static class CorrelationRulePanel extends Panel {
-
-        private static final long serialVersionUID = -4708008994320210839L;
-
-        private final ImplementationRestClient implRestClient = new ImplementationRestClient();
-
-        CorrelationRulePanel(final String id, final IModel<CorrelationRule> rule) {
-            super(id);
-
-            AjaxDropDownChoicePanel<String> anyType = new AjaxDropDownChoicePanel<>(
-                    "anyType", "any.type", new PropertyModel<String>(rule.getObject(), "any")).
-                    setNullValid(true).
-                    setChoices(new AnyTypeRestClient().list());
-            add(anyType);
-
-            final AjaxDropDownChoicePanel<CorrelationRuleType> ruleType = new AjaxDropDownChoicePanel<>(
-                    "ruleType", "rule.type", new PropertyModel<CorrelationRuleType>(rule.getObject(), "type"), false).
-                    setNullValid(true).
-                    setChoices(Arrays.stream(CorrelationRuleType.values()).collect(Collectors.toList()));
-            add(ruleType);
-
-            // ---------------------------------------------------------------
-            // Custom rule palette
-            // ---------------------------------------------------------------
-            List<String> rules = implRestClient.list(ImplementationType.PULL_CORRELATION_RULE).stream().
-                    map(EntityTO::getKey).sorted().collect(Collectors.toList());
-            final AjaxDropDownChoicePanel<String> customRule = new AjaxDropDownChoicePanel<>(
-                    "customRule", "rule.custom", new PropertyModel<String>(rule.getObject(), "rule")).setChoices(rules);
-            customRule.setOutputMarkupPlaceholderTag(true);
-            add(customRule.setVisible(CorrelationRuleType.CUSTOM == rule.getObject().getType()));
-            // ---------------------------------------------------------------
-
-            // ---------------------------------------------------------------
-            // JSON rule palette
-            // ---------------------------------------------------------------
-            AjaxPalettePanel.Builder<String> jsonRuleBuilder =
-                    new AjaxPalettePanel.Builder<String>().setName("rule.json");
-
-            final PropertyModel<List<String>> jsonRuleModel =
-                    new PropertyModel<List<String>>(rule.getObject(), "rule") {
-
-                private static final long serialVersionUID = 3799387950428254072L;
-
-                @Override
-                public List<String> getObject() {
-                    final List<String> res = new ArrayList<>();
-                    try {
-                        JsonNode obj = OBJECT_MAPPER.readTree(rule.getObject().getRule());
-                        if (obj.isArray()) {
-                            for (final JsonNode objNode : obj) {
-                                res.add(objNode.asText());
-                            }
-                        }
-                    } catch (IOException e) {
-                        LOG.warn("Error deserializing json tree", e);
-                    }
-                    return res;
-                }
-
-                @Override
-                public void setObject(final List<String> object) {
-                    final StringBuilder bld = new StringBuilder();
-                    bld.append("[");
-
-                    boolean comma = false;
-                    for (String obj : object) {
-                        if (comma) {
-                            bld.append(",");
-                        } else {
-                            comma = true;
-                        }
-                        bld.append("\"").append(obj).append("\"");
-                    }
-                    bld.append("]");
-                    rule.getObject().setRule(bld.toString());
-                }
-            };
-
-            final AjaxPalettePanel<String> jsonRule =
-                    jsonRuleBuilder.build("jsonRule", jsonRuleModel, new AjaxPalettePanel.Builder.Query<String>() {
-
-                        private static final long serialVersionUID = -7223078772249308813L;
-
-                        @Override
-                        public List<String> execute(final String filter) {
-                            return getPlainSchemas(rule.getObject());
-                        }
-                    });
-            jsonRule.hideLabel().setOutputMarkupPlaceholderTag(true);
-
-            anyType.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
-
-                private static final long serialVersionUID = -1107858522700306810L;
-
-                @Override
-                protected void onUpdate(final AjaxRequestTarget target) {
-                    if (jsonRule.isVisibleInHierarchy()) {
-                        rule.getObject().setRule("[]");
-                        jsonRule.reload(target);
-                        target.add(jsonRule);
-                    }
-                }
-            });
-
-            add(jsonRule.setVisible(CorrelationRuleType.PLAIN_ATTRIBUTES == rule.getObject().getType()));
-            // ---------------------------------------------------------------
-
-            ruleType.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
-
-                private static final long serialVersionUID = -1107858522700306810L;
-
-                @Override
-                protected void onUpdate(final AjaxRequestTarget target) {
-                    switch (ruleType.getModelObject()) {
-                        case PLAIN_ATTRIBUTES:
-                            jsonRule.setVisible(true);
-                            customRule.setVisible(false);
-                            jsonRule.reload(target);
-                            break;
-
-                        case CUSTOM:
-                            jsonRule.setVisible(false);
-                            customRule.setVisible(true);
-                            break;
-
-                        default:
-                            customRule.setVisible(false);
-                            jsonRule.setVisible(false);
-
-                    }
-                    target.add(jsonRule);
-                    target.add(customRule);
-                }
-            });
-        }
-
-        private static List<String> getPlainSchemas(final CorrelationRule rule) {
-            final List<String> choices = StringUtils.isEmpty(rule.getAny())
-                    ? new ArrayList<>()
-                    : new SchemaRestClient().getSchemas(SchemaType.PLAIN,
-                            rule.getAny().equals(AnyTypeKind.USER.name())
-                            ? AnyTypeKind.USER
-                            : rule.getAny().equals(AnyTypeKind.GROUP.name())
-                            ? AnyTypeKind.GROUP
-                            : AnyTypeKind.ANY_OBJECT).stream().map(EntityTO::getKey).
-                            collect(Collectors.toList());
-
-            choices.add("key");
-            choices.add(rule.getAny().equals(AnyTypeKind.USER.name()) ? "username" : "name");
-            Collections.sort(choices);
-            return choices;
-        }
-    }
-
-    private static class CorrelationRule implements Serializable {
-
-        private static final long serialVersionUID = 5250228867297353011L;
-
-        private String any;
-
-        private CorrelationRuleType type;
-
-        private String rule;
-
-        CorrelationRule() {
-            this.any = AnyTypeKind.USER.name();
-            this.type = CorrelationRuleType.PLAIN_ATTRIBUTES;
-            this.rule = "[]";
-        }
-
-        CorrelationRule(final String any, final String rule) {
-            this.any = any;
-            this.type = StringUtils.isEmpty(rule) || rule.trim().startsWith("[") ? CorrelationRuleType.PLAIN_ATTRIBUTES
-                    : CorrelationRuleType.CUSTOM;
-            this.rule = rule;
-        }
-
-        public String getAny() {
-            return any;
-        }
-
-        public CorrelationRuleType getType() {
-            return type;
-        }
-
-        public String getRule() {
-            return rule;
-        }
-
-        public void setAny(final String any) {
-            this.any = any;
-        }
-
-        public void setType(final CorrelationRuleType type) {
-            this.type = type;
-        }
-
-        public void setRule(final String rule) {
-            this.rule = rule;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java
index 5a29cae..735aa24 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.client.console.policies;
 
+import java.util.List;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
 import org.apache.syncope.common.lib.policy.PullPolicyTO;
@@ -26,6 +27,8 @@ import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.StringResourceModel;
@@ -50,6 +53,12 @@ public class PullPolicyDirectoryPanel extends PolicyDirectoryPanel<PullPolicyTO>
     }
 
     @Override
+    protected void addCustomColumnFields(final List<IColumn<PullPolicyTO, String>> columns) {
+        columns.add(new PropertyColumn<>(new StringResourceModel(
+                "conflictResolutionAction", this), "conflictResolutionAction", "conflictResolutionAction"));
+    }
+
+    @Override
     protected void addCustomActions(final ActionsPanel<PullPolicyTO> panel, final IModel<PullPolicyTO> model) {
         panel.add(new ActionLink<PullPolicyTO>() {
 
@@ -58,7 +67,7 @@ public class PullPolicyDirectoryPanel extends PolicyDirectoryPanel<PullPolicyTO>
             @Override
             public void onClick(final AjaxRequestTarget target, final PullPolicyTO ignore) {
                 target.add(policySpecModal.setContent(
-                        new PolicySpecModalPanel(model.getObject(), policySpecModal, pageRef)));
+                        new PullPolicyModalPanel(model.getObject(), policySpecModal, pageRef)));
 
                 policySpecModal.header(new StringResourceModel(
                         "policy.rules", PullPolicyDirectoryPanel.this, Model.of(model.getObject())));

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyModalPanel.java
new file mode 100644
index 0000000..23a2283
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyModalPanel.java
@@ -0,0 +1,338 @@
+/*
+ * 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.client.console.policies;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.panels.AbstractModalPanel;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
+import org.apache.syncope.client.console.rest.ImplementationRestClient;
+import org.apache.syncope.client.console.rest.PolicyRestClient;
+import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.MultiPanel;
+import org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf;
+import org.apache.syncope.common.lib.policy.PullPolicyTO;
+import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.to.ImplementationTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ImplementationEngine;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+public class PullPolicyModalPanel extends AbstractModalPanel<PullPolicyTO> {
+
+    private static final long serialVersionUID = 2988891313881271124L;
+
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+    private final PolicyRestClient restClient = new PolicyRestClient();
+
+    private final ImplementationRestClient implRestClient = new ImplementationRestClient();
+
+    private final SchemaRestClient schemaRestClient = new SchemaRestClient();
+
+    private final LoadableDetachableModel<Map<String, ImplementationTO>> implementations =
+            new LoadableDetachableModel<Map<String, ImplementationTO>>() {
+
+        private static final long serialVersionUID = 5275935387613157437L;
+
+        @Override
+        protected Map<String, ImplementationTO> load() {
+            return implRestClient.list(ImplementationType.PULL_CORRELATION_RULE).stream().
+                    collect(Collectors.toMap(EntityTO::getKey, Function.identity()));
+        }
+    };
+
+    private final IModel<List<CorrelationRule>> model;
+
+    public PullPolicyModalPanel(
+            final PullPolicyTO policyTO,
+            final BaseModal<PullPolicyTO> modal,
+            final PageReference pageRef) {
+
+        super(modal, pageRef);
+        modal.setFormModel(policyTO);
+
+        model = new PropertyModel<List<CorrelationRule>>(policyTO, "correlationRules") {
+
+            private static final long serialVersionUID = -8168676563540297301L;
+
+            private final List<CorrelationRule> rules = policyTO.getCorrelationRules().keySet().stream().
+                    map(anyType -> new CorrelationRule(anyType,
+                    implementations.getObject().get(policyTO.getCorrelationRules().get(anyType)))).
+                    collect(Collectors.toList());
+
+            @Override
+            public List<CorrelationRule> getObject() {
+                return rules;
+            }
+
+            @Override
+            public void setObject(final List<CorrelationRule> object) {
+                policyTO.getCorrelationRules().clear();
+                rules.forEach(rule -> {
+                    policyTO.getCorrelationRules().put(rule.getAnyType(), rule.getImpl().getKey());
+                });
+            }
+        };
+
+        add(new MultiPanel<CorrelationRule>("correlationRules", "correlationRules", model) {
+
+            private static final long serialVersionUID = -2481579077338205547L;
+
+            @Override
+            protected CorrelationRule newModelObject() {
+                return new CorrelationRule();
+            }
+
+            @Override
+            protected CorrelationRulePanel getItemPanel(final ListItem<CorrelationRule> item) {
+                return new CorrelationRulePanel("panel", Model.of(item.getModelObject()));
+            }
+        });
+    }
+
+    @Override
+    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        try {
+            getItem().getCorrelationRules().clear();
+            model.getObject().forEach(rule -> {
+                getItem().getCorrelationRules().put(rule.getAnyType(), rule.getImplKey());
+
+                if (rule.getImpl().getEngine() == ImplementationEngine.JAVA && rule.getDefaultRuleConf() != null) {
+                    try {
+                        implRestClient.update(rule.getImpl());
+                    } catch (Exception e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            });
+            restClient.updatePolicy(getItem());
+
+            SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+            this.modal.close(target);
+        } catch (Exception e) {
+            LOG.error("While creating/updating policy", e);
+            SyncopeConsoleSession.get().error(
+                    StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
+        }
+        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+    }
+
+    protected class CorrelationRulePanel extends Panel {
+
+        private static final long serialVersionUID = -5380414818290018189L;
+
+        CorrelationRulePanel(final String id, final IModel<CorrelationRule> correlationRule) {
+            super(id);
+
+            AjaxDropDownChoicePanel<String> anyType = new AjaxDropDownChoicePanel<>(
+                    "anyType", "anyType", new PropertyModel<String>(correlationRule.getObject(), "anyType")).
+                    setNullValid(true).
+                    setChoices(new AnyTypeRestClient().list());
+            anyType.setNullValid(false);
+            anyType.setRequired(true);
+            anyType.setOutputMarkupId(true);
+            add(anyType);
+
+            AjaxDropDownChoicePanel<String> rule = new AjaxDropDownChoicePanel<>(
+                    "rule", "rule", new PropertyModel<String>(correlationRule.getObject(), "implKey")).
+                    setChoices(implementations.getObject().keySet().stream().sorted().collect(Collectors.toList()));
+            rule.setNullValid(false);
+            rule.setRequired(true);
+            rule.setOutputMarkupId(true);
+            add(rule);
+
+            PropertyModel<List<String>> defaultRuleConfModel =
+                    new PropertyModel<List<String>>(correlationRule.getObject().getDefaultRuleConf(), "schemas") {
+
+                private static final long serialVersionUID = 3799387950428254072L;
+
+                @Override
+                public List<String> getObject() {
+                    List<String> schemas = new ArrayList<>();
+                    if (correlationRule.getObject().getDefaultRuleConf() != null) {
+                        schemas.addAll(correlationRule.getObject().getDefaultRuleConf().getSchemas());
+                    }
+                    return schemas;
+                }
+
+                @Override
+                public void setObject(final List<String> object) {
+                    if (correlationRule.getObject().getDefaultRuleConf() != null) {
+                        correlationRule.getObject().getDefaultRuleConf().getSchemas().clear();
+                        correlationRule.getObject().getDefaultRuleConf().getSchemas().addAll(object);
+                    }
+                }
+            };
+
+            AjaxPalettePanel<String> defaultRuleConf = new AjaxPalettePanel.Builder<String>().
+                    setName("defaultRuleConf").build("defaultRuleConf",
+                    defaultRuleConfModel, new AjaxPalettePanel.Builder.Query<String>() {
+
+                private static final long serialVersionUID = -7223078772249308813L;
+
+                @Override
+                public List<String> execute(final String filter) {
+                    return getSchemas(correlationRule.getObject());
+                }
+            });
+            defaultRuleConf.hideLabel().setOutputMarkupPlaceholderTag(true);
+            add(defaultRuleConf.setVisible(correlationRule.getObject().getDefaultRuleConf() != null));
+
+            anyType.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+                private static final long serialVersionUID = -1107858522700306810L;
+
+                @Override
+                protected void onUpdate(final AjaxRequestTarget target) {
+                    if (defaultRuleConf.isVisibleInHierarchy()) {
+                        correlationRule.getObject().setImpl(null);
+                        defaultRuleConf.reload(target);
+                        target.add(defaultRuleConf);
+                    }
+                }
+            });
+
+            rule.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+                private static final long serialVersionUID = -1107858522700306810L;
+
+                @Override
+                protected void onUpdate(final AjaxRequestTarget target) {
+                    if (correlationRule.getObject().getDefaultRuleConf() == null) {
+                        defaultRuleConf.setVisible(false);
+                    } else {
+                        defaultRuleConf.setVisible(true);
+                    }
+                    target.add(defaultRuleConf);
+                }
+            });
+        }
+
+        private List<String> getSchemas(final CorrelationRule rule) {
+            List<String> choices = StringUtils.isEmpty(rule.getAnyType())
+                    ? new ArrayList<>()
+                    : schemaRestClient.getSchemas(SchemaType.PLAIN,
+                            rule.getAnyType().equals(AnyTypeKind.USER.name())
+                            ? AnyTypeKind.USER
+                            : rule.getAnyType().equals(AnyTypeKind.GROUP.name())
+                            ? AnyTypeKind.GROUP
+                            : AnyTypeKind.ANY_OBJECT).stream().map(EntityTO::getKey).
+                            collect(Collectors.toList());
+            choices.add("key");
+            choices.add(rule.getAnyType().equals(AnyTypeKind.USER.name()) ? "username" : "name");
+            Collections.sort(choices);
+            return choices;
+        }
+    }
+
+    private class CorrelationRule implements Serializable {
+
+        private static final long serialVersionUID = 4221521483948294336L;
+
+        private String anyType;
+
+        private ImplementationTO impl;
+
+        private DefaultPullCorrelationRuleConf defaultRuleConf;
+
+        CorrelationRule() {
+            this.anyType = AnyTypeKind.USER.name();
+        }
+
+        CorrelationRule(final String anyType, final ImplementationTO impl) {
+            this.anyType = anyType;
+            setImpl(impl);
+        }
+
+        public String getAnyType() {
+            return anyType;
+        }
+
+        public void setAnyType(final String anyType) {
+            this.anyType = anyType;
+        }
+
+        public String getImplKey() {
+            return impl == null ? null : impl.getKey();
+        }
+
+        public void setImplKey(final String key) {
+            setImpl(implementations.getObject().get(key));
+        }
+
+        public final void setImpl(final ImplementationTO impl) {
+            this.impl = impl;
+            if (impl != null) {
+                this.defaultRuleConf = null;
+                try {
+                    this.defaultRuleConf = OBJECT_MAPPER.readValue(
+                            impl.getBody(), DefaultPullCorrelationRuleConf.class);
+                } catch (Exception e) {
+                    LOG.debug("Could not deserialize {} as {}",
+                            impl.getBody(), DefaultPullCorrelationRuleConf.class.getName());
+                }
+            }
+        }
+
+        public ImplementationTO getImpl() {
+            if (defaultRuleConf != null) {
+                try {
+                    this.impl.setBody(OBJECT_MAPPER.writeValueAsString(defaultRuleConf));
+                } catch (Exception e) {
+                    LOG.error("Could not serialize {}", defaultRuleConf);
+                }
+            }
+            return impl;
+        }
+
+        public void setDefaultRuleConf(final DefaultPullCorrelationRuleConf defaultRuleConf) {
+            this.defaultRuleConf = defaultRuleConf;
+        }
+
+        public DefaultPullCorrelationRuleConf getDefaultRuleConf() {
+            return defaultRuleConf;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java
index 667cc92..db7f4b8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.java
@@ -26,7 +26,6 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.stream.Collectors;
-import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.Constants;
@@ -138,20 +137,6 @@ public class ReportletDirectoryPanel extends DirectoryPanel<
             @Override
             public void onClick(final AjaxRequestTarget target, final ReportletWrapper ignore) {
                 ReportletDirectoryPanel.this.getTogglePanel().close(target);
-                ReportletConf clone = SerializationUtils.clone(model.getObject().getConf());
-
-                send(ReportletDirectoryPanel.this, Broadcast.EXACT,
-                        new AjaxWizard.EditItemActionEvent<>(
-                                new ReportletWrapper(true).setConf(clone), target));
-            }
-        }, ActionLink.ActionType.CLONE, StandardEntitlement.REPORT_CREATE);
-        panel.add(new ActionLink<ReportletWrapper>() {
-
-            private static final long serialVersionUID = -3722207913631435501L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target, final ReportletWrapper ignore) {
-                ReportletDirectoryPanel.this.getTogglePanel().close(target);
                 if (model.getObject().getConf() == null) {
                     SyncopeConsoleSession.get().info(getString("noConf"));
                 } else {

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java
index 7d64b7d..06e126b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Relationships.java
@@ -136,7 +136,7 @@ public class Relationships extends WizardStep implements ICondition {
                 public Panel getPanel(final String panelId) {
                     return new ListViewPanel.Builder<>(RelationshipTO.class, pageRef).
                             setItems(relationships.get(relationship)).
-                            includes("rightType", "rightKey").
+                            includes("otherEndType", "otherEndKey").
                             addAction(new ActionLink<RelationshipTO>() {
 
                                 private static final long serialVersionUID = -6847033126124401556L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/implementations/MyPullCorrelationRule.groovy
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/implementations/MyPullCorrelationRule.groovy b/client/console/src/main/resources/org/apache/syncope/client/console/implementations/MyPullCorrelationRule.groovy
index 6f48a4c..bb56ebe 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/implementations/MyPullCorrelationRule.groovy
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/implementations/MyPullCorrelationRule.groovy
@@ -17,15 +17,16 @@
  * under the License.
  */
 import groovy.transform.CompileStatic
+import org.apache.syncope.core.persistence.api.dao.PullCorrelationRule
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond
-import org.apache.syncope.core.provisioning.api.pushpull.PullCorrelationRule
+import org.apache.syncope.core.persistence.api.entity.resource.Provision
 import org.identityconnectors.framework.common.objects.ConnectorObject
 
 @CompileStatic
 class MyPullCorrelationRule implements PullCorrelationRule {
 
   @Override
-  SearchCond getSearchCond(ConnectorObject connObj) {
+  SearchCond getSearchCond(ConnectorObject connObj, Provision provision) {
     
   }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.properties
index be212f8..b9074b2 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel.properties
@@ -28,3 +28,4 @@ any.new=New Policy
 any.finish=Submit ${description}
 any.cancel=Cancel ${description}
 compose.title=rules
+conflictResolutionAction=Conflict Resolution Action

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_it.properties
index 9a00b8d..f93168d 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_it.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_it.properties
@@ -28,3 +28,4 @@ any.new=Nuova Policy
 any.finish=Invia ${description}
 any.cancel=Annulla ${description}
 compose.title=regole
+conflictResolutionAction=Azione di Risoluzione Conflitti

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_pt_BR.properties
index be212f8..b9074b2 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_pt_BR.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_pt_BR.properties
@@ -28,3 +28,4 @@ any.new=New Policy
 any.finish=Submit ${description}
 any.cancel=Cancel ${description}
 compose.title=rules
+conflictResolutionAction=Conflict Resolution Action

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_ru.properties
index afbd430..d161fdc 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_ru.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicyDirectoryPanel_ru.properties
@@ -29,3 +29,4 @@ any.new=\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u0438\u044
 any.finish=\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c ${description}
 any.cancel=\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c ${description}
 compose.title=rules
+conflictResolutionAction=Conflict Resolution Action

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel$CorrelationRulePanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel$CorrelationRulePanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel$CorrelationRulePanel.html
deleted file mode 100644
index d514604..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel$CorrelationRulePanel.html
+++ /dev/null
@@ -1,32 +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.
--->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:panel>
-    <div class="form-group">
-      <span wicket:id="anyType"/>
-    </div>
-    <div class="form-group">
-      <span wicket:id="ruleType"/>
-    </div>
-    <div class="form-group">
-      <span wicket:id="customRule"/>
-      <span wicket:id="jsonRule"/>
-    </div>
-  </wicket:panel>
-</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel.html
deleted file mode 100644
index 9aaced7..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel.html
+++ /dev/null
@@ -1,28 +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.
--->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:panel>
-    <div class="form-group">
-      <span wicket:id="conflictResolutionAction"/>
-    </div>
-    <div class="form-group">
-      <span wicket:id="correlationRules"/>
-    </div>
-  </wicket:panel>
-</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel.properties
deleted file mode 100644
index 1c6b31c..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel.properties
+++ /dev/null
@@ -1,22 +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.
-rule.custom=Custom
-rule.json=Plain attributes
-rule.type=Rule Type
-any.type=Applies to
-correlationRules=Correlation Rules
-conflictResolutionAction=Conflict Resolution Action

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_it.properties
deleted file mode 100644
index 040e8fd..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_it.properties
+++ /dev/null
@@ -1,22 +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.
-rule.custom=Custom
-rule.json=Attributi
-rule.type=Tipo Regola
-any.type=Applicata a
-correlationRules=Regole di Correlazione
-conflictResolutionAction=Azione di Risoluzione Conflitti

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_pt_BR.properties
deleted file mode 100644
index 1c6b31c..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_pt_BR.properties
+++ /dev/null
@@ -1,22 +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.
-rule.custom=Custom
-rule.json=Plain attributes
-rule.type=Rule Type
-any.type=Applies to
-correlationRules=Correlation Rules
-conflictResolutionAction=Conflict Resolution Action

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_ru.properties
deleted file mode 100644
index 8d35548..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PolicySpecModalPanel_ru.properties
+++ /dev/null
@@ -1,23 +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.
-#
-rule.custom=Custom
-rule.json=\u041f\u0440\u0430\u0432\u0438\u043b\u043e JSON
-rule.type=\u0422\u0438\u043f \u043f\u0440\u0430\u0432\u0438\u043b
-any.type=\u041e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438
-correlationRules=\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u043a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u0438
-conflictResolutionAction=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0438 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u043e\u0432

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel$CorrelationRulePanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel$CorrelationRulePanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel$CorrelationRulePanel.html
new file mode 100644
index 0000000..0092417
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel$CorrelationRulePanel.html
@@ -0,0 +1,31 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div class="form-group">
+      <span wicket:id="anyType"/>
+    </div>
+    <div class="form-group">
+      <span wicket:id="rule"/>
+    </div>
+    <div class="form-group">
+      <span wicket:id="defaultRuleConf"/>
+    </div>
+  </wicket:panel>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel.html
new file mode 100644
index 0000000..5ade68c
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel.html
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div class="form-group">
+      <span wicket:id="correlationRules"/>
+    </div>
+  </wicket:panel>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel.properties
new file mode 100644
index 0000000..a661523
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel.properties
@@ -0,0 +1,19 @@
+# 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.
+rule=Rule
+anyType=Applies to
+correlationRules=Correlation Rules

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_it.properties
new file mode 100644
index 0000000..18420ca
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_it.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+rule=Regola
+anyType=Applicata a
+correlationRules=Regole di Correlazione

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_pt_BR.properties
new file mode 100644
index 0000000..e8338c2
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_pt_BR.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+rule=Rule
+anyType=Applies to
+correlationRules=Correlation Rules

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_ru.properties
new file mode 100644
index 0000000..39701d7
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/policies/PullPolicyModalPanel_ru.properties
@@ -0,0 +1,20 @@
+# 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.
+#
+rule=Rule
+anyType=\u041e\u0431\u044a\u0435\u043a\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0438
+correlationRules=\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u043a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u0438

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/Schema.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/Schema.java b/common/lib/src/main/java/org/apache/syncope/common/lib/Schema.java
new file mode 100644
index 0000000..625e31d
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/Schema.java
@@ -0,0 +1,37 @@
+/*
+ * 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.common.lib;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Schema {
+
+    SchemaType[] type() default { SchemaType.PLAIN };
+
+    AnyTypeKind anyTypeKind() default AnyTypeKind.USER;
+
+    boolean includeFields() default false;
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPullCorrelationRuleConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPullCorrelationRuleConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPullCorrelationRuleConf.java
new file mode 100644
index 0000000..c545b9d
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPullCorrelationRuleConf.java
@@ -0,0 +1,52 @@
+/*
+ * 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.common.lib.policy;
+
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlType
+@XmlSeeAlso({ DefaultPullCorrelationRuleConf.class })
+public abstract class AbstractPullCorrelationRuleConf extends AbstractBaseBean implements PullCorrelationRuleConf {
+
+    private static final long serialVersionUID = -4080475005967851092L;
+
+    private String name;
+
+    public AbstractPullCorrelationRuleConf() {
+        this(StringUtils.EMPTY);
+        setName(getClass().getName());
+    }
+
+    public AbstractPullCorrelationRuleConf(final String name) {
+        super();
+        this.name = name;
+    }
+
+    @Override
+    public final String getName() {
+        return name;
+    }
+
+    public final void setName(final String name) {
+        this.name = name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAccountRuleConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAccountRuleConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAccountRuleConf.java
index 2788a4a..81b86c2 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAccountRuleConf.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAccountRuleConf.java
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
-import org.apache.syncope.common.lib.report.Schema;
+import org.apache.syncope.common.lib.Schema;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.SchemaType;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPasswordRuleConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPasswordRuleConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPasswordRuleConf.java
index b622546..71e7488 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPasswordRuleConf.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPasswordRuleConf.java
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
-import org.apache.syncope.common.lib.report.Schema;
+import org.apache.syncope.common.lib.Schema;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.SchemaType;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17174c7a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPullCorrelationRuleConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPullCorrelationRuleConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPullCorrelationRuleConf.java
new file mode 100644
index 0000000..c781f50
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPullCorrelationRuleConf.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.policy;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.Schema;
+import org.apache.syncope.common.lib.types.SchemaType;
+
+@XmlRootElement(name = "defaultPullCorrelationRuleConf")
+@XmlType
+public class DefaultPullCorrelationRuleConf extends AbstractPullCorrelationRuleConf implements PullCorrelationRuleConf {
+
+    private static final long serialVersionUID = 429126085793346273L;
+
+    @Schema(type = { SchemaType.PLAIN }, includeFields = true)
+    private final List<String> schemas = new ArrayList<>();
+
+    @XmlElementWrapper(name = "schemas")
+    @XmlElement(name = "schema")
+    @JsonProperty("schemas")
+    public List<String> getSchemas() {
+        return schemas;
+    }
+
+}