syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [03/18] syncope git commit: [SYNCOPE-956] Core implementation
Date Tue, 10 Oct 2017 06:36:52 GMT
http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
index 1b320b7..6f926cf 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
@@ -18,14 +18,15 @@
  */
 package org.apache.syncope.core.provisioning.java.job;
 
-import org.apache.commons.lang3.ClassUtils;
+import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.apache.syncope.core.provisioning.api.job.JobManager;
+import org.apache.syncope.core.spring.ImplementationManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,7 +36,7 @@ public class TaskJob extends AbstractInterruptableJob {
 
     public static final String DRY_RUN_JOBDETAIL_KEY = "dryRun";
 
-    public static final String DELEGATE_CLASS_KEY = "delegateClass";
+    public static final String DELEGATE_IMPLEMENTATION = "delegateImpl";
 
     /**
      * Task execution status.
@@ -69,14 +70,19 @@ public class TaskJob extends AbstractInterruptableJob {
             AuthContextUtils.execWithAuthContext(context.getMergedJobDataMap().getString(JobManager.DOMAIN_KEY),
                     () -> {
                         try {
-                            Class<?> delegateClass =
-                            ClassUtils.getClass(context.getMergedJobDataMap().getString(DELEGATE_CLASS_KEY));
-
-                            ((SchedTaskJobDelegate) ApplicationContextProvider.getBeanFactory().
-                                    createBean(delegateClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false)).
-                                    execute(taskKey,
-                                            context.getMergedJobDataMap().getBoolean(DRY_RUN_JOBDETAIL_KEY),
-                                            context);
+                            ImplementationDAO implementationDAO =
+                            ApplicationContextProvider.getApplicationContext().getBean(ImplementationDAO.class);
+                            Implementation taskJobDelegate = implementationDAO.find(
+                                    context.getMergedJobDataMap().getString(DELEGATE_IMPLEMENTATION));
+                            if (taskJobDelegate == null) {
+                                LOG.error("Could not find Implementation '{}', aborting",
+                                        context.getMergedJobDataMap().getString(DELEGATE_IMPLEMENTATION));
+                            } else {
+                                ImplementationManager.<SchedTaskJobDelegate>build(taskJobDelegate).
+                                        execute(taskKey,
+                                                context.getMergedJobDataMap().getBoolean(DRY_RUN_JOBDETAIL_KEY),
+                                                context);
+                            }
                         } catch (Exception e) {
                             LOG.error("While executing task {}", taskKey, e);
                             throw new RuntimeException(e);

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AbstractReportlet.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AbstractReportlet.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AbstractReportlet.java
index 2c85b20..ede3535 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AbstractReportlet.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/AbstractReportlet.java
@@ -31,15 +31,18 @@ public abstract class AbstractReportlet implements Reportlet {
 
     protected static final Logger LOG = LoggerFactory.getLogger(AbstractReportlet.class);
 
+    protected ReportletConf conf;
+
+    @Override
+    public void setConf(final ReportletConf conf) {
+        this.conf = conf;
+    }
+
     protected abstract void doExtract(ReportletConf conf, ContentHandler handler) throws SAXException;
 
     @Override
     @Transactional(readOnly = true)
-    public void extract(final ReportletConf conf, final ContentHandler handler) throws SAXException {
-        if (conf == null) {
-            throw new ReportException(new IllegalArgumentException("No configuration provided"));
-        }
-
+    public void extract(final ContentHandler handler) throws SAXException {
         AttributesImpl atts = new AttributesImpl();
         atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, conf.getName());
         atts.addAttribute("", "", ReportXMLConst.ATTR_CLASS, ReportXMLConst.XSD_STRING, getClass().getName());

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReportJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReportJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReportJobDelegate.java
index 28f4894..10a529f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReportJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/report/ReportJobDelegate.java
@@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Date;
+import java.util.Optional;
 import java.util.zip.Deflater;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
@@ -31,22 +32,20 @@ import javax.xml.transform.sax.SAXTransformerFactory;
 import javax.xml.transform.sax.TransformerHandler;
 import javax.xml.transform.stream.StreamResult;
 import org.apache.commons.io.IOUtils;
-import org.apache.syncope.common.lib.report.ReportletConf;
 import org.apache.syncope.common.lib.types.ReportExecStatus;
 import org.apache.syncope.core.provisioning.api.utils.ExceptionUtils2;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
-import org.apache.syncope.core.persistence.api.ImplementationLookup;
 import org.apache.syncope.core.persistence.api.dao.ReportDAO;
 import org.apache.syncope.core.persistence.api.dao.ReportExecDAO;
 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.persistence.api.entity.Report;
 import org.apache.syncope.core.persistence.api.entity.ReportExec;
+import org.apache.syncope.core.spring.ImplementationManager;
 import org.quartz.JobExecutionException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 import org.xml.sax.helpers.AttributesImpl;
@@ -71,9 +70,6 @@ public class ReportJobDelegate {
     @Autowired
     private EntityFactory entityFactory;
 
-    @Autowired
-    private ImplementationLookup implementationLookup;
-
     @Transactional
     public void execute(final String reportKey) throws JobExecutionException {
         Report report = reportDAO.find(reportKey);
@@ -132,27 +128,11 @@ public class ReportJobDelegate {
             handler.startElement("", "", ReportXMLConst.ELEMENT_REPORT, atts);
 
             // iterate over reportlet instances defined for this report
-            for (ReportletConf reportletConf : report.getReportletConfs()) {
-                Class<? extends Reportlet> reportletClass =
-                        implementationLookup.getReportletClass(reportletConf.getClass());
-                if (reportletClass == null) {
-                    LOG.warn("Could not find matching reportlet for {}", reportletConf.getClass());
-                } else {
-                    // fetch (or create) reportlet
-                    Reportlet reportlet;
-                    if (ApplicationContextProvider.getBeanFactory().containsSingleton(reportletClass.getName())) {
-                        reportlet = (Reportlet) ApplicationContextProvider.getBeanFactory().
-                                getSingleton(reportletClass.getName());
-                    } else {
-                        reportlet = (Reportlet) ApplicationContextProvider.getBeanFactory().
-                                createBean(reportletClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
-                        ApplicationContextProvider.getBeanFactory().
-                                registerSingleton(reportletClass.getName(), reportlet);
-                    }
-
-                    // invoke reportlet
+            for (Implementation impl : report.getReportlets()) {
+                Optional<Reportlet> reportlet = ImplementationManager.buildReportlet(impl);
+                if (reportlet.isPresent()) {
                     try {
-                        reportlet.extract(reportletConf, handler);
+                        reportlet.get().extract(handler);
                     } catch (Throwable t) {
                         LOG.error("While executing reportlet {} for report {}", reportlet, reportKey, t);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
index f2eeaf4..75b028f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/notification/NotificationManagerImpl.java
@@ -27,6 +27,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.commons.jexl3.MapContext;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
@@ -47,7 +48,6 @@ import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.Notification;
-import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.task.NotificationTask;
 import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
@@ -56,7 +56,6 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
 import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
@@ -73,14 +72,14 @@ import org.apache.syncope.core.provisioning.api.IntAttrName;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
 import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
-import org.apache.syncope.core.provisioning.api.notification.NotificationRecipientsProvider;
 import org.apache.syncope.core.provisioning.api.event.AfterHandlingEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
+import org.apache.syncope.core.provisioning.api.notification.RecipientsProvider;
+import org.apache.syncope.core.spring.ImplementationManager;
 
 @Component
 @Transactional(rollbackFor = { Throwable.class })
@@ -210,15 +209,13 @@ public class NotificationManagerImpl implements NotificationManager {
             recipientEmails.addAll(notification.getStaticRecipients());
         }
 
-        if (notification.getRecipientsProviderClassName() != null) {
+        if (notification.getRecipientsProvider() != null) {
             try {
-                NotificationRecipientsProvider recipientsProvider =
-                        (NotificationRecipientsProvider) ApplicationContextProvider.getBeanFactory().
-                                createBean(Class.forName(notification.getRecipientsProviderClassName()),
-                                        AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+                RecipientsProvider recipientsProvider =
+                        ImplementationManager.build(notification.getRecipientsProvider());
                 recipientEmails.addAll(recipientsProvider.provideRecipients(notification));
             } catch (Exception e) {
-                LOG.error("Could not fetch recipients from {}", notification.getRecipientsProviderClassName(), e);
+                LOG.error("While building {}", notification.getRecipientsProvider(), e);
             }
         }
 
@@ -470,10 +467,7 @@ public class NotificationManagerImpl implements NotificationManager {
     }
 
     protected Map<String, String> findAllSyncopeConfs() {
-        Map<String, String> syncopeConfMap = new HashMap<>();
-        for (PlainAttr<?> attr : confDAO.get().getPlainAttrs()) {
-            syncopeConfMap.put(attr.getSchema().getKey(), attr.getValuesAsStrings().get(0));
-        }
-        return syncopeConfMap;
+        return confDAO.get().getPlainAttrs().stream().collect(
+                Collectors.toMap(attr -> attr.getSchema().getKey(), attr -> attr.getValuesAsStrings().get(0)));
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index a36489d..e4f443f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -47,7 +47,6 @@ import org.apache.syncope.core.provisioning.api.TimeoutException;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationActions;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
 import org.apache.syncope.core.provisioning.api.utils.ExceptionUtils2;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
@@ -65,6 +64,7 @@ import org.apache.syncope.core.provisioning.api.data.TaskDataBinder;
 import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
 import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
+import org.apache.syncope.core.spring.ImplementationManager;
 import org.identityconnectors.framework.common.exceptions.ConnectorException;
 import org.identityconnectors.framework.common.objects.Attribute;
 import org.identityconnectors.framework.common.objects.AttributeBuilder;
@@ -77,7 +77,6 @@ import org.identityconnectors.framework.common.objects.Uid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.springframework.transaction.annotation.Transactional;
 
 @Transactional(rollbackFor = { Throwable.class })
@@ -162,17 +161,13 @@ public abstract class AbstractPropagationTaskExecutor implements PropagationTask
     protected List<PropagationActions> getPropagationActions(final ExternalResource resource) {
         List<PropagationActions> result = new ArrayList<>();
 
-        if (!resource.getPropagationActionsClassNames().isEmpty()) {
-            resource.getPropagationActionsClassNames().forEach(className -> {
-                try {
-                    Class<?> actionsClass = Class.forName(className);
-                    result.add((PropagationActions) ApplicationContextProvider.getBeanFactory().
-                            createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true));
-                } catch (ClassNotFoundException e) {
-                    LOG.error("Invalid PropagationAction class name '{}' for resource {}", resource, className, e);
-                }
-            });
-        }
+        resource.getPropagationActions().forEach(impl -> {
+            try {
+                result.add(ImplementationManager.build(impl));
+            } catch (Exception e) {
+                LOG.error("While building {}", impl, e);
+            }
+        });
 
         return result;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
index 8bfe089..8f3ee71 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullJobDelegate.java
@@ -44,7 +44,6 @@ import org.apache.syncope.core.provisioning.api.pushpull.ProvisioningProfile;
 import org.quartz.JobExecutionException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.apache.syncope.core.provisioning.api.pushpull.ReconciliationFilterBuilder;
 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
 import org.apache.syncope.core.provisioning.api.pushpull.AnyObjectPullResultHandler;
 import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
@@ -57,6 +56,8 @@ import org.apache.syncope.core.provisioning.java.utils.MappingUtils;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.identityconnectors.framework.common.objects.OperationOptions;
 import org.identityconnectors.framework.common.objects.SyncToken;
+import org.apache.syncope.core.provisioning.api.pushpull.ReconFilterBuilder;
+import org.apache.syncope.core.spring.ImplementationManager;
 
 public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> implements SyncopePullExecutor {
 
@@ -170,15 +171,11 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
         LOG.debug("Executing pull on {}", pullTask.getResource());
 
         List<PullActions> actions = new ArrayList<>();
-        pullTask.getActionsClassNames().forEach(className -> {
+        pullTask.getActions().forEach(impl -> {
             try {
-                Class<?> actionsClass = Class.forName(className);
-                PullActions pullActions = (PullActions) ApplicationContextProvider.getBeanFactory().
-                        createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
-
-                actions.add(pullActions);
+                actions.add(ImplementationManager.build(impl));
             } catch (Exception e) {
-                LOG.warn("Class '{}' not found", className, e);
+                LOG.warn("While building {}", impl, e);
             }
         });
 
@@ -223,10 +220,8 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
                         break;
 
                     case FILTERED_RECONCILIATION:
-                        ReconciliationFilterBuilder filterBuilder =
-                                (ReconciliationFilterBuilder) ApplicationContextProvider.getBeanFactory().
-                                        createBean(Class.forName(pullTask.getReconciliationFilterBuilderClassName()),
-                                                AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+                        ReconFilterBuilder filterBuilder =
+                                ImplementationManager.build(pullTask.getReconFilterBuilder());
                         connector.filteredReconciliation(orgUnit.getObjectClass(),
                                 filterBuilder,
                                 rhandler,
@@ -296,11 +291,8 @@ public class PullJobDelegate extends AbstractProvisioningJobDelegate<PullTask> i
                             break;
 
                         case FILTERED_RECONCILIATION:
-                            ReconciliationFilterBuilder filterBuilder =
-                                    (ReconciliationFilterBuilder) ApplicationContextProvider.getBeanFactory().
-                                            createBean(
-                                                    Class.forName(pullTask.getReconciliationFilterBuilderClassName()),
-                                                    AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+                            ReconFilterBuilder filterBuilder =
+                                    ImplementationManager.build(pullTask.getReconFilterBuilder());
                             connector.filteredReconciliation(provision.getObjectClass(),
                                     filterBuilder,
                                     handler,

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/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 15976b4..44c80bd 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
@@ -23,7 +23,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 import java.util.stream.Collectors;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.policy.PullPolicySpec;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
@@ -33,12 +32,15 @@ import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+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.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
@@ -68,6 +70,7 @@ import org.springframework.transaction.annotation.Transactional;
 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;
+import org.apache.syncope.core.spring.ImplementationManager;
 
 @Transactional(readOnly = true)
 @Component
@@ -109,6 +112,9 @@ public class PullUtils {
     private RealmDAO realmDAO;
 
     @Autowired
+    private ImplementationDAO implementationDAO;
+
+    @Autowired
     private AnyUtilsFactory anyUtilsFactory;
 
     @Autowired
@@ -264,32 +270,33 @@ public class PullUtils {
     private List<String> findByCorrelationRule(
             final ConnectorObject connObj, final PullCorrelationRule rule, final AnyTypeKind type) {
 
-        List<String> result = new ArrayList<>();
-        searchDAO.search(rule.getSearchCond(connObj), type).forEach(any -> {
-            result.add(any.getKey());
-        });
-
-        return result;
+        return searchDAO.search(rule.getSearchCond(connObj), type).stream().
+                map(Entity::getKey).collect(Collectors.toList());
     }
 
     private PullCorrelationRule getCorrelationRule(final Provision provision, final PullPolicySpec policySpec) {
-        PullCorrelationRule result = null;
+        PullCorrelationRule rule = null;
 
         String pullCorrelationRule = policySpec.getCorrelationRules().get(provision.getAnyType().getKey());
-        if (StringUtils.isNotBlank(pullCorrelationRule)) {
+        if (pullCorrelationRule != null) {
             if (pullCorrelationRule.charAt(0) == '[') {
-                result = new PlainAttrsPullCorrelationRule(
+                rule = new PlainAttrsPullCorrelationRule(
                         POJOHelper.deserialize(pullCorrelationRule, String[].class), provision);
             } else {
-                try {
-                    result = (PullCorrelationRule) Class.forName(pullCorrelationRule).newInstance();
-                } catch (Exception e) {
-                    LOG.error("Failure instantiating correlation rule class '{}'", pullCorrelationRule, e);
+                Implementation impl = implementationDAO.find(pullCorrelationRule);
+                if (impl == null) {
+                    LOG.error("Could not find any Implementation matching '{}'", pullCorrelationRule);
+                } else {
+                    try {
+                        rule = ImplementationManager.build(impl);
+                    } catch (Exception e) {
+                        LOG.error("While building {}", impl, e);
+                    }
                 }
             }
         }
 
-        return result;
+        return rule;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
index ad3ccfd..b1a8b07 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PushJobDelegate.java
@@ -48,6 +48,7 @@ import org.apache.syncope.core.provisioning.api.pushpull.PushActions;
 import org.apache.syncope.core.provisioning.api.pushpull.RealmPushResultHandler;
 import org.apache.syncope.core.provisioning.api.pushpull.SyncopePushResultHandler;
 import org.apache.syncope.core.provisioning.api.pushpull.UserPushResultHandler;
+import org.apache.syncope.core.spring.ImplementationManager;
 import org.quartz.JobExecutionException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -164,15 +165,11 @@ public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
         LOG.debug("Executing push on {}", pushTask.getResource());
 
         List<PushActions> actions = new ArrayList<>();
-        pushTask.getActionsClassNames().forEach(className -> {
+        pushTask.getActions().forEach(impl -> {
             try {
-                Class<?> actionsClass = Class.forName(className);
-
-                PushActions pushActions = (PushActions) ApplicationContextProvider.getBeanFactory().
-                        createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
-                actions.add(pushActions);
+                actions.add(ImplementationManager.build(impl));
             } catch (Exception e) {
-                LOG.info("Class '{}' not found", className, e);
+                LOG.warn("While building {}", impl, e);
             }
         });
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index c49c84a..6aa8e88 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -24,7 +24,6 @@ import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.AnyOperations;
 import org.apache.syncope.common.lib.patch.AnyPatch;
-import org.apache.syncope.common.lib.policy.PasswordRuleConf;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
@@ -41,6 +40,7 @@ import org.apache.syncope.core.spring.security.PasswordGenerator;
 import org.apache.syncope.core.spring.security.SecureRandomUtils;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.OrgUnit;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
@@ -171,26 +171,27 @@ public class ConnObjectUtils {
         if (anyTO instanceof UserTO && StringUtils.isBlank(((UserTO) anyTO).getPassword())) {
             UserTO userTO = (UserTO) anyTO;
 
-            List<PasswordRuleConf> ruleConfs = new ArrayList<>();
+            List<PasswordPolicy> passwordPolicies = new ArrayList<>();
 
             Realm realm = realmDAO.findByFullPath(userTO.getRealm());
             if (realm != null) {
                 realmDAO.findAncestors(realm).stream().
-                        filter(ancestor -> (ancestor.getPasswordPolicy() != null)).
-                        forEachOrdered(ancestor -> {
-                            ruleConfs.addAll(ancestor.getPasswordPolicy().getRuleConfs());
+                        filter(ancestor -> ancestor.getPasswordPolicy() != null).
+                        forEach(ancestor -> {
+                            passwordPolicies.add(ancestor.getPasswordPolicy());
                         });
             }
 
-            userTO.getResources().stream().map(resName -> resourceDAO.find(resName)).
-                    filter(resource -> (resource != null && resource.getPasswordPolicy() != null)).
-                    forEachOrdered(resource -> {
-                        ruleConfs.addAll(resource.getPasswordPolicy().getRuleConfs());
+            userTO.getResources().stream().
+                    map(resource -> resourceDAO.find(resource)).
+                    filter(resource -> resource != null && resource.getPasswordPolicy() != null).
+                    forEach(resource -> {
+                        passwordPolicies.add(resource.getPasswordPolicy());
                     });
 
             String password;
             try {
-                password = passwordGenerator.generate(ruleConfs);
+                password = passwordGenerator.generate(passwordPolicies);
             } catch (InvalidPasswordRuleConf e) {
                 LOG.error("Could not generate policy-compliant random password for {}", userTO, e);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
index eee6d9a..9041b10 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
@@ -27,9 +27,7 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.MapContext;
-import org.apache.commons.lang3.ClassUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.to.ItemTO;
 import org.apache.syncope.common.lib.types.MappingPurpose;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.Realm;
@@ -51,6 +49,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.apache.syncope.core.provisioning.api.data.ItemTransformer;
 import org.apache.syncope.core.provisioning.api.data.JEXLItemTransformer;
+import org.apache.syncope.core.spring.ImplementationManager;
 
 public final class MappingUtils {
 
@@ -69,14 +68,14 @@ public final class MappingUtils {
 
     public static List<? extends Item> getPropagationItems(final List<? extends Item> items) {
         return items.stream().
-                        filter(item -> item.getPurpose() == MappingPurpose.PROPAGATION
-                        || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
+                filter(item -> item.getPurpose() == MappingPurpose.PROPAGATION
+                || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
     }
 
     public static List<? extends Item> getPullItems(final List<? extends Item> items) {
         return items.stream().
-                        filter(item -> item.getPurpose() == MappingPurpose.PULL
-                        || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
+                filter(item -> item.getPurpose() == MappingPurpose.PULL
+                || item.getPurpose() == MappingPurpose.BOTH).collect(Collectors.toList());
     }
 
     private static Name evaluateNAME(final String evalConnObjectLink, final String connObjectKey) {
@@ -160,54 +159,33 @@ public final class MappingUtils {
         return evaluateNAME(evalConnObjectLink, connObjectKey);
     }
 
-    private static List<ItemTransformer> getItemTransformers(
-            final String propagationJEXLTransformer,
-            final String pullJEXLTransformer,
-            final List<String> mappingItemTransformerClassNames) {
-
+    public static List<ItemTransformer> getItemTransformers(final Item item) {
         List<ItemTransformer> result = new ArrayList<>();
 
         // First consider the JEXL transformation expressions
-        if (StringUtils.isNotBlank(propagationJEXLTransformer) || StringUtils.isNotBlank(pullJEXLTransformer)) {
-            JEXLItemTransformer jexlTransformer =
-                    (JEXLItemTransformer) ApplicationContextProvider.getBeanFactory().
-                            createBean(JEXLItemTransformerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME,
-                                    false);
-
-            jexlTransformer.setPropagationJEXL(propagationJEXLTransformer);
-            jexlTransformer.setPullJEXL(pullJEXLTransformer);
+        if (StringUtils.isNotBlank(item.getPropagationJEXLTransformer())
+                || StringUtils.isNotBlank(item.getPullJEXLTransformer())) {
+
+            JEXLItemTransformer jexlTransformer = (JEXLItemTransformer) ApplicationContextProvider.getBeanFactory().
+                    createBean(JEXLItemTransformerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+
+            jexlTransformer.setPropagationJEXL(item.getPropagationJEXLTransformer());
+            jexlTransformer.setPullJEXL(item.getPullJEXLTransformer());
             result.add(jexlTransformer);
         }
 
-        // Then other custom tranaformers
-        mappingItemTransformerClassNames.forEach(className -> {
+        // Then other custom transformers
+        item.getTransformers().forEach(impl -> {
             try {
-                Class<?> transformerClass = ClassUtils.getClass(className);
-
-                result.add((ItemTransformer) ApplicationContextProvider.getBeanFactory().
-                        createBean(transformerClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false));
+                result.add(ImplementationManager.build(impl));
             } catch (Exception e) {
-                LOG.error("Could not instantiate {}, ignoring...", className, e);
+                LOG.error("While building {}", impl, e);
             }
         });
 
         return result;
     }
 
-    public static List<ItemTransformer> getItemTransformers(final ItemTO item) {
-        return getItemTransformers(
-                item.getPropagationJEXLTransformer(),
-                item.getPullJEXLTransformer(),
-                item.getTransformerClassNames());
-    }
-
-    public static List<ItemTransformer> getItemTransformers(final Item item) {
-        return getItemTransformers(
-                item.getPropagationJEXLTransformer(),
-                item.getPullJEXLTransformer(),
-                item.getTransformerClassNames());
-    }
-
     /**
      * Build options for requesting all mapped connector attributes.
      *

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/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 cac936d..55e2a26 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
@@ -23,6 +23,7 @@ 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.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;
@@ -45,7 +46,7 @@ public class DummyImplementationLookup implements ImplementationLookup {
     }
 
     @Override
-    public Set<String> getClassNames(final Type type) {
+    public Set<String> getClassNames(final ImplementationType type) {
         return Collections.emptySet();
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ImplementationServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ImplementationServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ImplementationServiceImpl.java
new file mode 100644
index 0000000..c3190af
--- /dev/null
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ImplementationServiceImpl.java
@@ -0,0 +1,67 @@
+/*
+ * 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.rest.cxf.service;
+
+import java.net.URI;
+import java.util.List;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.common.lib.to.ImplementationTO;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.ImplementationService;
+import org.apache.syncope.core.logic.ImplementationLogic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ImplementationServiceImpl extends AbstractServiceImpl implements ImplementationService {
+
+    @Autowired
+    private ImplementationLogic logic;
+
+    @Override
+    public List<ImplementationTO> list(final ImplementationType type) {
+        return logic.list(type);
+    }
+
+    @Override
+    public ImplementationTO read(final String key) {
+        return logic.read(key);
+    }
+
+    @Override
+    public Response create(final ImplementationTO implementationTO) {
+        ImplementationTO created = logic.create(implementationTO);
+        URI location = uriInfo.getAbsolutePathBuilder().path(String.valueOf(created.getKey())).build();
+        return Response.created(location).
+                header(RESTHeaders.RESOURCE_KEY, created.getKey()).
+                build();
+    }
+
+    @Override
+    public void update(final ImplementationTO implementationTO) {
+        logic.update(implementationTO);
+    }
+
+    @Override
+    public void delete(final String key) {
+        logic.delete(key);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/pom.xml
----------------------------------------------------------------------
diff --git a/core/spring/pom.xml b/core/spring/pom.xml
index addb5d3..22ba98b 100644
--- a/core/spring/pom.xml
+++ b/core/spring/pom.xml
@@ -73,6 +73,11 @@ under the License.
     </dependency>
 
     <dependency>
+      <groupId>org.codehaus.groovy</groupId>
+      <artifactId>groovy-all</artifactId>
+    </dependency>
+
+    <dependency>
       <groupId>org.apache.syncope.core</groupId>
       <artifactId>syncope-core-provisioning-api</artifactId>
       <version>${project.version}</version>
@@ -91,6 +96,11 @@ under the License.
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter-engine</artifactId>
       <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/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
new file mode 100644
index 0000000..af1b2f7
--- /dev/null
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/ImplementationManager.java
@@ -0,0 +1,174 @@
+/*
+ * 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.spring;
+
+import groovy.lang.GroovyClassLoader;
+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.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.provisioning.api.serialization.POJOHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+
+public final class ImplementationManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ImplementationManager.class);
+
+    private static final GroovyClassLoader GROOVY_CLASSLOADER = new GroovyClassLoader();
+
+    public static Optional<Reportlet> buildReportlet(final Implementation impl)
+            throws InstantiationException, IllegalAccessException {
+
+        switch (impl.getEngine()) {
+            case GROOVY:
+                return Optional.of(ImplementationManager.<Reportlet>buildGroovy(impl.getBody()));
+
+            case JAVA:
+            default:
+                Reportlet reportlet = null;
+
+                ReportletConf reportletConf = POJOHelper.deserialize(impl.getBody(), ReportletConf.class);
+                Class<? extends Reportlet> reportletClass = ApplicationContextProvider.getApplicationContext().
+                        getBean(ImplementationLookup.class).getReportletClass(reportletConf.getClass());
+                if (reportletClass == null) {
+                    LOG.warn("Could not find matching reportlet for {}", reportletConf.getClass());
+                } else {
+                    // fetch (or create) reportlet
+                    if (ApplicationContextProvider.getBeanFactory().containsSingleton(reportletClass.getName())) {
+                        reportlet = (Reportlet) ApplicationContextProvider.getBeanFactory().
+                                getSingleton(reportletClass.getName());
+                    } else {
+                        reportlet = (Reportlet) ApplicationContextProvider.getBeanFactory().
+                                createBean(reportletClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+                        ApplicationContextProvider.getBeanFactory().
+                                registerSingleton(reportletClass.getName(), reportlet);
+                    }
+                    reportlet.setConf(reportletConf);
+                }
+
+                return Optional.ofNullable(reportlet);
+        }
+    }
+
+    public static Optional<AccountRule> buildAccountRule(final Implementation impl)
+            throws InstantiationException, IllegalAccessException {
+
+        switch (impl.getEngine()) {
+            case GROOVY:
+                return Optional.of(ImplementationManager.<AccountRule>buildGroovy(impl.getBody()));
+
+            case JAVA:
+            default:
+                AccountRule rule = null;
+
+                AccountRuleConf ruleConf = POJOHelper.deserialize(impl.getBody(), AccountRuleConf.class);
+                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());
+                } else {
+                    // fetch (or create) rule
+                    if (ApplicationContextProvider.getBeanFactory().containsSingleton(ruleClass.getName())) {
+                        rule = (AccountRule) ApplicationContextProvider.getBeanFactory().
+                                getSingleton(ruleClass.getName());
+                    } else {
+                        rule = (AccountRule) ApplicationContextProvider.getBeanFactory().
+                                createBean(ruleClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+                        ApplicationContextProvider.getBeanFactory().
+                                registerSingleton(ruleClass.getName(), rule);
+                    }
+                    rule.setConf(ruleConf);
+                }
+
+                return Optional.ofNullable(rule);
+        }
+    }
+
+    public static Optional<PasswordRule> buildPasswordRule(final Implementation impl)
+            throws InstantiationException, IllegalAccessException {
+
+        switch (impl.getEngine()) {
+            case GROOVY:
+                return Optional.of(ImplementationManager.<PasswordRule>buildGroovy(impl.getBody()));
+
+            case JAVA:
+            default:
+                PasswordRule rule = null;
+
+                PasswordRuleConf ruleConf = POJOHelper.deserialize(impl.getBody(), PasswordRuleConf.class);
+                Class<? extends PasswordRule> ruleClass = ApplicationContextProvider.getApplicationContext().
+                        getBean(ImplementationLookup.class).getPasswordRuleClass(ruleConf.getClass());
+                if (ruleClass == null) {
+                    LOG.warn("Could not find matching password rule for {}", impl.getClass());
+                } else {
+                    // fetch (or create) rule
+                    if (ApplicationContextProvider.getBeanFactory().containsSingleton(ruleClass.getName())) {
+                        rule = (PasswordRule) ApplicationContextProvider.getBeanFactory().
+                                getSingleton(ruleClass.getName());
+                    } else {
+                        rule = (PasswordRule) 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 {
+
+        switch (impl.getEngine()) {
+            case GROOVY:
+                return ImplementationManager.<T>buildGroovy(impl.getBody());
+
+            case JAVA:
+            default:
+                return ImplementationManager.<T>buildJava(impl.getBody());
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T buildGroovy(final String classBody) throws InstantiationException, IllegalAccessException {
+        Class<?> clazz = GROOVY_CLASSLOADER.parseClass(classBody);
+        return (T) ApplicationContextProvider.getBeanFactory().
+                createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T buildJava(final String className) throws ClassNotFoundException {
+        Class<?> clazz = Class.forName(className);
+        return (T) ApplicationContextProvider.getBeanFactory().
+                createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+    }
+
+    private ImplementationManager() {
+        // private constructor for static utility class
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
----------------------------------------------------------------------
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
index 3a5ee7b..691ff36 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/AuthDataAccessor.java
@@ -141,7 +141,7 @@ public class AuthDataAccessor {
                 jwtSSOProviders = new HashMap<>();
 
                 implementationLookup.getJWTSSOProviderClasses().stream().
-                        map((clazz) -> (JWTSSOProvider) ApplicationContextProvider.getBeanFactory().
+                        map(clazz -> (JWTSSOProvider) ApplicationContextProvider.getBeanFactory().
                         createBean(clazz, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true)).
                         forEachOrdered(jwtSSOProvider -> {
                             jwtSSOProviders.put(jwtSSOProvider.getIssuer(), jwtSSOProvider);

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
----------------------------------------------------------------------
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
index 93c750c..b0a4d95 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/DefaultPasswordGenerator.java
@@ -20,12 +20,17 @@ package org.apache.syncope.core.spring.security;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
-import org.apache.syncope.common.lib.policy.PasswordRuleConf;
-import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.dao.PasswordRule;
+import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
 import org.apache.syncope.core.provisioning.api.utils.policy.InvalidPasswordRuleConf;
 import org.apache.syncope.core.provisioning.api.utils.policy.PolicyPattern;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.spring.ImplementationManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.transaction.annotation.Transactional;
 
 /**
@@ -36,6 +41,8 @@ import org.springframework.transaction.annotation.Transactional;
  */
 public class DefaultPasswordGenerator implements PasswordGenerator {
 
+    private static final Logger LOG = LoggerFactory.getLogger(PasswordGenerator.class);
+
     private static final char[] SPECIAL_CHARS = { '!', '£', '%', '&', '(', ')', '?', '#', '$' };
 
     private static final int VERY_MIN_LENGTH = 0;
@@ -47,23 +54,29 @@ public class DefaultPasswordGenerator implements PasswordGenerator {
     @Transactional(readOnly = true)
     @Override
     public String generate(final ExternalResource resource) throws InvalidPasswordRuleConf {
-        List<PasswordRuleConf> ruleConfs = new ArrayList<>();
+        List<PasswordPolicy> policies = new ArrayList<>();
 
         if (resource.getPasswordPolicy() != null) {
-            ruleConfs.addAll(resource.getPasswordPolicy().getRuleConfs());
+            policies.add(resource.getPasswordPolicy());
         }
 
-        return generate(ruleConfs);
+        return generate(policies);
     }
 
     @Override
-    public String generate(final List<PasswordRuleConf> ruleConfs) throws InvalidPasswordRuleConf {
+    public String generate(final List<PasswordPolicy> policies) throws InvalidPasswordRuleConf {
         List<DefaultPasswordRuleConf> defaultRuleConfs = new ArrayList<>();
-        ruleConfs.stream().
-                filter(ruleConf -> (ruleConf instanceof DefaultPasswordRuleConf)).
-                forEachOrdered(ruleConf -> {
-                    defaultRuleConfs.add((DefaultPasswordRuleConf) ruleConf);
-                });
+
+        policies.stream().forEach(policy -> policy.getRules().forEach(impl -> {
+            try {
+                Optional<PasswordRule> rule = ImplementationManager.buildPasswordRule(impl);
+                if (rule.isPresent() && rule.get().getConf() instanceof DefaultPasswordRuleConf) {
+                    defaultRuleConfs.add((DefaultPasswordRuleConf) rule.get().getConf());
+                }
+            } catch (Exception e) {
+                LOG.error("Invalid {}, ignoring...", impl, e);
+            }
+        }));
 
         DefaultPasswordRuleConf ruleConf = merge(defaultRuleConfs);
         check(ruleConf);
@@ -301,17 +314,17 @@ public class DefaultPasswordGenerator implements PasswordGenerator {
     }
 
     private void checkPrefixAndSuffix(final String[] generatedPassword, final DefaultPasswordRuleConf ruleConf) {
-        for (String prefix : ruleConf.getPrefixesNotPermitted()) {
+        ruleConf.getPrefixesNotPermitted().forEach(prefix -> {
             if (StringUtils.join(generatedPassword).startsWith(prefix)) {
                 checkStartChar(generatedPassword, ruleConf);
             }
-        }
+        });
 
-        for (String suffix : ruleConf.getSuffixesNotPermitted()) {
+        ruleConf.getSuffixesNotPermitted().forEach(suffix -> {
             if (StringUtils.join(generatedPassword).endsWith(suffix)) {
                 checkEndChar(generatedPassword, ruleConf);
             }
-        }
+        });
     }
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java
----------------------------------------------------------------------
diff --git a/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java b/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java
index 06b73e4..cf40d5f 100644
--- a/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java
+++ b/core/spring/src/main/java/org/apache/syncope/core/spring/security/PasswordGenerator.java
@@ -19,7 +19,7 @@
 package org.apache.syncope.core.spring.security;
 
 import java.util.List;
-import org.apache.syncope.common.lib.policy.PasswordRuleConf;
+import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.provisioning.api.utils.policy.InvalidPasswordRuleConf;
 
@@ -27,6 +27,6 @@ public interface PasswordGenerator {
 
     String generate(ExternalResource resource) throws InvalidPasswordRuleConf;
 
-    String generate(List<PasswordRuleConf> ruleConfs) throws InvalidPasswordRuleConf;
+    String generate(List<PasswordPolicy> policies) throws InvalidPasswordRuleConf;
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/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
new file mode 100644
index 0000000..e644645
--- /dev/null
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/DummyImplementationLookup.java
@@ -0,0 +1,80 @@
+/*
+ * 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.spring.security;
+
+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.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.Reportlet;
+
+public class DummyImplementationLookup implements ImplementationLookup {
+
+    @Override
+    public Integer getPriority() {
+        return -1;
+    }
+
+    @Override
+    public void load() {
+        // do nothing
+    }
+
+    @Override
+    public Set<String> getClassNames(final ImplementationType type) {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<Class<?>> getJWTSSOProviderClasses() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Class<Reportlet> getReportletClass(
+            final Class<? extends ReportletConf> reportletConfClass) {
+
+        return null;
+    }
+
+    @Override
+    public Class<? extends AccountRule> getAccountRuleClass(
+            final Class<? extends AccountRuleConf> accountRuleConfClass) {
+
+        return null;
+    }
+
+    @Override
+    public Class<? extends PasswordRule> getPasswordRuleClass(
+            final Class<? extends PasswordRuleConf> passwordRuleConfClass) {
+
+        return TestPasswordRule.class;
+    }
+
+    @Override
+    public Set<Class<?>> getAuditAppenderClasses() {
+        return Collections.emptySet();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/test/java/org/apache/syncope/core/spring/security/EncryptorTest.java
----------------------------------------------------------------------
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/EncryptorTest.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/EncryptorTest.java
index 0d1b801..4ec78b9 100644
--- a/core/spring/src/test/java/org/apache/syncope/core/spring/security/EncryptorTest.java
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/EncryptorTest.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.core.spring.security;
 
-import org.apache.syncope.core.spring.security.Encryptor;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java
----------------------------------------------------------------------
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java
index 2edab6d..8378a57 100644
--- a/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/PasswordGeneratorTest.java
@@ -27,11 +27,14 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
-import org.apache.syncope.common.lib.policy.PasswordRuleConf;
+import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.apache.syncope.core.provisioning.api.utils.policy.InvalidPasswordRuleConf;
 import org.apache.syncope.core.provisioning.api.utils.policy.PolicyPattern;
 import org.junit.jupiter.api.Test;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
 
+@SpringJUnitConfig(locations = { "classpath:springTest.xml" })
 public class PasswordGeneratorTest {
 
     private final DefaultPasswordGenerator passwordGenerator = new DefaultPasswordGenerator();
@@ -62,48 +65,72 @@ public class PasswordGeneratorTest {
 
     @Test
     public void startEndWithDigit() throws InvalidPasswordRuleConf {
-        DefaultPasswordRuleConf pwdRuleConf = createBaseDefaultPasswordRuleConf();
-        pwdRuleConf.setMustStartWithDigit(true);
+        DefaultPasswordRuleConf pwdRuleConf1 = createBaseDefaultPasswordRuleConf();
+        pwdRuleConf1.setMustStartWithDigit(true);
+        TestImplementation passwordRule1 = new TestImplementation();
+        passwordRule1.setBody(POJOHelper.serialize(pwdRuleConf1));
+        TestPasswordPolicy policy1 = new TestPasswordPolicy();
+        policy1.add(passwordRule1);
 
         DefaultPasswordRuleConf pwdRuleConf2 = createBaseDefaultPasswordRuleConf();
         pwdRuleConf2.setMustEndWithDigit(true);
-
-        List<PasswordRuleConf> ruleConfs = new ArrayList<>();
-        ruleConfs.add(pwdRuleConf);
-        ruleConfs.add(pwdRuleConf2);
-        String generatedPassword = passwordGenerator.generate(ruleConfs);
+        TestImplementation passwordRule2 = new TestImplementation();
+        passwordRule2.setBody(POJOHelper.serialize(pwdRuleConf2));
+        TestPasswordPolicy policy2 = new TestPasswordPolicy();
+        policy2.add(passwordRule2);
+
+        List<PasswordPolicy> policies = new ArrayList<>();
+        policies.add(policy1);
+        policies.add(policy2);
+        String generatedPassword = passwordGenerator.generate(policies);
         assertTrue(Character.isDigit(generatedPassword.charAt(0)));
         assertTrue(Character.isDigit(generatedPassword.charAt(generatedPassword.length() - 1)));
     }
 
     @Test
     public void startWithDigitAndWithAlpha() throws InvalidPasswordRuleConf {
-        DefaultPasswordRuleConf pwdRuleConf = createBaseDefaultPasswordRuleConf();
-        pwdRuleConf.setMustStartWithDigit(true);
+        DefaultPasswordRuleConf pwdRuleConf1 = createBaseDefaultPasswordRuleConf();
+        pwdRuleConf1.setMustStartWithDigit(true);
+        TestImplementation passwordRule1 = new TestImplementation();
+        passwordRule1.setBody(POJOHelper.serialize(pwdRuleConf1));
+        TestPasswordPolicy policy1 = new TestPasswordPolicy();
+        policy1.add(passwordRule1);
 
         DefaultPasswordRuleConf pwdRuleConf2 = createBaseDefaultPasswordRuleConf();
         pwdRuleConf2.setMustEndWithAlpha(true);
-
-        List<PasswordRuleConf> pwdRuleConfs = new ArrayList<>();
-        pwdRuleConfs.add(pwdRuleConf);
-        pwdRuleConfs.add(pwdRuleConf2);
-        String generatedPassword = passwordGenerator.generate(pwdRuleConfs);
+        TestImplementation passwordRule2 = new TestImplementation();
+        passwordRule2.setBody(POJOHelper.serialize(pwdRuleConf2));
+        TestPasswordPolicy policy2 = new TestPasswordPolicy();
+        policy2.add(passwordRule2);
+
+        List<PasswordPolicy> policies = new ArrayList<>();
+        policies.add(policy1);
+        policies.add(policy2);
+        String generatedPassword = passwordGenerator.generate(policies);
         assertTrue(Character.isDigit(generatedPassword.charAt(0)));
         assertTrue(Character.isLetter(generatedPassword.charAt(generatedPassword.length() - 1)));
     }
 
     @Test
     public void passwordWithNonAlpha() throws InvalidPasswordRuleConf {
-        DefaultPasswordRuleConf pwdRuleConf = createBaseDefaultPasswordRuleConf();
-        pwdRuleConf.setNonAlphanumericRequired(true);
+        DefaultPasswordRuleConf pwdRuleConf1 = createBaseDefaultPasswordRuleConf();
+        pwdRuleConf1.setNonAlphanumericRequired(true);
+        TestImplementation passwordRule1 = new TestImplementation();
+        passwordRule1.setBody(POJOHelper.serialize(pwdRuleConf1));
+        TestPasswordPolicy policy1 = new TestPasswordPolicy();
+        policy1.add(passwordRule1);
 
         DefaultPasswordRuleConf pwdRuleConf2 = createBaseDefaultPasswordRuleConf();
         pwdRuleConf2.setMustEndWithAlpha(true);
-
-        List<PasswordRuleConf> pwdRuleConfs = new ArrayList<>();
-        pwdRuleConfs.add(pwdRuleConf);
-        pwdRuleConfs.add(pwdRuleConf2);
-        String generatedPassword = passwordGenerator.generate(pwdRuleConfs);
+        TestImplementation passwordRule2 = new TestImplementation();
+        passwordRule2.setBody(POJOHelper.serialize(pwdRuleConf2));
+        TestPasswordPolicy policy2 = new TestPasswordPolicy();
+        policy2.add(passwordRule2);
+
+        List<PasswordPolicy> policies = new ArrayList<>();
+        policies.add(policy1);
+        policies.add(policy2);
+        String generatedPassword = passwordGenerator.generate(policies);
         assertTrue(PolicyPattern.NON_ALPHANUMERIC.matcher(generatedPassword).matches());
         assertTrue(Character.isLetter(generatedPassword.charAt(generatedPassword.length() - 1)));
     }
@@ -111,16 +138,24 @@ public class PasswordGeneratorTest {
     @Test
     public void incopatiblePolicies() {
         assertThrows(InvalidPasswordRuleConf.class, () -> {
-            DefaultPasswordRuleConf pwdRuleConf = createBaseDefaultPasswordRuleConf();
-            pwdRuleConf.setMinLength(12);
+            DefaultPasswordRuleConf pwdRuleConf1 = createBaseDefaultPasswordRuleConf();
+            pwdRuleConf1.setMinLength(12);
+            TestImplementation passwordRule1 = new TestImplementation();
+            passwordRule1.setBody(POJOHelper.serialize(pwdRuleConf1));
+            TestPasswordPolicy policy1 = new TestPasswordPolicy();
+            policy1.add(passwordRule1);
 
             DefaultPasswordRuleConf pwdRuleConf2 = createBaseDefaultPasswordRuleConf();
-            pwdRuleConf.setMaxLength(10);
-
-            List<PasswordRuleConf> pwdRuleConfs = new ArrayList<>();
-            pwdRuleConfs.add(pwdRuleConf);
-            pwdRuleConfs.add(pwdRuleConf2);
-            passwordGenerator.generate(pwdRuleConfs);
+            pwdRuleConf2.setMaxLength(10);
+            TestImplementation passwordRule2 = new TestImplementation();
+            passwordRule2.setBody(POJOHelper.serialize(pwdRuleConf2));
+            TestPasswordPolicy policy2 = new TestPasswordPolicy();
+            policy2.add(passwordRule2);
+
+            List<PasswordPolicy> policies = new ArrayList<>();
+            policies.add(policy1);
+            policies.add(policy2);
+            passwordGenerator.generate(policies);
         });
     }
 
@@ -128,17 +163,21 @@ public class PasswordGeneratorTest {
     public void issueSYNCOPE678() {
         String password = null;
         try {
-            password = passwordGenerator.generate(Collections.<PasswordRuleConf>emptyList());
+            password = passwordGenerator.generate(Collections.<PasswordPolicy>emptyList());
         } catch (InvalidPasswordRuleConf e) {
             fail(e.getMessage());
         }
         assertNotNull(password);
 
-        DefaultPasswordRuleConf ppSpec = createBaseDefaultPasswordRuleConf();
-        ppSpec.setMinLength(0);
+        DefaultPasswordRuleConf pwdRuleConf1 = createBaseDefaultPasswordRuleConf();
+        pwdRuleConf1.setMinLength(0);
+        TestImplementation passwordRule1 = new TestImplementation();
+        passwordRule1.setBody(POJOHelper.serialize(pwdRuleConf1));
+        TestPasswordPolicy policy1 = new TestPasswordPolicy();
+
         password = null;
         try {
-            password = passwordGenerator.generate(Collections.<PasswordRuleConf>singletonList(ppSpec));
+            password = passwordGenerator.generate(Collections.<PasswordPolicy>singletonList(policy1));
         } catch (InvalidPasswordRuleConf e) {
             fail(e.getMessage());
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestImplementation.java
----------------------------------------------------------------------
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestImplementation.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestImplementation.java
new file mode 100644
index 0000000..96479ce
--- /dev/null
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestImplementation.java
@@ -0,0 +1,71 @@
+/*
+ * 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.spring.security;
+
+import org.apache.syncope.common.lib.types.ImplementationEngine;
+import org.apache.syncope.common.lib.types.ImplementationType;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+
+public class TestImplementation implements Implementation {
+
+    private static final long serialVersionUID = -2362660463135828190L;
+
+    private String body;
+
+    @Override
+    public void setKey(final String key) {
+        // nothing to do
+    }
+
+    @Override
+    public String getKey() {
+        return "";
+    }
+
+    @Override
+    public ImplementationEngine getEngine() {
+        return ImplementationEngine.JAVA;
+    }
+
+    @Override
+    public void setEngine(ImplementationEngine engine) {
+        // nothing to do
+    }
+
+    @Override
+    public ImplementationType getType() {
+        return ImplementationType.PASSWORD_RULE;
+    }
+
+    @Override
+    public void setType(ImplementationType type) {
+        // nothing to do
+    }
+
+    @Override
+    public String getBody() {
+        return body;
+    }
+
+    @Override
+    public void setBody(final String body) {
+        this.body = body;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestPasswordPolicy.java
----------------------------------------------------------------------
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestPasswordPolicy.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestPasswordPolicy.java
new file mode 100644
index 0000000..bf2255d
--- /dev/null
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestPasswordPolicy.java
@@ -0,0 +1,77 @@
+/*
+ * 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.spring.security;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Implementation;
+import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
+
+public class TestPasswordPolicy implements PasswordPolicy {
+
+    private static final long serialVersionUID = 4978614846223679095L;
+
+    private final List<Implementation> rules = new ArrayList<>();
+
+    @Override
+    public String getKey() {
+        return "";
+    }
+
+    @Override
+    public String getDescription() {
+        return "";
+    }
+
+    @Override
+    public void setDescription(String description) {
+        // nothing to do
+    }
+
+    @Override
+    public boolean isAllowNullPassword() {
+        return false;
+    }
+
+    @Override
+    public void setAllowNullPassword(final boolean allowNullPassword) {
+        // nothing to do
+    }
+
+    @Override
+    public int getHistoryLength() {
+        return 0;
+    }
+
+    @Override
+    public void setHistoryLength(final int historyLength) {
+        // nothing to do
+    }
+
+    @Override
+    public boolean add(final Implementation rule) {
+        return this.rules.add(rule);
+    }
+
+    @Override
+    public List<? extends Implementation> getRules() {
+        return this.rules;
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestPasswordRule.java
----------------------------------------------------------------------
diff --git a/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestPasswordRule.java b/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestPasswordRule.java
new file mode 100644
index 0000000..549549a
--- /dev/null
+++ b/core/spring/src/test/java/org/apache/syncope/core/spring/security/TestPasswordRule.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.core.spring.security;
+
+import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
+import org.apache.syncope.common.lib.policy.PasswordRuleConf;
+import org.apache.syncope.core.persistence.api.dao.PasswordRule;
+import org.apache.syncope.core.persistence.api.dao.PasswordRuleConfClass;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+
+@PasswordRuleConfClass(DefaultPasswordRuleConf.class)
+public class TestPasswordRule implements PasswordRule {
+
+    private DefaultPasswordRuleConf conf;
+
+    @Override
+    public PasswordRuleConf getConf() {
+        return conf;
+    }
+
+    @Override
+    public void setConf(final PasswordRuleConf conf) {
+        if (conf instanceof DefaultPasswordRuleConf) {
+            this.conf = (DefaultPasswordRuleConf) conf;
+        } else {
+            throw new IllegalArgumentException(
+                    DefaultPasswordRuleConf.class.getName() + " expected, got " + conf.getClass().getName());
+        }
+    }
+
+    @Override
+    public void enforce(final User user) {
+        // nothing to do
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/core/spring/src/test/resources/springTest.xml
----------------------------------------------------------------------
diff --git a/core/spring/src/test/resources/springTest.xml b/core/spring/src/test/resources/springTest.xml
new file mode 100644
index 0000000..76ae511
--- /dev/null
+++ b/core/spring/src/test/resources/springTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context
+                           http://www.springframework.org/schema/context/spring-context.xsd">
+
+  <bean class="org.apache.syncope.core.spring.ApplicationContextProvider"/>
+  <bean class="org.apache.syncope.core.spring.security.DummyImplementationLookup"/>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/syncope/blob/d5b57922/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
----------------------------------------------------------------------
diff --git a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
index b11a530..9c78366 100644
--- a/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
+++ b/ext/saml2sp/common-lib/src/main/java/org/apache/syncope/common/lib/to/SAML2IdPTO.java
@@ -20,9 +20,7 @@ package org.apache.syncope.common.lib.to;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 import javax.ws.rs.PathParam;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
@@ -61,7 +59,7 @@ public class SAML2IdPTO extends AbstractBaseBean implements EntityTO, ItemContai
 
     private final List<ItemTO> items = new ArrayList<>();
 
-    private final Set<String> actionsClassNames = new HashSet<>();
+    private final List<String> actions = new ArrayList<>();
 
     @Override
     public String getKey() {
@@ -182,11 +180,11 @@ public class SAML2IdPTO extends AbstractBaseBean implements EntityTO, ItemContai
         return this.items.remove(item);
     }
 
-    @XmlElementWrapper(name = "actionsClassNames")
-    @XmlElement(name = "actionsClassName")
-    @JsonProperty("actionsClassNames")
-    public Set<String> getActionsClassNames() {
-        return actionsClassNames;
+    @XmlElementWrapper(name = "actions")
+    @XmlElement(name = "action")
+    @JsonProperty("actions")
+    public List<String> getActions() {
+        return actions;
     }
 
     public boolean isSupportUnsolicited() {


Mime
View raw message