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/10 06:36:53 UTC

[04/18] syncope git commit: [SYNCOPE-956] Core implementation

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
index 901cdc7..7b84fc5 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/Connector.java
@@ -32,7 +32,7 @@ import org.identityconnectors.framework.common.objects.SyncResultsHandler;
 import org.identityconnectors.framework.common.objects.SyncToken;
 import org.identityconnectors.framework.common.objects.Uid;
 import org.identityconnectors.framework.common.objects.filter.Filter;
-import org.apache.syncope.core.provisioning.api.pushpull.ReconciliationFilterBuilder;
+import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
 import org.identityconnectors.framework.common.objects.SearchResult;
 
 /**
@@ -115,7 +115,7 @@ public interface Connector {
      */
     void filteredReconciliation(
             ObjectClass objectClass,
-            ReconciliationFilterBuilder filterBuilder,
+            ReconFilterBuilder filterBuilder,
             SyncResultsHandler handler,
             OperationOptions options);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ImplementationDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ImplementationDataBinder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ImplementationDataBinder.java
new file mode 100644
index 0000000..8f88d63
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/ImplementationDataBinder.java
@@ -0,0 +1,32 @@
+/*
+ * 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.data;
+
+import org.apache.syncope.common.lib.to.ImplementationTO;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+
+public interface ImplementationDataBinder {
+
+    Implementation create(ImplementationTO implementationTO);
+
+    void update(Implementation implementation, ImplementationTO implementationTO);
+
+    ImplementationTO getImplementationTO(Implementation implementation);
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationRecipientsProvider.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationRecipientsProvider.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationRecipientsProvider.java
deleted file mode 100644
index 1b30768..0000000
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/NotificationRecipientsProvider.java
+++ /dev/null
@@ -1,27 +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.notification;
-
-import java.util.Set;
-import org.apache.syncope.core.persistence.api.entity.Notification;
-
-public interface NotificationRecipientsProvider {
-
-    Set<String> provideRecipients(Notification notification);
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/RecipientsProvider.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/RecipientsProvider.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/RecipientsProvider.java
new file mode 100644
index 0000000..61e430c
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/notification/RecipientsProvider.java
@@ -0,0 +1,27 @@
+/*
+ * 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.notification;
+
+import java.util.Set;
+import org.apache.syncope.core.persistence.api.entity.Notification;
+
+public interface RecipientsProvider {
+
+    Set<String> provideRecipients(Notification notification);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ReconFilterBuilder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ReconFilterBuilder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ReconFilterBuilder.java
new file mode 100644
index 0000000..8d77d6b
--- /dev/null
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ReconFilterBuilder.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.core.provisioning.api.pushpull;
+
+import org.identityconnectors.framework.common.objects.filter.Filter;
+import org.identityconnectors.framework.impl.api.local.operations.FilteredResultsHandler;
+
+/**
+ * Interface to be implemented for performing filtered reconciliation of a
+ * {@link org.apache.syncope.core.persistence.api.entity.task.PullTask}.
+ */
+public interface ReconFilterBuilder {
+
+    FilteredResultsHandler.PassThroughFilter PASS_THROUGH = new FilteredResultsHandler.PassThroughFilter();
+
+    default Filter build() {
+        return PASS_THROUGH;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ReconciliationFilterBuilder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ReconciliationFilterBuilder.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ReconciliationFilterBuilder.java
deleted file mode 100644
index 65d79bc..0000000
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/pushpull/ReconciliationFilterBuilder.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.core.provisioning.api.pushpull;
-
-import org.identityconnectors.framework.common.objects.filter.Filter;
-import org.identityconnectors.framework.impl.api.local.operations.FilteredResultsHandler;
-
-/**
- * Interface to be implemented for performing filtered reconciliation of a
- * {@link org.apache.syncope.core.persistence.api.entity.task.PullTask}.
- */
-public interface ReconciliationFilterBuilder {
-
-    FilteredResultsHandler.PassThroughFilter PASS_THROUGH = new FilteredResultsHandler.PassThroughFilter();
-
-    default Filter build() {
-        return PASS_THROUGH;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
index b122c9e..2b890ff 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
@@ -32,7 +32,6 @@ import org.apache.syncope.core.provisioning.api.utils.ConnPoolConfUtils;
 import org.apache.syncope.core.provisioning.api.Connector;
 import org.apache.syncope.core.provisioning.api.TimeoutException;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
-import org.apache.syncope.core.provisioning.api.pushpull.ReconciliationFilterBuilder;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.identityconnectors.common.security.GuardedByteArray;
 import org.identityconnectors.common.security.GuardedString;
@@ -62,6 +61,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ClassUtils;
+import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
 
 public class ConnectorFacadeProxy implements Connector {
 
@@ -314,7 +314,7 @@ public class ConnectorFacadeProxy implements Connector {
     @Override
     public void filteredReconciliation(
             final ObjectClass objectClass,
-            final ReconciliationFilterBuilder filterBuilder,
+            final ReconFilterBuilder filterBuilder,
             final SyncResultsHandler handler,
             final OperationOptions options) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
index 2caac56..0977a60 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.Membership;
@@ -102,14 +103,13 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
             String connObjectKeyValue = connObjectKeyItem.isPresent()
                     ? mappingManager.getConnObjectKeyValue(any, entry.getKey()).orElse(null)
                     : null;
-            if (!connObjectKeyItem.isPresent()) {
-                LOG.error("No ConnObjectKey found for {}, ignoring...", entry.getKey());
+            if (!connObjectKeyItem.isPresent() || connObjectKeyValue == null) {
+                LOG.error("No ConnObjectKey or value found for {}, ignoring...", entry.getKey());
             } else {
                 Set<MappingItem> linkingMappingItems = new HashSet<>();
                 linkingMappingItems.add(connObjectKeyItem.get());
-                for (VirSchema schema : entry.getValue()) {
-                    linkingMappingItems.add(schema.asLinkingMappingItem());
-                }
+                linkingMappingItems.addAll(entry.getValue().stream().
+                        map(schema -> schema.asLinkingMappingItem()).collect(Collectors.toSet()));
 
                 Connector connector = connFactory.getConnector(entry.getKey().getResource());
                 try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index fa838b7..5387a75 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -354,7 +354,7 @@ abstract class AbstractAnyDataBinder {
         for (StringPatchItem patch : anyPatch.getAuxClasses()) {
             AnyTypeClass auxClass = anyTypeClassDAO.find(patch.getValue());
             if (auxClass == null) {
-                LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName() + "{}, ignoring...", patch.getValue());
+                LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName() + " {}, ignoring...", patch.getValue());
             } else {
                 switch (patch.getOperation()) {
                     case ADD_REPLACE:
@@ -372,7 +372,7 @@ abstract class AbstractAnyDataBinder {
         for (StringPatchItem patch : anyPatch.getResources()) {
             ExternalResource resource = resourceDAO.find(patch.getValue());
             if (resource == null) {
-                LOG.debug("Invalid " + ExternalResource.class.getSimpleName() + "{}, ignoring...", patch.getValue());
+                LOG.debug("Invalid " + ExternalResource.class.getSimpleName() + " {}, ignoring...", patch.getValue());
             } else {
                 switch (patch.getOperation()) {
                     case ADD_REPLACE:
@@ -396,8 +396,8 @@ abstract class AbstractAnyDataBinder {
                 filter(patch -> patch.getAttrTO() != null).forEach(patch -> {
             PlainSchema schema = getPlainSchema(patch.getAttrTO().getSchema());
             if (schema == null) {
-                LOG.debug("Invalid " + PlainSchema.class.getSimpleName()
-                        + "{}, ignoring...", patch.getAttrTO().getSchema());
+                LOG.debug("Invalid " + PlainSchema.class.getSimpleName() + " {}, ignoring...",
+                        patch.getAttrTO().getSchema());
             } else {
                 PlainAttr<?> attr = (PlainAttr<?>) any.getPlainAttr(schema.getKey()).orElse(null);
                 if (attr == null) {
@@ -445,7 +445,7 @@ abstract class AbstractAnyDataBinder {
                 map(className -> anyTypeClassDAO.find(className)).
                 forEachOrdered(auxClass -> {
                     if (auxClass == null) {
-                        LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName() + "{}, ignoring...", auxClass);
+                        LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName() + " {}, ignoring...", auxClass);
                     } else {
                         any.add(auxClass);
                     }
@@ -488,7 +488,7 @@ abstract class AbstractAnyDataBinder {
         anyTO.getResources().forEach(resourceKey -> {
             ExternalResource resource = resourceDAO.find(resourceKey);
             if (resource == null) {
-                LOG.debug("Invalid " + ExternalResource.class.getSimpleName() + "{}, ignoring...", resourceKey);
+                LOG.debug("Invalid " + ExternalResource.class.getSimpleName() + " {}, ignoring...", resourceKey);
             } else {
                 any.add(resource);
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeClassDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeClassDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeClassDataBinderImpl.java
index e8ae693..a80ba3a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeClassDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeClassDataBinderImpl.java
@@ -19,15 +19,16 @@
 package org.apache.syncope.core.provisioning.java.data;
 
 import java.util.Collections;
+import java.util.stream.Collectors;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
-import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.provisioning.api.data.AnyTypeClassDataBinder;
@@ -69,12 +70,12 @@ public class AnyTypeClassDataBinderImpl implements AnyTypeClassDataBinder {
             anyTypeClass.setKey(anyTypeClassTO.getKey());
         }
 
-        for (PlainSchema schema : plainSchemaDAO.findByAnyTypeClasses(Collections.singletonList(anyTypeClass))) {
+        plainSchemaDAO.findByAnyTypeClasses(Collections.singletonList(anyTypeClass)).forEach(schema -> {
             schema.setAnyTypeClass(null);
-        }
+        });
 
         anyTypeClass.getPlainSchemas().clear();
-        for (String schemaName : anyTypeClassTO.getPlainSchemas()) {
+        anyTypeClassTO.getPlainSchemas().forEach(schemaName -> {
             PlainSchema schema = plainSchemaDAO.find(schemaName);
             if (schema == null || schema.getAnyTypeClass() != null) {
                 LOG.debug("Invalid or already in use" + PlainSchema.class.getSimpleName()
@@ -82,14 +83,14 @@ public class AnyTypeClassDataBinderImpl implements AnyTypeClassDataBinder {
             } else {
                 anyTypeClass.add(schema);
             }
-        }
+        });
 
-        for (DerSchema schema : derSchemaDAO.findByAnyTypeClasses(Collections.singletonList(anyTypeClass))) {
+        derSchemaDAO.findByAnyTypeClasses(Collections.singletonList(anyTypeClass)).forEach((schema) -> {
             schema.setAnyTypeClass(null);
-        }
+        });
 
         anyTypeClass.getDerSchemas().clear();
-        for (String schemaName : anyTypeClassTO.getDerSchemas()) {
+        anyTypeClassTO.getDerSchemas().forEach(schemaName -> {
             DerSchema schema = derSchemaDAO.find(schemaName);
             if (schema == null || schema.getAnyTypeClass() != null) {
                 LOG.debug("Invalid or already in use" + DerSchema.class.getSimpleName()
@@ -97,14 +98,14 @@ public class AnyTypeClassDataBinderImpl implements AnyTypeClassDataBinder {
             } else {
                 anyTypeClass.add(schema);
             }
-        }
+        });
 
-        for (VirSchema schema : virSchemaDAO.findByAnyTypeClasses(Collections.singletonList(anyTypeClass))) {
+        virSchemaDAO.findByAnyTypeClasses(Collections.singletonList(anyTypeClass)).forEach(schema -> {
             schema.setAnyTypeClass(null);
-        }
+        });
 
         anyTypeClass.getVirSchemas().clear();
-        for (String schemaName : anyTypeClassTO.getVirSchemas()) {
+        anyTypeClassTO.getVirSchemas().forEach(schemaName -> {
             VirSchema schema = virSchemaDAO.find(schemaName);
             if (schema == null || schema.getAnyTypeClass() != null) {
                 LOG.debug("Invalid or already in use" + VirSchema.class.getSimpleName()
@@ -112,7 +113,7 @@ public class AnyTypeClassDataBinderImpl implements AnyTypeClassDataBinder {
             } else {
                 anyTypeClass.add(schema);
             }
-        }
+        });
     }
 
     @Override
@@ -121,19 +122,15 @@ public class AnyTypeClassDataBinderImpl implements AnyTypeClassDataBinder {
 
         anyTypeClassTO.setKey(anyTypeClass.getKey());
 
-        for (AnyType anyType : anyTypeDAO.findByTypeClass(anyTypeClass)) {
-            anyTypeClassTO.getInUseByTypes().add(anyType.getKey());
-        }
+        anyTypeClassTO.getInUseByTypes().addAll(
+                anyTypeDAO.findByTypeClass(anyTypeClass).stream().map(Entity::getKey).collect(Collectors.toList()));
 
-        for (PlainSchema schema : anyTypeClass.getPlainSchemas()) {
-            anyTypeClassTO.getPlainSchemas().add(schema.getKey());
-        }
-        for (DerSchema schema : anyTypeClass.getDerSchemas()) {
-            anyTypeClassTO.getDerSchemas().add(schema.getKey());
-        }
-        for (VirSchema schema : anyTypeClass.getVirSchemas()) {
-            anyTypeClassTO.getVirSchemas().add(schema.getKey());
-        }
+        anyTypeClassTO.getPlainSchemas().addAll(
+                anyTypeClass.getPlainSchemas().stream().map(Entity::getKey).collect(Collectors.toList()));
+        anyTypeClassTO.getDerSchemas().addAll(
+                anyTypeClass.getDerSchemas().stream().map(Entity::getKey).collect(Collectors.toList()));
+        anyTypeClassTO.getVirSchemas().addAll(
+                anyTypeClass.getVirSchemas().stream().map(Entity::getKey).collect(Collectors.toList()));
 
         return anyTypeClassTO;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
index 45b5089..974088c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyTypeDataBinderImpl.java
@@ -119,7 +119,7 @@ public class AnyTypeDataBinderImpl implements AnyTypeDataBinder {
         anyTypeTO.getClasses().forEach(anyTypeClassName -> {
             AnyTypeClass anyTypeClass = anyTypeClassDAO.find(anyTypeClassName);
             if (anyTypeClass == null) {
-                LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName() + "{}, ignoring...", anyTypeClassName);
+                LOG.debug("Invalid " + AnyTypeClass.class.getSimpleName() + " {}, ignoring...", anyTypeClassName);
             } else {
                 anyType.add(anyTypeClass);
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/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
new file mode 100644
index 0000000..2b98076
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ImplementationDataBinderImpl.java
@@ -0,0 +1,184 @@
+/*
+ * 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.data;
+
+import java.lang.reflect.Modifier;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.policy.RuleConf;
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.common.lib.to.ImplementationTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ImplementationEngine;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.Validator;
+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.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+import org.apache.syncope.core.provisioning.api.LogicActions;
+import org.apache.syncope.core.provisioning.api.data.ImplementationDataBinder;
+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.provisioning.api.pushpull.PushActions;
+import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.spring.BeanUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.apache.syncope.core.provisioning.api.notification.RecipientsProvider;
+
+@Component
+public class ImplementationDataBinderImpl implements ImplementationDataBinder {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ImplementationDataBinder.class);
+
+    @Autowired
+    private EntityFactory entityFactory;
+
+    @Override
+    public Implementation create(final ImplementationTO implementationTO) {
+        Implementation implementation = entityFactory.newEntity(Implementation.class);
+        update(implementation, implementationTO);
+        return implementation;
+    }
+
+    @Override
+    public void update(final Implementation implementation, final ImplementationTO implementationTO) {
+        BeanUtils.copyProperties(implementationTO, implementation);
+
+        SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidImplementation);
+
+        if (implementation.getBody() == null) {
+            sce.getElements().add("No actual implementation provided");
+            throw sce;
+        }
+
+        if (implementation.getEngine() == ImplementationEngine.JAVA) {
+            Class<?> base = null;
+            switch (implementation.getType()) {
+                case REPORTLET:
+                    base = Reportlet.class;
+                    break;
+
+                case ACCOUNT_RULE:
+                    base = AccountRule.class;
+                    break;
+
+                case PASSWORD_RULE:
+                    base = PasswordRule.class;
+                    break;
+
+                case ITEM_TRANSFORMER:
+                    base = ItemTransformer.class;
+                    break;
+
+                case TASKJOB_DELEGATE:
+                    base = SchedTaskJobDelegate.class;
+                    break;
+
+                case RECON_FILTER_BUILDER:
+                    base = ReconFilterBuilder.class;
+                    break;
+
+                case LOGIC_ACTIONS:
+                    base = LogicActions.class;
+                    break;
+
+                case PROPAGATION_ACTIONS:
+                    base = PropagationActions.class;
+                    break;
+
+                case PULL_ACTIONS:
+                    base = PullActions.class;
+                    break;
+
+                case PUSH_ACTIONS:
+                    base = PushActions.class;
+                    break;
+
+                case PULL_CORRELATION_RULE:
+                    base = PullCorrelationRule.class;
+                    break;
+
+                case VALIDATOR:
+                    base = Validator.class;
+                    break;
+
+                case RECIPIENTS_PROVIDER:
+                    base = RecipientsProvider.class;
+                    break;
+
+                default:
+            }
+
+            if (base == null) {
+                sce.getElements().add("No Java interface found for " + implementation.getType());
+                throw sce;
+            }
+
+            if (implementation.getType() == ImplementationType.REPORTLET) {
+                ReportletConf reportlet = POJOHelper.deserialize(implementation.getBody(), ReportletConf.class);
+                if (reportlet == null) {
+                    sce.getElements().add("Could not deserialize as ReportletConf");
+                    throw sce;
+                }
+            } else if (implementation.getType() == ImplementationType.ACCOUNT_RULE
+                    || implementation.getType() == ImplementationType.PASSWORD_RULE) {
+
+                RuleConf rule = POJOHelper.deserialize(implementation.getBody(), RuleConf.class);
+                if (rule == null) {
+                    sce.getElements().add("Could not deserialize as neither Account nor Password RuleConf");
+                    throw sce;
+                }
+            } else {
+                Class<?> clazz = null;
+                try {
+                    clazz = Class.forName(implementation.getBody());
+                } catch (Exception e) {
+                    LOG.error("Class '{}' not found", implementation.getBody(), e);
+                    sce.getElements().add("No Java class found: " + implementation.getBody());
+                    throw sce;
+                }
+                if (!base.isAssignableFrom(clazz)) {
+                    sce.getElements().add(
+                            "Java class " + implementation.getBody() + " must comply with " + base.getName());
+                    throw sce;
+                }
+                if (Modifier.isAbstract(clazz.getModifiers())) {
+                    sce.getElements().add("Java class " + implementation.getBody() + " is abstract");
+                    throw sce;
+                }
+            }
+        }
+    }
+
+    @Override
+    public ImplementationTO getImplementationTO(final Implementation implementation) {
+        ImplementationTO implementationTO = new ImplementationTO();
+        BeanUtils.copyProperties(implementation, implementationTO);
+        return implementationTO;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
index 3afe622..84a3085 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/NotificationDataBinderImpl.java
@@ -31,9 +31,11 @@ import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.Notification;
 import org.apache.syncope.core.spring.BeanUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
+import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
 import org.apache.syncope.core.persistence.api.dao.MailTemplateDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyAbout;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.MailTemplate;
 import org.apache.syncope.core.provisioning.java.IntAttrNameParser;
 import org.slf4j.Logger;
@@ -46,7 +48,7 @@ public class NotificationDataBinderImpl implements NotificationDataBinder {
 
     private static final Logger LOG = LoggerFactory.getLogger(NotificationDataBinder.class);
 
-    private static final String[] IGNORE_PROPERTIES = { "key", "template", "abouts" };
+    private static final String[] IGNORE_PROPERTIES = { "key", "template", "abouts", "recipientsProvider" };
 
     @Autowired
     private MailTemplateDAO mailTemplateDAO;
@@ -55,6 +57,9 @@ public class NotificationDataBinderImpl implements NotificationDataBinder {
     private AnyTypeDAO anyTypeDAO;
 
     @Autowired
+    private ImplementationDAO implementationDAO;
+
+    @Autowired
     private EntityFactory entityFactory;
 
     @Autowired
@@ -62,17 +67,21 @@ public class NotificationDataBinderImpl implements NotificationDataBinder {
 
     @Override
     public NotificationTO getNotificationTO(final Notification notification) {
-        NotificationTO result = new NotificationTO();
-        result.setKey(notification.getKey());
-        result.setTemplate(notification.getTemplate().getKey());
+        NotificationTO notificationTO = new NotificationTO();
+        notificationTO.setKey(notification.getKey());
+        notificationTO.setTemplate(notification.getTemplate().getKey());
 
-        BeanUtils.copyProperties(notification, result, IGNORE_PROPERTIES);
+        BeanUtils.copyProperties(notification, notificationTO, IGNORE_PROPERTIES);
 
         notification.getAbouts().forEach(about -> {
-            result.getAbouts().put(about.getAnyType().getKey(), about.get());
+            notificationTO.getAbouts().put(about.getAnyType().getKey(), about.get());
         });
 
-        return result;
+        if (notification.getRecipientsProvider() != null) {
+            notificationTO.setRecipientsProvider(notification.getRecipientsProvider().getKey());
+        }
+
+        return notificationTO;
     }
 
     @Override
@@ -140,5 +149,17 @@ public class NotificationDataBinderImpl implements NotificationDataBinder {
 
         // 3. verify recipientAttrName
         intAttrNameParser.parse(notification.getRecipientAttrName(), AnyTypeKind.USER);
+
+        if (notificationTO.getRecipientsProvider() == null) {
+            notification.setRecipientsProvider(null);
+        } else {
+            Implementation recipientsProvider = implementationDAO.find(notificationTO.getRecipientsProvider());
+            if (recipientsProvider == null) {
+                LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
+                        notificationTO.getRecipientsProvider());
+            } else {
+                notification.setRecipientsProvider(recipientsProvider);
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/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 a049fe8..267a6a2 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
@@ -18,19 +18,23 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.SerializationUtils;
 import org.apache.syncope.core.provisioning.api.data.PolicyDataBinder;
-import org.apache.syncope.common.lib.policy.AbstractAccountRuleConf;
-import org.apache.syncope.common.lib.policy.AbstractPasswordRuleConf;
 import org.apache.syncope.common.lib.policy.AbstractPolicyTO;
 import org.apache.syncope.common.lib.policy.AccountPolicyTO;
-import org.apache.syncope.common.lib.policy.AccountRuleConf;
 import org.apache.syncope.common.lib.policy.PasswordPolicyTO;
-import org.apache.syncope.common.lib.policy.PasswordRuleConf;
+import org.apache.syncope.common.lib.policy.PullPolicySpec;
 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.RealmDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.policy.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
 import org.apache.syncope.core.persistence.api.entity.Policy;
@@ -53,6 +57,12 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
     private RealmDAO realmDAO;
 
     @Autowired
+    private AnyTypeDAO anyTypeDAO;
+
+    @Autowired
+    private ImplementationDAO implementationDAO;
+
+    @Autowired
     private EntityFactory entityFactory;
 
     @SuppressWarnings("unchecked")
@@ -70,10 +80,18 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
             passwordPolicy.setAllowNullPassword(passwordPolicyTO.isAllowNullPassword());
             passwordPolicy.setHistoryLength(passwordPolicyTO.getHistoryLength());
 
-            passwordPolicy.removeAllRuleConfs();
-            for (PasswordRuleConf conf : passwordPolicyTO.getRuleConfs()) {
-                passwordPolicy.add(conf);
-            }
+            passwordPolicyTO.getRules().forEach(ruleKey -> {
+                Implementation rule = implementationDAO.find(ruleKey);
+                if (rule == null) {
+                    LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", ruleKey);
+                } else {
+                    passwordPolicy.add(rule);
+                }
+            });
+            // remove all implementations not contained in the TO
+            passwordPolicy.getRules().removeAll(passwordPolicy.getRules().stream().
+                    filter(implementation -> !passwordPolicyTO.getRules().contains(implementation.getKey())).
+                    collect(Collectors.toList()));
         } else if (policyTO instanceof AccountPolicyTO) {
             if (result == null) {
                 result = (T) entityFactory.newEntity(AccountPolicy.class);
@@ -85,26 +103,54 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
             accountPolicy.setMaxAuthenticationAttempts(accountPolicyTO.getMaxAuthenticationAttempts());
             accountPolicy.setPropagateSuspension(accountPolicyTO.isPropagateSuspension());
 
-            accountPolicy.removeAllRuleConfs();
-            for (AccountRuleConf conf : accountPolicyTO.getRuleConfs()) {
-                accountPolicy.add(conf);
-            }
+            accountPolicyTO.getRules().forEach(ruleKey -> {
+                Implementation rule = implementationDAO.find(ruleKey);
+                if (rule == null) {
+                    LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", ruleKey);
+                } else {
+                    accountPolicy.add(rule);
+                }
+            });
+            // remove all implementations not contained in the TO
+            accountPolicy.getRules().removeAll(accountPolicy.getRules().stream().
+                    filter(implementation -> !accountPolicyTO.getRules().contains(implementation.getKey())).
+                    collect(Collectors.toList()));
 
             accountPolicy.getResources().clear();
-            for (String resourceName : accountPolicyTO.getPassthroughResources()) {
+            accountPolicyTO.getPassthroughResources().forEach(resourceName -> {
                 ExternalResource resource = resourceDAO.find(resourceName);
                 if (resource == null) {
                     LOG.debug("Ignoring invalid resource {} ", resourceName);
                 } else {
                     accountPolicy.add(resource);
                 }
-            }
+            });
         } else if (policyTO instanceof PullPolicyTO) {
             if (result == null) {
                 result = (T) entityFactory.newEntity(PullPolicy.class);
             }
 
-            ((PullPolicy) result).setSpecification(((PullPolicyTO) policyTO).getSpecification());
+            PullPolicy pullPolicy = PullPolicy.class.cast(result);
+            PullPolicyTO pullPolicyTO = PullPolicyTO.class.cast(policyTO);
+
+            PullPolicySpec pullPolicySpec = SerializationUtils.clone(pullPolicyTO.getSpecification());
+            pullPolicySpec.getCorrelationRules().clear();
+            pullPolicyTO.getSpecification().getCorrelationRules().entrySet().forEach(entry -> {
+                AnyType anyType = anyTypeDAO.find(entry.getKey());
+                if (anyType == null) {
+                    LOG.debug("Invalid " + AnyType.class.getSimpleName() + " {}, ignoring...",
+                            entry.getKey());
+                } else {
+                    Implementation rule = implementationDAO.find(entry.getValue());
+                    if (rule == null) {
+                        LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
+                                entry.getValue());
+                    } else {
+                        pullPolicySpec.getCorrelationRules().put(anyType.getKey(), rule.getKey());
+                    }
+                }
+            });
+            pullPolicy.setSpecification(pullPolicySpec);
         }
 
         if (result != null) {
@@ -137,9 +183,8 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
             passwordPolicyTO.setAllowNullPassword(passwordPolicy.isAllowNullPassword());
             passwordPolicyTO.setHistoryLength(passwordPolicy.getHistoryLength());
 
-            for (PasswordRuleConf ruleConf : passwordPolicy.getRuleConfs()) {
-                passwordPolicyTO.getRuleConfs().add((AbstractPasswordRuleConf) ruleConf);
-            }
+            passwordPolicyTO.getRules().addAll(
+                    passwordPolicy.getRules().stream().map(Entity::getKey).collect(Collectors.toList()));
         } else if (policy instanceof AccountPolicy) {
             AccountPolicy accountPolicy = AccountPolicy.class.cast(policy);
             AccountPolicyTO accountPolicyTO = new AccountPolicyTO();
@@ -148,11 +193,11 @@ public class PolicyDataBinderImpl implements PolicyDataBinder {
             accountPolicyTO.setMaxAuthenticationAttempts(accountPolicy.getMaxAuthenticationAttempts());
             accountPolicyTO.setPropagateSuspension(accountPolicy.isPropagateSuspension());
 
-            for (AccountRuleConf ruleConf : accountPolicy.getRuleConfs()) {
-                accountPolicyTO.getRuleConfs().add((AbstractAccountRuleConf) ruleConf);
-            }
+            accountPolicyTO.getRules().addAll(
+                    accountPolicy.getRules().stream().map(Entity::getKey).collect(Collectors.toList()));
 
-            accountPolicyTO.getPassthroughResources().addAll(accountPolicy.getResourceKeys());
+            accountPolicyTO.getPassthroughResources().addAll(
+                    accountPolicy.getResources().stream().map(Entity::getKey).collect(Collectors.toList()));
         } else if (policy instanceof PullPolicy) {
             policyTO = (T) new PullPolicyTO();
             ((PullPolicyTO) policyTO).setSpecification(((PullPolicy) policy).getSpecification());

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
index c7fc089..08bd787 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
@@ -27,13 +27,14 @@ import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.provisioning.java.utils.TemplateUtils;
 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.PolicyDAO;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
-import org.apache.syncope.core.persistence.api.entity.AnyTemplate;
 import org.apache.syncope.core.persistence.api.entity.AnyTemplateRealm;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.policy.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.Policy;
 import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
 import org.apache.syncope.core.persistence.api.entity.Realm;
@@ -53,6 +54,9 @@ public class RealmDataBinderImpl implements RealmDataBinder {
     private AnyTypeDAO anyTypeDAO;
 
     @Autowired
+    private ImplementationDAO implementationDAO;
+
+    @Autowired
     private RealmDAO realmDAO;
 
     @Autowired
@@ -123,14 +127,21 @@ public class RealmDataBinderImpl implements RealmDataBinder {
             }
         }
 
-        realm.getActionsClassNames().addAll(realmTO.getActionsClassNames());
+        realmTO.getActions().forEach(logicActionsKey -> {
+            Implementation logicAction = implementationDAO.find(logicActionsKey);
+            if (logicAction == null) {
+                LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", logicActionsKey);
+            } else {
+                realm.add(logicAction);
+            }
+        });
 
         setTemplates(realmTO, realm);
 
         realmTO.getResources().forEach(resourceKey -> {
             ExternalResource resource = resourceDAO.find(resourceKey);
             if (resource == null) {
-                LOG.debug("Invalid " + ExternalResource.class.getSimpleName() + "{}, ignoring...", resourceKey);
+                LOG.debug("Invalid " + ExternalResource.class.getSimpleName() + " {}, ignoring...", resourceKey);
             } else {
                 realm.add(resource);
             }
@@ -172,16 +183,26 @@ public class RealmDataBinderImpl implements RealmDataBinder {
             }
         }
 
-        realm.getActionsClassNames().clear();
-        realm.getActionsClassNames().addAll(realmTO.getActionsClassNames());
+        realmTO.getActions().forEach(logicActionsKey -> {
+            Implementation logicActions = implementationDAO.find(logicActionsKey);
+            if (logicActions == null) {
+                LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", logicActionsKey);
+            } else {
+                realm.add(logicActions);
+            }
+        });
+        // remove all implementations not contained in the TO
+        realm.getActions().removeAll(realm.getActions().stream().
+                filter(implementation -> !realmTO.getActions().contains(implementation.getKey())).
+                collect(Collectors.toList()));
 
         setTemplates(realmTO, realm);
 
-        final PropagationByResource propByRes = new PropagationByResource();
+        PropagationByResource propByRes = new PropagationByResource();
         realmTO.getResources().forEach(resourceKey -> {
             ExternalResource resource = resourceDAO.find(resourceKey);
             if (resource == null) {
-                LOG.debug("Invalid " + ExternalResource.class.getSimpleName() + "{}, ignoring...", resourceKey);
+                LOG.debug("Invalid " + ExternalResource.class.getSimpleName() + " {}, ignoring...", resourceKey);
             } else {
                 realm.add(resource);
                 propByRes.add(ResourceOperation.CREATE, resource.getKey());
@@ -212,15 +233,18 @@ public class RealmDataBinderImpl implements RealmDataBinder {
         if (admin) {
             realmTO.setAccountPolicy(realm.getAccountPolicy() == null ? null : realm.getAccountPolicy().getKey());
             realmTO.setPasswordPolicy(realm.getPasswordPolicy() == null ? null : realm.getPasswordPolicy().getKey());
-            realmTO.getActionsClassNames().addAll(realm.getActionsClassNames());
 
-            for (AnyTemplate template : realm.getTemplates()) {
+            realm.getActions().forEach(action -> {
+                realmTO.getActions().add(action.getKey());
+            });
+
+            realm.getTemplates().forEach(template -> {
                 realmTO.getTemplates().put(template.getAnyType().getKey(), template.get());
-            }
+            });
 
-            for (ExternalResource resource : realm.getResources()) {
+            realm.getResources().forEach(resource -> {
                 realmTO.getResources().add(resource.getKey());
-            }
+            });
         }
 
         return realmTO;

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ReportDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ReportDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ReportDataBinderImpl.java
index 7b12665..b2b9808 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ReportDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ReportDataBinderImpl.java
@@ -18,21 +18,23 @@
  */
 package org.apache.syncope.core.provisioning.java.data;
 
+import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.report.AbstractReportletConf;
 import org.apache.syncope.core.provisioning.api.data.ReportDataBinder;
-import org.apache.syncope.common.lib.report.ReportletConf;
 import org.apache.syncope.common.lib.to.ExecTO;
 import org.apache.syncope.common.lib.to.ReportTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.JobType;
+import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
 import org.apache.syncope.core.persistence.api.dao.ReportExecDAO;
 import org.apache.syncope.core.persistence.api.entity.Report;
 import org.apache.syncope.core.persistence.api.entity.ReportExec;
 import org.apache.syncope.core.provisioning.api.job.JobNamer;
 import org.apache.syncope.core.spring.BeanUtils;
 import org.apache.syncope.core.persistence.api.dao.ReportTemplateDAO;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.ReportTemplate;
 import org.quartz.Scheduler;
 import org.quartz.SchedulerException;
@@ -60,6 +62,9 @@ public class ReportDataBinderImpl implements ReportDataBinder {
     private ReportExecDAO reportExecDAO;
 
     @Autowired
+    private ImplementationDAO implementationDAO;
+
+    @Autowired
     private SchedulerFactoryBean scheduler;
 
     @Override
@@ -74,10 +79,18 @@ public class ReportDataBinderImpl implements ReportDataBinder {
         }
         report.setTemplate(template);
 
-        report.removeAllReportletConfs();
-        for (ReportletConf conf : reportTO.getReportletConfs()) {
-            report.add(conf);
-        }
+        reportTO.getReportlets().forEach(reportletKey -> {
+            Implementation reportlet = implementationDAO.find(reportletKey);
+            if (reportlet == null) {
+                LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", reportletKey);
+            } else {
+                report.add(reportlet);
+            }
+        });
+        // remove all implementations not contained in the TO
+        report.getReportlets().removeAll(report.getReportlets().stream().
+                filter(reportlet -> !reportTO.getReportlets().contains(reportlet.getKey())).
+                collect(Collectors.toList()));
     }
 
     @Override
@@ -88,10 +101,8 @@ public class ReportDataBinderImpl implements ReportDataBinder {
 
         BeanUtils.copyProperties(report, reportTO, IGNORE_REPORT_PROPERTIES);
 
-        reportTO.getReportletConfs().clear();
-        for (ReportletConf reportletConf : report.getReportletConfs()) {
-            reportTO.getReportletConfs().add((AbstractReportletConf) reportletConf);
-        }
+        reportTO.getReportlets().addAll(
+                report.getReportlets().stream().map(Entity::getKey).collect(Collectors.toList()));
 
         ReportExec latestExec = reportExecDAO.findLatestStarted(report);
         if (latestExec == null) {
@@ -104,9 +115,8 @@ public class ReportDataBinderImpl implements ReportDataBinder {
             reportTO.setLastExec(reportTO.getStart());
         }
 
-        for (ReportExec reportExec : report.getExecs()) {
-            reportTO.getExecutions().add(getExecTO(reportExec));
-        }
+        reportTO.getExecutions().addAll(report.getExecs().stream().
+                map(reportExec -> getExecTO(reportExec)).collect(Collectors.toList()));
 
         String triggerName = JobNamer.getTriggerName(JobNamer.getJobKey(report).getName());
         try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
index 07ddf15..db151af 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ResourceDataBinderImpl.java
@@ -52,9 +52,12 @@ import org.apache.syncope.core.spring.BeanUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceHistoryConfDAO;
+import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
 import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResourceHistoryConf;
@@ -77,7 +80,7 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
 
     private static final Logger LOG = LoggerFactory.getLogger(ResourceDataBinder.class);
 
-    private static final String[] ITEM_IGNORE_PROPERTIES = { "key", "mapping" };
+    private static final String[] ITEM_IGNORE_PROPERTIES = { "key", "mapping", "transformers" };
 
     @Autowired
     private AnyTypeDAO anyTypeDAO;
@@ -101,6 +104,9 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
     private ConfDAO confDAO;
 
     @Autowired
+    private ImplementationDAO implementationDAO;
+
+    @Autowired
     private EntityFactory entityFactory;
 
     @Autowired
@@ -321,6 +327,19 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
                             orgUnit.add(item);
                         }
 
+                        itemTO.getTransformers().forEach(transformerKey -> {
+                            Implementation transformer = implementationDAO.find(transformerKey);
+                            if (transformer == null) {
+                                LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
+                                        transformerKey);
+                            } else {
+                                item.add(transformer);
+                            }
+                        });
+                        // remove all implementations not contained in the TO
+                        item.getTransformers().removeAll(item.getTransformers().stream().
+                                filter(implementation -> !itemTO.getTransformers().contains(implementation.getKey())).
+                                collect(Collectors.toList()));
                     }
                 }
             }
@@ -352,8 +371,18 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
         resource.getCapabilitiesOverride().clear();
         resource.getCapabilitiesOverride().addAll(resourceTO.getCapabilitiesOverride());
 
-        resource.getPropagationActionsClassNames().clear();
-        resource.getPropagationActionsClassNames().addAll(resourceTO.getPropagationActionsClassNames());
+        resourceTO.getPropagationActions().forEach(propagationActionKey -> {
+            Implementation propagationAction = implementationDAO.find(propagationActionKey);
+            if (propagationAction == null) {
+                LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", propagationActionKey);
+            } else {
+                resource.add(propagationAction);
+            }
+        });
+        // remove all implementations not contained in the TO
+        resource.getPropagationActions().removeAll(resource.getPropagationActions().stream().
+                filter(implementation -> !resourceTO.getPropagationActions().contains(implementation.getKey())).
+                collect(Collectors.toList()));
 
         return resource;
     }
@@ -421,6 +450,7 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
                         MappingItem item = entityFactory.newEntity(MappingItem.class);
                         BeanUtils.copyProperties(itemTO, item, ITEM_IGNORE_PROPERTIES);
                         item.setMapping(mapping);
+
                         if (item.isConnObjectKey()) {
                             if (intAttrName.getSchemaType() == SchemaType.VIRTUAL) {
                                 invalidMapping.getElements().
@@ -436,6 +466,20 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
                             mapping.add(item);
                         }
 
+                        itemTO.getTransformers().forEach(transformerKey -> {
+                            Implementation transformer = implementationDAO.find(transformerKey);
+                            if (transformer == null) {
+                                LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
+                                        transformerKey);
+                            } else {
+                                item.add(transformer);
+                            }
+                        });
+                        // remove all implementations not contained in the TO
+                        item.getTransformers().removeAll(item.getTransformers().stream().
+                                filter(implementation -> !itemTO.getTransformers().contains(implementation.getKey())).
+                                collect(Collectors.toList()));
+
                         if (intAttrName.getEnclosingGroup() != null
                                 && item.getPurpose() != MappingPurpose.PROPAGATION) {
 
@@ -495,6 +539,10 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
             } else {
                 containerTO.add(itemTO);
             }
+
+            item.getTransformers().forEach(transformer -> {
+                itemTO.getTransformers().add(transformer.getKey());
+            });
         });
     }
 
@@ -583,7 +631,8 @@ public class ResourceDataBinderImpl implements ResourceDataBinder {
         resourceTO.setOverrideCapabilities(resource.isOverrideCapabilities());
         resourceTO.getCapabilitiesOverride().addAll(resource.getCapabilitiesOverride());
 
-        resourceTO.getPropagationActionsClassNames().addAll(resource.getPropagationActionsClassNames());
+        resourceTO.getPropagationActions().addAll(
+                resource.getPropagationActions().stream().map(Entity::getKey).collect(Collectors.toList()));
 
         return resourceTO;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
index 2066cb2..e469d66 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
@@ -31,6 +31,8 @@ import org.apache.syncope.common.lib.to.PullTaskTO;
 import org.apache.syncope.common.lib.to.ExecTO;
 import org.apache.syncope.common.lib.to.NotificationTaskTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ImplementationEngine;
+import org.apache.syncope.common.lib.types.ImplementationType;
 import org.apache.syncope.common.lib.types.JobType;
 import org.apache.syncope.common.lib.types.MatchingRule;
 import org.apache.syncope.common.lib.types.TaskType;
@@ -50,9 +52,12 @@ import org.apache.syncope.core.persistence.api.entity.task.TaskUtils;
 import org.apache.syncope.core.provisioning.api.job.JobNamer;
 import org.apache.syncope.core.spring.BeanUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
+import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
 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;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask;
 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
@@ -77,7 +82,7 @@ public class TaskDataBinderImpl implements TaskDataBinder {
 
     private static final String[] IGNORE_TASK_PROPERTIES = {
         "destinationRealm", "templates", "filters", "executions", "resource", "matchingRule", "unmatchingRule",
-        "notification" };
+        "notification", "jobDelegate", "actions" };
 
     private static final String[] IGNORE_TASK_EXECUTION_PROPERTIES = { "key", "task" };
 
@@ -94,6 +99,9 @@ public class TaskDataBinderImpl implements TaskDataBinder {
     private AnyTypeDAO anyTypeDAO;
 
     @Autowired
+    private ImplementationDAO implementationDAO;
+
+    @Autowired
     private EntityFactory entityFactory;
 
     @Autowired
@@ -108,11 +116,22 @@ public class TaskDataBinderImpl implements TaskDataBinder {
     private void fill(final ProvisioningTask task, final AbstractProvisioningTaskTO taskTO) {
         if (task instanceof PushTask && taskTO instanceof PushTaskTO) {
             PushTask pushTask = (PushTask) task;
-            final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
-
-            pushTask.setJobDelegateClassName(pushTaskTO.getJobDelegateClassName() == null
-                    ? PushJobDelegate.class.getName()
-                    : pushTaskTO.getJobDelegateClassName());
+            PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
+
+            Implementation jobDelegate = pushTaskTO.getJobDelegate() == null
+                    ? implementationDAO.find(ImplementationType.TASKJOB_DELEGATE).stream().
+                            filter(impl -> PushJobDelegate.class.getName().equals(impl.getBody())).
+                            findFirst().orElse(null)
+                    : implementationDAO.find(pushTaskTO.getJobDelegate());
+            if (jobDelegate == null) {
+                jobDelegate = entityFactory.newEntity(Implementation.class);
+                jobDelegate.setKey(PushJobDelegate.class.getSimpleName());
+                jobDelegate.setEngine(ImplementationEngine.JAVA);
+                jobDelegate.setType(ImplementationType.TASKJOB_DELEGATE);
+                jobDelegate.setBody(PushJobDelegate.class.getName());
+                jobDelegate = implementationDAO.save(jobDelegate);
+            }
+            pushTask.setJobDelegate(jobDelegate);
 
             pushTask.setSourceRealm(realmDAO.findByFullPath(pushTaskTO.getSourceRealm()));
 
@@ -143,16 +162,38 @@ public class TaskDataBinderImpl implements TaskDataBinder {
                             collect(Collectors.toList()));
         } else if (task instanceof PullTask && taskTO instanceof PullTaskTO) {
             PullTask pullTask = (PullTask) task;
-            final PullTaskTO pullTaskTO = (PullTaskTO) taskTO;
+            PullTaskTO pullTaskTO = (PullTaskTO) taskTO;
+
+            Implementation jobDelegate = pullTaskTO.getJobDelegate() == null
+                    ? implementationDAO.find(ImplementationType.TASKJOB_DELEGATE).stream().
+                            filter(impl -> PullJobDelegate.class.getName().equals(impl.getBody())).
+                            findFirst().orElse(null)
+                    : implementationDAO.find(pullTaskTO.getJobDelegate());
+            if (jobDelegate == null) {
+                jobDelegate = entityFactory.newEntity(Implementation.class);
+                jobDelegate.setKey(PullJobDelegate.class.getSimpleName());
+                jobDelegate.setEngine(ImplementationEngine.JAVA);
+                jobDelegate.setType(ImplementationType.TASKJOB_DELEGATE);
+                jobDelegate.setBody(PullJobDelegate.class.getName());
+                jobDelegate = implementationDAO.save(jobDelegate);
+            }
+            pullTask.setJobDelegate(jobDelegate);
 
             pullTask.setPullMode(pullTaskTO.getPullMode());
-            pullTask.setReconciliationFilterBuilderClassName(pullTaskTO.getReconciliationFilterBuilderClassName());
 
-            pullTask.setDestinationRealm(realmDAO.findByFullPath(pullTaskTO.getDestinationRealm()));
+            if (pullTaskTO.getReconFilterBuilder() == null) {
+                pullTask.setReconFilterBuilder(null);
+            } else {
+                Implementation reconFilterBuilder = implementationDAO.find(pullTaskTO.getReconFilterBuilder());
+                if (reconFilterBuilder == null) {
+                    LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
+                            pullTaskTO.getReconFilterBuilder());
+                } else {
+                    pullTask.setReconFilterBuilder(reconFilterBuilder);
+                }
+            }
 
-            pullTask.setJobDelegateClassName(pullTaskTO.getJobDelegateClassName() == null
-                    ? PullJobDelegate.class.getName()
-                    : pullTaskTO.getJobDelegateClassName());
+            pullTask.setDestinationRealm(realmDAO.findByFullPath(pullTaskTO.getDestinationRealm()));
 
             pullTask.setMatchingRule(pullTaskTO.getMatchingRule() == null
                     ? MatchingRule.UPDATE : pullTaskTO.getMatchingRule());
@@ -189,8 +230,19 @@ public class TaskDataBinderImpl implements TaskDataBinder {
         task.setPerformUpdate(taskTO.isPerformUpdate());
         task.setPerformDelete(taskTO.isPerformDelete());
         task.setSyncStatus(taskTO.isSyncStatus());
-        task.getActionsClassNames().clear();
-        task.getActionsClassNames().addAll(taskTO.getActionsClassNames());
+
+        taskTO.getActions().forEach(action -> {
+            Implementation implementation = implementationDAO.find(action);
+            if (implementation == null) {
+                LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", action);
+            } else {
+                task.add(implementation);
+            }
+        });
+        // remove all implementations not contained in the TO
+        task.getActions().removeAll(task.getActions().stream().
+                filter(implementation -> !taskTO.getActions().contains(implementation.getKey())).
+                collect(Collectors.toList()));
     }
 
     @Override
@@ -208,7 +260,11 @@ public class TaskDataBinderImpl implements TaskDataBinder {
         task.setActive(taskTO.isActive());
 
         if (taskUtils.getType() == TaskType.SCHEDULED) {
-            task.setJobDelegateClassName(taskTO.getJobDelegateClassName());
+            Implementation implementation = implementationDAO.find(taskTO.getJobDelegate());
+            if (implementation == null) {
+                throw new NotFoundException("Implementation " + taskTO.getJobDelegate());
+            }
+            task.setJobDelegate(implementation);
         } else if (taskTO instanceof AbstractProvisioningTaskTO) {
             AbstractProvisioningTaskTO provisioningTaskTO = (AbstractProvisioningTaskTO) taskTO;
 
@@ -314,49 +370,80 @@ public class TaskDataBinderImpl implements TaskDataBinder {
 
         switch (taskUtils.getType()) {
             case PROPAGATION:
-                ((PropagationTaskTO) taskTO).setAnyTypeKind(((PropagationTask) task).getAnyTypeKind());
-                ((PropagationTaskTO) taskTO).setEntityKey(((PropagationTask) task).getEntityKey());
-                ((PropagationTaskTO) taskTO).setResource(((PropagationTask) task).getResource().getKey());
-                ((PropagationTaskTO) taskTO).setAttributes(((PropagationTask) task).getSerializedAttributes());
+                PropagationTask propagationTask = (PropagationTask) task;
+                PropagationTaskTO propagationTaskTO = (PropagationTaskTO) taskTO;
+
+                propagationTaskTO.setAnyTypeKind(propagationTask.getAnyTypeKind());
+                propagationTaskTO.setEntityKey(propagationTask.getEntityKey());
+                propagationTaskTO.setResource(propagationTask.getResource().getKey());
+                propagationTaskTO.setAttributes(propagationTask.getSerializedAttributes());
                 break;
 
             case SCHEDULED:
-                setExecTime((SchedTaskTO) taskTO, task);
+                SchedTask schedTask = (SchedTask) task;
+                SchedTaskTO schedTaskTO = (SchedTaskTO) taskTO;
+
+                setExecTime(schedTaskTO, task);
+
+                if (schedTask.getJobDelegate() != null) {
+                    schedTaskTO.setJobDelegate(schedTask.getJobDelegate().getKey());
+                }
                 break;
 
             case PULL:
-                setExecTime((SchedTaskTO) taskTO, task);
-                ((PullTaskTO) taskTO).setDestinationRealm(((PullTask) task).getDestinatioRealm().getFullPath());
-                ((PullTaskTO) taskTO).setResource(((PullTask) task).getResource().getKey());
-                ((PullTaskTO) taskTO).setMatchingRule(((PullTask) task).getMatchingRule() == null
-                        ? MatchingRule.UPDATE : ((PullTask) task).getMatchingRule());
-                ((PullTaskTO) taskTO).setUnmatchingRule(((PullTask) task).getUnmatchingRule() == null
-                        ? UnmatchingRule.PROVISION : ((PullTask) task).getUnmatchingRule());
-
-                ((PullTask) task).getTemplates().forEach(template -> {
-                    ((PullTaskTO) taskTO).getTemplates().put(template.getAnyType().getKey(), template.get());
+                PullTask pullTask = (PullTask) task;
+                PullTaskTO pullTaskTO = (PullTaskTO) taskTO;
+
+                setExecTime(pullTaskTO, task);
+
+                pullTaskTO.setDestinationRealm(pullTask.getDestinatioRealm().getFullPath());
+                pullTaskTO.setResource(pullTask.getResource().getKey());
+                pullTaskTO.setMatchingRule(pullTask.getMatchingRule() == null
+                        ? MatchingRule.UPDATE : pullTask.getMatchingRule());
+                pullTaskTO.setUnmatchingRule(pullTask.getUnmatchingRule() == null
+                        ? UnmatchingRule.PROVISION : pullTask.getUnmatchingRule());
+
+                if (pullTask.getReconFilterBuilder() != null) {
+                    pullTaskTO.setReconFilterBuilder(pullTask.getReconFilterBuilder().getKey());
+                }
+
+                pullTaskTO.getActions().addAll(
+                        pullTask.getActions().stream().map(Entity::getKey).collect(Collectors.toList()));
+
+                pullTask.getTemplates().forEach(template -> {
+                    pullTaskTO.getTemplates().put(template.getAnyType().getKey(), template.get());
                 });
                 break;
 
             case PUSH:
-                setExecTime((SchedTaskTO) taskTO, task);
-                ((PushTaskTO) taskTO).setSourceRealm(((PushTask) task).getSourceRealm().getFullPath());
-                ((PushTaskTO) taskTO).setResource(((PushTask) task).getResource().getKey());
-                ((PushTaskTO) taskTO).setMatchingRule(((PushTask) task).getMatchingRule() == null
-                        ? MatchingRule.LINK : ((PushTask) task).getMatchingRule());
-                ((PushTaskTO) taskTO).setUnmatchingRule(((PushTask) task).getUnmatchingRule() == null
-                        ? UnmatchingRule.ASSIGN : ((PushTask) task).getUnmatchingRule());
-
-                ((PushTask) task).getFilters().forEach(filter -> {
-                    ((PushTaskTO) taskTO).getFilters().put(filter.getAnyType().getKey(), filter.getFIQLCond());
+                PushTask pushTask = (PushTask) task;
+                PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
+
+                setExecTime(pushTaskTO, task);
+
+                pushTaskTO.setSourceRealm(pushTask.getSourceRealm().getFullPath());
+                pushTaskTO.setResource(pushTask.getResource().getKey());
+                pushTaskTO.setMatchingRule(pushTask.getMatchingRule() == null
+                        ? MatchingRule.LINK : pushTask.getMatchingRule());
+                pushTaskTO.setUnmatchingRule(pushTask.getUnmatchingRule() == null
+                        ? UnmatchingRule.ASSIGN : pushTask.getUnmatchingRule());
+
+                pushTaskTO.getActions().addAll(
+                        pushTask.getActions().stream().map(Entity::getKey).collect(Collectors.toList()));
+
+                pushTask.getFilters().forEach(filter -> {
+                    pushTaskTO.getFilters().put(filter.getAnyType().getKey(), filter.getFIQLCond());
                 });
                 break;
 
             case NOTIFICATION:
-                ((NotificationTaskTO) taskTO).setNotification(((NotificationTask) task).getNotification().getKey());
-                ((NotificationTaskTO) taskTO).setAnyTypeKind(((NotificationTask) task).getAnyTypeKind());
-                ((NotificationTaskTO) taskTO).setEntityKey(((NotificationTask) task).getEntityKey());
-                if (((NotificationTask) task).isExecuted() && StringUtils.isBlank(taskTO.getLatestExecStatus())) {
+                NotificationTask notificationTask = (NotificationTask) task;
+                NotificationTaskTO notificationTaskTO = (NotificationTaskTO) taskTO;
+
+                notificationTaskTO.setNotification(notificationTask.getNotification().getKey());
+                notificationTaskTO.setAnyTypeKind(notificationTask.getAnyTypeKind());
+                notificationTaskTO.setEntityKey(notificationTask.getEntityKey());
+                if (notificationTask.isExecuted() && StringUtils.isBlank(taskTO.getLatestExecStatus())) {
                     taskTO.setLatestExecStatus("[EXECUTED]");
                 }
                 break;

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
index 42daca5..d24e11d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
@@ -31,6 +31,7 @@ import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.types.ImplementationType;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
@@ -46,6 +47,8 @@ import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.SyncopeLoader;
 import org.apache.syncope.core.persistence.api.DomainsHolder;
+import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.quartz.CronScheduleBuilder;
 import org.quartz.Job;
 import org.quartz.JobBuilder;
@@ -92,6 +95,9 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
     @Autowired
     private ConfDAO confDAO;
 
+    @Autowired
+    private ImplementationDAO implementationDAO;
+
     private boolean disableQuartzInstance;
 
     public void setDisableQuartzInstance(final boolean disableQuartzInstance) {
@@ -215,22 +221,26 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
         TaskJob job = createSpringBean(TaskJob.class);
         job.setTaskKey(task.getKey());
 
-        String jobDelegateClassName = task.getJobDelegateClassName() == null
+        Implementation jobDelegate = task.getJobDelegate() == null
                 ? task instanceof PullTask
-                        ? PullJobDelegate.class.getName()
+                        ? implementationDAO.find(ImplementationType.TASKJOB_DELEGATE).stream().
+                                filter(impl -> PullJobDelegate.class.getName().equals(impl.getBody())).
+                                findFirst().orElse(null)
                         : task instanceof PushTask
-                                ? PushJobDelegate.class.getName()
+                                ? implementationDAO.find(ImplementationType.TASKJOB_DELEGATE).stream().
+                                        filter(impl -> PushJobDelegate.class.getName().equals(impl.getBody())).
+                                        findFirst().orElse(null)
                                 : null
-                : task.getJobDelegateClassName();
-        if (jobDelegateClassName == null) {
+                : task.getJobDelegate();
+        if (jobDelegate == null) {
             throw new IllegalArgumentException("Task " + task
                     + " does not provide any " + SchedTaskJobDelegate.class.getSimpleName());
         }
 
         Map<String, Object> jobMap = new HashMap<>();
         jobMap.put(JobManager.DOMAIN_KEY, AuthContextUtils.getDomain());
-        jobMap.put(TaskJob.DELEGATE_CLASS_KEY, jobDelegateClassName);
-        jobMap.put(INTERRUPT_MAX_RETRIES_KEY, interruptMaxRetries);
+        jobMap.put(TaskJob.DELEGATE_IMPLEMENTATION, jobDelegate.getKey());
+        jobMap.put(JobManager.INTERRUPT_MAX_RETRIES_KEY, interruptMaxRetries);
 
         registerJob(
                 JobNamer.getJobKey(task).getName(),
@@ -250,7 +260,7 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
 
         Map<String, Object> jobMap = new HashMap<>();
         jobMap.put(JobManager.DOMAIN_KEY, AuthContextUtils.getDomain());
-        jobMap.put(INTERRUPT_MAX_RETRIES_KEY, interruptMaxRetries);
+        jobMap.put(JobManager.INTERRUPT_MAX_RETRIES_KEY, interruptMaxRetries);
 
         registerJob(JobNamer.getJobKey(report).getName(), job, report.getCronExpression(), startAt, jobMap);
     }
@@ -342,7 +352,7 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
 
         Map<String, Object> jobMap = new HashMap<>();
         jobMap.put(JobManager.DOMAIN_KEY, AuthContextUtils.getDomain());
-        jobMap.put(INTERRUPT_MAX_RETRIES_KEY, conf.getRight());
+        jobMap.put(JobManager.INTERRUPT_MAX_RETRIES_KEY, conf.getRight());
 
         // 3. NotificationJob
         if (StringUtils.isBlank(conf.getLeft())) {