syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mdisabat...@apache.org
Subject [11/31] syncope git commit: [SYNCOPE-652] Still several things to refine, but it starts taking shape
Date Fri, 14 Aug 2015 08:30:40 GMT
http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractTaskJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractTaskJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractTaskJob.java
deleted file mode 100644
index 728ab41..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractTaskJob.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.provisioning.java.job;
-
-import java.util.Date;
-import java.util.concurrent.atomic.AtomicReference;
-import org.apache.syncope.common.lib.types.AuditElements;
-import org.apache.syncope.common.lib.types.AuditElements.Result;
-import org.apache.syncope.core.persistence.api.dao.TaskDAO;
-import org.apache.syncope.core.persistence.api.dao.TaskExecDAO;
-import org.apache.syncope.core.persistence.api.entity.EntityFactory;
-import org.apache.syncope.core.persistence.api.entity.task.Task;
-import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
-import org.apache.syncope.core.provisioning.api.job.TaskJob;
-import org.apache.syncope.core.misc.AuditManager;
-import org.apache.syncope.core.misc.DataFormat;
-import org.apache.syncope.core.misc.ExceptionUtils2;
-import org.apache.syncope.core.persistence.api.dao.ConfDAO;
-import org.apache.syncope.core.provisioning.api.notification.NotificationManager;
-import org.quartz.DisallowConcurrentExecution;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-import org.quartz.UnableToInterruptJobException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * Abstract job implementation that delegates to concrete implementation the actual job execution and provides some
- * base features.
- * <strong>Extending this class will not provide support transaction management.</strong><br/>
- * Extend <tt>AbstractTransactionalTaskJob</tt> for this purpose.
- *
- * @see AbstractTransactionalTaskJob
- */
-@DisallowConcurrentExecution
-public abstract class AbstractTaskJob implements TaskJob {
-
-    /**
-     * Task execution status.
-     */
-    public enum Status {
-
-        SUCCESS,
-        FAILURE
-
-    }
-
-    /**
-     * Logger.
-     */
-    protected static final Logger LOG = LoggerFactory.getLogger(AbstractTaskJob.class);
-
-    /**
-     * Task DAO.
-     */
-    @Autowired
-    protected TaskDAO taskDAO;
-
-    /**
-     * Task execution DAO.
-     */
-    @Autowired
-    private TaskExecDAO taskExecDAO;
-
-    /**
-     * Configuration DAO.
-     */
-    @Autowired
-    private ConfDAO confDAO;
-
-    /**
-     * Notification manager.
-     */
-    @Autowired
-    private NotificationManager notificationManager;
-
-    /**
-     * Audit manager.
-     */
-    @Autowired
-    private AuditManager auditManager;
-
-    @Autowired
-    private EntityFactory entityFactory;
-
-    /**
-     * Id, set by the caller, for identifying the task to be executed.
-     */
-    protected Long taskId;
-
-    /**
-     * The actual task to be executed.
-     */
-    protected Task task;
-
-    /**
-     * The current running thread containing the task to be executed.
-     */
-    protected AtomicReference<Thread> runningThread = new AtomicReference<Thread>();
-
-    /**
-     * Task id setter.
-     *
-     * @param taskId to be set
-     */
-    @Override
-    public void setTaskId(final Long taskId) {
-        this.taskId = taskId;
-    }
-
-    @Override
-    public void execute(final JobExecutionContext context) throws JobExecutionException {
-        this.runningThread.set(Thread.currentThread());
-        task = taskDAO.find(taskId);
-        if (task == null) {
-            throw new JobExecutionException("Task " + taskId + " not found");
-        }
-
-        TaskExec execution = entityFactory.newEntity(TaskExec.class);
-        execution.setStartDate(new Date());
-        execution.setTask(task);
-
-        Result result;
-
-        try {
-            execution.setMessage(doExecute(context.getMergedJobDataMap().getBoolean(DRY_RUN_JOBDETAIL_KEY)));
-            execution.setStatus(Status.SUCCESS.name());
-            result = Result.SUCCESS;
-        } catch (JobExecutionException e) {
-            LOG.error("While executing task " + taskId, e);
-            result = Result.FAILURE;
-
-            execution.setMessage(ExceptionUtils2.getFullStackTrace(e));
-            execution.setStatus(Status.FAILURE.name());
-        }
-        execution.setEndDate(new Date());
-
-        if (hasToBeRegistered(execution)) {
-            taskExecDAO.saveAndAdd(taskId, execution);
-        }
-        task = taskDAO.save(task);
-
-        notificationManager.createTasks(
-                AuditElements.EventCategoryType.TASK,
-                this.getClass().getSimpleName(),
-                null,
-                this.getClass().getSimpleName(), // searching for before object is too much expensive ...
-                result,
-                task,
-                execution);
-
-        auditManager.audit(
-                AuditElements.EventCategoryType.TASK,
-                task.getClass().getSimpleName(),
-                null,
-                null, // searching for before object is too much expensive ...
-                result,
-                task,
-                (Object[]) null);
-    }
-
-    /**
-     * The actual execution, delegated to child classes.
-     *
-     * @param dryRun whether to actually touch the data
-     * @return the task execution status to be set
-     * @throws JobExecutionException if anything goes wrong
-     */
-    protected abstract String doExecute(boolean dryRun) throws JobExecutionException;
-
-    /**
-     * Template method to determine whether this job's task execution has to be persisted or not.
-     *
-     * @param execution task execution
-     * @return wether to persist or not
-     */
-    protected boolean hasToBeRegistered(final TaskExec execution) {
-        return false;
-    }
-
-    @Override
-    public void interrupt() throws UnableToInterruptJobException {
-        Thread thread = this.runningThread.getAndSet(null);
-        if (thread == null) {
-            LOG.warn("Unable to retrieve the thread of the current job execution");
-        } else {
-            LOG.info("Interrupting job from thread {} at {} ", thread.getId(), DataFormat.format(new Date()));
-
-            long maxRetry = confDAO.find("tasks.interruptMaxRetries", "1").getValues().get(0).getLongValue();
-            for (int i = 0; i < maxRetry && thread.isAlive(); i++) {
-                thread.interrupt();
-            }
-            // if the thread is still alive, it should be available in the next stop
-            if (thread.isAlive()) {
-                this.runningThread.set(thread);
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractTransactionalTaskJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractTransactionalTaskJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractTransactionalTaskJob.java
deleted file mode 100644
index b90c142..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractTransactionalTaskJob.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.java.job;
-
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * Abstract job implementation for transactional execution.
- */
-public abstract class AbstractTransactionalTaskJob extends AbstractTaskJob {
-
-    @Transactional
-    @Override
-    public void execute(final JobExecutionContext context) throws JobExecutionException {
-        super.execute(context);
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SampleJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SampleJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SampleJob.java
deleted file mode 100644
index e031905..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SampleJob.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.provisioning.java.job;
-
-import org.apache.syncope.core.persistence.api.entity.task.SchedTask;
-import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
-import org.quartz.JobExecutionException;
-
-/**
- * Sample implementation for execution a scheduled task.
- *
- * @see SchedTask
- */
-public class SampleJob extends AbstractTaskJob {
-
-    @Override
-    protected String doExecute(final boolean dryRun) throws JobExecutionException {
-        if (!(task instanceof SchedTask)) {
-            throw new JobExecutionException("Task " + taskId + " isn't a SchedTask");
-        }
-        final SchedTask schedTask = (SchedTask) this.task;
-
-        LOG.info("SampleJob {}running [SchedTask {}]", (dryRun
-                ? "dry "
-                : ""), schedTask.getKey());
-
-        return (dryRun
-                ? "DRY "
-                : "") + "RUNNING";
-    }
-
-    @Override
-    protected boolean hasToBeRegistered(final TaskExec execution) {
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SpringBeanJobFactory.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SpringBeanJobFactory.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SpringBeanJobFactory.java
index fc3938e..925c6e6 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SpringBeanJobFactory.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SpringBeanJobFactory.java
@@ -26,6 +26,10 @@ import org.springframework.beans.PropertyAccessorFactory;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ConfigurableApplicationContext;
 
+/**
+ * An implementation of SpringBeanJobFactory that retrieves the bean from the Spring context so that autowiring and
+ * transactions work.
+ */
 public class SpringBeanJobFactory extends org.springframework.scheduling.quartz.SpringBeanJobFactory {
 
     private String[] ignoredUnknownProperties;
@@ -33,7 +37,7 @@ public class SpringBeanJobFactory extends org.springframework.scheduling.quartz.
     private SchedulerContext schedulerContext;
 
     @Override
-    public void setIgnoredUnknownProperties(final String[] ignoredUnknownProperties) {
+    public void setIgnoredUnknownProperties(final String... ignoredUnknownProperties) {
         String[] defensiveCopy = ignoredUnknownProperties.clone();
         super.setIgnoredUnknownProperties(defensiveCopy);
         this.ignoredUnknownProperties = defensiveCopy;
@@ -45,12 +49,6 @@ public class SpringBeanJobFactory extends org.springframework.scheduling.quartz.
         this.schedulerContext = schedulerContext;
     }
 
-    /**
-     * An implementation of SpringBeanJobFactory that retrieves the bean from the Spring context so that autowiring and
-     * transactions work.
-     *
-     * {@inheritDoc}
-     */
     @Override
     protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
         final ApplicationContext ctx = ((ConfigurableApplicationContext) schedulerContext.get("applicationContext"));

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/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
new file mode 100644
index 0000000..2001e22
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
@@ -0,0 +1,119 @@
+/*
+ * 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.job;
+
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicReference;
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.misc.security.AuthContextUtils;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.provisioning.api.job.JobInstanceLoader;
+import org.apache.syncope.core.provisioning.api.job.SchedTaskJobDelegate;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.InterruptableJob;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.quartz.UnableToInterruptJobException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+
+@DisallowConcurrentExecution
+public class TaskJob implements InterruptableJob {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TaskJob.class);
+
+    public static final String DRY_RUN_JOBDETAIL_KEY = "dryRun";
+
+    public static final String DELEGATE_CLASS_KEY = "delegateClass";
+
+    public static final String INTERRUPT_MAX_RETRIES_KEY = "interruptMaxRetries";
+
+    /**
+     * Task execution status.
+     */
+    public enum Status {
+
+        SUCCESS,
+        FAILURE
+
+    }
+
+    /**
+     * The current running thread containing the task to be executed.
+     */
+    private final AtomicReference<Thread> runningThread = new AtomicReference<>();
+
+    /**
+     * Key, set by the caller, for identifying the task to be executed.
+     */
+    private Long taskKey;
+
+    private long interruptMaxRetries = 1;
+
+    /**
+     * Task key setter.
+     *
+     * @param taskKey to be set
+     */
+    public void setTaskKey(final Long taskKey) {
+        this.taskKey = taskKey;
+    }
+
+    @Override
+    public void execute(final JobExecutionContext context) throws JobExecutionException {
+        this.runningThread.set(Thread.currentThread());
+        this.interruptMaxRetries = context.getMergedJobDataMap().getLong(INTERRUPT_MAX_RETRIES_KEY);
+
+        AuthContextUtils.setFakeAuth(context.getMergedJobDataMap().getString(JobInstanceLoader.DOMAIN));
+        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));
+        } catch (Exception e) {
+            throw new JobExecutionException(e);
+        } finally {
+            AuthContextUtils.clearFakeAuth();
+        }
+    }
+
+    @Override
+    public void interrupt() throws UnableToInterruptJobException {
+        Thread thread = this.runningThread.getAndSet(null);
+        if (thread == null) {
+            LOG.warn("Unable to retrieve the thread of the current job execution");
+        } else {
+            LOG.info("Interrupting job from thread {} at {} ", thread.getId(), DataFormat.format(new Date()));
+
+            if (interruptMaxRetries < 1) {
+                interruptMaxRetries = 1;
+            }
+            for (int i = 0; i < interruptMaxRetries && thread.isAlive(); i++) {
+                thread.interrupt();
+            }
+            // if the thread is still alive, it should be available in the next stop
+            if (thread.isAlive()) {
+                this.runningThread.set(thread);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
index a73f5b9..1c704df 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PropagationManagerImpl.java
@@ -195,11 +195,11 @@ public class PropagationManagerImpl implements PropagationManager {
     }
 
     @Override
-    public List<PropagationTask> getUserUpdateTasks(final User user, final Boolean enable,
+    public List<PropagationTask> getUserUpdateTasks(final Long key, final Boolean enable,
             final Collection<String> noPropResourceNames) {
 
         return getUpdateTasks(
-                user, // user to be updated on external resources
+                userDAO.find(key), // user to be updated on external resources
                 null, // no password
                 false,
                 enable, // status to be propagated
@@ -236,7 +236,7 @@ public class PropagationManagerImpl implements PropagationManager {
         } else {
             // b. generate the propagation task list in two phases: first the ones containing password,
             // the the rest (with no password)
-            final PropagationByResource origPropByRes = new PropagationByResource();
+            PropagationByResource origPropByRes = new PropagationByResource();
             origPropByRes.merge(wfResult.getPropByRes());
 
             Set<String> pwdResourceNames = new HashSet<>(userMod.getPwdPropRequest().getResourceNames());

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractProvisioningJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractProvisioningJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractProvisioningJob.java
deleted file mode 100644
index 34ca299..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractProvisioningJob.java
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.provisioning.java.sync;
-
-import static org.apache.syncope.common.lib.types.AnyTypeKind.USER;
-
-import java.lang.reflect.ParameterizedType;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import javax.annotation.Resource;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
-import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.types.Entitlement;
-import org.apache.syncope.common.lib.types.TraceLevel;
-import org.apache.syncope.core.misc.security.SyncopeAuthenticationDetails;
-import org.apache.syncope.core.misc.security.SyncopeGrantedAuthority;
-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.PolicyDAO;
-import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
-import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
-import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
-import org.apache.syncope.core.provisioning.api.Connector;
-import org.apache.syncope.core.provisioning.api.ConnectorFactory;
-import org.apache.syncope.core.provisioning.api.sync.ProvisioningActions;
-import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult;
-import org.apache.syncope.core.provisioning.java.job.AbstractTaskJob;
-import org.quartz.JobExecutionException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.core.userdetails.User;
-
-/**
- * Job for executing synchronization tasks.
- *
- * @see AbstractTaskJob
- * @see org.apache.syncope.core.persistence.api.entity.task.SyncTask
- * @see org.apache.syncope.core.persistence.api.entity.task.PushTask
- */
-public abstract class AbstractProvisioningJob<T extends ProvisioningTask, A extends ProvisioningActions>
-        extends AbstractTaskJob {
-
-    @Resource(name = "adminUser")
-    protected String adminUser;
-
-    /**
-     * ConnInstance loader.
-     */
-    @Autowired
-    protected ConnectorFactory connFactory;
-
-    @Autowired
-    protected AnyTypeDAO anyTypeDAO;
-
-    /**
-     * Resource DAO.
-     */
-    @Autowired
-    protected ExternalResourceDAO resourceDAO;
-
-    /**
-     * Policy DAO.
-     */
-    @Autowired
-    protected PolicyDAO policyDAO;
-
-    /**
-     * SyncJob actions.
-     */
-    protected List<A> actions;
-
-    public void setActions(final List<A> actions) {
-        this.actions = actions;
-    }
-
-    /**
-     * Create a textual report of the synchronization, based on the trace level.
-     *
-     * @param provResults Sync results
-     * @param syncTraceLevel Sync trace level
-     * @param dryRun dry run?
-     * @return report as string
-     */
-    protected String createReport(final Collection<ProvisioningResult> provResults, final TraceLevel syncTraceLevel,
-            final boolean dryRun) {
-
-        if (syncTraceLevel == TraceLevel.NONE) {
-            return null;
-        }
-
-        StringBuilder report = new StringBuilder();
-
-        if (dryRun) {
-            report.append("==>Dry run only, no modifications were made<==\n\n");
-        }
-
-        List<ProvisioningResult> uSuccCreate = new ArrayList<>();
-        List<ProvisioningResult> uFailCreate = new ArrayList<>();
-        List<ProvisioningResult> uSuccUpdate = new ArrayList<>();
-        List<ProvisioningResult> uFailUpdate = new ArrayList<>();
-        List<ProvisioningResult> uSuccDelete = new ArrayList<>();
-        List<ProvisioningResult> uFailDelete = new ArrayList<>();
-        List<ProvisioningResult> uSuccNone = new ArrayList<>();
-        List<ProvisioningResult> uIgnore = new ArrayList<>();
-        List<ProvisioningResult> gSuccCreate = new ArrayList<>();
-        List<ProvisioningResult> gFailCreate = new ArrayList<>();
-        List<ProvisioningResult> gSuccUpdate = new ArrayList<>();
-        List<ProvisioningResult> gFailUpdate = new ArrayList<>();
-        List<ProvisioningResult> gSuccDelete = new ArrayList<>();
-        List<ProvisioningResult> gFailDelete = new ArrayList<>();
-        List<ProvisioningResult> gSuccNone = new ArrayList<>();
-        List<ProvisioningResult> gIgnore = new ArrayList<>();
-        List<ProvisioningResult> aSuccCreate = new ArrayList<>();
-        List<ProvisioningResult> aFailCreate = new ArrayList<>();
-        List<ProvisioningResult> aSuccUpdate = new ArrayList<>();
-        List<ProvisioningResult> aFailUpdate = new ArrayList<>();
-        List<ProvisioningResult> aSuccDelete = new ArrayList<>();
-        List<ProvisioningResult> aFailDelete = new ArrayList<>();
-        List<ProvisioningResult> aSuccNone = new ArrayList<>();
-        List<ProvisioningResult> aIgnore = new ArrayList<>();
-
-        for (ProvisioningResult provResult : provResults) {
-            AnyType anyType = anyTypeDAO.find(provResult.getAnyType());
-
-            switch (provResult.getStatus()) {
-                case SUCCESS:
-                    switch (provResult.getOperation()) {
-                        case CREATE:
-                            switch (anyType.getKind()) {
-                                case USER:
-                                    uSuccCreate.add(provResult);
-                                    break;
-
-                                case GROUP:
-                                    gSuccCreate.add(provResult);
-                                    break;
-
-                                case ANY_OBJECT:
-                                default:
-                                    aSuccCreate.add(provResult);
-                            }
-                            break;
-
-                        case UPDATE:
-                            switch (anyType.getKind()) {
-                                case USER:
-                                    uSuccUpdate.add(provResult);
-                                    break;
-
-                                case GROUP:
-                                    gSuccUpdate.add(provResult);
-                                    break;
-
-                                case ANY_OBJECT:
-                                default:
-                                    aSuccUpdate.add(provResult);
-                            }
-                            break;
-
-                        case DELETE:
-                            switch (anyType.getKind()) {
-                                case USER:
-                                    uSuccDelete.add(provResult);
-                                    break;
-
-                                case GROUP:
-                                    gSuccDelete.add(provResult);
-                                    break;
-
-                                case ANY_OBJECT:
-                                default:
-                                    aSuccDelete.add(provResult);
-                            }
-                            break;
-
-                        case NONE:
-                            switch (anyType.getKind()) {
-                                case USER:
-                                    uSuccNone.add(provResult);
-                                    break;
-
-                                case GROUP:
-                                    gSuccNone.add(provResult);
-                                    break;
-
-                                case ANY_OBJECT:
-                                default:
-                                    aSuccNone.add(provResult);
-                            }
-                            break;
-
-                        default:
-                    }
-                    break;
-
-                case FAILURE:
-                    switch (provResult.getOperation()) {
-                        case CREATE:
-                            switch (anyType.getKind()) {
-                                case USER:
-                                    uFailCreate.add(provResult);
-                                    break;
-
-                                case GROUP:
-                                    gFailCreate.add(provResult);
-                                    break;
-
-                                case ANY_OBJECT:
-                                default:
-                                    aFailCreate.add(provResult);
-                            }
-                            break;
-
-                        case UPDATE:
-                            switch (anyType.getKind()) {
-                                case USER:
-                                    uFailUpdate.add(provResult);
-                                    break;
-
-                                case GROUP:
-                                    gFailUpdate.add(provResult);
-                                    break;
-
-                                case ANY_OBJECT:
-                                default:
-                                    aFailUpdate.add(provResult);
-                            }
-                            break;
-
-                        case DELETE:
-                            switch (anyType.getKind()) {
-                                case USER:
-                                    uFailDelete.add(provResult);
-                                    break;
-
-                                case GROUP:
-                                    gFailDelete.add(provResult);
-                                    break;
-
-                                case ANY_OBJECT:
-                                default:
-                                    aFailDelete.add(provResult);
-                            }
-                            break;
-
-                        default:
-                    }
-                    break;
-
-                case IGNORE:
-                    switch (anyType.getKind()) {
-                        case USER:
-                            uIgnore.add(provResult);
-                            break;
-
-                        case GROUP:
-                            gIgnore.add(provResult);
-                            break;
-
-                        case ANY_OBJECT:
-                        default:
-                            aIgnore.add(provResult);
-                    }
-                    break;
-
-                default:
-            }
-        }
-
-        // Summary, also to be included for FAILURE and ALL, so create it anyway.
-        report.append("Users ").
-                append("[created/failures]: ").append(uSuccCreate.size()).append('/').append(uFailCreate.size()).
-                append(' ').
-                append("[updated/failures]: ").append(uSuccUpdate.size()).append('/').append(uFailUpdate.size()).
-                append(' ').
-                append("[deleted/failures]: ").append(uSuccDelete.size()).append('/').append(uFailDelete.size()).
-                append(' ').
-                append("[no operation/ignored]: ").append(uSuccNone.size()).append('/').append(uIgnore.size()).
-                append('\n');
-        report.append("Groups ").
-                append("[created/failures]: ").append(gSuccCreate.size()).append('/').append(gFailCreate.size()).
-                append(' ').
-                append("[updated/failures]: ").append(gSuccUpdate.size()).append('/').append(gFailUpdate.size()).
-                append(' ').
-                append("[deleted/failures]: ").append(gSuccDelete.size()).append('/').append(gFailDelete.size()).
-                append(' ').
-                append("[no operation/ignored]: ").append(gSuccNone.size()).append('/').append(gIgnore.size()).
-                append('\n');
-        report.append("Any objects ").
-                append("[created/failures]: ").append(aSuccCreate.size()).append('/').append(aFailCreate.size()).
-                append(' ').
-                append("[updated/failures]: ").append(aSuccUpdate.size()).append('/').append(aFailUpdate.size()).
-                append(' ').
-                append("[deleted/failures]: ").append(aSuccDelete.size()).append('/').append(aFailDelete.size()).
-                append(' ').
-                append("[no operation/ignored]: ").append(aSuccNone.size()).append('/').append(aIgnore.size());
-
-        // Failures
-        if (syncTraceLevel == TraceLevel.FAILURES || syncTraceLevel == TraceLevel.ALL) {
-            if (!uFailCreate.isEmpty()) {
-                report.append("\n\nUsers failed to create: ");
-                report.append(ProvisioningResult.produceReport(uFailCreate, syncTraceLevel));
-            }
-            if (!uFailUpdate.isEmpty()) {
-                report.append("\nUsers failed to update: ");
-                report.append(ProvisioningResult.produceReport(uFailUpdate, syncTraceLevel));
-            }
-            if (!uFailDelete.isEmpty()) {
-                report.append("\nUsers failed to delete: ");
-                report.append(ProvisioningResult.produceReport(uFailDelete, syncTraceLevel));
-            }
-
-            if (!gFailCreate.isEmpty()) {
-                report.append("\n\nGroups failed to create: ");
-                report.append(ProvisioningResult.produceReport(gFailCreate, syncTraceLevel));
-            }
-            if (!gFailUpdate.isEmpty()) {
-                report.append("\nGroups failed to update: ");
-                report.append(ProvisioningResult.produceReport(gFailUpdate, syncTraceLevel));
-            }
-            if (!gFailDelete.isEmpty()) {
-                report.append("\nGroups failed to delete: ");
-                report.append(ProvisioningResult.produceReport(gFailDelete, syncTraceLevel));
-            }
-
-            if (!aFailCreate.isEmpty()) {
-                report.append("\nAny objects failed to create: ");
-                report.append(ProvisioningResult.produceReport(aFailCreate, syncTraceLevel));
-            }
-            if (!aFailUpdate.isEmpty()) {
-                report.append("\nAny objects failed to update: ");
-                report.append(ProvisioningResult.produceReport(aFailUpdate, syncTraceLevel));
-            }
-            if (!aFailDelete.isEmpty()) {
-                report.append("\nAny objects failed to delete: ");
-                report.append(ProvisioningResult.produceReport(aFailDelete, syncTraceLevel));
-            }
-        }
-
-        // Succeeded, only if on 'ALL' level
-        if (syncTraceLevel == TraceLevel.ALL) {
-            report.append("\n\nUsers created:\n").
-                    append(ProvisioningResult.produceReport(uSuccCreate, syncTraceLevel)).
-                    append("\nUsers updated:\n").
-                    append(ProvisioningResult.produceReport(uSuccUpdate, syncTraceLevel)).
-                    append("\nUsers deleted:\n").
-                    append(ProvisioningResult.produceReport(uSuccDelete, syncTraceLevel)).
-                    append("\nUsers no operation:\n").
-                    append(ProvisioningResult.produceReport(uSuccNone, syncTraceLevel)).
-                    append("\nUsers ignored:\n").
-                    append(ProvisioningResult.produceReport(uIgnore, syncTraceLevel));
-            report.append("\n\nGroups created:\n").
-                    append(ProvisioningResult.produceReport(gSuccCreate, syncTraceLevel)).
-                    append("\nGroups updated:\n").
-                    append(ProvisioningResult.produceReport(gSuccUpdate, syncTraceLevel)).
-                    append("\nGroups deleted:\n").
-                    append(ProvisioningResult.produceReport(gSuccDelete, syncTraceLevel)).
-                    append("\nGroups no operation:\n").
-                    append(ProvisioningResult.produceReport(gSuccNone, syncTraceLevel)).
-                    append("\nGroups ignored:\n").
-                    append(ProvisioningResult.produceReport(gSuccNone, syncTraceLevel));
-            report.append("\n\nAny objects created:\n").
-                    append(ProvisioningResult.produceReport(aSuccCreate, syncTraceLevel)).
-                    append("\nAny objects updated:\n").
-                    append(ProvisioningResult.produceReport(aSuccUpdate, syncTraceLevel)).
-                    append("\nAny objects deleted:\n").
-                    append(ProvisioningResult.produceReport(aSuccDelete, syncTraceLevel)).
-                    append("\nAny objects no operation:\n").
-                    append(ProvisioningResult.produceReport(aSuccNone, syncTraceLevel)).
-                    append("\nAny objects ignored:\n").
-                    append(ProvisioningResult.produceReport(aSuccNone, syncTraceLevel));
-        }
-
-        return report.toString();
-    }
-
-    @Override
-    protected String doExecute(final boolean dryRun) throws JobExecutionException {
-        // PRE: grant all authorities (i.e. setup the SecurityContextHolder)
-        List<GrantedAuthority> authorities = CollectionUtils.collect(Entitlement.values(),
-                new Transformer<String, GrantedAuthority>() {
-
-                    @Override
-                    public GrantedAuthority transform(final String entitlement) {
-                        return new SyncopeGrantedAuthority(entitlement, SyncopeConstants.ROOT_REALM);
-                    }
-                }, new ArrayList<GrantedAuthority>());
-
-        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
-                new User(adminUser, "FAKE_PASSWORD", authorities), "FAKE_PASSWORD", authorities);
-        auth.setDetails(new SyncopeAuthenticationDetails(taskDAO.getDomain(task)));
-        SecurityContextHolder.getContext().setAuthentication(auth);
-
-        try {
-            Class<T> clazz = getTaskClassReference();
-            if (!clazz.isAssignableFrom(task.getClass())) {
-                throw new JobExecutionException("Task " + taskId + " isn't a SyncTask");
-            }
-
-            T provisioningTask = clazz.cast(task);
-
-            Connector connector;
-            try {
-                connector = connFactory.getConnector(provisioningTask.getResource());
-            } catch (Exception e) {
-                String msg = String.format("Connector instance bean for resource %s and connInstance %s not found",
-                        provisioningTask.getResource(), provisioningTask.getResource().getConnector());
-                throw new JobExecutionException(msg, e);
-            }
-
-            boolean noMapping = true;
-            for (Provision provision : provisioningTask.getResource().getProvisions()) {
-                Mapping mapping = provision.getMapping();
-                if (mapping != null) {
-                    noMapping = false;
-                    if (mapping.getConnObjectKeyItem() == null) {
-                        throw new JobExecutionException(
-                                "Invalid ConnObjectKey mapping for provision " + provision);
-                    }
-                }
-            }
-            if (noMapping) {
-                return "No mapping configured for both users and groups: aborting...";
-            }
-
-            return executeWithSecurityContext(
-                    provisioningTask,
-                    connector,
-                    dryRun);
-        } catch (Throwable t) {
-            LOG.error("While executing provisioning job {}", getClass().getName(), t);
-            throw t;
-        } finally {
-            // POST: clean up the SecurityContextHolder
-            SecurityContextHolder.clearContext();
-        }
-    }
-
-    protected abstract String executeWithSecurityContext(
-            final T task,
-            final Connector connector,
-            final boolean dryRun) throws JobExecutionException;
-
-    @Override
-    protected boolean hasToBeRegistered(final TaskExec execution) {
-        final ProvisioningTask provTask = (ProvisioningTask) task;
-
-        // True if either failed and failures have to be registered, or if ALL has to be registered.
-        return (Status.valueOf(execution.getStatus()) == Status.FAILURE
-                && provTask.getResource().getSyncTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal())
-                || provTask.getResource().getSyncTraceLevel().ordinal() >= TraceLevel.SUMMARY.ordinal();
-    }
-
-    @SuppressWarnings("unchecked")
-    private Class<T> getTaskClassReference() {
-        return (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractProvisioningJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractProvisioningJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractProvisioningJobDelegate.java
new file mode 100644
index 0000000..0c8deb2
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractProvisioningJobDelegate.java
@@ -0,0 +1,434 @@
+/*
+ * 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.sync;
+
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Resource;
+import org.apache.syncope.common.lib.types.TraceLevel;
+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.PolicyDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask;
+import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.ConnectorFactory;
+import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult;
+import org.apache.syncope.core.provisioning.java.job.AbstractSchedTaskJobDelegate;
+import org.apache.syncope.core.provisioning.java.job.TaskJob;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public abstract class AbstractProvisioningJobDelegate<T extends ProvisioningTask>
+        extends AbstractSchedTaskJobDelegate {
+
+    @Resource(name = "adminUser")
+    protected String adminUser;
+
+    /**
+     * ConnInstance loader.
+     */
+    @Autowired
+    protected ConnectorFactory connFactory;
+
+    @Autowired
+    protected AnyTypeDAO anyTypeDAO;
+
+    /**
+     * Resource DAO.
+     */
+    @Autowired
+    protected ExternalResourceDAO resourceDAO;
+
+    /**
+     * Policy DAO.
+     */
+    @Autowired
+    protected PolicyDAO policyDAO;
+
+    /**
+     * Create a textual report of the synchronization, based on the trace level.
+     *
+     * @param provResults Sync results
+     * @param syncTraceLevel Sync trace level
+     * @param dryRun dry run?
+     * @return report as string
+     */
+    protected String createReport(final Collection<ProvisioningResult> provResults, final TraceLevel syncTraceLevel,
+            final boolean dryRun) {
+
+        if (syncTraceLevel == TraceLevel.NONE) {
+            return null;
+        }
+
+        StringBuilder report = new StringBuilder();
+
+        if (dryRun) {
+            report.append("==>Dry run only, no modifications were made<==\n\n");
+        }
+
+        List<ProvisioningResult> uSuccCreate = new ArrayList<>();
+        List<ProvisioningResult> uFailCreate = new ArrayList<>();
+        List<ProvisioningResult> uSuccUpdate = new ArrayList<>();
+        List<ProvisioningResult> uFailUpdate = new ArrayList<>();
+        List<ProvisioningResult> uSuccDelete = new ArrayList<>();
+        List<ProvisioningResult> uFailDelete = new ArrayList<>();
+        List<ProvisioningResult> uSuccNone = new ArrayList<>();
+        List<ProvisioningResult> uIgnore = new ArrayList<>();
+        List<ProvisioningResult> gSuccCreate = new ArrayList<>();
+        List<ProvisioningResult> gFailCreate = new ArrayList<>();
+        List<ProvisioningResult> gSuccUpdate = new ArrayList<>();
+        List<ProvisioningResult> gFailUpdate = new ArrayList<>();
+        List<ProvisioningResult> gSuccDelete = new ArrayList<>();
+        List<ProvisioningResult> gFailDelete = new ArrayList<>();
+        List<ProvisioningResult> gSuccNone = new ArrayList<>();
+        List<ProvisioningResult> gIgnore = new ArrayList<>();
+        List<ProvisioningResult> aSuccCreate = new ArrayList<>();
+        List<ProvisioningResult> aFailCreate = new ArrayList<>();
+        List<ProvisioningResult> aSuccUpdate = new ArrayList<>();
+        List<ProvisioningResult> aFailUpdate = new ArrayList<>();
+        List<ProvisioningResult> aSuccDelete = new ArrayList<>();
+        List<ProvisioningResult> aFailDelete = new ArrayList<>();
+        List<ProvisioningResult> aSuccNone = new ArrayList<>();
+        List<ProvisioningResult> aIgnore = new ArrayList<>();
+
+        for (ProvisioningResult provResult : provResults) {
+            AnyType anyType = anyTypeDAO.find(provResult.getAnyType());
+
+            switch (provResult.getStatus()) {
+                case SUCCESS:
+                    switch (provResult.getOperation()) {
+                        case CREATE:
+                            switch (anyType.getKind()) {
+                                case USER:
+                                    uSuccCreate.add(provResult);
+                                    break;
+
+                                case GROUP:
+                                    gSuccCreate.add(provResult);
+                                    break;
+
+                                case ANY_OBJECT:
+                                default:
+                                    aSuccCreate.add(provResult);
+                            }
+                            break;
+
+                        case UPDATE:
+                            switch (anyType.getKind()) {
+                                case USER:
+                                    uSuccUpdate.add(provResult);
+                                    break;
+
+                                case GROUP:
+                                    gSuccUpdate.add(provResult);
+                                    break;
+
+                                case ANY_OBJECT:
+                                default:
+                                    aSuccUpdate.add(provResult);
+                            }
+                            break;
+
+                        case DELETE:
+                            switch (anyType.getKind()) {
+                                case USER:
+                                    uSuccDelete.add(provResult);
+                                    break;
+
+                                case GROUP:
+                                    gSuccDelete.add(provResult);
+                                    break;
+
+                                case ANY_OBJECT:
+                                default:
+                                    aSuccDelete.add(provResult);
+                            }
+                            break;
+
+                        case NONE:
+                            switch (anyType.getKind()) {
+                                case USER:
+                                    uSuccNone.add(provResult);
+                                    break;
+
+                                case GROUP:
+                                    gSuccNone.add(provResult);
+                                    break;
+
+                                case ANY_OBJECT:
+                                default:
+                                    aSuccNone.add(provResult);
+                            }
+                            break;
+
+                        default:
+                    }
+                    break;
+
+                case FAILURE:
+                    switch (provResult.getOperation()) {
+                        case CREATE:
+                            switch (anyType.getKind()) {
+                                case USER:
+                                    uFailCreate.add(provResult);
+                                    break;
+
+                                case GROUP:
+                                    gFailCreate.add(provResult);
+                                    break;
+
+                                case ANY_OBJECT:
+                                default:
+                                    aFailCreate.add(provResult);
+                            }
+                            break;
+
+                        case UPDATE:
+                            switch (anyType.getKind()) {
+                                case USER:
+                                    uFailUpdate.add(provResult);
+                                    break;
+
+                                case GROUP:
+                                    gFailUpdate.add(provResult);
+                                    break;
+
+                                case ANY_OBJECT:
+                                default:
+                                    aFailUpdate.add(provResult);
+                            }
+                            break;
+
+                        case DELETE:
+                            switch (anyType.getKind()) {
+                                case USER:
+                                    uFailDelete.add(provResult);
+                                    break;
+
+                                case GROUP:
+                                    gFailDelete.add(provResult);
+                                    break;
+
+                                case ANY_OBJECT:
+                                default:
+                                    aFailDelete.add(provResult);
+                            }
+                            break;
+
+                        default:
+                    }
+                    break;
+
+                case IGNORE:
+                    switch (anyType.getKind()) {
+                        case USER:
+                            uIgnore.add(provResult);
+                            break;
+
+                        case GROUP:
+                            gIgnore.add(provResult);
+                            break;
+
+                        case ANY_OBJECT:
+                        default:
+                            aIgnore.add(provResult);
+                    }
+                    break;
+
+                default:
+            }
+        }
+
+        // Summary, also to be included for FAILURE and ALL, so create it anyway.
+        report.append("Users ").
+                append("[created/failures]: ").append(uSuccCreate.size()).append('/').append(uFailCreate.size()).
+                append(' ').
+                append("[updated/failures]: ").append(uSuccUpdate.size()).append('/').append(uFailUpdate.size()).
+                append(' ').
+                append("[deleted/failures]: ").append(uSuccDelete.size()).append('/').append(uFailDelete.size()).
+                append(' ').
+                append("[no operation/ignored]: ").append(uSuccNone.size()).append('/').append(uIgnore.size()).
+                append('\n');
+        report.append("Groups ").
+                append("[created/failures]: ").append(gSuccCreate.size()).append('/').append(gFailCreate.size()).
+                append(' ').
+                append("[updated/failures]: ").append(gSuccUpdate.size()).append('/').append(gFailUpdate.size()).
+                append(' ').
+                append("[deleted/failures]: ").append(gSuccDelete.size()).append('/').append(gFailDelete.size()).
+                append(' ').
+                append("[no operation/ignored]: ").append(gSuccNone.size()).append('/').append(gIgnore.size()).
+                append('\n');
+        report.append("Any objects ").
+                append("[created/failures]: ").append(aSuccCreate.size()).append('/').append(aFailCreate.size()).
+                append(' ').
+                append("[updated/failures]: ").append(aSuccUpdate.size()).append('/').append(aFailUpdate.size()).
+                append(' ').
+                append("[deleted/failures]: ").append(aSuccDelete.size()).append('/').append(aFailDelete.size()).
+                append(' ').
+                append("[no operation/ignored]: ").append(aSuccNone.size()).append('/').append(aIgnore.size());
+
+        // Failures
+        if (syncTraceLevel == TraceLevel.FAILURES || syncTraceLevel == TraceLevel.ALL) {
+            if (!uFailCreate.isEmpty()) {
+                report.append("\n\nUsers failed to create: ");
+                report.append(ProvisioningResult.produceReport(uFailCreate, syncTraceLevel));
+            }
+            if (!uFailUpdate.isEmpty()) {
+                report.append("\nUsers failed to update: ");
+                report.append(ProvisioningResult.produceReport(uFailUpdate, syncTraceLevel));
+            }
+            if (!uFailDelete.isEmpty()) {
+                report.append("\nUsers failed to delete: ");
+                report.append(ProvisioningResult.produceReport(uFailDelete, syncTraceLevel));
+            }
+
+            if (!gFailCreate.isEmpty()) {
+                report.append("\n\nGroups failed to create: ");
+                report.append(ProvisioningResult.produceReport(gFailCreate, syncTraceLevel));
+            }
+            if (!gFailUpdate.isEmpty()) {
+                report.append("\nGroups failed to update: ");
+                report.append(ProvisioningResult.produceReport(gFailUpdate, syncTraceLevel));
+            }
+            if (!gFailDelete.isEmpty()) {
+                report.append("\nGroups failed to delete: ");
+                report.append(ProvisioningResult.produceReport(gFailDelete, syncTraceLevel));
+            }
+
+            if (!aFailCreate.isEmpty()) {
+                report.append("\nAny objects failed to create: ");
+                report.append(ProvisioningResult.produceReport(aFailCreate, syncTraceLevel));
+            }
+            if (!aFailUpdate.isEmpty()) {
+                report.append("\nAny objects failed to update: ");
+                report.append(ProvisioningResult.produceReport(aFailUpdate, syncTraceLevel));
+            }
+            if (!aFailDelete.isEmpty()) {
+                report.append("\nAny objects failed to delete: ");
+                report.append(ProvisioningResult.produceReport(aFailDelete, syncTraceLevel));
+            }
+        }
+
+        // Succeeded, only if on 'ALL' level
+        if (syncTraceLevel == TraceLevel.ALL) {
+            report.append("\n\nUsers created:\n").
+                    append(ProvisioningResult.produceReport(uSuccCreate, syncTraceLevel)).
+                    append("\nUsers updated:\n").
+                    append(ProvisioningResult.produceReport(uSuccUpdate, syncTraceLevel)).
+                    append("\nUsers deleted:\n").
+                    append(ProvisioningResult.produceReport(uSuccDelete, syncTraceLevel)).
+                    append("\nUsers no operation:\n").
+                    append(ProvisioningResult.produceReport(uSuccNone, syncTraceLevel)).
+                    append("\nUsers ignored:\n").
+                    append(ProvisioningResult.produceReport(uIgnore, syncTraceLevel));
+            report.append("\n\nGroups created:\n").
+                    append(ProvisioningResult.produceReport(gSuccCreate, syncTraceLevel)).
+                    append("\nGroups updated:\n").
+                    append(ProvisioningResult.produceReport(gSuccUpdate, syncTraceLevel)).
+                    append("\nGroups deleted:\n").
+                    append(ProvisioningResult.produceReport(gSuccDelete, syncTraceLevel)).
+                    append("\nGroups no operation:\n").
+                    append(ProvisioningResult.produceReport(gSuccNone, syncTraceLevel)).
+                    append("\nGroups ignored:\n").
+                    append(ProvisioningResult.produceReport(gSuccNone, syncTraceLevel));
+            report.append("\n\nAny objects created:\n").
+                    append(ProvisioningResult.produceReport(aSuccCreate, syncTraceLevel)).
+                    append("\nAny objects updated:\n").
+                    append(ProvisioningResult.produceReport(aSuccUpdate, syncTraceLevel)).
+                    append("\nAny objects deleted:\n").
+                    append(ProvisioningResult.produceReport(aSuccDelete, syncTraceLevel)).
+                    append("\nAny objects no operation:\n").
+                    append(ProvisioningResult.produceReport(aSuccNone, syncTraceLevel)).
+                    append("\nAny objects ignored:\n").
+                    append(ProvisioningResult.produceReport(aSuccNone, syncTraceLevel));
+        }
+
+        return report.toString();
+    }
+
+    @Override
+    protected String doExecute(final boolean dryRun) throws JobExecutionException {
+        try {
+            Class<T> clazz = getTaskClassReference();
+            if (!clazz.isAssignableFrom(task.getClass())) {
+                throw new JobExecutionException("Task " + task.getKey() + " isn't a ProvisioningTask");
+            }
+
+            T provisioningTask = clazz.cast(task);
+
+            Connector connector;
+            try {
+                connector = connFactory.getConnector(provisioningTask.getResource());
+            } catch (Exception e) {
+                String msg = String.format("Connector instance bean for resource %s and connInstance %s not found",
+                        provisioningTask.getResource(), provisioningTask.getResource().getConnector());
+                throw new JobExecutionException(msg, e);
+            }
+
+            boolean noMapping = true;
+            for (Provision provision : provisioningTask.getResource().getProvisions()) {
+                Mapping mapping = provision.getMapping();
+                if (mapping != null) {
+                    noMapping = false;
+                    if (mapping.getConnObjectKeyItem() == null) {
+                        throw new JobExecutionException(
+                                "Invalid ConnObjectKey mapping for provision " + provision);
+                    }
+                }
+            }
+            if (noMapping) {
+                return "No mapping configured for both users and groups: aborting...";
+            }
+
+            return doExecuteProvisioning(
+                    provisioningTask,
+                    connector,
+                    dryRun);
+        } catch (Throwable t) {
+            LOG.error("While executing provisioning job {}", getClass().getName(), t);
+            throw t;
+        }
+    }
+
+    protected abstract String doExecuteProvisioning(
+            final T task,
+            final Connector connector,
+            final boolean dryRun) throws JobExecutionException;
+
+    @Override
+    protected boolean hasToBeRegistered(final TaskExec execution) {
+        final ProvisioningTask provTask = (ProvisioningTask) task;
+
+        // True if either failed and failures have to be registered, or if ALL has to be registered.
+        return (TaskJob.Status.valueOf(execution.getStatus()) == TaskJob.Status.FAILURE
+                && provTask.getResource().getSyncTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal())
+                || provTask.getResource().getSyncTraceLevel().ordinal() >= TraceLevel.SUMMARY.ordinal();
+    }
+
+    @SuppressWarnings("unchecked")
+    private Class<T> getTaskClassReference() {
+        return (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
index fd5a482..6be2167 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractPushResultHandler.java
@@ -50,6 +50,7 @@ import org.apache.syncope.core.provisioning.api.sync.SyncopePushResultHandler;
 import org.identityconnectors.framework.common.objects.ConnectorObject;
 import org.identityconnectors.framework.common.objects.ObjectClass;
 import org.quartz.JobExecutionException;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHandler<PushTask, PushActions>
@@ -71,7 +72,7 @@ public abstract class AbstractPushResultHandler extends AbstractSyncopeResultHan
 
     protected abstract ConnectorObject getRemoteObject(String connObjectKey, ObjectClass objectClass);
 
-    @Transactional
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
     @Override
     public boolean handle(final long anyKey) {
         Any<?, ?, ?> any = null;

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
index 6d8986a..b0b5a58 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncResultHandler.java
@@ -44,7 +44,9 @@ import org.identityconnectors.framework.common.objects.SyncDelta;
 import org.identityconnectors.framework.common.objects.SyncDeltaType;
 import org.quartz.JobExecutionException;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
 
+@Transactional(rollbackFor = Throwable.class)
 public abstract class AbstractSyncResultHandler extends AbstractSyncopeResultHandler<SyncTask, SyncActions>
         implements SyncopeSyncResultHandler {
 
@@ -614,9 +616,7 @@ public abstract class AbstractSyncResultHandler extends AbstractSyncopeResultHan
      * @param provision provisioning info
      * @throws JobExecutionException in case of synchronization failure.
      */
-    protected void doHandle(final SyncDelta delta, final Provision provision)
-            throws JobExecutionException {
-
+    protected void doHandle(final SyncDelta delta, final Provision provision) throws JobExecutionException {
         AnyUtils anyUtils = getAnyUtils();
 
         LOG.debug("Process {} for {} as {}",

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java
index cf08d8d..49a38d3 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/AbstractSyncopeResultHandler.java
@@ -28,7 +28,6 @@ import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
 import org.apache.syncope.core.provisioning.api.data.UserDataBinder;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
-import org.apache.syncope.core.provisioning.api.sync.ProvisioningActions;
 import org.apache.syncope.core.provisioning.api.sync.ProvisioningProfile;
 import org.apache.syncope.core.provisioning.api.sync.SyncopeResultHandler;
 import org.apache.syncope.core.misc.AuditManager;
@@ -39,6 +38,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
 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.sync.ProvisioningActions;
 import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
 import org.apache.syncope.core.workflow.api.GroupWorkflowAdapter;
 import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java
new file mode 100644
index 0000000..ff6ff21
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobDelegate.java
@@ -0,0 +1,192 @@
+/*
+ * 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.sync;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.misc.search.SearchCondConverter;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.dao.AnyDAO;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.persistence.api.entity.task.PushTask;
+import org.apache.syncope.core.provisioning.api.Connector;
+import org.apache.syncope.core.provisioning.api.sync.AnyObjectPushResultHandler;
+import org.apache.syncope.core.provisioning.api.sync.GroupPushResultHandler;
+import org.apache.syncope.core.provisioning.api.sync.ProvisioningProfile;
+import org.apache.syncope.core.provisioning.api.sync.PushActions;
+import org.apache.syncope.core.provisioning.api.sync.SyncopePushResultHandler;
+import org.apache.syncope.core.provisioning.api.sync.UserPushResultHandler;
+import org.quartz.JobExecutionException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+
+public class PushJobDelegate extends AbstractProvisioningJobDelegate<PushTask> {
+
+    private static final int PAGE_SIZE = 1000;
+
+    /**
+     * User DAO.
+     */
+    @Autowired
+    private UserDAO userDAO;
+
+    /**
+     * Search DAO.
+     */
+    @Autowired
+    private AnySearchDAO searchDAO;
+
+    /**
+     * Group DAO.
+     */
+    @Autowired
+    private GroupDAO groupDAO;
+
+    @Autowired
+    private AnyObjectDAO anyObjectDAO;
+
+    private AnyDAO<?> getAnyDAO(final AnyTypeKind anyTypeKind) {
+        AnyDAO<?> result;
+        switch (anyTypeKind) {
+            case USER:
+                result = userDAO;
+                break;
+
+            case GROUP:
+                result = groupDAO;
+                break;
+
+            case ANY_OBJECT:
+            default:
+                result = anyObjectDAO;
+        }
+
+        return result;
+    }
+
+    @Override
+    protected String doExecuteProvisioning(
+            final PushTask pushTask,
+            final Connector connector,
+            final boolean dryRun) throws JobExecutionException {
+
+        LOG.debug("Executing push on {}", pushTask.getResource());
+
+        List<PushActions> actions = new ArrayList<>();
+        for (String className : pushTask.getActionsClassNames()) {
+            try {
+                Class<?> actionsClass = Class.forName(className);
+
+                PushActions syncActions = (PushActions) ApplicationContextProvider.getBeanFactory().
+                        createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
+                actions.add(syncActions);
+            } catch (Exception e) {
+                LOG.info("Class '{}' not found", className, e);
+            }
+        }
+
+        ProvisioningProfile<PushTask, PushActions> profile = new ProvisioningProfile<>(connector, pushTask);
+        profile.setDryRun(dryRun);
+        profile.setResAct(null);
+
+        AnyObjectPushResultHandler ahandler =
+                (AnyObjectPushResultHandler) ApplicationContextProvider.getBeanFactory().
+                createBean(AnyObjectPushResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+        ahandler.setProfile(profile);
+
+        UserPushResultHandler uhandler =
+                (UserPushResultHandler) ApplicationContextProvider.getBeanFactory().
+                createBean(UserPushResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+        uhandler.setProfile(profile);
+
+        GroupPushResultHandler ghandler =
+                (GroupPushResultHandler) ApplicationContextProvider.getBeanFactory().
+                createBean(GroupPushResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+        ghandler.setProfile(profile);
+
+        if (!profile.isDryRun()) {
+            for (PushActions action : actions) {
+                action.beforeAll(profile);
+            }
+        }
+
+        for (Provision provision : pushTask.getResource().getProvisions()) {
+            if (provision.getMapping() != null) {
+                AnyDAO<?> anyDAO = getAnyDAO(provision.getAnyType().getKind());
+                String filter = pushTask.getFilter(provision.getAnyType()) == null
+                        ? null
+                        : pushTask.getFilter(provision.getAnyType()).get();
+
+                int count = anyDAO.count(SyncopeConstants.FULL_ADMIN_REALMS);
+                for (int page = 1; page <= (count / PAGE_SIZE) + 1; page++) {
+                    List<? extends Any<?, ?, ?>> localAnys = StringUtils.isBlank(filter)
+                            ? anyDAO.findAll(SyncopeConstants.FULL_ADMIN_REALMS, page, PAGE_SIZE)
+                            : searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
+                                    SearchCondConverter.convert(filter),
+                                    Collections.<OrderByClause>emptyList(), provision.getAnyType().getKind());
+
+                    for (Any<?, ?, ?> any : localAnys) {
+                        SyncopePushResultHandler handler;
+                        switch (provision.getAnyType().getKind()) {
+                            case USER:
+                                handler = uhandler;
+                                break;
+
+                            case GROUP:
+                                handler = ghandler;
+                                break;
+
+                            case ANY_OBJECT:
+                            default:
+                                handler = ahandler;
+                        }
+
+                        try {
+                            handler.handle(any.getKey());
+                        } catch (Exception e) {
+                            LOG.warn("Failure pushing '{}' on '{}'", any, pushTask.getResource(), e);
+                            throw new JobExecutionException(
+                                    "While pushing " + any + " on " + pushTask.getResource(), e);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (!profile.isDryRun()) {
+            for (PushActions action : actions) {
+                action.afterAll(profile);
+            }
+        }
+
+        String result = createReport(profile.getResults(), pushTask.getResource().getSyncTraceLevel(), dryRun);
+        LOG.debug("Sync result: {}", result);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/6dfedd8f/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobImpl.java
deleted file mode 100644
index b658bc4..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/sync/PushJobImpl.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.provisioning.java.sync;
-
-import java.util.Collections;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.core.persistence.api.dao.GroupDAO;
-import org.apache.syncope.core.persistence.api.dao.UserDAO;
-import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
-import org.apache.syncope.core.persistence.api.entity.task.PushTask;
-import org.apache.syncope.core.provisioning.api.Connector;
-import org.apache.syncope.core.provisioning.api.sync.ProvisioningProfile;
-import org.apache.syncope.core.provisioning.api.sync.PushActions;
-import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
-import org.apache.syncope.core.misc.search.SearchCondConverter;
-import org.apache.syncope.core.persistence.api.dao.AnyDAO;
-import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
-import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.resource.Provision;
-import org.apache.syncope.core.provisioning.api.job.PushJob;
-import org.apache.syncope.core.provisioning.api.sync.AnyObjectPushResultHandler;
-import org.apache.syncope.core.provisioning.api.sync.GroupPushResultHandler;
-import org.apache.syncope.core.provisioning.api.sync.SyncopePushResultHandler;
-import org.apache.syncope.core.provisioning.api.sync.UserPushResultHandler;
-import org.quartz.JobExecutionException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
-
-/**
- * Job for executing synchronization (towards external resource) tasks.
- *
- * @see AbstractProvisioningJob
- * @see PushTask
- * @see PushActions
- */
-public class PushJobImpl extends AbstractProvisioningJob<PushTask, PushActions> implements PushJob {
-
-    private static final int PAGE_SIZE = 1000;
-
-    /**
-     * User DAO.
-     */
-    @Autowired
-    private UserDAO userDAO;
-
-    /**
-     * Search DAO.
-     */
-    @Autowired
-    private AnySearchDAO searchDAO;
-
-    /**
-     * Group DAO.
-     */
-    @Autowired
-    private GroupDAO groupDAO;
-
-    @Autowired
-    private AnyObjectDAO anyObjectDAO;
-
-    private AnyDAO<?> getAnyDAO(final AnyTypeKind anyTypeKind) {
-        AnyDAO<?> result;
-        switch (anyTypeKind) {
-            case USER:
-                result = userDAO;
-                break;
-
-            case GROUP:
-                result = groupDAO;
-                break;
-
-            case ANY_OBJECT:
-            default:
-                result = anyObjectDAO;
-        }
-
-        return result;
-    }
-
-    @Override
-    protected String executeWithSecurityContext(
-            final PushTask pushTask,
-            final Connector connector,
-            final boolean dryRun) throws JobExecutionException {
-
-        LOG.debug("Executing push on {}", pushTask.getResource());
-
-        ProvisioningProfile<PushTask, PushActions> profile = new ProvisioningProfile<>(connector, pushTask);
-        if (actions != null) {
-            profile.getActions().addAll(actions);
-        }
-        profile.setDryRun(dryRun);
-        profile.setResAct(null);
-
-        AnyObjectPushResultHandler ahandler =
-                (AnyObjectPushResultHandler) ApplicationContextProvider.getApplicationContext().getBeanFactory().
-                createBean(AnyObjectPushResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
-        ahandler.setProfile(profile);
-
-        UserPushResultHandler uhandler =
-                (UserPushResultHandler) ApplicationContextProvider.getApplicationContext().getBeanFactory().
-                createBean(UserPushResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
-        uhandler.setProfile(profile);
-
-        GroupPushResultHandler ghandler =
-                (GroupPushResultHandler) ApplicationContextProvider.getApplicationContext().getBeanFactory().
-                createBean(GroupPushResultHandlerImpl.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
-        ghandler.setProfile(profile);
-
-        if (actions != null && !profile.isDryRun()) {
-            for (PushActions action : actions) {
-                action.beforeAll(profile);
-            }
-        }
-
-        for (Provision provision : pushTask.getResource().getProvisions()) {
-            if (provision.getMapping() != null) {
-                AnyDAO<?> anyDAO = getAnyDAO(provision.getAnyType().getKind());
-                String filter = pushTask.getFilter(provision.getAnyType()) == null
-                        ? null
-                        : pushTask.getFilter(provision.getAnyType()).get();
-
-                int count = anyDAO.count(SyncopeConstants.FULL_ADMIN_REALMS);
-                for (int page = 1; page <= (count / PAGE_SIZE) + 1; page++) {
-                    List<? extends Any<?, ?, ?>> localAnys = StringUtils.isBlank(filter)
-                            ? anyDAO.findAll(SyncopeConstants.FULL_ADMIN_REALMS, page, PAGE_SIZE)
-                            : searchDAO.search(SyncopeConstants.FULL_ADMIN_REALMS,
-                                    SearchCondConverter.convert(filter),
-                                    Collections.<OrderByClause>emptyList(), provision.getAnyType().getKind());
-
-                    for (Any<?, ?, ?> any : localAnys) {
-                        SyncopePushResultHandler handler;
-                        switch (provision.getAnyType().getKind()) {
-                            case USER:
-                                handler = uhandler;
-                                break;
-
-                            case GROUP:
-                                handler = ghandler;
-                                break;
-
-                            case ANY_OBJECT:
-                            default:
-                                handler = ahandler;
-                        }
-
-                        try {
-                            handler.handle(any.getKey());
-                        } catch (Exception e) {
-                            LOG.warn("Failure pushing '{}' on '{}'", any, pushTask.getResource(), e);
-                            throw new JobExecutionException(
-                                    "While pushing " + any + " on " + pushTask.getResource(), e);
-                        }
-                    }
-                }
-            }
-        }
-
-        if (actions != null && !profile.isDryRun()) {
-            for (PushActions action : actions) {
-                action.afterAll(profile);
-            }
-        }
-
-        String result = createReport(profile.getResults(), pushTask.getResource().getSyncTraceLevel(), dryRun);
-        LOG.debug("Sync result: {}", result);
-        return result;
-    }
-}


Mime
View raw message