You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/08/02 07:45:17 UTC

[03/15] syncope git commit: [SYNCOPE-652] Still several things to refine, but it starts taking shape

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/provisioning-java/src/test/resources/provisioningTest.xml
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/test/resources/provisioningTest.xml b/core/provisioning-java/src/test/resources/provisioningTest.xml
index b6621c3..54797a5 100644
--- a/core/provisioning-java/src/test/resources/provisioningTest.xml
+++ b/core/provisioning-java/src/test/resources/provisioningTest.xml
@@ -26,6 +26,7 @@ under the License.
     <property name="locations">
       <list>
         <value>classpath:persistence.properties</value>
+        <value>classpath:domains/*.properties</value>
         <value>classpath:security.properties</value>
         <value>classpath:connid.properties</value>
         <value>classpath:mail.properties</value>
@@ -37,10 +38,4 @@ under the License.
     <property name="ignoreUnresolvablePlaceholders" value="true"/>
   </bean>
   
-  <bean id="contentXML" class="org.apache.syncope.core.misc.spring.ResourceWithFallbackLoader">
-    <property name="primary" value="file:${conf.directory}/content.xml"/>
-    <property name="fallback" value="classpath:content.xml"/>
-  </bean>
-  <bean class="org.apache.syncope.core.persistence.jpa.content.XMLContentLoader" init-method="load"/>
-  
 </beans>

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
index 600b6d0..d54dbca 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.core.rest.cxf.service;
 
-import static org.apache.syncope.core.rest.cxf.service.AbstractServiceImpl.LOG;
-
 import java.util.List;
 import javax.ws.rs.core.Response;
 import org.apache.commons.collections4.CollectionUtils;
@@ -34,7 +32,7 @@ import org.apache.syncope.common.lib.to.BulkAction;
 import org.apache.syncope.common.lib.to.BulkActionResult;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.PropagationStatus;
-import org.apache.syncope.common.lib.types.ResourceAssociationActionType;
+import org.apache.syncope.common.lib.types.ResourceAssociationAction;
 import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
 import org.apache.syncope.common.lib.wrap.ResourceKey;
 import org.apache.syncope.common.rest.api.CollectionWrapper;
@@ -129,7 +127,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, MOD extends AnyMod>
     }
 
     @Override
-    public Response bulkDeassociation(
+    public Response deassociate(
             final Long key, final ResourceDeassociationActionType type, final List<ResourceKey> resourceNames) {
 
         TO any = getAnyLogic().read(key);
@@ -174,8 +172,8 @@ public abstract class AbstractAnyService<TO extends AnyTO, MOD extends AnyMod>
     }
 
     @Override
-    public Response bulkAssociation(
-            final Long key, final ResourceAssociationActionType type, final ResourceAssociationMod associationMod) {
+    public Response associate(
+            final Long key, final ResourceAssociationAction type, final ResourceAssociationMod associationMod) {
 
         TO any = getAnyLogic().read(key);
 
@@ -211,7 +209,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, MOD extends AnyMod>
 
         BulkActionResult result = new BulkActionResult();
 
-        if (type == ResourceAssociationActionType.LINK) {
+        if (type == ResourceAssociationAction.LINK) {
             for (ResourceKey resourceName : associationMod.getTargetResources()) {
                 result.getResults().put(resourceName.getElement(),
                         updated.getResources().contains(resourceName.getElement())
@@ -234,7 +232,7 @@ public abstract class AbstractAnyService<TO extends AnyTO, MOD extends AnyMod>
 
         BulkActionResult result = new BulkActionResult();
 
-        switch (bulkAction.getOperation()) {
+        switch (bulkAction.getType()) {
             case DELETE:
                 for (String key : bulkAction.getTargets()) {
                     try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConnectorServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConnectorServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConnectorServiceImpl.java
index 6725bf9..bc43165 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConnectorServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ConnectorServiceImpl.java
@@ -132,7 +132,7 @@ public class ConnectorServiceImpl extends AbstractServiceImpl implements Connect
     public BulkActionResult bulk(final BulkAction bulkAction) {
         BulkActionResult result = new BulkActionResult();
 
-        if (bulkAction.getOperation() == BulkAction.Type.DELETE) {
+        if (bulkAction.getType() == BulkAction.Type.DELETE) {
             for (String key : bulkAction.getTargets()) {
                 try {
                     result.getResults().put(

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
index ae7c426..179e021 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/ResourceServiceImpl.java
@@ -144,7 +144,7 @@ public class ResourceServiceImpl extends AbstractServiceImpl implements Resource
     public BulkActionResult bulk(final BulkAction bulkAction) {
         BulkActionResult result = new BulkActionResult();
 
-        if (bulkAction.getOperation() == BulkAction.Type.DELETE) {
+        if (bulkAction.getType() == BulkAction.Type.DELETE) {
             for (String name : bulkAction.getTargets()) {
                 try {
                     result.getResults().put(logic.delete(name).getKey(), BulkActionResult.Status.SUCCESS);

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java
index 5fb19e2..3acf5c8 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java
@@ -124,7 +124,7 @@ public class TaskServiceImpl extends AbstractServiceImpl implements TaskService
     public BulkActionResult bulk(final BulkAction bulkAction) {
         BulkActionResult result = new BulkActionResult();
 
-        switch (bulkAction.getOperation()) {
+        switch (bulkAction.getType()) {
             case DELETE:
                 for (String key : bulkAction.getTargets()) {
                     try {

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiDefinitionLoader.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiDefinitionLoader.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiDefinitionLoader.java
index 6108b2b..494a03e 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiDefinitionLoader.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiDefinitionLoader.java
@@ -24,15 +24,17 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
+import java.util.Map;
 import javax.annotation.Resource;
 import org.activiti.editor.constants.ModelDataJsonConstants;
-import org.activiti.engine.RepositoryService;
+import org.activiti.engine.ProcessEngine;
 import org.activiti.engine.repository.Model;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.activiti.spring.SpringProcessEngineConfiguration;
 import org.apache.commons.io.IOUtils;
 import org.apache.syncope.core.misc.spring.ResourceWithFallbackLoader;
 import org.apache.syncope.core.persistence.api.SyncopeLoader;
+import org.apache.syncope.core.workflow.activiti.spring.DomainProcessEngine;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -47,13 +49,7 @@ public class ActivitiDefinitionLoader implements SyncopeLoader {
     private ResourceWithFallbackLoader userWorkflowDef;
 
     @Autowired
-    private RepositoryService repositoryService;
-
-    @Autowired
-    private SpringProcessEngineConfiguration conf;
-
-    @Autowired
-    private ActivitiImportUtils importUtils;
+    private DomainProcessEngine dpEngine;
 
     @Override
     public Integer getPriority() {
@@ -62,22 +58,34 @@ public class ActivitiDefinitionLoader implements SyncopeLoader {
 
     @Override
     public void load() {
-        List<ProcessDefinition> processes = repositoryService.createProcessDefinitionQuery().processDefinitionKey(
-                ActivitiUserWorkflowAdapter.WF_PROCESS_ID).list();
-        LOG.debug(ActivitiUserWorkflowAdapter.WF_PROCESS_ID + " Activiti processes in repository: {}", processes);
+        byte[] wfDef = new byte[0];
 
-        // Only loads process definition from file if not found in repository
-        if (processes.isEmpty()) {
-            InputStream wfIn = null;
-            try {
-                wfIn = userWorkflowDef.getResource().getInputStream();
-                repositoryService.createDeployment().addInputStream(ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE,
-                        new ByteArrayInputStream(IOUtils.toByteArray(wfIn))).deploy();
+        InputStream wfIn = null;
+        try {
+            wfIn = userWorkflowDef.getResource().getInputStream();
+            wfDef = IOUtils.toByteArray(wfIn);
+        } catch (IOException e) {
+            LOG.error("While loading " + ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE, e);
+        } finally {
+            IOUtils.closeQuietly(wfIn);
+        }
 
-                ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().processDefinitionKey(
-                        ActivitiUserWorkflowAdapter.WF_PROCESS_ID).latestVersion().singleResult();
+        for (Map.Entry<String, ProcessEngine> entry : dpEngine.getEngines().entrySet()) {
+            List<ProcessDefinition> processes = entry.getValue().getRepositoryService().
+                    createProcessDefinitionQuery().processDefinitionKey(ActivitiUserWorkflowAdapter.WF_PROCESS_ID).
+                    list();
+            LOG.debug(ActivitiUserWorkflowAdapter.WF_PROCESS_ID + " Activiti processes in repository: {}", processes);
 
-                Model model = repositoryService.newModel();
+            // Only loads process definition from file if not found in repository
+            if (processes.isEmpty()) {
+                entry.getValue().getRepositoryService().createDeployment().addInputStream(
+                        ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE, new ByteArrayInputStream(wfDef)).deploy();
+
+                ProcessDefinition procDef = entry.getValue().getRepositoryService().createProcessDefinitionQuery().
+                        processDefinitionKey(ActivitiUserWorkflowAdapter.WF_PROCESS_ID).latestVersion().
+                        singleResult();
+
+                Model model = entry.getValue().getRepositoryService().newModel();
                 ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
                 modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, procDef.getName());
                 modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
@@ -85,19 +93,16 @@ public class ActivitiDefinitionLoader implements SyncopeLoader {
                 model.setMetaInfo(modelObjectNode.toString());
                 model.setName(procDef.getName());
                 model.setDeploymentId(procDef.getDeploymentId());
-                importUtils.fromJSON(procDef, model);
+                ActivitiImportUtils.fromJSON(entry.getValue(), procDef, model);
 
-                LOG.debug("Activiti Workflow definition loaded");
-            } catch (IOException e) {
-                LOG.error("While loading " + ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE, e);
-            } finally {
-                IOUtils.closeQuietly(wfIn);
+                LOG.debug("Activiti Workflow definition loaded for domain {}", entry.getKey());
             }
-        }
 
-        // jump to the next ID block
-        for (int i = 0; i < conf.getIdBlockSize(); i++) {
-            conf.getIdGenerator().getNextId();
+            // jump to the next ID block
+            for (int i = 0; i < entry.getValue().getProcessEngineConfiguration().getIdBlockSize(); i++) {
+                SpringProcessEngineConfiguration.class.cast(entry.getValue().getProcessEngineConfiguration()).
+                        getIdGenerator().getNextId();
+            }
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiImportUtils.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiImportUtils.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiImportUtils.java
index 973584d..5df8ac4 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiImportUtils.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiImportUtils.java
@@ -28,53 +28,50 @@ import org.activiti.bpmn.converter.BpmnXMLConverter;
 import org.activiti.bpmn.model.BpmnModel;
 import org.activiti.editor.language.json.converter.BpmnJsonConverter;
 import org.activiti.engine.ActivitiException;
-import org.activiti.engine.RepositoryService;
+import org.activiti.engine.ProcessEngine;
 import org.activiti.engine.repository.Model;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.apache.commons.io.IOUtils;
 import org.apache.syncope.core.workflow.api.WorkflowException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
 
-@Component
-public class ActivitiImportUtils {
+public final class ActivitiImportUtils {
 
-    @Autowired
-    private RepositoryService repositoryService;
-
-    public void fromXML(final byte[] definition) {
+    public static void fromXML(final ProcessEngine engine, final byte[] definition) {
         try {
-            repositoryService.createDeployment().addInputStream(ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE,
-                    new ByteArrayInputStream(definition)).deploy();
+            engine.getRepositoryService().createDeployment().
+                    addInputStream(ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE,
+                            new ByteArrayInputStream(definition)).deploy();
         } catch (ActivitiException e) {
             throw new WorkflowException("While updating process " + ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE, e);
         }
     }
 
-    public void fromJSON(final byte[] definition, final ProcessDefinition procDef, final Model model) {
+    public static void fromJSON(
+            final ProcessEngine engine, final byte[] definition, final ProcessDefinition procDef, final Model model) {
+
         try {
             model.setVersion(procDef.getVersion());
             model.setDeploymentId(procDef.getDeploymentId());
-            repositoryService.saveModel(model);
+            engine.getRepositoryService().saveModel(model);
 
-            repositoryService.addModelEditorSource(model.getId(), definition);
+            engine.getRepositoryService().addModelEditorSource(model.getId(), definition);
         } catch (Exception e) {
             throw new WorkflowException("While updating process " + ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE, e);
         }
     }
 
-    public void fromJSON(final ProcessDefinition procDef, final Model model) {
+    public static void fromJSON(final ProcessEngine engine, final ProcessDefinition procDef, final Model model) {
         InputStream bpmnStream = null;
         InputStreamReader isr = null;
         XMLStreamReader xtr = null;
         try {
-            bpmnStream = repositoryService.getResourceAsStream(
+            bpmnStream = engine.getRepositoryService().getResourceAsStream(
                     procDef.getDeploymentId(), procDef.getResourceName());
             isr = new InputStreamReader(bpmnStream);
             xtr = XMLInputFactory.newInstance().createXMLStreamReader(isr);
             BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
 
-            fromJSON(new BpmnJsonConverter().convertToJson(bpmnModel).toString().getBytes(), procDef, model);
+            fromJSON(engine, new BpmnJsonConverter().convertToJson(bpmnModel).toString().getBytes(), procDef, model);
         } catch (Exception e) {
             throw new WorkflowException("While updating process " + ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE, e);
         } finally {
@@ -89,4 +86,8 @@ public class ActivitiImportUtils {
             IOUtils.closeQuietly(bpmnStream);
         }
     }
+
+    private ActivitiImportUtils() {
+        // private constructor for static utility class
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
index c124c05..1ce0d97 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
@@ -38,11 +38,7 @@ import org.activiti.bpmn.model.BpmnModel;
 import org.activiti.editor.constants.ModelDataJsonConstants;
 import org.activiti.editor.language.json.converter.BpmnJsonConverter;
 import org.activiti.engine.ActivitiException;
-import org.activiti.engine.FormService;
-import org.activiti.engine.HistoryService;
-import org.activiti.engine.RepositoryService;
-import org.activiti.engine.RuntimeService;
-import org.activiti.engine.TaskService;
+import org.activiti.engine.ProcessEngine;
 import org.activiti.engine.form.FormProperty;
 import org.activiti.engine.form.FormType;
 import org.activiti.engine.form.TaskFormData;
@@ -136,22 +132,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     protected String adminUser;
 
     @Autowired
-    protected RuntimeService runtimeService;
-
-    @Autowired
-    protected TaskService taskService;
-
-    @Autowired
-    protected FormService formService;
-
-    @Autowired
-    protected HistoryService historyService;
-
-    @Autowired
-    protected RepositoryService repositoryService;
-
-    @Autowired
-    protected ActivitiImportUtils importUtils;
+    protected ProcessEngine engine;
 
     @Autowired
     protected UserDataBinder userDataBinder;
@@ -176,7 +157,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     }
 
     protected void updateStatus(final User user) {
-        List<Task> tasks = taskService.createTaskQuery().processInstanceId(user.getWorkflowId()).list();
+        List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(user.getWorkflowId()).list();
         if (tasks.isEmpty() || tasks.size() > 1) {
             LOG.warn("While setting user status: unexpected task number ({})", tasks.size());
         } else {
@@ -187,12 +168,12 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     protected String getFormTask(final User user) {
         String result = null;
 
-        List<Task> tasks = taskService.createTaskQuery().processInstanceId(user.getWorkflowId()).list();
+        List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(user.getWorkflowId()).list();
         if (tasks.isEmpty() || tasks.size() > 1) {
             LOG.warn("While checking if form task: unexpected task number ({})", tasks.size());
         } else {
             try {
-                TaskFormData formData = formService.getTaskFormData(tasks.get(0).getId());
+                TaskFormData formData = engine.getFormService().getTaskFormData(tasks.get(0).getId());
                 if (formData != null && !formData.getFormProperties().isEmpty()) {
                     result = tasks.get(0).getId();
                 }
@@ -207,8 +188,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     protected Set<String> getPerformedTasks(final User user) {
         final Set<String> result = new HashSet<>();
 
-        for (HistoricActivityInstance task
-                : historyService.createHistoricActivityInstanceQuery().executionId(user.getWorkflowId()).list()) {
+        for (HistoricActivityInstance task : engine.getHistoryService().createHistoricActivityInstanceQuery().
+                executionId(user.getWorkflowId()).list()) {
 
             result.add(task.getActivityId());
         }
@@ -223,14 +204,14 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         String formTaskId = getFormTask(user);
         if (formTaskId != null) {
             // SYNCOPE-238: This is needed to simplify the task query in this.getForms()
-            taskService.setVariableLocal(formTaskId, TASK_IS_FORM, Boolean.TRUE);
-            runtimeService.setVariable(user.getWorkflowId(), PROP_BY_RESOURCE, propByRes);
+            engine.getTaskService().setVariableLocal(formTaskId, TASK_IS_FORM, Boolean.TRUE);
+            engine.getRuntimeService().setVariable(user.getWorkflowId(), PROP_BY_RESOURCE, propByRes);
             if (propByRes != null) {
                 propByRes.clear();
             }
 
             if (StringUtils.isNotBlank(password)) {
-                runtimeService.setVariable(user.getWorkflowId(), ENCRYPTED_PWD, encrypt(password));
+                engine.getRuntimeService().setVariable(user.getWorkflowId(), ENCRYPTED_PWD, encrypt(password));
             }
         }
     }
@@ -259,15 +240,15 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
         ProcessInstance processInstance = null;
         try {
-            processInstance = runtimeService.startProcessInstanceByKey(WF_PROCESS_ID, variables);
+            processInstance = engine.getRuntimeService().startProcessInstanceByKey(WF_PROCESS_ID, variables);
         } catch (ActivitiException e) {
             throwException(e, "While starting " + WF_PROCESS_ID + " instance");
         }
 
-        User user = runtimeService.getVariable(processInstance.getProcessInstanceId(), USER, User.class);
+        User user = engine.getRuntimeService().getVariable(processInstance.getProcessInstanceId(), USER, User.class);
 
         Boolean updatedEnabled =
-                runtimeService.getVariable(processInstance.getProcessInstanceId(), ENABLED, Boolean.class);
+                engine.getRuntimeService().getVariable(processInstance.getProcessInstanceId(), ENABLED, Boolean.class);
         if (updatedEnabled != null) {
             user.setSuspended(!updatedEnabled);
         }
@@ -280,8 +261,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         updateStatus(user);
         user = userDAO.save(user);
 
-        Boolean propagateEnable =
-                runtimeService.getVariable(processInstance.getProcessInstanceId(), PROPAGATE_ENABLE, Boolean.class);
+        Boolean propagateEnable = engine.getRuntimeService().getVariable(
+                processInstance.getProcessInstanceId(), PROPAGATE_ENABLE, Boolean.class);
         if (propagateEnable == null) {
             propagateEnable = enabled;
         }
@@ -315,10 +296,10 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
             throw new WorkflowException(new NotFoundException("Empty workflow id for " + user));
         }
 
-        List<Task> tasks = taskService.createTaskQuery().processInstanceId(user.getWorkflowId()).list();
+        List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(user.getWorkflowId()).list();
         if (tasks.size() == 1) {
             try {
-                taskService.complete(tasks.get(0).getId(), variables);
+                engine.getTaskService().complete(tasks.get(0).getId(), variables);
             } catch (ActivitiException e) {
                 throwException(e, "While completing task '" + tasks.get(0).getName() + "' for " + user);
             }
@@ -349,14 +330,15 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         updateStatus(user);
         User updated = userDAO.save(user);
 
-        PropagationByResource propByRes =
-                runtimeService.getVariable(user.getWorkflowId(), PROP_BY_RESOURCE, PropagationByResource.class);
-        UserMod updatedMod =
-                runtimeService.getVariable(user.getWorkflowId(), USER_MOD, UserMod.class);
+        PropagationByResource propByRes = engine.getRuntimeService().getVariable(
+                user.getWorkflowId(), PROP_BY_RESOURCE, PropagationByResource.class);
+        UserMod updatedMod = engine.getRuntimeService().getVariable(
+                user.getWorkflowId(), USER_MOD, UserMod.class);
 
         saveForFormSubmit(updated, updatedMod.getPassword(), propByRes);
 
-        Boolean propagateEnable = runtimeService.getVariable(user.getWorkflowId(), PROPAGATE_ENABLE, Boolean.class);
+        Boolean propagateEnable = engine.getRuntimeService().getVariable(
+                user.getWorkflowId(), PROPAGATE_ENABLE, Boolean.class);
 
         return new WorkflowResult<Pair<UserMod, Boolean>>(
                 new ImmutablePair<>(updatedMod, propagateEnable), propByRes, tasks);
@@ -413,15 +395,15 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
         saveForFormSubmit(user, null, propByRes);
 
-        if (runtimeService.createProcessInstanceQuery().
+        if (engine.getRuntimeService().createProcessInstanceQuery().
                 processInstanceId(user.getWorkflowId()).active().list().isEmpty()) {
 
             userDAO.delete(user.getKey());
 
-            if (!historyService.createHistoricProcessInstanceQuery().
+            if (!engine.getHistoryService().createHistoricProcessInstanceQuery().
                     processInstanceId(user.getWorkflowId()).list().isEmpty()) {
 
-                historyService.deleteHistoricProcessInstance(user.getWorkflowId());
+                engine.getHistoryService().deleteHistoricProcessInstance(user.getWorkflowId());
             }
         } else {
             updateStatus(user);
@@ -445,7 +427,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
     protected ProcessDefinition getProcessDefinition() {
         try {
-            return repositoryService.createProcessDefinitionQuery().processDefinitionKey(
+            return engine.getRepositoryService().createProcessDefinitionQuery().processDefinitionKey(
                     ActivitiUserWorkflowAdapter.WF_PROCESS_ID).latestVersion().singleResult();
         } catch (ActivitiException e) {
             throw new WorkflowException("While accessing process " + ActivitiUserWorkflowAdapter.WF_PROCESS_ID, e);
@@ -455,7 +437,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
     protected Model getModel(final ProcessDefinition procDef) {
         try {
-            Model model = repositoryService.createModelQuery().deploymentId(procDef.getDeploymentId()).singleResult();
+            Model model = engine.getRepositoryService().createModelQuery().
+                    deploymentId(procDef.getDeploymentId()).singleResult();
             if (model == null) {
                 throw new NotFoundException("Could not find Model for deployment " + procDef.getDeploymentId());
             }
@@ -468,7 +451,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     protected void exportProcessResource(final String resourceName, final OutputStream os) {
         ProcessDefinition procDef = getProcessDefinition();
 
-        InputStream procDefIS = repositoryService.getResourceAsStream(procDef.getDeploymentId(), resourceName);
+        InputStream procDefIS = engine.getRepositoryService().getResourceAsStream(procDef.getDeploymentId(),
+                resourceName);
         try {
             IOUtils.copy(procDefIS, os);
         } catch (IOException e) {
@@ -486,7 +470,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
             ObjectNode modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
             modelNode.put(ModelDataJsonConstants.MODEL_ID, model.getId());
             modelNode.replace(MODEL_DATA_JSON_MODEL,
-                    objectMapper.readTree(repositoryService.getModelEditorSource(model.getId())));
+                    objectMapper.readTree(engine.getRepositoryService().getModelEditorSource(model.getId())));
 
             os.write(modelNode.toString().getBytes());
         } catch (IOException e) {
@@ -529,20 +513,21 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
                     }
 
                     BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(definitionNode);
-                    importUtils.fromXML(new BpmnXMLConverter().convertToXML(bpmnModel));
+                    ActivitiImportUtils.fromXML(engine, new BpmnXMLConverter().convertToXML(bpmnModel));
                 } catch (Exception e) {
                     throw new WorkflowException("While updating process "
                             + ActivitiUserWorkflowAdapter.WF_PROCESS_RESOURCE, e);
                 }
 
-                importUtils.fromJSON(definitionNode.toString().getBytes(), getProcessDefinition(), model);
+                ActivitiImportUtils.fromJSON(
+                        engine, definitionNode.toString().getBytes(), getProcessDefinition(), model);
                 break;
 
             case XML:
             default:
-                importUtils.fromXML(definition.getBytes());
+                ActivitiImportUtils.fromXML(engine, definition.getBytes());
 
-                importUtils.fromJSON(getProcessDefinition(), model);
+                ActivitiImportUtils.fromJSON(engine, getProcessDefinition(), model);
         }
     }
 
@@ -569,7 +554,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     }
 
     protected WorkflowFormTO getFormTO(final Task task) {
-        return getFormTO(task, formService.getTaskFormData(task.getId()));
+        return getFormTO(task, engine.getFormService().getTaskFormData(task.getId()));
     }
 
     protected WorkflowFormTO getFormTO(final Task task, final TaskFormData fd) {
@@ -583,7 +568,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     protected WorkflowFormTO getFormTO(final HistoricTaskInstance task) {
         final List<HistoricFormPropertyEntity> props = new ArrayList<>();
 
-        for (HistoricDetail historicDetail : historyService.createHistoricDetailQuery().taskId(task.getId()).list()) {
+        for (HistoricDetail historicDetail
+                : engine.getHistoryService().createHistoricDetailQuery().taskId(task.getId()).list()) {
 
             if (historicDetail instanceof HistoricFormPropertyEntity) {
                 props.add((HistoricFormPropertyEntity) historicDetail);
@@ -594,7 +580,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
                 task.getProcessInstanceId(), task.getId(), task.getFormKey(), props);
         BeanUtils.copyProperties(task, formTO);
 
-        final HistoricActivityInstance historicActivityInstance = historyService.createHistoricActivityInstanceQuery().
+        final HistoricActivityInstance historicActivityInstance = engine.getHistoryService().
+                createHistoricActivityInstanceQuery().
                 executionId(task.getExecutionId()).activityType("userTask").activityName(task.getName()).singleResult();
 
         if (historicActivityInstance != null) {
@@ -676,7 +663,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
         final String authUser = AuthContextUtils.getUsername();
         if (adminUser.equals(authUser)) {
-            forms.addAll(getForms(taskService.createTaskQuery().
+            forms.addAll(getForms(engine.getTaskService().createTaskQuery().
                     taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE)));
         } else {
             User user = userDAO.find(authUser);
@@ -684,7 +671,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
                 throw new NotFoundException("Syncope User " + authUser);
             }
 
-            forms.addAll(getForms(taskService.createTaskQuery().
+            forms.addAll(getForms(engine.getTaskService().createTaskQuery().
                     taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE).
                     taskCandidateOrAssigned(user.getKey().toString())));
 
@@ -693,7 +680,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
                 candidateGroups.add(groupId.toString());
             }
             if (!candidateGroups.isEmpty()) {
-                forms.addAll(getForms(taskService.createTaskQuery().
+                forms.addAll(getForms(engine.getTaskService().createTaskQuery().
                         taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE).
                         taskCandidateGroupIn(candidateGroups)));
             }
@@ -705,10 +692,10 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     @Override
     public List<WorkflowFormTO> getForms(final String workflowId, final String name) {
         List<WorkflowFormTO> forms = getForms(
-                taskService.createTaskQuery().processInstanceId(workflowId).taskName(name).
+                engine.getTaskService().createTaskQuery().processInstanceId(workflowId).taskName(name).
                 taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE));
 
-        forms.addAll(getForms(historyService.createHistoricTaskInstanceQuery().taskName(name).
+        forms.addAll(getForms(engine.getHistoryService().createHistoricTaskInstanceQuery().taskName(name).
                 taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE)));
 
         return forms;
@@ -739,14 +726,14 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     public WorkflowFormTO getForm(final String workflowId) {
         Task task;
         try {
-            task = taskService.createTaskQuery().processInstanceId(workflowId).singleResult();
+            task = engine.getTaskService().createTaskQuery().processInstanceId(workflowId).singleResult();
         } catch (ActivitiException e) {
             throw new WorkflowException("While reading form for workflow instance " + workflowId, e);
         }
 
         TaskFormData formData;
         try {
-            formData = formService.getTaskFormData(task.getId());
+            formData = engine.getFormService().getTaskFormData(task.getId());
         } catch (ActivitiException e) {
             LOG.debug("No form found for task {}", task.getId(), e);
             formData = null;
@@ -763,14 +750,14 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     protected Pair<Task, TaskFormData> checkTask(final String taskId, final String authUser) {
         Task task;
         try {
-            task = taskService.createTaskQuery().taskId(taskId).singleResult();
+            task = engine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
         } catch (ActivitiException e) {
             throw new NotFoundException("Activiti Task " + taskId, e);
         }
 
         TaskFormData formData;
         try {
-            formData = formService.getTaskFormData(task.getId());
+            formData = engine.getFormService().getTaskFormData(task.getId());
         } catch (ActivitiException e) {
             throw new NotFoundException("Form for Activiti Task " + taskId, e);
         }
@@ -792,7 +779,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         Pair<Task, TaskFormData> checked = checkTask(taskId, authUser);
 
         if (!adminUser.equals(authUser)) {
-            List<Task> tasksForUser = taskService.createTaskQuery().taskId(taskId).taskCandidateUser(authUser).list();
+            List<Task> tasksForUser = engine.getTaskService().createTaskQuery().taskId(taskId).taskCandidateUser(
+                    authUser).list();
             if (tasksForUser.isEmpty()) {
                 throw new WorkflowException(
                         new IllegalArgumentException(authUser + " is not candidate for task " + taskId));
@@ -801,8 +789,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
         Task task;
         try {
-            taskService.setOwner(taskId, authUser);
-            task = taskService.createTaskQuery().taskId(taskId).singleResult();
+            engine.getTaskService().setOwner(taskId, authUser);
+            task = engine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
         } catch (ActivitiException e) {
             throw new WorkflowException("While reading task " + taskId, e);
         }
@@ -828,8 +816,8 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
         Set<String> preTasks = getPerformedTasks(user);
         try {
-            formService.submitTaskFormData(form.getTaskId(), form.getPropertiesForSubmit());
-            runtimeService.setVariable(user.getWorkflowId(), FORM_SUBMITTER, authUser);
+            engine.getFormService().submitTaskFormData(form.getTaskId(), form.getPropertiesForSubmit());
+            engine.getRuntimeService().setVariable(user.getWorkflowId(), FORM_SUBMITTER, authUser);
         } catch (ActivitiException e) {
             throwException(e, "While submitting form for task " + form.getTaskId());
         }
@@ -842,12 +830,12 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         User updated = userDAO.save(user);
 
         // see if there is any propagation to be done
-        PropagationByResource propByRes =
-                runtimeService.getVariable(user.getWorkflowId(), PROP_BY_RESOURCE, PropagationByResource.class);
+        PropagationByResource propByRes = engine.getRuntimeService().getVariable(
+                user.getWorkflowId(), PROP_BY_RESOURCE, PropagationByResource.class);
 
         // fetch - if available - the encrypted password
         String clearPassword = null;
-        String encryptedPwd = runtimeService.getVariable(user.getWorkflowId(), ENCRYPTED_PWD, String.class);
+        String encryptedPwd = engine.getRuntimeService().getVariable(user.getWorkflowId(), ENCRYPTED_PWD, String.class);
         if (StringUtils.isNotBlank(encryptedPwd)) {
             clearPassword = decrypt(encryptedPwd);
         }
@@ -855,7 +843,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         // supports approval chains
         saveForFormSubmit(user, clearPassword, propByRes);
 
-        UserMod userMod = runtimeService.getVariable(user.getWorkflowId(), USER_MOD, UserMod.class);
+        UserMod userMod = engine.getRuntimeService().getVariable(user.getWorkflowId(), USER_MOD, UserMod.class);
         if (userMod == null) {
             userMod = new UserMod();
             userMod.setKey(updated.getKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/spring/DomainProcessEngine.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/spring/DomainProcessEngine.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/spring/DomainProcessEngine.java
new file mode 100644
index 0000000..83619c7
--- /dev/null
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/spring/DomainProcessEngine.java
@@ -0,0 +1,102 @@
+/*
+ * 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.workflow.activiti.spring;
+
+import java.util.Collections;
+import java.util.Map;
+import org.activiti.engine.FormService;
+import org.activiti.engine.HistoryService;
+import org.activiti.engine.IdentityService;
+import org.activiti.engine.ManagementService;
+import org.activiti.engine.ProcessEngine;
+import org.activiti.engine.ProcessEngineConfiguration;
+import org.activiti.engine.RepositoryService;
+import org.activiti.engine.RuntimeService;
+import org.activiti.engine.TaskService;
+import org.apache.syncope.core.misc.security.AuthContextUtils;
+
+/**
+ * {@link ProcessEngine} delegating actual method invocation to the inner map of {@link ProcessEngine} instances,
+ * one for each Syncope domain.
+ */
+public class DomainProcessEngine implements ProcessEngine {
+
+    private final Map<String, ProcessEngine> engines;
+
+    public DomainProcessEngine(final Map<String, ProcessEngine> engines) {
+        this.engines = Collections.synchronizedMap(engines);
+    }
+
+    public Map<String, ProcessEngine> getEngines() {
+        return engines;
+    }
+
+    @Override
+    public String getName() {
+        return engines.get(AuthContextUtils.getDomain()).getName();
+    }
+
+    @Override
+    public void close() {
+        for (ProcessEngine engine : engines.values()) {
+            engine.close();
+        }
+    }
+
+    @Override
+    public RepositoryService getRepositoryService() {
+        return engines.get(AuthContextUtils.getDomain()).getRepositoryService();
+    }
+
+    @Override
+    public RuntimeService getRuntimeService() {
+        return engines.get(AuthContextUtils.getDomain()).getRuntimeService();
+    }
+
+    @Override
+    public FormService getFormService() {
+        return engines.get(AuthContextUtils.getDomain()).getFormService();
+    }
+
+    @Override
+    public TaskService getTaskService() {
+        return engines.get(AuthContextUtils.getDomain()).getTaskService();
+    }
+
+    @Override
+    public HistoryService getHistoryService() {
+        return engines.get(AuthContextUtils.getDomain()).getHistoryService();
+    }
+
+    @Override
+    public IdentityService getIdentityService() {
+        return engines.get(AuthContextUtils.getDomain()).getIdentityService();
+    }
+
+    @Override
+    public ManagementService getManagementService() {
+        return engines.get(AuthContextUtils.getDomain()).getManagementService();
+    }
+
+    @Override
+    public ProcessEngineConfiguration getProcessEngineConfiguration() {
+        return engines.get(AuthContextUtils.getDomain()).getProcessEngineConfiguration();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/spring/DomainProcessEngineFactoryBean.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/spring/DomainProcessEngineFactoryBean.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/spring/DomainProcessEngineFactoryBean.java
new file mode 100644
index 0000000..cf112bd
--- /dev/null
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/spring/DomainProcessEngineFactoryBean.java
@@ -0,0 +1,104 @@
+/*
+ * 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.workflow.activiti.spring;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.sql.DataSource;
+import org.activiti.engine.ProcessEngine;
+import org.activiti.engine.impl.cfg.SpringBeanFactoryProxyMap;
+import org.activiti.spring.SpringExpressionManager;
+import org.activiti.spring.SpringProcessEngineConfiguration;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.transaction.PlatformTransactionManager;
+
+/**
+ * Spring factory for {@link DomainProcessEngine} which takes the provided {@link SpringProcessEngineConfiguration} as
+ * template for each of the configured Syncope domains.
+ */
+public class DomainProcessEngineFactoryBean
+        implements FactoryBean<DomainProcessEngine>, DisposableBean, ApplicationContextAware {
+
+    private ApplicationContext ctx;
+
+    private DomainProcessEngine engine;
+
+    @Override
+    public void setApplicationContext(final ApplicationContext ctx) throws BeansException {
+        this.ctx = ctx;
+    }
+
+    @Override
+    public DomainProcessEngine getObject() throws Exception {
+        if (engine == null) {
+            Map<String, ProcessEngine> engines = new HashMap<>();
+
+            for (Map.Entry<String, DataSource> entry : ctx.getBeansOfType(DataSource.class).entrySet()) {
+                if (!entry.getKey().startsWith("local")) {
+                    String domain = StringUtils.substringBefore(entry.getKey(), DataSource.class.getSimpleName());
+                    DataSource dataSource = entry.getValue();
+                    PlatformTransactionManager transactionManager = ctx.getBean(
+                            domain + "TransactionManager", PlatformTransactionManager.class);
+                    Object entityManagerFactory = ctx.getBean(domain + "EntityManagerFactory");
+
+                    SpringProcessEngineConfiguration conf = ctx.getBean(SpringProcessEngineConfiguration.class);
+                    conf.setDataSource(dataSource);
+                    conf.setTransactionManager(transactionManager);
+                    conf.setTransactionsExternallyManaged(true);
+                    conf.setJpaEntityManagerFactory(entityManagerFactory);
+                    if (conf.getBeans() == null) {
+                        conf.setBeans(new SpringBeanFactoryProxyMap(ctx));
+                    }
+                    if (conf.getExpressionManager() == null) {
+                        conf.setExpressionManager(new SpringExpressionManager(ctx, conf.getBeans()));
+                    }
+
+                    engines.put(domain, conf.buildProcessEngine());
+                }
+            }
+
+            engine = new DomainProcessEngine(engines);
+        }
+
+        return engine;
+    }
+
+    @Override
+    public Class<DomainProcessEngine> getObjectType() {
+        return DomainProcessEngine.class;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+    @Override
+    public void destroy() throws Exception {
+        if (engine != null) {
+            engine.close();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AbstractActivitiServiceTask.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AbstractActivitiServiceTask.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AbstractActivitiServiceTask.java
index 85a0ac0..ff898ad 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AbstractActivitiServiceTask.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AbstractActivitiServiceTask.java
@@ -18,7 +18,7 @@
  */
 package org.apache.syncope.core.workflow.activiti.task;
 
-import org.activiti.engine.RuntimeService;
+import org.activiti.engine.ProcessEngine;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,13 +31,10 @@ import org.springframework.transaction.annotation.Transactional;
 @Component
 public abstract class AbstractActivitiServiceTask {
 
-    /**
-     * Logger.
-     */
     protected static final Logger LOG = LoggerFactory.getLogger(AbstractActivitiServiceTask.class);
 
     @Autowired
-    protected RuntimeService runtimeService;
+    protected ProcessEngine engine;
 
     @Transactional(rollbackFor = { Throwable.class })
     public void execute(final String executionId) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AutoActivate.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AutoActivate.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AutoActivate.java
index 370e6e3..51dfb50 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AutoActivate.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/AutoActivate.java
@@ -26,6 +26,6 @@ public class AutoActivate extends AbstractActivitiServiceTask {
 
     @Override
     protected void doExecute(final String executionId) {
-        runtimeService.setVariable(executionId, ActivitiUserWorkflowAdapter.PROPAGATE_ENABLE, Boolean.TRUE);
+        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.PROPAGATE_ENABLE, Boolean.TRUE);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Create.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Create.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Create.java
index adf36ad..e911f98 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Create.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Create.java
@@ -37,15 +37,17 @@ public class Create extends AbstractActivitiServiceTask {
 
     @Override
     protected void doExecute(final String executionId) {
-        UserTO userTO = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.USER_TO, UserTO.class);
+        UserTO userTO = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.USER_TO, UserTO.class);
         Boolean storePassword =
-                runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.STORE_PASSWORD, Boolean.class);
+                engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.STORE_PASSWORD, Boolean.class);
         // create and set workflow id
         User user = entityFactory.newEntity(User.class);
         dataBinder.create(user, userTO, storePassword == null ? true : storePassword);
         user.setWorkflowId(executionId);
 
         // report user as result
-        runtimeService.setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
+        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Delete.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Delete.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Delete.java
index d386388..7933751 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Delete.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Delete.java
@@ -27,7 +27,8 @@ public class Delete extends AbstractActivitiServiceTask {
 
     @Override
     protected void doExecute(final String executionId) {
-        User user = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
+        User user = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
 
         // Do something with user...
         if (user != null) {
@@ -35,6 +36,6 @@ public class Delete extends AbstractActivitiServiceTask {
         }
 
         // remove user variable
-        runtimeService.removeVariable(executionId, ActivitiUserWorkflowAdapter.USER);
+        engine.getRuntimeService().removeVariable(executionId, ActivitiUserWorkflowAdapter.USER);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/GenerateToken.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/GenerateToken.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/GenerateToken.java
index dcbcfd0..9ce6941 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/GenerateToken.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/GenerateToken.java
@@ -32,12 +32,13 @@ public class GenerateToken extends AbstractActivitiServiceTask {
 
     @Override
     protected void doExecute(final String executionId) {
-        User user = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
+        User user = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
 
         user.generateToken(
                 confDAO.find("token.length", "256").getValues().get(0).getLongValue().intValue(),
                 confDAO.find("token.expireTime", "60").getValues().get(0).getLongValue().intValue());
 
-        runtimeService.setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
+        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Notify.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Notify.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Notify.java
index 3c886fe..54e7852 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Notify.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Notify.java
@@ -40,9 +40,12 @@ public class Notify extends AbstractActivitiServiceTask {
 
     @Override
     protected void doExecute(final String executionId) {
-        User user = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
-        UserTO userTO = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.USER_TO, UserTO.class);
-        String event = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.EVENT, String.class);
+        User user = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
+        UserTO userTO = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.USER_TO, UserTO.class);
+        String event = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.EVENT, String.class);
 
         if (StringUtils.isNotBlank(event)) {
             notificationManager.createTasks(

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java
index 2fc8097..10e9afe 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/PasswordReset.java
@@ -28,9 +28,12 @@ public class PasswordReset extends AbstractActivitiServiceTask {
 
     @Override
     protected void doExecute(final String executionId) {
-        User user = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
-        String token = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.TOKEN, String.class);
-        String password = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.PASSWORD, String.class);
+        User user = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
+        String token = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.TOKEN, String.class);
+        String password = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.PASSWORD, String.class);
 
         if (!user.checkToken(token)) {
             throw new WorkflowException(new IllegalArgumentException("Wrong token: " + token + " for " + user));
@@ -38,7 +41,7 @@ public class PasswordReset extends AbstractActivitiServiceTask {
 
         user.removeToken();
         user.setPassword(password, user.getCipherAlgorithm());
-        runtimeService.setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
+        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java
index 4da56c6..e4ee649 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/task/Update.java
@@ -35,9 +35,11 @@ public class Update extends AbstractActivitiServiceTask {
 
     @Override
     protected void doExecute(final String executionId) {
-        User user = runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
+        User user = engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.USER, User.class);
         UserMod userMod =
-                runtimeService.getVariable(executionId, ActivitiUserWorkflowAdapter.USER_MOD, UserMod.class);
+                engine.getRuntimeService().
+                getVariable(executionId, ActivitiUserWorkflowAdapter.USER_MOD, UserMod.class);
 
         // update password internally only if required
         UserMod updatedMod = SerializationUtils.clone(userMod);
@@ -50,8 +52,8 @@ public class Update extends AbstractActivitiServiceTask {
         updatedMod.setPassword(updatedPwd);
 
         // report updated user and propagation by resource as result
-        runtimeService.setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
-        runtimeService.setVariable(executionId, ActivitiUserWorkflowAdapter.USER_MOD, updatedMod);
-        runtimeService.setVariable(executionId, ActivitiUserWorkflowAdapter.PROP_BY_RESOURCE, propByRes);
+        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER, user);
+        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.USER_MOD, updatedMod);
+        engine.getRuntimeService().setVariable(executionId, ActivitiUserWorkflowAdapter.PROP_BY_RESOURCE, propByRes);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-activiti/src/main/resources/workflowActivitiContext.xml
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/resources/workflowActivitiContext.xml b/core/workflow-activiti/src/main/resources/workflowActivitiContext.xml
index 75f0c38..81058e1 100644
--- a/core/workflow-activiti/src/main/resources/workflowActivitiContext.xml
+++ b/core/workflow-activiti/src/main/resources/workflowActivitiContext.xml
@@ -35,13 +35,10 @@ under the License.
   <bean id="syncopeActivitiUserManager" class="org.apache.syncope.core.workflow.activiti.SyncopeUserManager"/>
   <bean id="syncopeActivitiGroupManager" class="org.apache.syncope.core.workflow.activiti.SyncopeGroupManager"/>
 
-  <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
-    <property name="dataSource" ref="dataSource"/>
-    <property name="transactionManager" ref="transactionManager"/>
+  <bean class="org.activiti.spring.SpringProcessEngineConfiguration" scope="prototype">
     <property name="transactionsExternallyManaged" value="true"/>
     <property name="databaseSchemaUpdate" value="true"/>
 
-    <property name="jpaEntityManagerFactory" ref="entityManagerFactory"/>
     <property name="jpaHandleTransaction" value="true"/>
     <property name="jpaCloseEntityManager" value="false"/>
 
@@ -64,17 +61,7 @@ under the License.
     </property>
   </bean>
 
-  <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
-    <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
-  </bean>
-
-  <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
-  <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
-  <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
-  <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
-  <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService"/>
-  <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/>
-  <bean id="formService" factory-bean="processEngine" factory-method="getFormService"/>
+  <bean class="org.apache.syncope.core.workflow.activiti.spring.DomainProcessEngineFactoryBean"/>
 
   <context:component-scan base-package="org.apache.syncope.core.workflow.activiti"/>
     

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java b/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java
index 0d7c86a..fbf29c3 100644
--- a/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java
+++ b/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java
@@ -90,15 +90,15 @@ public interface UserWorkflowAdapter extends WorkflowAdapter {
     /**
      * Suspend an user.
      *
-     * @param userKey user to be suspended
+     * @param key to be suspended
      * @return user just suspended
      */
-    WorkflowResult<Long> suspend(Long userKey);
+    WorkflowResult<Long> suspend(Long key);
 
     /**
      * Suspend an user.
      *
-     * @param user to be suspended
+     * @param user user to be suspended
      * @return user just suspended
      */
     WorkflowResult<Long> suspend(User user);

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java
index ef15ab0..3f0d61a 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractAnyObjectWorkflowAdapter.java
@@ -26,9 +26,10 @@ import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
 import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
-@Transactional(rollbackFor = { Throwable.class })
+@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = { Throwable.class })
 public abstract class AbstractAnyObjectWorkflowAdapter implements AnyObjectWorkflowAdapter {
 
     @Autowired

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractGroupWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractGroupWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractGroupWorkflowAdapter.java
index 97a8b1f..2b921ce 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractGroupWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractGroupWorkflowAdapter.java
@@ -26,9 +26,10 @@ import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.provisioning.api.data.GroupDataBinder;
 import org.apache.syncope.core.workflow.api.GroupWorkflowAdapter;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
-@Transactional(rollbackFor = { Throwable.class })
+@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = { Throwable.class })
 public abstract class AbstractGroupWorkflowAdapter implements GroupWorkflowAdapter {
 
     @Autowired

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
index fc75987..ecc1c01 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java
@@ -29,9 +29,10 @@ import org.apache.syncope.core.workflow.api.UserWorkflowAdapter;
 import org.identityconnectors.common.Base64;
 import org.identityconnectors.common.security.EncryptorFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
-@Transactional(rollbackFor = { Throwable.class })
+@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = { Throwable.class })
 public abstract class AbstractUserWorkflowAdapter implements UserWorkflowAdapter {
 
     @Autowired

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
index 78360a9..3d56daf 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
@@ -35,12 +35,10 @@ import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.workflow.api.WorkflowDefinitionFormat;
 import org.apache.syncope.core.workflow.api.WorkflowException;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
 
 /**
  * Simple implementation basically not involving any workflow engine.
  */
-@Transactional(rollbackFor = { Throwable.class })
 public class DefaultUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
     @Autowired

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java
----------------------------------------------------------------------
diff --git a/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java b/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java
index 4359e7b..97bb299 100644
--- a/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java
+++ b/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import javax.sql.DataSource;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.misc.spring.ResourceWithFallbackLoader;
+import org.apache.syncope.core.persistence.api.DomainsHolder;
 import org.apache.syncope.core.persistence.api.SyncopeLoader;
 import org.apache.syncope.core.persistence.api.entity.CamelEntityFactory;
 import org.apache.syncope.core.persistence.api.entity.CamelRoute;
@@ -60,7 +61,7 @@ public class CamelRouteLoader implements SyncopeLoader {
     private ResourceWithFallbackLoader anyObjectRoutesLoader;
 
     @Autowired
-    private DataSource dataSource;
+    private DomainsHolder domainsHolder;
 
     @Autowired
     private CamelEntityFactory entityFactory;
@@ -77,15 +78,20 @@ public class CamelRouteLoader implements SyncopeLoader {
     public void load() {
         synchronized (this) {
             if (!loaded) {
-                loadRoutes(userRoutesLoader.getResource(), AnyTypeKind.USER);
-                loadRoutes(groupRoutesLoader.getResource(), AnyTypeKind.GROUP);
-                loadRoutes(anyObjectRoutesLoader.getResource(), AnyTypeKind.ANY_OBJECT);
+                for (Map.Entry<String, DataSource> entry : domainsHolder.getDomains().entrySet()) {
+                    loadRoutes(entry.getKey(), entry.getValue(),
+                            userRoutesLoader.getResource(), AnyTypeKind.USER);
+                    loadRoutes(entry.getKey(), entry.getValue(),
+                            groupRoutesLoader.getResource(), AnyTypeKind.GROUP);
+                    loadRoutes(entry.getKey(), entry.getValue(),
+                            anyObjectRoutesLoader.getResource(), AnyTypeKind.ANY_OBJECT);
+                }
                 loaded = true;
             }
         }
     }
 
-    private boolean loadRoutesFor(final AnyTypeKind anyTypeKind) {
+    private boolean loadRoutesFor(final DataSource dataSource, final AnyTypeKind anyTypeKind) {
         final String sql = String.format("SELECT * FROM %s WHERE ANYTYPEKIND = ?", CamelRoute.class.getSimpleName());
         final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
         final List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, new Object[] { anyTypeKind.name() });
@@ -106,8 +112,10 @@ public class CamelRouteLoader implements SyncopeLoader {
         return writer.toString();
     }
 
-    private void loadRoutes(final Resource resource, final AnyTypeKind anyTypeKind) {
-        if (loadRoutesFor(anyTypeKind)) {
+    private void loadRoutes(
+            final String domain, final DataSource dataSource, final Resource resource, final AnyTypeKind anyTypeKind) {
+
+        if (loadRoutesFor(dataSource, anyTypeKind)) {
             String query = String.format("INSERT INTO %s(NAME, ANYTYPEKIND, CONTENT) VALUES (?, ?, ?)",
                     CamelRoute.class.getSimpleName());
             JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
@@ -132,12 +140,12 @@ public class CamelRouteLoader implements SyncopeLoader {
                     route.setContent(routeContent);
 
                     jdbcTemplate.update(query, new Object[] { routeId, anyTypeKind.name(), routeContent });
-                    LOG.info("Route successfully loaded: {}", routeId);
+                    LOG.info("[{}] Route successfully loaded: {}", domain, routeId);
                 }
             } catch (DataAccessException e) {
-                LOG.error("While trying to store queries {}", e);
+                LOG.error("[{}] While trying to store queries", domain, e);
             } catch (Exception e) {
-                LOG.error("Route load failed {}", e.getMessage());
+                LOG.error("[{}] Route load failed {}", domain, e.getMessage());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPACamelRouteDAO.java
----------------------------------------------------------------------
diff --git a/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPACamelRouteDAO.java b/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPACamelRouteDAO.java
index e9f2c72..8894992 100644
--- a/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPACamelRouteDAO.java
+++ b/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPACamelRouteDAO.java
@@ -32,13 +32,13 @@ public class JPACamelRouteDAO extends AbstractDAO<CamelRoute, String> implements
 
     @Override
     public CamelRoute find(final String key) {
-        return entityManager.find(JPACamelRoute.class, key);
+        return entityManager().find(JPACamelRoute.class, key);
     }
 
     @Transactional(readOnly = true)
     @Override
     public List<CamelRoute> find(final AnyTypeKind anyTypeKind) {
-        TypedQuery<CamelRoute> query = entityManager.createQuery(
+        TypedQuery<CamelRoute> query = entityManager().createQuery(
                 "SELECT e FROM " + JPACamelRoute.class.getSimpleName()
                 + " e WHERE e.anyTypeKind = :anyTypeKind", CamelRoute.class);
         query.setParameter("anyTypeKind", anyTypeKind);
@@ -49,21 +49,21 @@ public class JPACamelRouteDAO extends AbstractDAO<CamelRoute, String> implements
     @Transactional(readOnly = true)
     @Override
     public List<CamelRoute> findAll() {
-        TypedQuery<CamelRoute> query = entityManager.createQuery(
+        TypedQuery<CamelRoute> query = entityManager().createQuery(
                 "SELECT e FROM " + JPACamelRoute.class.getSimpleName() + " e ", CamelRoute.class);
         return query.getResultList();
     }
 
     @Override
     public CamelRoute save(final CamelRoute route) {
-        return entityManager.merge(route);
+        return entityManager().merge(route);
     }
 
     @Override
     public void delete(final String key) {
         CamelRoute route = find(key);
         if (route != null) {
-            entityManager.remove(route);
+            entityManager().remove(route);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java
index ae29501..bb01cd3 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java
@@ -143,6 +143,25 @@ public class CamelAnyObjectProvisioningManager
 
     @Override
     @SuppressWarnings("unchecked")
+    public List<PropagationStatus> provision(final Long key, final Collection<String> resources) {
+        PollingConsumer pollingConsumer = getConsumer("direct:provisionAnyObjectPort");
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("resources", resources);
+
+        sendMessage("direct:provisionAnyObject", key, props);
+
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(List.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
     public List<PropagationStatus> deprovision(final Long anyObjectKey, final Collection<String> resources) {
         PollingConsumer pollingConsumer = getConsumer("direct:deprovisionAnyObjectPort");
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/34a1c214/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelGroupProvisioningManager.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelGroupProvisioningManager.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelGroupProvisioningManager.java
index f97203a..bc0c854 100644
--- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelGroupProvisioningManager.java
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelGroupProvisioningManager.java
@@ -163,13 +163,32 @@ public class CamelGroupProvisioningManager
 
     @Override
     @SuppressWarnings("unchecked")
-    public List<PropagationStatus> deprovision(final Long groupKey, final Collection<String> resources) {
+    public List<PropagationStatus> provision(final Long key, final Collection<String> resources) {
+        PollingConsumer pollingConsumer = getConsumer("direct:provisionGroupPort");
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("resources", resources);
+
+        sendMessage("direct:provisionGroup", key, props);
+
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(List.class);
+    }
+    
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<PropagationStatus> deprovision(final Long key, final Collection<String> resources) {
         PollingConsumer pollingConsumer = getConsumer("direct:deprovisionGroupPort");
 
         Map<String, Object> props = new HashMap<>();
         props.put("resources", resources);
 
-        sendMessage("direct:deprovisionGroup", groupKey, props);
+        sendMessage("direct:deprovisionGroup", key, props);
 
         Exchange exchange = pollingConsumer.receive();