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/02/03 13:03:14 UTC

[1/3] syncope git commit: [SYNCOPE-620] IT for Camel: success

Repository: syncope
Updated Branches:
  refs/heads/2_0_X c7e819311 -> 721f3276e


http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserUpdateInSyncProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserUpdateInSyncProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserUpdateInSyncProcessor.java
new file mode 100644
index 0000000..23092e7
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserUpdateInSyncProcessor.java
@@ -0,0 +1,73 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserUpdateInSyncProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserUpdateInSyncProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        WorkflowResult<Map.Entry<UserMod, Boolean>> updated = (WorkflowResult) exchange.getIn().getBody();
+        Set<String> excludedResource = exchange.getProperty("excludedResources", Set.class);
+
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+
+        List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(updated, updated.getResult().getKey().
+                getPassword() != null, excludedResource);
+
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.getOut().setBody(new AbstractMap.SimpleEntry<>(
+                updated.getResult().getKey().getKey(), propagationReporter.getStatuses()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserUpdateProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserUpdateProcessor.java
new file mode 100644
index 0000000..e921847
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserUpdateProcessor.java
@@ -0,0 +1,105 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.common.lib.mod.MembershipMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.server.provisioning.java.VirAttrHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserUpdateProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserUpdateProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    protected VirAttrHandler virtAttrHandler;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void process(final Exchange exchange) {
+        WorkflowResult<Map.Entry<UserMod, Boolean>> updated = (WorkflowResult) exchange.getIn().getBody();
+        UserMod actual = exchange.getProperty("actual", UserMod.class);
+        boolean removeMemberships = exchange.getProperty("removeMemberships", boolean.class);
+
+        List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(updated);
+        if (tasks.isEmpty()) {
+            // SYNCOPE-459: take care of user virtual attributes ...
+            final PropagationByResource propByResVirAttr = virtAttrHandler.fillVirtual(
+                    updated.getResult().getKey().getKey(),
+                    actual.getVirAttrsToRemove(),
+                    actual.getVirAttrsToUpdate());
+            // SYNCOPE-501: update only virtual attributes (if any of them changed), password propagation is
+            // not required, take care also of membership virtual attributes
+            boolean addOrUpdateMemberships = false;
+            for (MembershipMod membershipMod : actual.getMembershipsToAdd()) {
+                if (!virtAttrHandler.fillMembershipVirtual(
+                        updated.getResult().getKey().getKey(),
+                        membershipMod.getRole(),
+                        null,
+                        membershipMod.getVirAttrsToRemove(),
+                        membershipMod.getVirAttrsToUpdate(),
+                        false).isEmpty()) {
+
+                    addOrUpdateMemberships = true;
+                }
+            }
+            tasks.addAll(!propByResVirAttr.isEmpty() || addOrUpdateMemberships || removeMemberships
+                    ? propagationManager.getUserUpdateTaskIds(updated, false, null)
+                    : Collections.<PropagationTask>emptyList());
+        }
+
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        if (!tasks.isEmpty()) {
+            try {
+                taskExecutor.execute(tasks, propagationReporter);
+            } catch (PropagationException e) {
+                LOG.error("Error propagation primary resource", e);
+                propagationReporter.onPrimaryResourceFailure(tasks);
+            }
+        }
+
+        exchange.getOut().setBody(new AbstractMap.SimpleEntry<>(
+                updated.getResult().getKey().getKey(), propagationReporter.getStatuses()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml b/syncope620/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml
index e46b58a..8363127 100644
--- a/syncope620/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml
+++ b/syncope620/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml
@@ -19,8 +19,11 @@ under the License.
 -->
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans   
-                           http://www.springframework.org/schema/beans/spring-beans.xsd">
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context
+                           http://www.springframework.org/schema/context/spring-context.xsd">
 
   <bean id="userRoutes" class="org.apache.syncope.server.misc.spring.ResourceWithFallbackLoader">
     <property name="primary" value="file:${camel.directory}/userWorkflow.bpmn20.xml"/>
@@ -31,4 +34,6 @@ under the License.
     <property name="fallback" value="classpath:roleRoutes.xml"/>
   </bean>
     
+  <context:component-scan base-package="org.apache.syncope.server.provisioning.camel"/>
+
 </beans>

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/resources/roleRoutes.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/resources/roleRoutes.xml b/syncope620/ext/camel/provisioning-camel/src/main/resources/roleRoutes.xml
index 827d16e..04c2dc4 100644
--- a/syncope620/ext/camel/provisioning-camel/src/main/resources/roleRoutes.xml
+++ b/syncope620/ext/camel/provisioning-camel/src/main/resources/roleRoutes.xml
@@ -18,15 +18,7 @@ specific language governing permissions and limitations
 under the License.
 -->
 <routes>
- 
-  <!--
-      The default routes define each task involved in user creation:
-      main operations consist in user workflow creation and its propagation.         
-  -->
-  <!--
-      CREATE ROLE
-  -->
-        
+     
   <route id="createRole">
     <from uri="direct:createRole"/>
     <setProperty propertyName="subject">
@@ -34,7 +26,7 @@ under the License.
     </setProperty>
     <doTry>
       <bean ref="rwfAdapter" method="create(${body})"/>
-      <process ref="defaultRoleCreatePropagation" />
+      <process ref="roleCreateProcessor"/>
       <to uri="direct:createRolePort"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
@@ -46,32 +38,25 @@ under the License.
     </doTry>
   </route> 
                
-  <!--
-      CREATE ROLE SYNC
-  -->
   <route id="createRoleSync">
-    <from uri="direct:createRoleSync"/>
+    <from uri="direct:createRoleInSync"/>
     <setProperty propertyName="subject">
       <simple>${body}</simple>
     </setProperty>
     <doTry>
       <bean ref="rwfAdapter" method="create(${body})"/>
-      <process ref="defaultRoleCreateSyncPropagation" />
-      <to uri="direct:createRoleSyncPort"/>
+      <process ref="roleCreateInSyncProcessor"/>
+      <to uri="direct:createRoleInSyncPort"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
         <handled>
           <constant>false</constant>
         </handled>
-        <to uri="direct:createRoleSyncPort"/>
+        <to uri="direct:createRoleInSyncPort"/>
       </doCatch>
     </doTry>
   </route> 
-        
          
-  <!--
-      UPDATE ROLE
-  -->
   <route id="updateRole">
     <from uri="direct:updateRole"/>
     <setProperty propertyName="subjectMod">
@@ -79,7 +64,7 @@ under the License.
     </setProperty>
     <doTry>
       <bean ref="rwfAdapter" method="update(${body})"/>
-      <process ref="defaultRoleUpdatePropagation" />
+      <process ref="roleUpdateProcessor"/>
       <to uri="direct:updateRolePort"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
@@ -90,14 +75,11 @@ under the License.
       </doCatch>
     </doTry>
   </route>
-               
-  <!--
-      DELETE ROLE
-  -->
+
   <route id="deleteRole">
     <from uri="direct:deleteRole"/>
     <doTry>
-      <process ref="defaultRoleDeletePropagation" />
+      <process ref="roleDeleteProcessor"/>
       <bean ref="rwfAdapter" method="delete(${body})"/>
       <setBody>
         <simple>${property.statuses}</simple>
@@ -112,10 +94,7 @@ under the License.
       </doCatch>
     </doTry>
   </route>
-        
-  <!-- 
-      UNLINK USER
-  -->
+
   <route id="unlinkRole">
     <from uri="direct:unlinkRole"/>
     <doTry>
@@ -134,10 +113,6 @@ under the License.
     </doTry>            
   </route>
         
-  <!--
-      LINK USER
-  -->
-        
   <route id="linkRole">
     <from uri="direct:linkRole"/>
     <doTry>
@@ -156,12 +131,9 @@ under the License.
     </doTry>            
   </route>
         
-  <!--
-      DEPROVISION ROLE
-  -->
   <route id="deprovisionRole">
     <from uri="direct:deprovisionRole"/>            
-    <process ref="defaultRoleDeprovisionPropagation" />
+    <process ref="roleDeprovisionProcessor"/>
     <to uri="direct:deprovisionRolePort"/>              
   </route>
     

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml b/syncope620/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml
index d62ab76..06e68d1 100644
--- a/syncope620/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml
+++ b/syncope620/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml
@@ -18,21 +18,7 @@ specific language governing permissions and limitations
 under the License.
 -->
 <routes>
- 
-  <!--
-      The default routes define each task involved in user creation:
-      main operations consist in user workflow creation and its propagation.         
-  -->  	
-  <!--
-      CREATE USER
-      This is the entry point of the route and is involved in accepting
-      the UserTO. When it arrives, the user workflow is created. If the
-      creation is successfull, the result is sent to propagation, otherwise
-      if an exception was raised, the exception has to be returned to the
-      caller. The property actual allows to store the received UserTO in
-      order to use it later.
-  -->
-        
+  
   <route id="createUser">
     <from uri="direct:createUser"/>
     <setProperty propertyName="actual">
@@ -40,8 +26,8 @@ under the License.
     </setProperty>
     <doTry>
       <bean ref="uwfAdapter" method="create(${body},${property.disablePwdPolicyCheck},
-                                 ${property.enabled},${property.storePassword})"/>
-      <process ref="defaultUserCreatePropagation" />
+                                     ${property.enabled},${property.storePassword})"/>
+      <process ref="userCreateProcessor"/>
       <to uri="direct:createPort"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
@@ -52,16 +38,7 @@ under the License.
       </doCatch>
     </doTry>
   </route> 
-        
-  <!--
-      The propagation route deals with propagation of created user. In this
-      case we used a custom processor to perform this task: it means that
-      a custom java class contains the propagation strategy.
-  -->
        
-  <!--
-      UPDATE USER
-  -->
   <route id="updateUser">
     <from uri="direct:updateUser"/>
     <setProperty propertyName="actual">
@@ -69,7 +46,7 @@ under the License.
     </setProperty>
     <doTry>
       <bean ref="uwfAdapter" method="update(${body})"/>
-      <process ref="defaultUserUpdatePropagation" />
+      <process ref="userUpdateProcessor"/>
       <to uri="direct:updatePort"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
@@ -80,40 +57,33 @@ under the License.
       </doCatch>
     </doTry>
   </route>
-        
-
                 
-  <!--
-      UPDATE SYNC USER
-  -->
-  <route id="updateSyncUser">
-    <from uri="direct:updateSyncUser"/>            
+  <route id="updateUserInSync">
+    <from uri="direct:updateUserInSync"/>            
     <doTry>
       <bean ref="uwfAdapter" method="update(${body})"/>
-      <to uri="direct:syncUserStatus"/>
+      <to uri="direct:userInSync"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
         <handled>
           <constant>false</constant>
         </handled>
-        <to uri="direct:updateSyncPort"/>
+        <to uri="direct:updateInSyncPort"/>
       </doCatch>
     </doTry>
   </route>
         
-  <route id="syncUserStatus">
-    <from uri="direct:syncUserStatus"/>
-    <process ref="userStatusOnSync" />
-    <process ref="defaultUserUpdateInSyncPropagation" />
-    <to uri="direct:updateSyncPort"/>
+  <route id="userInSync">
+    <from uri="direct:userInSync"/>
+    <process ref="userSetStatusInSyncProcessor"/>
+    <process ref="userUpdateInSyncProcessor"/>
+    <to uri="direct:updateInSyncPort"/>
   </route>
-  <!--
-      DELETE USER
-  -->
+  
   <route id="deleteUser">
     <from uri="direct:deleteUser"/>
     <doTry>
-      <process ref="defaultUserDeletePropagation" />
+      <process ref="userDeleteProcessor"/>
       <bean ref="uwfAdapter" method="delete(${body})"/>
       <setBody>
         <simple>${property.statuses}</simple>
@@ -129,9 +99,6 @@ under the License.
     </doTry>
   </route>
         
-  <!-- 
-      UNLINK USER
-  -->
   <route id="unlinkUser">
     <from uri="direct:unlinkUser"/>
     <doTry>
@@ -150,10 +117,6 @@ under the License.
     </doTry>            
   </route>
         
-  <!--
-      LINK USER
-  -->
-        
   <route id="linkUser">
     <from uri="direct:linkUser"/>
     <doTry>
@@ -172,14 +135,11 @@ under the License.
     </doTry>            
   </route>
         
-  <!-- 
-      ACTIVATE USER
-  -->
   <route id="activateUser">
     <from uri="direct:activateUser"/>
     <doTry>
       <bean ref="uwfAdapter" method="activate(${body}, ${property.token})"/>
-      <to uri="direct:statusUser"/>
+      <to uri="direct:userStatusPropagation"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
         <handled>
@@ -189,14 +149,12 @@ under the License.
       </doCatch>
     </doTry>    
   </route>
-  <!-- 
-      REACTIVATE USER
-  -->
+  
   <route id="reactivateUser">
     <from uri="direct:reactivateUser"/>
     <doTry>
       <bean ref="uwfAdapter" method="reactivate(${body})"/>
-      <to uri="direct:statusUser"/>
+      <to uri="direct:userStatusPropagation"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
         <handled>
@@ -206,14 +164,12 @@ under the License.
       </doCatch>
     </doTry>    
   </route>
-  <!-- 
-      SUSPEND USER
-  -->
+  
   <route id="suspendUser">
     <from uri="direct:suspendUser"/>
     <doTry>
       <bean ref="uwfAdapter" method="suspend(${body})"/>
-      <to uri="direct:statusUser"/>
+      <to uri="direct:userStatusPropagation"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
         <handled>
@@ -224,50 +180,34 @@ under the License.
     </doTry>  
   </route>
         
-  <!-- 
-      STATUS PROPAGATION
-  -->
-        
-  <route id="statusUser">
-    <from uri="direct:statusUser"/>            
-    <process ref="defaultUserStatusPropagation" />
-    <to uri="direct:statusPort"/>              
+  <route id="userStatusPropagation">
+    <from uri="direct:userStatusPropagation"/>            
+    <process ref="userStatusPropagationProcessor"/>
+    <to uri="direct:statusPort"/> 
   </route>
         
-        
-  <!--
-      DEPROVISION USER
-  -->
   <route id="deprovisionUser">
     <from uri="direct:deprovisionUser"/>            
-    <process ref="defaultUserDeprovisionPropagation" />
+    <process ref="userDeprovisionProcessor"/>
     <to uri="direct:deprovisionPort"/>              
   </route>
     
-  <!--
-      SUSPEND USER AFTER POLICY VIOLATION
-  -->
-        
-  <route id="suspendUserWF">
-    <from uri="direct:suspendUserWF"/>
+  <route id="innerSuspendUser">
+    <from uri="direct:innerSuspendUser"/>
     <doTry>
       <bean ref="uwfAdapter" method="suspend(${body})"/>
-      <process ref="defaultUserWFSuspendPropagation"/>
-      <to uri="direct:suspendWFPort"/>
+      <process ref="userInnerSuspendProcessor"/>
+      <to uri="direct:innerSuspendUserPort"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
         <handled>
           <constant>false</constant>
         </handled>
-        <to uri="direct:suspendWFPort"/>
+        <to uri="direct:innerSuspendUserPort"/>
       </doCatch>
     </doTry>  
   </route>
         
-  <!--
-      REQUEST PASSWORD RESET ROUTE
-  -->
-        
   <route id="requestPwdReset">
     <from uri="direct:requestPwdReset"/>
     <doTry>
@@ -282,14 +222,12 @@ under the License.
       </doCatch>
     </doTry>  
   </route>
-  <!--
-      CONFIRM PASSWORD RESET
-  -->
+  
   <route id="confirmPwdReset">
     <from uri="direct:confirmPwdReset"/>
     <doTry>
-      <bean ref="uwfAdapter" method="confirmPasswordReset(${property.userId},${property.token},${property.password})"/>
-      <process ref="defaultUserConfirmPwdResetPropagation" />
+      <bean ref="uwfAdapter" method="confirmPasswordReset(${property.userKey},${property.token},${property.password})"/>
+      <process ref="userConfirmPwdResetProcessor"/>
       <to uri="direct:confirmPwdResetPort"/>
       <doCatch>        
         <exception>java.lang.RuntimeException</exception>
@@ -300,5 +238,5 @@ under the License.
       </doCatch>
     </doTry>
   </route>
-
+  
 </routes>

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/CamelRouteService.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/CamelRouteService.java b/syncope620/ext/camel/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/CamelRouteService.java
index d16b812..3a282b3 100644
--- a/syncope620/ext/camel/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/CamelRouteService.java
+++ b/syncope620/ext/camel/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/CamelRouteService.java
@@ -22,6 +22,8 @@ import java.util.List;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
+import javax.ws.rs.MatrixParam;
+import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
@@ -34,18 +36,20 @@ import org.apache.syncope.common.lib.types.SubjectType;
 public interface CamelRouteService extends JAXRSService {
 
     @GET
-    @Path("{subjectType}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    List<CamelRouteTO> list(@NotNull @PathParam("subjectType") SubjectType subjectType);
+    List<CamelRouteTO> list(@NotNull @MatrixParam("subjectType") SubjectType subjectType);
 
     @GET
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    CamelRouteTO read(@PathParam("key") String key);
+    CamelRouteTO read(@NotNull @PathParam("key") String key);
 
     @PUT
     @Path("{key}")
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    void update(@PathParam("key") String key, CamelRouteTO route);
+    void update(@NotNull @PathParam("key") String key, @NotNull CamelRouteTO route);
 
+    @POST
+    @Path("restartContext")
+    void restartContext();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/CamelRouteServiceImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/CamelRouteServiceImpl.java b/syncope620/ext/camel/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/CamelRouteServiceImpl.java
index 2d85376..bc3e89c 100644
--- a/syncope620/ext/camel/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/CamelRouteServiceImpl.java
+++ b/syncope620/ext/camel/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/CamelRouteServiceImpl.java
@@ -48,4 +48,9 @@ public class CamelRouteServiceImpl extends AbstractServiceImpl implements CamelR
         logic.update(route);
     }
 
+    @Override
+    public void restartContext() {
+        logic.restartContext();
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/fit/reference/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/pom.xml b/syncope620/fit/reference/pom.xml
index ec094cb..fd8583b 100644
--- a/syncope620/fit/reference/pom.xml
+++ b/syncope620/fit/reference/pom.xml
@@ -135,6 +135,12 @@ under the License.
     
     <!-- TEST -->
     <dependency>
+      <groupId>org.apache.syncope.ext.camel</groupId>
+      <artifactId>syncope-ext-camel-rest-cxf</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>          
+    </dependency>
+    <dependency>
       <groupId>org.apache.syncope.client</groupId>
       <artifactId>syncope-client-lib</artifactId>
       <version>${project.version}</version>
@@ -440,6 +446,22 @@ under the License.
           <artifactId>syncope-server-workflow-activiti</artifactId>
           <version>${project.version}</version>
         </dependency>
+
+        <dependency>
+          <groupId>org.apache.syncope.ext.camel</groupId>
+          <artifactId>syncope-ext-camel-rest-cxf</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.syncope.ext.camel</groupId>
+          <artifactId>syncope-ext-camel-persistence-jpa</artifactId>
+          <version>${project.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.syncope.ext.camel</groupId>
+          <artifactId>syncope-ext-camel-provisioning</artifactId>
+          <version>${project.version}</version>
+        </dependency>
       </dependencies>
       
       <build>

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/fit/reference/src/main/resources/log4j2.xml
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/main/resources/log4j2.xml b/syncope620/fit/reference/src/main/resources/log4j2.xml
index d8acf8c..0ed8903 100644
--- a/syncope620/fit/reference/src/main/resources/log4j2.xml
+++ b/syncope620/fit/reference/src/main/resources/log4j2.xml
@@ -113,10 +113,16 @@ under the License.
       <appender-ref ref="connid"/>
     </asyncLogger>
     
+    <asyncLogger name="org.apache.syncope.server.provisioning" additivity="false" level="INFO">
+      <appender-ref ref="main"/>
+    </asyncLogger>
     <asyncLogger name="org.springframework" additivity="false" level="INFO">
       <appender-ref ref="main"/>
     </asyncLogger>
-     
+    <asyncLogger name="org.apache.camel" additivity="false" level="ERROR">
+      <appender-ref ref="main"/>
+    </asyncLogger>
+         
     <logger name="syncope.audit" additivity="false" level="DEBUG">
       <appender-ref ref="audit"/>
     </logger>

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/fit/reference/src/main/resources/provisioning.properties
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/main/resources/provisioning.properties b/syncope620/fit/reference/src/main/resources/provisioning.properties
new file mode 100644
index 0000000..b0c8917
--- /dev/null
+++ b/syncope620/fit/reference/src/main/resources/provisioning.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+camel.directory=${conf.directory}
+userProvisioningManager=org.apache.syncope.server.provisioning.camel.CamelUserProvisioningManager
+roleProvisioningManager=org.apache.syncope.server.provisioning.camel.CamelRoleProvisioningManager

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java
index e1e5769..cf545a7 100644
--- a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java
+++ b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/AbstractITCase.java
@@ -49,6 +49,7 @@ import org.apache.syncope.common.lib.types.AttributableType;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.CamelRouteService;
 import org.apache.syncope.common.rest.api.service.ConfigurationService;
 import org.apache.syncope.common.rest.api.service.ConnectorService;
 import org.apache.syncope.common.rest.api.service.EntitlementService;
@@ -177,6 +178,8 @@ public abstract class AbstractITCase {
     protected static PolicyService policyService;
 
     protected static SecurityQuestionService securityQuestionService;
+    
+    protected static CamelRouteService camelRouteService;
 
     @Autowired
     protected DataSource testDataSource;
@@ -228,6 +231,7 @@ public abstract class AbstractITCase {
         notificationService = adminClient.getService(NotificationService.class);
         schemaService = adminClient.getService(SchemaService.class);
         securityQuestionService = adminClient.getService(SecurityQuestionService.class);
+        camelRouteService = adminClient.getService(CamelRouteService.class);
     }
 
     protected static String getUUIDString() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ActivitiDetector.java
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ActivitiDetector.java b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ActivitiDetector.java
index 03b686b..f16dbe6 100644
--- a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ActivitiDetector.java
+++ b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/ActivitiDetector.java
@@ -19,13 +19,9 @@
 package org.apache.syncope.fit.server.reference;
 
 import org.apache.syncope.common.rest.api.service.SyncopeService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class ActivitiDetector {
 
-    private static final Logger LOG = LoggerFactory.getLogger(ActivitiDetector.class);
-
     public static boolean isActivitiEnabledForUsers(final SyncopeService syncopeService) {
         return syncopeService.info().getUserWorkflowAdapter().indexOf("Activiti") != -1;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/CamelDetector.java
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/CamelDetector.java b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/CamelDetector.java
new file mode 100644
index 0000000..81eaa4e
--- /dev/null
+++ b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/CamelDetector.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.fit.server.reference;
+
+import org.apache.syncope.common.rest.api.service.SyncopeService;
+
+public class CamelDetector {
+
+    public static boolean isCamelEnabledForUsers(final SyncopeService syncopeService) {
+        return syncopeService.info().getUserProvisioningManager().indexOf("Camel") != -1;
+    }
+
+    public static boolean isCamelEnabledForRoles(final SyncopeService syncopeService) {
+        return syncopeService.info().getRoleProvisioningManager().indexOf("Camel") != -1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/CamelRouteITCase.java
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/CamelRouteITCase.java b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/CamelRouteITCase.java
new file mode 100644
index 0000000..46d813e
--- /dev/null
+++ b/syncope620/fit/reference/src/test/java/org/apache/syncope/fit/server/reference/CamelRouteITCase.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.fit.server.reference;
+
+import static org.apache.syncope.fit.server.reference.AbstractITCase.syncopeService;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.List;
+import org.apache.syncope.common.lib.to.CamelRouteTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.junit.Assume;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.JVM)
+public class CamelRouteITCase extends AbstractITCase {
+
+    @Test
+    public void userRoutes() {
+        Assume.assumeTrue(CamelDetector.isCamelEnabledForUsers(syncopeService));
+
+        List<CamelRouteTO> userRoutes = camelRouteService.list(SubjectType.USER);
+        assertNotNull(userRoutes);
+        assertEquals(15, userRoutes.size());
+        for (CamelRouteTO route : userRoutes) {
+            assertNotNull(route.getContent());
+        }
+    }
+
+    @Test
+    public void roleRoutes() {
+        Assume.assumeTrue(CamelDetector.isCamelEnabledForRoles(syncopeService));
+
+        List<CamelRouteTO> roleRoutes = camelRouteService.list(SubjectType.ROLE);
+        assertNotNull(roleRoutes);
+        assertEquals(7, roleRoutes.size());
+        for (CamelRouteTO route : roleRoutes) {
+            assertNotNull(route.getContent());
+        }
+    }
+
+    private CamelRouteTO doUpdate(final String key, String content) {
+        CamelRouteTO route = camelRouteService.read(key);
+        route.setContent(content);
+        camelRouteService.update(route.getKey(), route);
+        //getting new route definition
+        return camelRouteService.read(key);
+    }
+
+    @Test
+    public void update() {
+        Assume.assumeTrue(CamelDetector.isCamelEnabledForUsers(syncopeService));
+
+        CamelRouteTO oldRoute = camelRouteService.read("createUser");
+        assertNotNull(oldRoute);
+        String routeContent = "<route id=\"createUser\">\n"
+                + "  <from uri=\"direct:createUser\"/>\n"
+                + "  <setProperty propertyName=\"actual\">\n"
+                + "    <simple>${body}</simple>\n"
+                + "  </setProperty>\n"
+                + "  <doTry>\n"
+                + "    <bean ref=\"uwfAdapter\" method=\"create(${body},${property.disablePwdPolicyCheck},\n"
+                + "                             ${property.enabled},${property.storePassword})\"/>\n"
+                + "    <process ref=\"userCreateProcessor\" />\n"
+                + "    <to uri=\"direct:createPort\"/>\n"
+                + "    <to uri=\"log:myLog\"/>\n"
+                + "    <doCatch>        \n"
+                + "      <exception>java.lang.RuntimeException</exception>\n"
+                + "      <handled>\n"
+                + "        <constant>false</constant>\n"
+                + "      </handled>\n"
+                + "      <to uri=\"direct:createPort\"/>\n"
+                + "    </doCatch>\n"
+                + "  </doTry>\n"
+                + "</route>";
+        try {
+            CamelRouteTO route = doUpdate("createUser", routeContent);
+            assertEquals(routeContent, route.getContent());
+        } finally {
+            doUpdate(oldRoute.getKey(), oldRoute.getContent());
+        }
+    }
+
+    @Test
+    public void scriptingUpdate() {
+        Assume.assumeTrue(CamelDetector.isCamelEnabledForUsers(syncopeService));
+
+        CamelRouteTO oldRoute = camelRouteService.read("createUser");
+        //updating route content including new attribute management
+        String routeContent = "<route id=\"createUser\">\n"
+                + "  <from uri=\"direct:createUser\"/>\n"
+                + "  <setProperty propertyName=\"actual\">\n"
+                + "    <simple>${body}</simple>\n"
+                + "  </setProperty>\n"
+                + "  <setBody>\n"
+                + "   <groovy>\n"
+                + "       request.body.getPlainAttrs().get(3).getValues().set(0,\"true\")\n"
+                + "       return request.body\n"
+                + "   </groovy>\n"
+                + "  </setBody>\n"
+                + "  <doTry>\n"
+                + "      <bean ref=\"uwfAdapter\" method=\"create(${body},${property.disablePwdPolicyCheck},\n"
+                + "                            ${property.enabled},${property.storePassword})\"/>\n"
+                + "      <process ref=\"userCreateProcessor\" />\n"
+                + "      <to uri=\"direct:createPort\"/>\n"
+                + "      <doCatch>        \n"
+                + "      <exception>java.lang.RuntimeException</exception>\n"
+                + "          <handled>\n"
+                + "           <constant>false</constant>\n"
+                + "          </handled>\n"
+                + "      <to uri=\"direct:createPort\"/>\n"
+                + "      </doCatch>\n"
+                + "   </doTry>\n"
+                + "</route>";
+        try {
+            doUpdate("createUser", routeContent);
+
+            //creating new schema attribute for user
+            PlainSchemaTO schemaTO = new PlainSchemaTO();
+            schemaTO.setKey("camelAttribute");
+            schemaTO.setType(AttrSchemaType.String);
+            createSchema(AttributableType.USER, SchemaType.PLAIN, schemaTO);
+
+            UserTO userTO = new UserTO();
+            String userId = getUUIDString() + "camelUser@syncope.apache.org";
+            userTO.setUsername(userId);
+            userTO.setPassword("password");
+            userTO.getPlainAttrs().add(attrTO("userId", userId));
+            userTO.getPlainAttrs().add(attrTO("fullname", userId));
+            userTO.getPlainAttrs().add(attrTO("surname", userId));
+            userTO.getPlainAttrs().add(attrTO("camelAttribute", "false"));
+
+            userTO = createUser(userTO);
+            assertNotNull(userTO);
+            assertEquals("true", userTO.getPlainAttrs().get(3).getValues().get(0));
+        } finally {
+            doUpdate(oldRoute.getKey(), oldRoute.getContent());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java
new file mode 100644
index 0000000..4dd3991
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.persistence.jpa.spring;
+
+import javax.persistence.Entity;
+import org.apache.syncope.server.persistence.jpa.entity.AbstractEntity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
+import org.springframework.core.type.filter.AnnotationTypeFilter;
+import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
+import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
+
+public class MultiJarAwarePersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MultiJarAwarePersistenceUnitPostProcessor.class);
+
+    @Override
+    public void postProcessPersistenceUnitInfo(final MutablePersistenceUnitInfo pui) {
+        ClassPathScanningCandidateComponentProvider scanner =
+                new ClassPathScanningCandidateComponentProvider(false);
+        scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
+
+        for (BeanDefinition bd : scanner.findCandidateComponents(AbstractEntity.class.getPackage().getName())) {
+            LOG.debug("Adding JPA entity {}", bd.getBeanClassName());
+            pui.addManagedClassName(bd.getBeanClassName());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/server/persistence-jpa/src/main/resources/persistenceContextEMFactory.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/resources/persistenceContextEMFactory.xml b/syncope620/server/persistence-jpa/src/main/resources/persistenceContextEMFactory.xml
index 3337dd3..605c47c 100644
--- a/syncope620/server/persistence-jpa/src/main/resources/persistenceContextEMFactory.xml
+++ b/syncope620/server/persistence-jpa/src/main/resources/persistenceContextEMFactory.xml
@@ -26,6 +26,11 @@ under the License.
         class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
     <property name="persistenceXmlLocation" value="classpath*:META-INF/spring-persistence.xml"/>
     <property name="persistenceUnitName" value="syncopePersistenceUnit"/>
+    <property name="persistenceUnitPostProcessors">
+      <list>
+        <bean class="org.apache.syncope.server.persistence.jpa.spring.MultiJarAwarePersistenceUnitPostProcessor"/>
+      </list>
+    </property>
     <property name="dataSource" ref="dataSource"/>
     <property name="jpaVendorAdapter">
       <bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter">
@@ -38,8 +43,8 @@ under the License.
       <map>
         <!--<entry key="openjpa.Log" value="SQL=TRACE"/>
         <entry key="openjpa.ConnectionFactoryProperties" 
-               value="PrintParameters=true, PrettyPrint=true, PrettyPrintLineLength=80"/>-->
-                
+        value="PrintParameters=true, PrettyPrint=true, PrettyPrintLineLength=80"/>-->
+                                
         <entry key="openjpa.NontransactionalWrite" value="false"/>
         <entry key="openjpa.AutoDetach" value="close, commit, nontx-read, rollback"/>
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultRoleProvisioningManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultRoleProvisioningManager.java b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultRoleProvisioningManager.java
index 31a5704..c57b35a 100644
--- a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultRoleProvisioningManager.java
+++ b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultRoleProvisioningManager.java
@@ -77,7 +77,8 @@ public class DefaultRoleProvisioningManager implements RoleProvisioningManager {
         AuthContextUtil.extendAuthContext(
                 created.getResult(), RoleEntitlementUtil.getEntitlementNameFromRoleKey(created.getResult()));
 
-        List<PropagationTask> tasks = propagationManager.getRoleCreateTaskIds(created, subject.getVirAttrs());
+        List<PropagationTask> tasks =
+                propagationManager.getRoleCreateTaskIds(created, subject.getVirAttrs(), excludedResources);
         PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().getBean(
                 PropagationReporter.class);
         try {
@@ -87,16 +88,14 @@ public class DefaultRoleProvisioningManager implements RoleProvisioningManager {
             propagationReporter.onPrimaryResourceFailure(tasks);
         }
 
-        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(
-                created.getResult(), propagationReporter.getStatuses());
-        return result;
+        return new AbstractMap.SimpleEntry<>(created.getResult(), propagationReporter.getStatuses());
     }
 
     @Override
     public Map.Entry<Long, List<PropagationStatus>> create(
             final RoleTO roleTO, final Map<Long, String> roleOwnerMap, final Set<String> excludedResources) {
 
-        WorkflowResult<Long> created = rwfAdapter.create((RoleTO) roleTO);
+        WorkflowResult<Long> created = rwfAdapter.create(roleTO);
         AttrTO roleOwner = roleTO.getPlainAttrMap().get(StringUtils.EMPTY);
         if (roleOwner != null) {
             roleOwnerMap.put(created.getResult(), roleOwner.getValues().iterator().next());
@@ -110,7 +109,7 @@ public class DefaultRoleProvisioningManager implements RoleProvisioningManager {
 
         taskExecutor.execute(tasks);
 
-        return new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(created.getResult(), null);
+        return new AbstractMap.SimpleEntry<>(created.getResult(), null);
     }
 
     @Override
@@ -126,8 +125,8 @@ public class DefaultRoleProvisioningManager implements RoleProvisioningManager {
 
         List<PropagationTask> tasks = propagationManager.getRoleUpdateTaskIds(updated,
                 subjectMod.getVirAttrsToRemove(), subjectMod.getVirAttrsToUpdate());
-        PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().getBean(
-                PropagationReporter.class);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
         try {
             taskExecutor.execute(tasks, propagationReporter);
         } catch (PropagationException e) {
@@ -135,16 +134,16 @@ public class DefaultRoleProvisioningManager implements RoleProvisioningManager {
             propagationReporter.onPrimaryResourceFailure(tasks);
         }
 
-        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(
+        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<>(
                 updated.getResult(), propagationReporter.getStatuses());
         return result;
     }
 
     @Override
-    public List<PropagationStatus> delete(final Long subjectId) {
+    public List<PropagationStatus> delete(final Long subjectKey) {
         final List<Role> toBeDeprovisioned = new ArrayList<>();
 
-        final Role syncopeRole = roleDAO.find(subjectId);
+        final Role syncopeRole = roleDAO.find(subjectKey);
 
         if (syncopeRole != null) {
             toBeDeprovisioned.add(syncopeRole);
@@ -182,7 +181,7 @@ public class DefaultRoleProvisioningManager implements RoleProvisioningManager {
         }
 
         try {
-            rwfAdapter.delete(subjectId);
+            rwfAdapter.delete(subjectKey);
         } catch (RuntimeException e) {
             throw e;
         }
@@ -198,15 +197,15 @@ public class DefaultRoleProvisioningManager implements RoleProvisioningManager {
 
     @Override
     public List<PropagationStatus> deprovision(final Long roleKey, final Collection<String> resources) {
-        final Role role = roleDAO.authFetch(roleKey);
+        Role role = roleDAO.authFetch(roleKey);
 
-        final Set<String> noPropResourceName = role.getResourceNames();
+        Set<String> noPropResourceName = role.getResourceNames();
         noPropResourceName.removeAll(resources);
 
-        final List<PropagationTask> tasks = propagationManager.getRoleDeleteTaskIds(roleKey, new HashSet<String>(
-                resources), noPropResourceName);
-        PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().getBean(
-                PropagationReporter.class);
+        List<PropagationTask> tasks = propagationManager.getRoleDeleteTaskIds(
+                roleKey, new HashSet<>(resources), noPropResourceName);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
         try {
             taskExecutor.execute(tasks, propagationReporter);
         } catch (PropagationException e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultUserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultUserProvisioningManager.java b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultUserProvisioningManager.java
index 85a489b..cbe64f0 100644
--- a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultUserProvisioningManager.java
+++ b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/DefaultUserProvisioningManager.java
@@ -89,8 +89,8 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
 
         List<PropagationTask> tasks = propagationManager.getUserCreateTaskIds(
                 created, userTO.getPassword(), userTO.getVirAttrs(), excludedResources, userTO.getMemberships());
-        PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().
-                getBean(PropagationReporter.class);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
         try {
             taskExecutor.execute(tasks, propagationReporter);
         } catch (PropagationException e) {
@@ -98,9 +98,7 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
             propagationReporter.onPrimaryResourceFailure(tasks);
         }
 
-        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<>(
-                created.getResult().getKey(), propagationReporter.getStatuses());
-        return result;
+        return new AbstractMap.SimpleEntry<>(created.getResult().getKey(), propagationReporter.getStatuses());
     }
 
     @Override
@@ -160,10 +158,15 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
 
     @Override
     public List<PropagationStatus> delete(final Long subjectId, final Set<String> excludedResources) {
+        // Note here that we can only notify about "delete", not any other
+        // task defined in workflow process definition: this because this
+        // information could only be available after uwfAdapter.delete(), which
+        // will also effectively remove user from db, thus making virtually
+        // impossible by NotificationManager to fetch required user information
         List<PropagationTask> tasks = propagationManager.getUserDeleteTaskIds(subjectId, excludedResources);
 
-        PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().
-                getBean(PropagationReporter.class);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
         try {
             taskExecutor.execute(tasks, propagationReporter);
         } catch (PropagationException e) {
@@ -289,14 +292,14 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
     }
 
     @Override
-    public Map.Entry<Long, List<PropagationStatus>> update(final UserMod userMod, final Long id,
+    public Map.Entry<Long, List<PropagationStatus>> update(final UserMod userMod, final Long key,
             final ProvisioningResult result, final Boolean enabled, final Set<String> excludedResources) {
 
         WorkflowResult<Map.Entry<UserMod, Boolean>> updated;
         try {
             updated = uwfAdapter.update(userMod);
         } catch (Exception e) {
-            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", id, e);
+            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", key, e);
 
             result.setStatus(ProvisioningResult.Status.FAILURE);
             result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
@@ -307,15 +310,15 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager {
         }
 
         if (enabled != null) {
-            User user = userDAO.find(id);
+            User user = userDAO.find(key);
 
             WorkflowResult<Long> enableUpdate = null;
             if (user.isSuspended() == null) {
-                enableUpdate = uwfAdapter.activate(id, null);
+                enableUpdate = uwfAdapter.activate(key, null);
             } else if (enabled && user.isSuspended()) {
-                enableUpdate = uwfAdapter.reactivate(id);
+                enableUpdate = uwfAdapter.reactivate(key);
             } else if (!enabled && !user.isSuspended()) {
-                enableUpdate = uwfAdapter.suspend(id);
+                enableUpdate = uwfAdapter.suspend(key);
             }
 
             if (enableUpdate != null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/sync/UserSyncResultHandlerImpl.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/sync/UserSyncResultHandlerImpl.java b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/sync/UserSyncResultHandlerImpl.java
index 9a7e1ba..23915b8 100644
--- a/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/sync/UserSyncResultHandlerImpl.java
+++ b/syncope620/server/provisioning-java/src/main/java/org/apache/syncope/server/provisioning/java/sync/UserSyncResultHandlerImpl.java
@@ -73,7 +73,6 @@ public class UserSyncResultHandlerImpl extends AbstractSyncResultHandler impleme
         UserTO userTO = UserTO.class.cast(subjectTO);
 
         Boolean enabled = syncUtilities.readEnabled(delta.getObject(), profile.getTask());
-        //Delegate User Workflow Creation and its Propagation to provisioning manager
         Map.Entry<Long, List<PropagationStatus>> created = userProvisioningManager.create(userTO, true, true, enabled,
                 Collections.singleton(profile.getTask().getResource().getKey()));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/server/rest-cxf/src/main/resources/META-INF/org.apache.cxf.Logger
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/resources/META-INF/org.apache.cxf.Logger b/syncope620/server/rest-cxf/src/main/resources/META-INF/org.apache.cxf.Logger
new file mode 100644
index 0000000..6e7bd36
--- /dev/null
+++ b/syncope620/server/rest-cxf/src/main/resources/META-INF/org.apache.cxf.Logger
@@ -0,0 +1 @@
+org.apache.cxf.common.logging.Slf4jLogger

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/server/workflow-java/src/main/resources/workflowContext.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-java/src/main/resources/workflowContext.xml b/syncope620/server/workflow-java/src/main/resources/workflowContext.xml
index 9323891..54ac139 100644
--- a/syncope620/server/workflow-java/src/main/resources/workflowContext.xml
+++ b/syncope620/server/workflow-java/src/main/resources/workflowContext.xml
@@ -22,7 +22,7 @@ under the License.
        xsi:schemaLocation="http://www.springframework.org/schema/beans   
                            http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-  <bean class="${uwfAdapter}"/>
-  <bean class="${rwfAdapter}"/>
+  <bean id="uwfAdapter" class="${uwfAdapter}"/>
+  <bean id="rwfAdapter" class="${rwfAdapter}"/>
     
 </beans>


[3/3] syncope git commit: [SYNCOPE-620] Several enhancements

Posted by il...@apache.org.
[SYNCOPE-620] Several enhancements


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

Branch: refs/heads/2_0_X
Commit: 721f3276e6eb5b54dd6750365c37df83b63da458
Parents: 42f78fe
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Feb 3 13:03:04 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Feb 3 13:03:04 2015 +0100

----------------------------------------------------------------------
 syncope620/fit/reference/pom.xml                |  21 ++
 .../resources/light/provisioning.properties     |  18 ++
 .../main/resources/light/workflow.properties    |  20 ++
 .../init/ImplementationClassNamesLoader.java    | 116 ++++----
 ...ltiJarAwarePersistenceUnitPostProcessor.java |   6 +-
 .../rest/cxf/QueryResourceInfoComparator.java   | 114 ++++++++
 .../rest/cxf/RestServiceExceptionMapper.java    | 285 +++++++++++++++++++
 .../cxf/service/RestServiceExceptionMapper.java | 285 -------------------
 .../META-INF/cxf/org.apache.cxf.Logger          |   1 +
 .../src/main/resources/restCXFContext.xml       |   5 +-
 10 files changed, 525 insertions(+), 346 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/fit/reference/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/pom.xml b/syncope620/fit/reference/pom.xml
index fd8583b..0fa46dd 100644
--- a/syncope620/fit/reference/pom.xml
+++ b/syncope620/fit/reference/pom.xml
@@ -435,6 +435,27 @@ under the License.
     </profile>
     
     <profile>
+      <id>light</id>
+      
+      <build>
+        <resources>
+          <resource>
+            <directory>src/main/resources</directory>
+            <filtering>true</filtering>
+            <excludes>
+              <exclude>workflow.properties</exclude>
+              <exclude>provisioning.properties</exclude>
+            </excludes>
+          </resource>
+          <resource>
+            <directory>src/main/resources/light</directory>
+            <filtering>true</filtering>
+          </resource>
+        </resources>
+      </build>
+    </profile>
+    
+    <profile>
       <id>all</id>
       <activation>
         <activeByDefault>true</activeByDefault>

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/fit/reference/src/main/resources/light/provisioning.properties
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/main/resources/light/provisioning.properties b/syncope620/fit/reference/src/main/resources/light/provisioning.properties
new file mode 100644
index 0000000..2ed4d0d
--- /dev/null
+++ b/syncope620/fit/reference/src/main/resources/light/provisioning.properties
@@ -0,0 +1,18 @@
+# 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.
+userProvisioningManager=org.apache.syncope.server.provisioning.java.DefaultUserProvisioningManager
+roleProvisioningManager=org.apache.syncope.server.provisioning.java.DefaultRoleProvisioningManager

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/fit/reference/src/main/resources/light/workflow.properties
----------------------------------------------------------------------
diff --git a/syncope620/fit/reference/src/main/resources/light/workflow.properties b/syncope620/fit/reference/src/main/resources/light/workflow.properties
new file mode 100644
index 0000000..2c08d50
--- /dev/null
+++ b/syncope620/fit/reference/src/main/resources/light/workflow.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+wf.directory=${conf.directory}
+jobExecutorActivate=false
+uwfAdapter=org.apache.syncope.server.workflow.java.DefaultUserWorkflowAdapter
+rwfAdapter=org.apache.syncope.server.workflow.java.DefaultRoleWorkflowAdapter
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java
index 3546089..2a5098c 100644
--- a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java
@@ -18,12 +18,13 @@
  */
 package org.apache.syncope.server.logic.init;
 
-import java.io.IOException;
+import java.lang.reflect.Modifier;
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.server.provisioning.api.job.PushJob;
 import org.apache.syncope.server.provisioning.api.job.SyncJob;
 import org.apache.syncope.server.provisioning.api.job.TaskJob;
@@ -36,11 +37,10 @@ import org.apache.syncope.server.persistence.api.SyncopeLoader;
 import org.apache.syncope.server.persistence.api.attrvalue.validation.Validator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.ResourcePatternResolver;
-import org.springframework.core.type.ClassMetadata;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
 import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.filter.AssignableTypeFilter;
 import org.springframework.stereotype.Component;
 import org.springframework.util.ClassUtils;
 
@@ -68,9 +68,6 @@ public class ImplementationClassNamesLoader implements SyncopeLoader {
      */
     private static final Logger LOG = LoggerFactory.getLogger(ImplementationClassNamesLoader.class);
 
-    @Autowired
-    private ResourcePatternResolver resResolver;
-
     private Map<Type, Set<String>> classNames;
 
     @Override
@@ -87,59 +84,62 @@ public class ImplementationClassNamesLoader implements SyncopeLoader {
             classNames.put(type, new HashSet<String>());
         }
 
-        try {
-            for (Resource resource : resResolver.getResources("classpath*:**/*.class")) {
-                ClassMetadata metadata = factory.getMetadataReader(resource).getClassMetadata();
-
-                try {
-                    Class<?> clazz = ClassUtils.forName(metadata.getClassName(), ClassUtils.getDefaultClassLoader());
-                    Set<Class<?>> interfaces = ClassUtils.getAllInterfacesForClassAsSet(clazz);
-
-                    if (interfaces.contains(Reportlet.class) && !metadata.isAbstract()) {
-                        classNames.get(Type.REPORTLET).add(clazz.getName());
-                    }
-
-                    if ((interfaces.contains(TaskJob.class))
-                            && !metadata.isAbstract()
-                            && !SyncJob.class.getName().equals(metadata.getClassName())
-                            && !PushJob.class.getName().equals(metadata.getClassName())) {
-
-                        classNames.get(Type.TASKJOB).add(metadata.getClassName());
-                    }
-
-                    if (interfaces.contains(SyncActions.class) && !metadata.isAbstract()) {
-                        classNames.get(Type.SYNC_ACTIONS).add(metadata.getClassName());
-                    }
-
-                    if (interfaces.contains(PushActions.class) && !metadata.isAbstract()) {
-                        classNames.get(Type.PUSH_ACTIONS).add(metadata.getClassName());
-                    }
-
-                    if (interfaces.contains(SyncCorrelationRule.class) && !metadata.isAbstract()) {
-                        classNames.get(Type.SYNC_CORRELATION_RULE).add(metadata.getClassName());
-                    }
-
-                    // TODO: SYNCOPE-631
-                    /* if (interfaces.contains(PushCorrelationRule.class) && !metadata.isAbstract()) {
-                     * classNames.get(Type.PUSH_CORRELATION_RULES).add(metadata.getClassName());
-                     * } */
-                    if (interfaces.contains(PropagationActions.class) && !metadata.isAbstract()) {
-                        classNames.get(Type.PROPAGATION_ACTIONS).add(metadata.getClassName());
-                    }
-
-                    if (interfaces.contains(Validator.class) && !metadata.isAbstract()) {
-                        classNames.get(Type.VALIDATOR).add(metadata.getClassName());
-                    }
-                } catch (ClassNotFoundException e) {
-                    LOG.warn("Could not load class {}", metadata.getClassName());
-                } catch (LinkageError e) {
-                    LOG.warn("Could not link class {}", metadata.getClassName());
+        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
+        scanner.addIncludeFilter(new AssignableTypeFilter(Reportlet.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(TaskJob.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(SyncActions.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(PushActions.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(SyncCorrelationRule.class));
+        // TODO: SYNCOPE-631
+        //scanner.addIncludeFilter(new AssignableTypeFilter(PushCorrelationRule.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(PropagationActions.class));
+        scanner.addIncludeFilter(new AssignableTypeFilter(Validator.class));
+
+        for (BeanDefinition bd : scanner.findCandidateComponents(StringUtils.EMPTY)) {
+            try {
+                Class<?> clazz = ClassUtils.resolveClassName(
+                        bd.getBeanClassName(), ClassUtils.getDefaultClassLoader());
+                boolean isAbsractClazz = Modifier.isAbstract(clazz.getModifiers());
+
+                if (Reportlet.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                    classNames.get(Type.REPORTLET).add(clazz.getName());
+                }
+
+                if (TaskJob.class.isAssignableFrom(clazz) && !isAbsractClazz
+                        && !SyncJob.class.isAssignableFrom(clazz)
+                        && !PushJob.class.isAssignableFrom(clazz)) {
+
+                    classNames.get(Type.TASKJOB).add(bd.getBeanClassName());
+                }
+
+                if (SyncActions.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                    classNames.get(Type.SYNC_ACTIONS).add(bd.getBeanClassName());
+                }
+
+                if (PushActions.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                    classNames.get(Type.PUSH_ACTIONS).add(bd.getBeanClassName());
                 }
+
+                if (SyncCorrelationRule.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                    classNames.get(Type.SYNC_CORRELATION_RULE).add(bd.getBeanClassName());
+                }
+
+                // TODO: SYNCOPE-631
+                /* if (PushCorrelationRule.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                 * classNames.get(Type.PUSH_CORRELATION_RULES).add(metadata.getClassName());
+                 * } */
+                
+                if (PropagationActions.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                    classNames.get(Type.PROPAGATION_ACTIONS).add(bd.getBeanClassName());
+                }
+
+                if (Validator.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                    classNames.get(Type.VALIDATOR).add(bd.getBeanClassName());
+                }
+            } catch (Throwable t) {
+                LOG.warn("Could not inspect class {}", bd.getBeanClassName(), t);
             }
-        } catch (IOException e) {
-            LOG.error("While searching for implementatiom classes", e);
         }
-
         classNames = Collections.unmodifiableMap(classNames);
 
         LOG.debug("Implementation classes found: {}", classNames);

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java
index 4dd3991..bd26305 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java
@@ -28,14 +28,16 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
 import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
 import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
 
+/**
+ * Allows having JPA entities spread in several JAR files; this is needed in order to support the Syncope extensions.
+ */
 public class MultiJarAwarePersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
 
     private static final Logger LOG = LoggerFactory.getLogger(MultiJarAwarePersistenceUnitPostProcessor.class);
 
     @Override
     public void postProcessPersistenceUnitInfo(final MutablePersistenceUnitInfo pui) {
-        ClassPathScanningCandidateComponentProvider scanner =
-                new ClassPathScanningCandidateComponentProvider(false);
+        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
         scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
 
         for (BeanDefinition bd : scanner.findCandidateComponents(AbstractEntity.class.getPackage().getName())) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/QueryResourceInfoComparator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/QueryResourceInfoComparator.java b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/QueryResourceInfoComparator.java
new file mode 100644
index 0000000..0f2768c
--- /dev/null
+++ b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/QueryResourceInfoComparator.java
@@ -0,0 +1,114 @@
+/*
+ * 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.server.rest.cxf;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.jaxrs.ext.ResourceComparator;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfoComparator;
+import org.apache.cxf.jaxrs.model.Parameter;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.message.Message;
+
+public class QueryResourceInfoComparator extends OperationResourceInfoComparator implements ResourceComparator {
+
+    public QueryResourceInfoComparator() {
+        super(null, null);
+    }
+
+    @Override
+    public int compare(final ClassResourceInfo cri1, final ClassResourceInfo cri2, final Message message) {
+        // Leave Class selection to CXF
+        return 0;
+    }
+
+    @Override
+    public int compare(final OperationResourceInfo oper1, final OperationResourceInfo oper2, final Message message) {
+        // Check if CXF can make a decision
+        int cxfResult = super.compare(oper1, oper2);
+        if (cxfResult != 0) {
+            return cxfResult;
+        }
+
+        int op1Counter = getMatchingRate(oper1, message);
+        int op2Counter = getMatchingRate(oper2, message);
+
+        return op1Counter == op2Counter
+                ? 0
+                : op1Counter < op2Counter
+                ? 1
+                : -1;
+    }
+
+    /**
+     * This method calculates a number indicating a good or bad match between values provided within the request and
+     * expected method parameters. A higher number means a better match.
+     *
+     * @param operation The operation to be rated, based on contained parameterInfo values.
+     * @param message A message containing query and header values from user request
+     * @return A positive or negative number, indicating a good match between query and method
+     */
+    protected int getMatchingRate(final OperationResourceInfo operation, final Message message) {
+        List<Parameter> params = operation.getParameters();
+        if (params == null || params.isEmpty()) {
+            return 0;
+        }
+
+        // Get Request QueryParams
+        String query = (String) message.get(Message.QUERY_STRING);
+        String path = (String) message.get(Message.REQUEST_URI);
+        Map<String, List<String>> qParams = JAXRSUtils.getStructuredParams(query, "&", true, false);
+        Map<String, List<String>> mParams = JAXRSUtils.getMatrixParams(path, true);
+        // Get Request Headers
+        Map<?, ?> qHeader = (java.util.Map<?, ?>) message.get(Message.PROTOCOL_HEADERS);
+
+        int rate = 0;
+        for (Parameter p : params) {
+            switch (p.getType()) {
+                case QUERY:
+                    if (qParams.containsKey(p.getName())) {
+                        rate += 2;
+                    } else if (p.getDefaultValue() == null) {
+                        rate -= 1;
+                    }
+                    break;
+                case MATRIX:
+                    if (mParams.containsKey(p.getName())) {
+                        rate += 2;
+                    } else if (p.getDefaultValue() == null) {
+                        rate -= 1;
+                    }
+                    break;
+                case HEADER:
+                    if (qHeader.containsKey(p.getName())) {
+                        rate += 2;
+                    } else if (p.getDefaultValue() == null) {
+                        rate -= 1;
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+        return rate;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/RestServiceExceptionMapper.java
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/RestServiceExceptionMapper.java b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/RestServiceExceptionMapper.java
new file mode 100644
index 0000000..dac6a1c
--- /dev/null
+++ b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/RestServiceExceptionMapper.java
@@ -0,0 +1,285 @@
+/*
+ * 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.server.rest.cxf;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.persistence.EntityExistsException;
+import javax.persistence.PersistenceException;
+import javax.persistence.RollbackException;
+import javax.validation.ValidationException;
+import javax.ws.rs.BadRequestException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.jaxrs.validation.ValidationExceptionMapper;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.ErrorTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.server.misc.security.UnauthorizedRoleException;
+import org.apache.syncope.server.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.server.persistence.api.attrvalue.validation.ParsingValidationException;
+import org.apache.syncope.server.persistence.api.dao.DuplicateException;
+import org.apache.syncope.server.persistence.api.dao.NotFoundException;
+import org.apache.syncope.server.workflow.api.WorkflowException;
+import org.identityconnectors.framework.common.exceptions.ConfigurationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.orm.jpa.JpaSystemException;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.transaction.TransactionSystemException;
+
+@Provider
+public class RestServiceExceptionMapper implements ExceptionMapper<Exception>, ResponseExceptionMapper<Exception> {
+
+    private static final String BASIC_REALM_UNAUTHORIZED = "Basic realm=\"Apache Syncope authentication\"";
+
+    private static final Logger LOG = LoggerFactory.getLogger(RestServiceExceptionMapper.class);
+
+    private final ValidationExceptionMapper validationEM = new ValidationExceptionMapper();
+
+    @Override
+    public Response toResponse(final Exception ex) {
+        LOG.error("Exception thrown by REST method: " + ex.getMessage(), ex);
+
+        ResponseBuilder builder;
+
+        if (ex instanceof SyncopeClientException) {
+            SyncopeClientException sce = (SyncopeClientException) ex;
+            builder = sce.isComposite()
+                    ? getSyncopeClientCompositeExceptionResponse(sce.asComposite())
+                    : getSyncopeClientExceptionResponse(sce);
+        } else if (ex instanceof WebApplicationException) {
+            Response response = ((WebApplicationException) ex).getResponse();
+
+            ErrorTO error = new ErrorTO();
+            error.setStatus(response.getStatus());
+            error.setType(ClientExceptionType.Unknown);
+            error.getElements().add(getExMessage(ex));
+
+            builder = JAXRSUtils.fromResponse(response).entity(error);
+        } else if (ex instanceof AccessDeniedException) {
+            builder = Response.status(Response.Status.UNAUTHORIZED).
+                    header(HttpHeaders.WWW_AUTHENTICATE, BASIC_REALM_UNAUTHORIZED);
+        } else if (ex instanceof UnauthorizedRoleException) {
+            builder = builder(Response.Status.UNAUTHORIZED, ClientExceptionType.UnauthorizedRole, getExMessage(ex));
+        } else if (ex instanceof EntityExistsException || ex instanceof DuplicateException) {
+            builder = builder(Response.Status.CONFLICT, ClientExceptionType.EntityExists, getExMessage(ex));
+        } else if (ex instanceof DataIntegrityViolationException) {
+            builder = builder(Response.Status.CONFLICT, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
+        } else {
+            builder = processNotFoundExceptions(ex);
+            if (builder == null) {
+                builder = processInvalidEntityExceptions(ex);
+                if (builder == null) {
+                    builder = processBadRequestExceptions(ex);
+                }
+                // process JAX-RS validation errors
+                if (builder == null && ex instanceof ValidationException) {
+                    builder = JAXRSUtils.fromResponse(validationEM.toResponse((ValidationException) ex)).
+                            header(RESTHeaders.ERROR_CODE, ClientExceptionType.RESTValidation.getHeaderValue()).
+                            header(RESTHeaders.ERROR_INFO,
+                                    ClientExceptionType.RESTValidation.getInfoHeaderValue(getExMessage(ex)));
+
+                    ErrorTO error = new ErrorTO();
+                    error.setStatus(ClientExceptionType.RESTValidation.getResponseStatus().getStatusCode());
+                    error.setType(ClientExceptionType.RESTValidation);
+                    error.getElements().add(getExMessage(ex));
+                    builder.entity(error);
+                }
+                // ...or just report as InternalServerError
+                if (builder == null) {
+                    builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR).
+                            header(RESTHeaders.ERROR_INFO,
+                                    ClientExceptionType.Unknown.getInfoHeaderValue(getExMessage(ex)));
+
+                    ErrorTO error = new ErrorTO();
+                    error.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
+                    error.setType(ClientExceptionType.Unknown);
+                    error.getElements().add(getExMessage(ex));
+                    builder.entity(error);
+                }
+            }
+        }
+
+        return builder.build();
+    }
+
+    @Override
+    public Exception fromResponse(final Response r) {
+        throw new UnsupportedOperationException(
+                "Call of fromResponse() method is not expected in RestServiceExceptionMapper");
+    }
+
+    private ResponseBuilder getSyncopeClientExceptionResponse(final SyncopeClientException ex) {
+        ResponseBuilder builder = Response.status(ex.getType().getResponseStatus());
+        builder.header(RESTHeaders.ERROR_CODE, ex.getType().getHeaderValue());
+
+        ErrorTO error = new ErrorTO();
+        error.setStatus(ex.getType().getResponseStatus().getStatusCode());
+        error.setType(ex.getType());
+
+        for (String element : ex.getElements()) {
+            builder.header(RESTHeaders.ERROR_INFO, ex.getType().getInfoHeaderValue(element));
+            error.getElements().add(element);
+        }
+
+        return builder.entity(error);
+    }
+
+    private ResponseBuilder getSyncopeClientCompositeExceptionResponse(final SyncopeClientCompositeException ex) {
+        if (ex.getExceptions().size() == 1) {
+            return getSyncopeClientExceptionResponse(ex.getExceptions().iterator().next());
+        }
+
+        ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
+
+        List<ErrorTO> errors = new ArrayList<ErrorTO>();
+        for (SyncopeClientException sce : ex.getExceptions()) {
+            builder.header(RESTHeaders.ERROR_CODE, sce.getType().getHeaderValue());
+
+            ErrorTO error = new ErrorTO();
+            error.setStatus(sce.getType().getResponseStatus().getStatusCode());
+            error.setType(sce.getType());
+
+            for (String element : sce.getElements()) {
+                builder.header(RESTHeaders.ERROR_INFO, ex.getType().getInfoHeaderValue(element));
+                error.getElements().add(element);
+            }
+
+            errors.add(error);
+        }
+
+        return builder.entity(errors);
+    }
+
+    private ResponseBuilder processNotFoundExceptions(final Exception ex) {
+        if (ex instanceof javax.ws.rs.NotFoundException || ex instanceof NotFoundException) {
+            return builder(Response.Status.NOT_FOUND, ClientExceptionType.NotFound, getExMessage(ex));
+        }
+
+        return null;
+    }
+
+    private ResponseBuilder processInvalidEntityExceptions(final Exception ex) {
+        InvalidEntityException iee = null;
+
+        if (ex instanceof InvalidEntityException) {
+            iee = (InvalidEntityException) ex;
+        }
+        if (ex instanceof TransactionSystemException && ex.getCause() instanceof RollbackException
+                && ex.getCause().getCause() instanceof InvalidEntityException) {
+
+            iee = (InvalidEntityException) ex.getCause().getCause();
+        }
+
+        if (iee != null) {
+            ClientExceptionType exType =
+                    iee.getEntityClassSimpleName().endsWith("Policy")
+                            ? ClientExceptionType.InvalidPolicy
+                            : ClientExceptionType.valueOf("Invalid" + iee.getEntityClassSimpleName());
+
+            ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
+            builder.header(RESTHeaders.ERROR_CODE, exType.getHeaderValue());
+
+            ErrorTO error = new ErrorTO();
+            error.setStatus(exType.getResponseStatus().getStatusCode());
+            error.setType(exType);
+
+            for (Map.Entry<Class<?>, Set<EntityViolationType>> violation : iee.getViolations().entrySet()) {
+                for (EntityViolationType violationType : violation.getValue()) {
+                    builder.header(RESTHeaders.ERROR_INFO,
+                            exType.getInfoHeaderValue(violationType.name() + ": " + violationType.getMessage()));
+                    error.getElements().add(violationType.name() + ": " + violationType.getMessage());
+                }
+            }
+
+            return builder;
+        }
+
+        return null;
+    }
+
+    private ResponseBuilder processBadRequestExceptions(final Exception ex) {
+        ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
+
+        // This exception might be raised by Activiti (if enabled)
+        Class<?> ibatisPersistenceException = null;
+        try {
+            ibatisPersistenceException = Class.forName("org.apache.ibatis.exceptions.PersistenceException");
+        } catch (ClassNotFoundException e) {
+            // ignore
+        }
+
+        if (ex instanceof BadRequestException) {
+            if (((BadRequestException) ex).getResponse() == null) {
+                return builder;
+            } else {
+                return JAXRSUtils.fromResponse(((BadRequestException) ex).getResponse());
+            }
+        } else if (ex instanceof WorkflowException) {
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.Workflow, getExMessage(ex));
+        } else if (ex instanceof PersistenceException) {
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.GenericPersistence, getExMessage(ex));
+        } else if (ibatisPersistenceException != null && ibatisPersistenceException.isAssignableFrom(ex.getClass())) {
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.Workflow,
+                    getMessage(ex, "Currently unavailable. Please try later."));
+        } else if (ex instanceof JpaSystemException) {
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
+        } else if (ex instanceof ConfigurationException) {
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.InvalidConnIdConf, getExMessage(ex));
+        } else if (ex instanceof ParsingValidationException) {
+            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.InvalidValues, getExMessage(ex));
+        }
+
+        return null;
+    }
+
+    private ResponseBuilder builder(final Response.Status status, final ClientExceptionType hType, final String msg) {
+        ResponseBuilder builder = Response.status(status).
+                header(RESTHeaders.ERROR_CODE, hType.getHeaderValue()).
+                header(RESTHeaders.ERROR_INFO, hType.getInfoHeaderValue(msg));
+
+        ErrorTO error = new ErrorTO();
+        error.setStatus(status.getStatusCode());
+        error.setType(hType);
+        error.getElements().add(msg);
+
+        return builder.entity(error);
+    }
+
+    private String getMessage(final Throwable ex, final String msg) {
+        return (msg == null) ? getExMessage(ex) : msg;
+    }
+
+    private String getExMessage(final Throwable ex) {
+        return (ex.getCause() == null) ? ex.getMessage() : ex.getCause().getMessage();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/RestServiceExceptionMapper.java
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/RestServiceExceptionMapper.java b/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/RestServiceExceptionMapper.java
deleted file mode 100644
index fc78a54..0000000
--- a/syncope620/server/rest-cxf/src/main/java/org/apache/syncope/server/rest/cxf/service/RestServiceExceptionMapper.java
+++ /dev/null
@@ -1,285 +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.server.rest.cxf.service;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.persistence.EntityExistsException;
-import javax.persistence.PersistenceException;
-import javax.persistence.RollbackException;
-import javax.validation.ValidationException;
-import javax.ws.rs.BadRequestException;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.ResponseBuilder;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
-import org.apache.cxf.jaxrs.utils.JAXRSUtils;
-import org.apache.cxf.jaxrs.validation.ValidationExceptionMapper;
-import org.apache.syncope.common.lib.SyncopeClientCompositeException;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.ErrorTO;
-import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.common.lib.types.EntityViolationType;
-import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.server.misc.security.UnauthorizedRoleException;
-import org.apache.syncope.server.persistence.api.attrvalue.validation.InvalidEntityException;
-import org.apache.syncope.server.persistence.api.attrvalue.validation.ParsingValidationException;
-import org.apache.syncope.server.persistence.api.dao.DuplicateException;
-import org.apache.syncope.server.persistence.api.dao.NotFoundException;
-import org.apache.syncope.server.workflow.api.WorkflowException;
-import org.identityconnectors.framework.common.exceptions.ConfigurationException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.dao.DataIntegrityViolationException;
-import org.springframework.orm.jpa.JpaSystemException;
-import org.springframework.security.access.AccessDeniedException;
-import org.springframework.transaction.TransactionSystemException;
-
-@Provider
-public class RestServiceExceptionMapper implements ExceptionMapper<Exception>, ResponseExceptionMapper<Exception> {
-
-    private static final String BASIC_REALM_UNAUTHORIZED = "Basic realm=\"Apache Syncope authentication\"";
-
-    private static final Logger LOG = LoggerFactory.getLogger(RestServiceExceptionMapper.class);
-
-    private final ValidationExceptionMapper validationEM = new ValidationExceptionMapper();
-
-    @Override
-    public Response toResponse(final Exception ex) {
-        LOG.error("Exception thrown by REST method: " + ex.getMessage(), ex);
-
-        ResponseBuilder builder;
-
-        if (ex instanceof SyncopeClientException) {
-            SyncopeClientException sce = (SyncopeClientException) ex;
-            builder = sce.isComposite()
-                    ? getSyncopeClientCompositeExceptionResponse(sce.asComposite())
-                    : getSyncopeClientExceptionResponse(sce);
-        } else if (ex instanceof WebApplicationException) {
-            Response response = ((WebApplicationException) ex).getResponse();
-
-            ErrorTO error = new ErrorTO();
-            error.setStatus(response.getStatus());
-            error.setType(ClientExceptionType.Unknown);
-            error.getElements().add(getExMessage(ex));
-
-            builder = JAXRSUtils.fromResponse(response).entity(error);
-        } else if (ex instanceof AccessDeniedException) {
-            builder = Response.status(Response.Status.UNAUTHORIZED).
-                    header(HttpHeaders.WWW_AUTHENTICATE, BASIC_REALM_UNAUTHORIZED);
-        } else if (ex instanceof UnauthorizedRoleException) {
-            builder = builder(Response.Status.UNAUTHORIZED, ClientExceptionType.UnauthorizedRole, getExMessage(ex));
-        } else if (ex instanceof EntityExistsException || ex instanceof DuplicateException) {
-            builder = builder(Response.Status.CONFLICT, ClientExceptionType.EntityExists, getExMessage(ex));
-        } else if (ex instanceof DataIntegrityViolationException) {
-            builder = builder(Response.Status.CONFLICT, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
-        } else {
-            builder = processNotFoundExceptions(ex);
-            if (builder == null) {
-                builder = processInvalidEntityExceptions(ex);
-                if (builder == null) {
-                    builder = processBadRequestExceptions(ex);
-                }
-                // process JAX-RS validation errors
-                if (builder == null && ex instanceof ValidationException) {
-                    builder = JAXRSUtils.fromResponse(validationEM.toResponse((ValidationException) ex)).
-                            header(RESTHeaders.ERROR_CODE, ClientExceptionType.RESTValidation.getHeaderValue()).
-                            header(RESTHeaders.ERROR_INFO,
-                                    ClientExceptionType.RESTValidation.getInfoHeaderValue(getExMessage(ex)));
-
-                    ErrorTO error = new ErrorTO();
-                    error.setStatus(ClientExceptionType.RESTValidation.getResponseStatus().getStatusCode());
-                    error.setType(ClientExceptionType.RESTValidation);
-                    error.getElements().add(getExMessage(ex));
-                    builder.entity(error);
-                }
-                // ...or just report as InternalServerError
-                if (builder == null) {
-                    builder = Response.status(Response.Status.INTERNAL_SERVER_ERROR).
-                            header(RESTHeaders.ERROR_INFO,
-                                    ClientExceptionType.Unknown.getInfoHeaderValue(getExMessage(ex)));
-
-                    ErrorTO error = new ErrorTO();
-                    error.setStatus(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
-                    error.setType(ClientExceptionType.Unknown);
-                    error.getElements().add(getExMessage(ex));
-                    builder.entity(error);
-                }
-            }
-        }
-
-        return builder.build();
-    }
-
-    @Override
-    public Exception fromResponse(final Response r) {
-        throw new UnsupportedOperationException(
-                "Call of fromResponse() method is not expected in RestServiceExceptionMapper");
-    }
-
-    private ResponseBuilder getSyncopeClientExceptionResponse(final SyncopeClientException ex) {
-        ResponseBuilder builder = Response.status(ex.getType().getResponseStatus());
-        builder.header(RESTHeaders.ERROR_CODE, ex.getType().getHeaderValue());
-
-        ErrorTO error = new ErrorTO();
-        error.setStatus(ex.getType().getResponseStatus().getStatusCode());
-        error.setType(ex.getType());
-
-        for (String element : ex.getElements()) {
-            builder.header(RESTHeaders.ERROR_INFO, ex.getType().getInfoHeaderValue(element));
-            error.getElements().add(element);
-        }
-
-        return builder.entity(error);
-    }
-
-    private ResponseBuilder getSyncopeClientCompositeExceptionResponse(final SyncopeClientCompositeException ex) {
-        if (ex.getExceptions().size() == 1) {
-            return getSyncopeClientExceptionResponse(ex.getExceptions().iterator().next());
-        }
-
-        ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
-
-        List<ErrorTO> errors = new ArrayList<ErrorTO>();
-        for (SyncopeClientException sce : ex.getExceptions()) {
-            builder.header(RESTHeaders.ERROR_CODE, sce.getType().getHeaderValue());
-
-            ErrorTO error = new ErrorTO();
-            error.setStatus(sce.getType().getResponseStatus().getStatusCode());
-            error.setType(sce.getType());
-
-            for (String element : sce.getElements()) {
-                builder.header(RESTHeaders.ERROR_INFO, ex.getType().getInfoHeaderValue(element));
-                error.getElements().add(element);
-            }
-
-            errors.add(error);
-        }
-
-        return builder.entity(errors);
-    }
-
-    private ResponseBuilder processNotFoundExceptions(final Exception ex) {
-        if (ex instanceof javax.ws.rs.NotFoundException || ex instanceof NotFoundException) {
-            return builder(Response.Status.NOT_FOUND, ClientExceptionType.NotFound, getExMessage(ex));
-        }
-
-        return null;
-    }
-
-    private ResponseBuilder processInvalidEntityExceptions(final Exception ex) {
-        InvalidEntityException iee = null;
-
-        if (ex instanceof InvalidEntityException) {
-            iee = (InvalidEntityException) ex;
-        }
-        if (ex instanceof TransactionSystemException && ex.getCause() instanceof RollbackException
-                && ex.getCause().getCause() instanceof InvalidEntityException) {
-
-            iee = (InvalidEntityException) ex.getCause().getCause();
-        }
-
-        if (iee != null) {
-            ClientExceptionType exType =
-                    iee.getEntityClassSimpleName().endsWith("Policy")
-                            ? ClientExceptionType.InvalidPolicy
-                            : ClientExceptionType.valueOf("Invalid" + iee.getEntityClassSimpleName());
-
-            ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
-            builder.header(RESTHeaders.ERROR_CODE, exType.getHeaderValue());
-
-            ErrorTO error = new ErrorTO();
-            error.setStatus(exType.getResponseStatus().getStatusCode());
-            error.setType(exType);
-
-            for (Map.Entry<Class<?>, Set<EntityViolationType>> violation : iee.getViolations().entrySet()) {
-                for (EntityViolationType violationType : violation.getValue()) {
-                    builder.header(RESTHeaders.ERROR_INFO,
-                            exType.getInfoHeaderValue(violationType.name() + ": " + violationType.getMessage()));
-                    error.getElements().add(violationType.name() + ": " + violationType.getMessage());
-                }
-            }
-
-            return builder;
-        }
-
-        return null;
-    }
-
-    private ResponseBuilder processBadRequestExceptions(final Exception ex) {
-        ResponseBuilder builder = Response.status(Response.Status.BAD_REQUEST);
-
-        // This exception might be raised by Activiti (if enabled)
-        Class<?> ibatisPersistenceException = null;
-        try {
-            ibatisPersistenceException = Class.forName("org.apache.ibatis.exceptions.PersistenceException");
-        } catch (ClassNotFoundException e) {
-            // ignore
-        }
-
-        if (ex instanceof BadRequestException) {
-            if (((BadRequestException) ex).getResponse() == null) {
-                return builder;
-            } else {
-                return JAXRSUtils.fromResponse(((BadRequestException) ex).getResponse());
-            }
-        } else if (ex instanceof WorkflowException) {
-            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.Workflow, getExMessage(ex));
-        } else if (ex instanceof PersistenceException) {
-            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.GenericPersistence, getExMessage(ex));
-        } else if (ibatisPersistenceException != null && ibatisPersistenceException.isAssignableFrom(ex.getClass())) {
-            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.Workflow,
-                    getMessage(ex, "Currently unavailable. Please try later."));
-        } else if (ex instanceof JpaSystemException) {
-            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.DataIntegrityViolation, getExMessage(ex));
-        } else if (ex instanceof ConfigurationException) {
-            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.InvalidConnIdConf, getExMessage(ex));
-        } else if (ex instanceof ParsingValidationException) {
-            return builder(Response.Status.BAD_REQUEST, ClientExceptionType.InvalidValues, getExMessage(ex));
-        }
-
-        return null;
-    }
-
-    private ResponseBuilder builder(final Response.Status status, final ClientExceptionType hType, final String msg) {
-        ResponseBuilder builder = Response.status(status).
-                header(RESTHeaders.ERROR_CODE, hType.getHeaderValue()).
-                header(RESTHeaders.ERROR_INFO, hType.getInfoHeaderValue(msg));
-
-        ErrorTO error = new ErrorTO();
-        error.setStatus(status.getStatusCode());
-        error.setType(hType);
-        error.getElements().add(msg);
-
-        return builder.entity(error);
-    }
-
-    private String getMessage(final Throwable ex, final String msg) {
-        return (msg == null) ? getExMessage(ex) : msg;
-    }
-
-    private String getExMessage(final Throwable ex) {
-        return (ex.getCause() == null) ? ex.getMessage() : ex.getCause().getMessage();
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/server/rest-cxf/src/main/resources/META-INF/cxf/org.apache.cxf.Logger
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/resources/META-INF/cxf/org.apache.cxf.Logger b/syncope620/server/rest-cxf/src/main/resources/META-INF/cxf/org.apache.cxf.Logger
new file mode 100644
index 0000000..6e7bd36
--- /dev/null
+++ b/syncope620/server/rest-cxf/src/main/resources/META-INF/cxf/org.apache.cxf.Logger
@@ -0,0 +1 @@
+org.apache.cxf.common.logging.Slf4jLogger

http://git-wip-us.apache.org/repos/asf/syncope/blob/721f3276/syncope620/server/rest-cxf/src/main/resources/restCXFContext.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/rest-cxf/src/main/resources/restCXFContext.xml b/syncope620/server/rest-cxf/src/main/resources/restCXFContext.xml
index f98fcef..f4c8f48 100644
--- a/syncope620/server/rest-cxf/src/main/resources/restCXFContext.xml
+++ b/syncope620/server/rest-cxf/src/main/resources/restCXFContext.xml
@@ -66,7 +66,7 @@ under the License.
     <property name="mapper" ref="jacksonObjectMapper"/>
   </bean>
 
-  <bean id="exceptionMapper" class="org.apache.syncope.server.rest.cxf.service.RestServiceExceptionMapper"/>
+  <bean id="exceptionMapper" class="org.apache.syncope.server.rest.cxf.RestServiceExceptionMapper"/>
 
   <bean id="validationProvider" class="org.apache.cxf.validation.BeanValidationProvider"/>
   <bean id="validationInInterceptor" class="org.apache.cxf.jaxrs.validation.JAXRSBeanValidationInInterceptor">
@@ -93,6 +93,9 @@ under the License.
   <jaxrs:server id="restContainer" address="/" 
                 basePackages="org.apache.syncope.common.rest.api.service, org.apache.syncope.server.rest.cxf.service" 
                 staticSubresourceResolution="true">
+    <jaxrs:resourceComparator>
+      <bean class="org.apache.syncope.server.rest.cxf.QueryResourceInfoComparator"/>
+    </jaxrs:resourceComparator>
     <jaxrs:properties> 
       <entry key="search.lax.property.match" value="true"/> 
     </jaxrs:properties> 


[2/3] syncope git commit: [SYNCOPE-620] IT for Camel: success

Posted by il...@apache.org.
[SYNCOPE-620] IT for Camel: success


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

Branch: refs/heads/2_0_X
Commit: 42f78fee6e0419fb5be8cd334cee8e076749a12e
Parents: c7e8193
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Feb 3 12:06:14 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Feb 3 12:06:14 2015 +0100

----------------------------------------------------------------------
 .../common/rest/api/service/SyncopeService.java |   2 +-
 .../syncope/server/logic/CamelRouteLogic.java   |   7 +-
 .../server/logic/init/CamelRouteLoader.java     |  42 ++---
 .../persistence/jpa/dao/JPACamelRouteDAO.java   |   2 +-
 .../persistence/jpa/entity/JPACamelRoute.java   |   8 +-
 .../camel/AbstractCamelProvisioningManager.java |   2 +-
 .../camel/CamelRoleProvisioningManager.java     |  30 ++--
 .../camel/CamelUserProvisioningManager.java     |  76 ++++-----
 .../provisioning/camel/SyncopeCamelContext.java |  25 +--
 .../processor/RoleCreateInSyncProcessor.java    |  72 ++++++++
 .../camel/processor/RoleCreateProcessor.java    |  77 +++++++++
 .../camel/processor/RoleDeleteProcessor.java    | 105 ++++++++++++
 .../processor/RoleDeprovisionProcessor.java     |  78 +++++++++
 .../camel/processor/RoleUpdateProcessor.java    |  71 ++++++++
 .../processor/UserConfirmPwdResetProcessor.java |  61 +++++++
 .../camel/processor/UserCreateProcessor.java    |  76 +++++++++
 .../camel/processor/UserDeleteProcessor.java    |  72 ++++++++
 .../processor/UserDeprovisionProcessor.java     |  78 +++++++++
 .../processor/UserInnerSuspendProcessor.java    |  61 +++++++
 .../processor/UserSetStatusInSyncProcessor.java |  74 +++++++++
 .../UserStatusPropagationProcessor.java         |  76 +++++++++
 .../processor/UserUpdateInSyncProcessor.java    |  73 +++++++++
 .../camel/processor/UserUpdateProcessor.java    | 105 ++++++++++++
 .../main/resources/provisioningCamelContext.xml |   9 +-
 .../src/main/resources/roleRoutes.xml           |  50 ++----
 .../src/main/resources/userRoutes.xml           | 130 ++++-----------
 .../rest/api/service/CamelRouteService.java     |  12 +-
 .../rest/cxf/service/CamelRouteServiceImpl.java |   5 +
 syncope620/fit/reference/pom.xml                |  22 +++
 .../fit/reference/src/main/resources/log4j2.xml |   8 +-
 .../src/main/resources/provisioning.properties  |  19 +++
 .../fit/server/reference/AbstractITCase.java    |   4 +
 .../fit/server/reference/ActivitiDetector.java  |   4 -
 .../fit/server/reference/CamelDetector.java     |  32 ++++
 .../fit/server/reference/CamelRouteITCase.java  | 164 +++++++++++++++++++
 ...ltiJarAwarePersistenceUnitPostProcessor.java |  47 ++++++
 .../resources/persistenceContextEMFactory.xml   |   9 +-
 .../java/DefaultRoleProvisioningManager.java    |  35 ++--
 .../java/DefaultUserProvisioningManager.java    |  29 ++--
 .../java/sync/UserSyncResultHandlerImpl.java    |   1 -
 .../resources/META-INF/org.apache.cxf.Logger    |   1 +
 .../src/main/resources/workflowContext.xml      |   4 +-
 42 files changed, 1580 insertions(+), 278 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java
index 55cc092..cdd6dbc 100644
--- a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/SyncopeService.java
@@ -28,6 +28,6 @@ import org.apache.syncope.common.lib.to.SyncopeTO;
 public interface SyncopeService extends JAXRSService {
 
     @GET
-    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XHTML_XML })
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     SyncopeTO info();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/CamelRouteLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/CamelRouteLogic.java b/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/CamelRouteLogic.java
index 4602b51..1b13166 100644
--- a/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/CamelRouteLogic.java
+++ b/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/CamelRouteLogic.java
@@ -77,7 +77,12 @@ public class CamelRouteLogic extends AbstractTransactionalLogic<CamelRouteTO> {
         LOG.debug("Updating route {} with content {}", routeTO.getKey(), routeTO.getContent());
         binder.update(route, routeTO);
 
-        context.reloadContext(routeTO.getKey());
+        context.updateContext(routeTO.getKey());
+    }
+
+    @PreAuthorize("hasRole('ROUTE_UPDATE')")
+    public void restartContext() {
+        context.restartContext();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/init/CamelRouteLoader.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/init/CamelRouteLoader.java b/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/init/CamelRouteLoader.java
index 34181ae..a7f24a7 100644
--- a/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/init/CamelRouteLoader.java
+++ b/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/init/CamelRouteLoader.java
@@ -22,8 +22,6 @@ import java.io.StringWriter;
 import java.util.List;
 import java.util.Map;
 import javax.sql.DataSource;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.transform.TransformerFactory;
 import org.apache.syncope.common.lib.types.SubjectType;
 import org.apache.syncope.server.misc.spring.ResourceWithFallbackLoader;
 import org.apache.syncope.server.persistence.api.SyncopeLoader;
@@ -52,10 +50,6 @@ public class CamelRouteLoader implements SyncopeLoader {
 
     private static final Logger LOG = LoggerFactory.getLogger(CamelRouteLoader.class);
 
-    private static final DocumentBuilderFactory DOC_FACTORY = DocumentBuilderFactory.newInstance();
-
-    private static final TransformerFactory T_FACTORY = TransformerFactory.newInstance();
-
     @javax.annotation.Resource(name = "userRoutes")
     private ResourceWithFallbackLoader userRoutesLoader;
 
@@ -68,8 +62,6 @@ public class CamelRouteLoader implements SyncopeLoader {
     @Autowired
     private CamelEntityFactory entityFactory;
 
-    private int size = 0;
-
     private boolean loaded = false;
 
     @Override
@@ -89,18 +81,19 @@ public class CamelRouteLoader implements SyncopeLoader {
         }
     }
 
-    private boolean routesAvailable(final SubjectType subject) {
-        final String sql = String.format("SELECT * FROM %s WHERE SUBJECT = ?", CamelRoute.class.getSimpleName());
+    private boolean loadRoutesFor(final SubjectType subject) {
+        final String sql = String.format("SELECT * FROM %s WHERE SUBJECTTYPE = ?", CamelRoute.class.getSimpleName());
         final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
         final List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql, new Object[] { subject.name() });
-        return !rows.isEmpty();
+        return rows.isEmpty();
     }
 
-    private String nodeToString(final Node content, final DOMImplementationLS impl) {
+    private String nodeToString(final Node content, final DOMImplementationLS domImpl) {
         StringWriter writer = new StringWriter();
         try {
-            LSSerializer serializer = impl.createLSSerializer();
-            LSOutput lso = impl.createLSOutput();
+            LSSerializer serializer = domImpl.createLSSerializer();
+            serializer.getDomConfig().setParameter("xml-declaration", false);
+            LSOutput lso = domImpl.createLSOutput();
             lso.setCharacterStream(writer);
             serializer.write(content, lso);
         } catch (Exception e) {
@@ -110,8 +103,8 @@ public class CamelRouteLoader implements SyncopeLoader {
     }
 
     private void loadRoutes(final Resource resource, final SubjectType subjectType) {
-        if (routesAvailable(subjectType)) {
-            String query = String.format("INSERT INTO %s(NAME, SUBJECT, ROUTECONTENT) VALUES (?, ?, ?, ?)",
+        if (loadRoutesFor(subjectType)) {
+            String query = String.format("INSERT INTO %s(NAME, SUBJECTTYPE, CONTENT) VALUES (?, ?, ?)",
                     CamelRoute.class.getSimpleName());
             JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
 
@@ -123,20 +116,19 @@ public class CamelRouteLoader implements SyncopeLoader {
 
                 LSParser parser = domImpl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
 
-                NodeList routeNodes = parser.parse(lsinput).getElementsByTagName("route");
+                NodeList routeNodes = parser.parse(lsinput).getDocumentElement().getElementsByTagName("route");
                 for (int s = 0; s < routeNodes.getLength(); s++) {
                     Node routeElement = routeNodes.item(s);
                     String routeContent = nodeToString(routeNodes.item(s), domImpl);
+                    String routeId = ((Element) routeElement).getAttribute("id");
 
-                    //crate an instance of CamelRoute Entity
                     CamelRoute route = entityFactory.newCamelRoute();
                     route.setSubjectType(subjectType);
-                    route.setKey(((Element) routeElement).getAttribute("id"));
+                    route.setKey(routeId);
                     route.setContent(routeContent);
 
-                    jdbcTemplate.update(query, new Object[] {
-                        ((Element) routeElement).getAttribute("id"), subjectType.name(), routeContent });
-                    LOG.debug("Route {} successfully loaded", ((Element) routeElement).getAttribute("id"));
+                    jdbcTemplate.update(query, new Object[] { routeId, subjectType.name(), routeContent });
+                    LOG.debug("Route {} successfully loaded", routeId);
                 }
             } catch (DataAccessException e) {
                 LOG.error("While trying to store queries {}", e);
@@ -148,8 +140,8 @@ public class CamelRouteLoader implements SyncopeLoader {
 
     private void loadEntitlements() {
         final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
-        jdbcTemplate.update("INSERT INTO Entitlement VALUES('ROUTE_READ')");
-        jdbcTemplate.update("INSERT INTO Entitlement VALUES('ROUTE_LIST')");
-        jdbcTemplate.update("INSERT INTO Entitlement VALUES('ROUTE_UPDATE')");
+        jdbcTemplate.update("INSERT INTO Entitlement(NAME) VALUES('ROUTE_READ')");
+        jdbcTemplate.update("INSERT INTO Entitlement(NAME) VALUES('ROUTE_LIST')");
+        jdbcTemplate.update("INSERT INTO Entitlement(NAME) VALUES('ROUTE_UPDATE')");
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/dao/JPACamelRouteDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/dao/JPACamelRouteDAO.java b/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/dao/JPACamelRouteDAO.java
index 3302150..6b5fcb2 100644
--- a/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/dao/JPACamelRouteDAO.java
+++ b/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/dao/JPACamelRouteDAO.java
@@ -33,7 +33,7 @@ public class JPACamelRouteDAO extends AbstractDAO<CamelRoute, String> implements
 
     @Override
     public CamelRoute find(final String key) {
-        return entityManager.find(CamelRoute.class, key);
+        return entityManager.find(JPACamelRoute.class, key);
     }
 
     @Transactional(readOnly = true)

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelRoute.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelRoute.java b/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelRoute.java
index d9d5fad..2606305 100644
--- a/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelRoute.java
+++ b/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelRoute.java
@@ -41,7 +41,7 @@ public class JPACamelRoute extends AbstractEntity<String> implements CamelRoute
 
     @NotNull
     @Enumerated(EnumType.STRING)
-    private SubjectType subject;
+    private SubjectType subjectType;
 
     @Lob
     private String content;
@@ -58,12 +58,12 @@ public class JPACamelRoute extends AbstractEntity<String> implements CamelRoute
 
     @Override
     public SubjectType getSubjectType() {
-        return subject;
+        return subjectType;
     }
 
     @Override
-    public void setSubjectType(final SubjectType subject) {
-        this.subject = subject;
+    public void setSubjectType(final SubjectType subjectType) {
+        this.subjectType = subjectType;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/AbstractCamelProvisioningManager.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/AbstractCamelProvisioningManager.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/AbstractCamelProvisioningManager.java
index b932d66..843e817 100644
--- a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/AbstractCamelProvisioningManager.java
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/AbstractCamelProvisioningManager.java
@@ -37,7 +37,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 
 abstract class AbstractCamelProvisioningManager {
 
-    private static final Logger LOG = LoggerFactory.getLogger(CamelUserProvisioningManager.class);
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractCamelProvisioningManager.class);
 
     @Autowired
     protected CamelRouteDAO routeDAO;

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelRoleProvisioningManager.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelRoleProvisioningManager.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelRoleProvisioningManager.java
index 4dbe36a..73703f1 100644
--- a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelRoleProvisioningManager.java
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelRoleProvisioningManager.java
@@ -42,13 +42,13 @@ public class CamelRoleProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public Map.Entry<Long, List<PropagationStatus>> create(final RoleTO roleTO, final Set<String> excludedResources) {
+        PollingConsumer pollingConsumer = getConsumer("direct:createRolePort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("excludedResources", excludedResources);
 
         sendMessage("direct:createRole", roleTO, props);
 
-        String uri = "direct:createRolePort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -63,14 +63,14 @@ public class CamelRoleProvisioningManager extends AbstractCamelProvisioningManag
     public Map.Entry<Long, List<PropagationStatus>> create(final RoleTO roleTO, final Map<Long, String> roleOwnerMap,
             final Set<String> excludedResources) throws PropagationException {
 
+        PollingConsumer pollingConsumer = getConsumer("direct:createRoleInSyncPort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("roleOwnerMap", roleOwnerMap);
         props.put("excludedResources", excludedResources);
 
-        sendMessage("direct:createRoleSync", roleTO, props);
+        sendMessage("direct:createRoleInSync", roleTO, props);
 
-        String uri = "direct:createRoleSyncPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -90,13 +90,13 @@ public class CamelRoleProvisioningManager extends AbstractCamelProvisioningManag
     public Map.Entry<Long, List<PropagationStatus>> update(
             final RoleMod subjectMod, final Set<String> excludedResources) {
 
+        PollingConsumer pollingConsumer = getConsumer("direct:updateRolePort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("excludedResources", excludedResources);
 
         sendMessage("direct:updateRole", subjectMod, props);
 
-        String uri = "direct:updateRolePort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -109,10 +109,10 @@ public class CamelRoleProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public List<PropagationStatus> delete(final Long roleKey) {
+        PollingConsumer pollingConsumer = getConsumer("direct:deleteRolePort");
+
         sendMessage("direct:deleteRole", roleKey);
 
-        String uri = "direct:deleteRolePort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -124,10 +124,10 @@ public class CamelRoleProvisioningManager extends AbstractCamelProvisioningManag
 
     @Override
     public Long unlink(final RoleMod roleMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:unlinkRolePort");
+
         sendMessage("direct:unlinkRole", roleMod);
 
-        String uri = "direct:unlinkRolePort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -139,10 +139,10 @@ public class CamelRoleProvisioningManager extends AbstractCamelProvisioningManag
 
     @Override
     public Long link(final RoleMod roleMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:linkRolePort");
+
         sendMessage("direct:linkRole", roleMod);
 
-        String uri = "direct:linkRolePort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -155,13 +155,13 @@ public class CamelRoleProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public List<PropagationStatus> deprovision(final Long roleKey, Collection<String> resources) {
+        PollingConsumer pollingConsumer = getConsumer("direct:deprovisionRolePort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("resources", resources);
 
         sendMessage("direct:deprovisionRole", roleKey, props);
 
-        String uri = "direct:deprovisionRolePort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelUserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelUserProvisioningManager.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelUserProvisioningManager.java
index 1ed83fd..2c5afc5 100644
--- a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelUserProvisioningManager.java
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelUserProvisioningManager.java
@@ -59,6 +59,8 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword,
             boolean disablePwdPolicyCheck, Boolean enabled, Set<String> excludedResources) {
 
+        PollingConsumer pollingConsumer = getConsumer("direct:createPort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("storePassword", storePassword);
         props.put("disablePwdPolicyCheck", disablePwdPolicyCheck);
@@ -67,8 +69,6 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
 
         sendMessage("direct:createUser", userTO, props);
 
-        String uri = "direct:createPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -86,13 +86,13 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public Map.Entry<Long, List<PropagationStatus>> update(UserMod userMod, boolean removeMemberships) {
+        PollingConsumer pollingConsumer = getConsumer("direct:updatePort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("removeMemberships", removeMemberships);
 
         sendMessage("direct:updateUser", userMod, props);
 
-        String uri = "direct:updatePort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -110,13 +110,13 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public List<PropagationStatus> delete(final Long userKey, final Set<String> excludedResources) {
+        PollingConsumer pollingConsumer = getConsumer("direct:deletePort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("excludedResources", excludedResources);
 
         sendMessage("direct:deleteUser", userKey, props);
 
-        String uri = "direct:deletePort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -128,10 +128,10 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
 
     @Override
     public Long unlink(final UserMod userMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:unlinkPort");
+
         sendMessage("direct:unlinkUser", userMod);
 
-        String uri = "direct:unlinkPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -145,6 +145,8 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public Map.Entry<Long, List<PropagationStatus>> activate(final User user, final StatusMod statusMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:statusPort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("token", statusMod.getToken());
         props.put("user", user);
@@ -155,11 +157,9 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
         } else {
             WorkflowResult<Long> updated =
                     new WorkflowResult<>(user.getKey(), null, statusMod.getType().name().toLowerCase());
-            sendMessage("direct:statusUser", updated, props);
+            sendMessage("direct:userStatusPropagation", updated, props);
         }
 
-        String uri = "direct:statusPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -172,6 +172,8 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public Map.Entry<Long, List<PropagationStatus>> reactivate(final User user, final StatusMod statusMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:statusPort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("user", user);
         props.put("statusMod", statusMod);
@@ -181,11 +183,9 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
         } else {
             WorkflowResult<Long> updated =
                     new WorkflowResult<>(user.getKey(), null, statusMod.getType().name().toLowerCase());
-            sendMessage("direct:statusUser", updated, props);
+            sendMessage("direct:userStatusPropagation", updated, props);
         }
 
-        String uri = "direct:statusPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -198,6 +198,8 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public Map.Entry<Long, List<PropagationStatus>> suspend(final User user, final StatusMod statusMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:statusPort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("user", user);
         props.put("statusMod", statusMod);
@@ -207,11 +209,9 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
         } else {
             WorkflowResult<Long> updated =
                     new WorkflowResult<>(user.getKey(), null, statusMod.getType().name().toLowerCase());
-            sendMessage("direct:statusUser", updated, props);
+            sendMessage("direct:userStatusPropagation", updated, props);
         }
 
-        String uri = "direct:statusPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -223,10 +223,10 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
 
     @Override
     public Long link(final UserMod subjectMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:linkPort");
+
         sendMessage("direct:linkUser", subjectMod);
 
-        String uri = "direct:linkPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -240,13 +240,13 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public List<PropagationStatus> deprovision(final Long user, final Collection<String> resources) {
+        PollingConsumer pollingConsumer = getConsumer("direct:deprovisionPort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("resources", resources);
 
         sendMessage("direct:deprovisionUser", user, props);
 
-        String uri = "direct:deprovisionPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -259,24 +259,24 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     @Override
     @SuppressWarnings("unchecked")
     public Map.Entry<Long, List<PropagationStatus>> update(
-            final UserMod userMod, Long id, final ProvisioningResult result,
+            final UserMod userMod, final Long key, final ProvisioningResult result,
             final Boolean enabled, final Set<String> excludedResources) {
 
+        PollingConsumer pollingConsumer = getConsumer("direct:updateInSyncPort");
+
         Map<String, Object> props = new HashMap<>();
-        props.put("id", id);
+        props.put("key", key);
         props.put("result", result);
         props.put("enabled", enabled);
         props.put("excludedResources", excludedResources);
 
-        sendMessage("direct:updateSyncUser", userMod, props);
+        sendMessage("direct:updateUserInSync", userMod, props);
 
-        String uri = "direct:updateSyncPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         Exception e;
         if ((e = (Exception) exchange.getProperty(Exchange.EXCEPTION_CAUGHT)) != null) {
-            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", id, e);
+            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", key, e);
 
             result.setStatus(ProvisioningResult.Status.FAILURE);
             result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
@@ -284,7 +284,7 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
             WorkflowResult<Map.Entry<UserMod, Boolean>> updated = new WorkflowResult<Map.Entry<UserMod, Boolean>>(
                     new AbstractMap.SimpleEntry<>(userMod, false), new PropagationByResource(),
                     new HashSet<String>());
-            sendMessage("direct:syncUserStatus", updated, props);
+            sendMessage("direct:userInSync", updated, props);
             exchange = pollingConsumer.receive();
         }
 
@@ -292,14 +292,14 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
     }
 
     @Override
-    public void innerSuspend(final User user, final boolean suspend) {
+    public void innerSuspend(final User user, final boolean propagate) {
+        PollingConsumer pollingConsumer = getConsumer("direct:innerSuspendUserPort");
+
         Map<String, Object> props = new HashMap<>();
-        props.put("suspend", suspend);
+        props.put("propagate", propagate);
 
-        sendMessage("direct:suspendUserWF", user, props);
+        sendMessage("direct:innerSuspendUser", user, props);
 
-        String uri = "direct:suspendWFPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -309,10 +309,10 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
 
     @Override
     public void requestPasswordReset(final Long userKey) {
+        PollingConsumer pollingConsumer = getConsumer("direct:requestPwdResetPort");
+
         sendMessage("direct:requestPwdReset", userKey);
 
-        String uri = "direct:requestPwdResetPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
@@ -322,16 +322,16 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag
 
     @Override
     public void confirmPasswordReset(final User user, final String token, final String password) {
+        PollingConsumer pollingConsumer = getConsumer("direct:confirmPwdResetPort");
+
         Map<String, Object> props = new HashMap<>();
         props.put("user", user);
-        props.put("userId", user.getKey());
+        props.put("userKey", user.getKey());
         props.put("token", token);
         props.put("password", password);
 
         sendMessage("direct:confirmPwdReset", user, props);
 
-        String uri = "direct:confirmPwdResetPort";
-        PollingConsumer pollingConsumer = getConsumer(uri);
         Exchange exchange = pollingConsumer.receive();
 
         if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/SyncopeCamelContext.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/SyncopeCamelContext.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/SyncopeCamelContext.java
index 2a7de7b..02c82cb 100644
--- a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/SyncopeCamelContext.java
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/SyncopeCamelContext.java
@@ -18,9 +18,7 @@
  */
 package org.apache.syncope.server.provisioning.camel;
 
-import java.io.ByteArrayInputStream;
 import java.io.InputStream;
-import java.net.URLDecoder;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -30,7 +28,6 @@ import org.apache.camel.model.Constants;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.spring.SpringCamelContext;
 import org.apache.commons.io.IOUtils;
-import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
 import org.apache.syncope.server.persistence.api.dao.CamelRouteDAO;
 import org.apache.syncope.server.persistence.api.entity.CamelRoute;
@@ -64,7 +61,7 @@ public class SyncopeCamelContext {
         if (camelContext.getRouteDefinitions().isEmpty()) {
             List<CamelRoute> routes = routeDAO.findAll();
             LOG.debug("{} route(s) are going to be loaded ", routes.size());
-            loadContext(routeDAO, routes);
+            loadContext(routes);
             try {
                 camelContext.start();
             } catch (Exception e) {
@@ -75,7 +72,7 @@ public class SyncopeCamelContext {
         return camelContext;
     }
 
-    public void loadContext(final CamelRouteDAO routeDAO, final List<CamelRoute> routes) {
+    private void loadContext(final List<CamelRoute> routes) {
         try {
             DOMImplementationRegistry reg = DOMImplementationRegistry.newInstance();
             DOMImplementationLS domImpl = (DOMImplementationLS) reg.getDOMImplementation("LS");
@@ -87,12 +84,11 @@ public class SyncopeCamelContext {
             for (CamelRoute route : routes) {
                 InputStream input = null;
                 try {
-                    input = new ByteArrayInputStream(
-                            URLDecoder.decode(route.getContent(), SyncopeConstants.DEFAULT_ENCODING).getBytes());
+                    input = IOUtils.toInputStream(route.getContent());
                     LSInput lsinput = domImpl.createLSInput();
                     lsinput.setByteStream(input);
 
-                    Node routeElement = parser.parse(lsinput).getElementsByTagName("route").item(0);
+                    Node routeElement = parser.parse(lsinput).getDocumentElement();
                     routeDefs.add(unmarshaller.unmarshal(routeElement, RouteDefinition.class).getValue());
                 } finally {
                     IOUtils.closeQuietly(input);
@@ -104,15 +100,24 @@ public class SyncopeCamelContext {
         }
     }
 
-    public void reloadContext(final String routeKey) {
+    public void updateContext(final String routeKey) {
         if (camelContext == null) {
             getContext();
         } else {
             if (!camelContext.getRouteDefinitions().isEmpty()) {
                 camelContext.getRouteDefinitions().remove(camelContext.getRouteDefinition(routeKey));
-                loadContext(routeDAO, Collections.singletonList(routeDAO.find(routeKey)));
+                loadContext(Collections.singletonList(routeDAO.find(routeKey)));
             }
         }
     }
 
+    public void restartContext() {
+        try {
+            camelContext.stop();
+            camelContext.start();
+        } catch (Exception e) {
+            LOG.error("While restarting Camel context", e);
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleCreateInSyncProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleCreateInSyncProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleCreateInSyncProcessor.java
new file mode 100644
index 0000000..aaced42
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleCreateInSyncProcessor.java
@@ -0,0 +1,72 @@
+package org.apache.syncope.server.provisioning.camel.processor;
+
+/*
+ * 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.
+ */
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.server.misc.security.AuthContextUtil;
+import org.apache.syncope.server.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RoleCreateInSyncProcessor implements Processor {
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void process(final Exchange exchange) {
+        WorkflowResult<Long> created = (WorkflowResult) exchange.getIn().getBody();
+
+        RoleTO actual = exchange.getProperty("subject", RoleTO.class);
+        Map<Long, String> roleOwnerMap = exchange.getProperty("roleOwnerMap", Map.class);
+        Set<String> excludedResource = exchange.getProperty("excludedResources", Set.class);
+
+        AttrTO roleOwner = actual.getPlainAttrMap().get(StringUtils.EMPTY);
+        if (roleOwner != null) {
+            roleOwnerMap.put(created.getResult(), roleOwner.getValues().iterator().next());
+        }
+
+        AuthContextUtil.extendAuthContext(
+                created.getResult(), RoleEntitlementUtil.getEntitlementNameFromRoleKey(created.getResult()));
+
+        List<PropagationTask> tasks = propagationManager.getRoleCreateTaskIds(
+                created, actual.getVirAttrs(), excludedResource);
+
+        taskExecutor.execute(tasks);
+
+        exchange.getOut().setBody(new AbstractMap.SimpleEntry<>(created.getResult(), null));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleCreateProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleCreateProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleCreateProcessor.java
new file mode 100644
index 0000000..d2219ba
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleCreateProcessor.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.provisioning.camel.processor;
+
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.server.misc.security.AuthContextUtil;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RoleCreateProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RoleCreateProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        WorkflowResult<Long> created = (WorkflowResult) exchange.getIn().getBody();
+        RoleTO subject = exchange.getProperty("subject", RoleTO.class);
+        Set<String> excludedResource = exchange.getProperty("excludedResources", Set.class);
+
+        AuthContextUtil.extendAuthContext(
+                created.getResult(), RoleEntitlementUtil.getEntitlementNameFromRoleKey(created.getResult()));
+
+        List<PropagationTask> tasks =
+                propagationManager.getRoleCreateTaskIds(created, subject.getVirAttrs(), excludedResource);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.getOut().setBody(new AbstractMap.SimpleEntry<>(
+                created.getResult(), propagationReporter.getStatuses()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleDeleteProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleDeleteProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleDeleteProcessor.java
new file mode 100644
index 0000000..7c6e816
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleDeleteProcessor.java
@@ -0,0 +1,105 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.dao.RoleDAO;
+import org.apache.syncope.server.persistence.api.entity.role.Role;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.server.workflow.api.RoleWorkflowAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RoleDeleteProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RoleDeleteProcessor.class);
+
+    @Autowired
+    protected RoleWorkflowAdapter rwfAdapter;
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    protected RoleDAO roleDAO;
+
+    @Override
+    public void process(final Exchange exchange) throws Exception {
+        final List<Role> toBeDeprovisioned = new ArrayList<>();
+
+        Long subjectKey = exchange.getIn().getBody(Long.class);
+        final Role syncopeRole = roleDAO.find(subjectKey);
+
+        if (syncopeRole != null) {
+            toBeDeprovisioned.add(syncopeRole);
+
+            final List<Role> descendants = roleDAO.findDescendants(toBeDeprovisioned.get(0));
+            if (descendants != null) {
+                toBeDeprovisioned.addAll(descendants);
+            }
+        }
+
+        final List<PropagationTask> tasks = new ArrayList<>();
+
+        for (Role role : toBeDeprovisioned) {
+            // Generate propagation tasks for deleting users from role resources, if they are on those resources only
+            // because of the reason being deleted (see SYNCOPE-357)
+            for (Map.Entry<Long, PropagationByResource> entry : roleDAO.findUsersWithIndirectResources(role.
+                    getKey()).entrySet()) {
+
+                WorkflowResult<Long> wfResult =
+                        new WorkflowResult<>(entry.getKey(), entry.getValue(), Collections.<String>emptySet());
+                tasks.addAll(propagationManager.getUserDeleteTaskIds(wfResult));
+            }
+
+            // Generate propagation tasks for deleting this role from resources
+            tasks.addAll(propagationManager.getRoleDeleteTaskIds(role.getKey()));
+        }
+
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.setProperty("statuses", propagationReporter.getStatuses());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleDeprovisionProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleDeprovisionProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleDeprovisionProcessor.java
new file mode 100644
index 0000000..4753cd8
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleDeprovisionProcessor.java
@@ -0,0 +1,78 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.dao.RoleDAO;
+import org.apache.syncope.server.persistence.api.entity.role.Role;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RoleDeprovisionProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserDeprovisionProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    protected RoleDAO roleDAO;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        Long roleKey = exchange.getIn().getBody(Long.class);
+        List<String> resources = exchange.getProperty("resources", List.class);
+
+        Role role = roleDAO.authFetch(roleKey);
+
+        Set<String> noPropResourceName = role.getResourceNames();
+        noPropResourceName.removeAll(resources);
+
+        List<PropagationTask> tasks =
+                propagationManager.getRoleDeleteTaskIds(roleKey, new HashSet<>(resources), noPropResourceName);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.getOut().setBody(propagationReporter.getStatuses());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleUpdateProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleUpdateProcessor.java
new file mode 100644
index 0000000..e91be21
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/RoleUpdateProcessor.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.provisioning.camel.processor;
+
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RoleUpdateProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserUpdateProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        WorkflowResult<Long> updated = (WorkflowResult) exchange.getIn().getBody();
+        RoleMod subjectMod = exchange.getProperty("subjectMod", RoleMod.class);
+        Set<String> excludedResource = exchange.getProperty("excludedResources", Set.class);
+
+        List<PropagationTask> tasks = propagationManager.getRoleUpdateTaskIds(updated,
+                subjectMod.getVirAttrsToRemove(), subjectMod.getVirAttrsToUpdate(), excludedResource);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.getOut().setBody(new AbstractMap.SimpleEntry<>(updated.getResult(), propagationReporter.getStatuses()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserConfirmPwdResetProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
new file mode 100644
index 0000000..3fb5ced
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserConfirmPwdResetProcessor.java
@@ -0,0 +1,61 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.List;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.persistence.api.entity.user.User;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserConfirmPwdResetProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserConfirmPwdResetProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Override
+    public void process(final Exchange exchange) {
+        User user = exchange.getProperty("user", User.class);
+
+        List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(user, null, null);
+        PropagationReporter propReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propReporter.onPrimaryResourceFailure(tasks);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserCreateProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserCreateProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserCreateProcessor.java
new file mode 100644
index 0000000..bcca679
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserCreateProcessor.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserCreateProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserCreateProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        if ((exchange.getIn().getBody() instanceof WorkflowResult)) {
+
+            WorkflowResult<Map.Entry<Long, Boolean>> created = (WorkflowResult) exchange.getIn().getBody();
+            UserTO actual = exchange.getProperty("actual", UserTO.class);
+            Set<String> excludedResource = exchange.getProperty("excludedResources", Set.class);
+
+            List<PropagationTask> tasks = propagationManager.getUserCreateTaskIds(
+                    created, actual.getPassword(), actual.getVirAttrs(), excludedResource, actual.getMemberships());
+            PropagationReporter propagationReporter =
+                    ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+            try {
+                taskExecutor.execute(tasks, propagationReporter);
+            } catch (PropagationException e) {
+                LOG.error("Error propagation primary resource {}", e);
+                propagationReporter.onPrimaryResourceFailure(tasks);
+            }
+
+            exchange.getOut().setBody(
+                    new AbstractMap.SimpleEntry<>(created.getResult().getKey(), propagationReporter.getStatuses()));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserDeleteProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserDeleteProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserDeleteProcessor.java
new file mode 100644
index 0000000..b9795ad
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserDeleteProcessor.java
@@ -0,0 +1,72 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserDeleteProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserDeleteProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) throws Exception {
+        Long userKey = (Long) exchange.getIn().getBody();
+        Set<String> excludedResource = exchange.getProperty("excludedResources", Set.class);
+
+        // Note here that we can only notify about "delete", not any other
+        // task defined in workflow process definition: this because this
+        // information could only be available after uwfAdapter.delete(), which
+        // will also effectively remove user from db, thus making virtually
+        // impossible by NotificationManager to fetch required user information
+        List<PropagationTask> tasks = propagationManager.getUserDeleteTaskIds(userKey, excludedResource);
+
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.setProperty("statuses", propagationReporter.getStatuses());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserDeprovisionProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserDeprovisionProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserDeprovisionProcessor.java
new file mode 100644
index 0000000..042c287
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserDeprovisionProcessor.java
@@ -0,0 +1,78 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.dao.UserDAO;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.persistence.api.entity.user.User;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserDeprovisionProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserDeprovisionProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    protected UserDAO userDAO;
+
+    @Override
+    public void process(final Exchange exchange) {
+        Long userKey = exchange.getIn().getBody(Long.class);
+        @SuppressWarnings("unchecked")
+        List<String> resources = exchange.getProperty("resources", List.class);
+
+        final User user = userDAO.authFetch(userKey);
+
+        final Set<String> noPropResourceName = user.getResourceNames();
+        noPropResourceName.removeAll(resources);
+
+        final List<PropagationTask> tasks =
+                propagationManager.getUserDeleteTaskIds(userKey, new HashSet<>(resources), noPropResourceName);
+        final PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.getOut().setBody(propagationReporter.getStatuses());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserInnerSuspendProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserInnerSuspendProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserInnerSuspendProcessor.java
new file mode 100644
index 0000000..69760f8
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserInnerSuspendProcessor.java
@@ -0,0 +1,61 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.AbstractMap.SimpleEntry;
+import java.util.List;
+import java.util.Map;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserInnerSuspendProcessor implements Processor {
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        WorkflowResult<Long> updated = (WorkflowResult) exchange.getIn().getBody();
+        Boolean propagate = exchange.getProperty("propagate", Boolean.class);
+
+        if (propagate) {
+            UserMod userMod = new UserMod();
+            userMod.setKey(updated.getResult());
+
+            final List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(
+                    new WorkflowResult<Map.Entry<UserMod, Boolean>>(
+                            new SimpleEntry<>(userMod, Boolean.FALSE),
+                            updated.getPropByRes(), updated.getPerformedTasks()));
+            taskExecutor.execute(tasks);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserSetStatusInSyncProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserSetStatusInSyncProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserSetStatusInSyncProcessor.java
new file mode 100644
index 0000000..11d0ff6
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserSetStatusInSyncProcessor.java
@@ -0,0 +1,74 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.Map;
+import org.apache.camel.Processor;
+import org.apache.camel.Exchange;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.server.persistence.api.dao.UserDAO;
+import org.apache.syncope.server.persistence.api.entity.user.User;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.workflow.api.UserWorkflowAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserSetStatusInSyncProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserSetStatusInSyncProcessor.class);
+
+    @Autowired
+    protected UserDAO userDAO;
+
+    @Autowired
+    protected UserWorkflowAdapter uwfAdapter;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        WorkflowResult<Map.Entry<UserMod, Boolean>> updated = (WorkflowResult) exchange.getIn().getBody();
+
+        Boolean enabled = exchange.getProperty("enabled", Boolean.class);
+        Long key = exchange.getProperty("key", Long.class);
+
+        if (enabled != null) {
+            User user = userDAO.find(key);
+
+            WorkflowResult<Long> enableUpdate = null;
+            if (user.isSuspended() == null) {
+                enableUpdate = uwfAdapter.activate(key, null);
+            } else if (enabled && user.isSuspended()) {
+                enableUpdate = uwfAdapter.reactivate(key);
+            } else if (!enabled && !user.isSuspended()) {
+                enableUpdate = uwfAdapter.suspend(key);
+            }
+
+            if (enableUpdate != null) {
+                if (enableUpdate.getPropByRes() != null) {
+                    updated.getPropByRes().merge(enableUpdate.getPropByRes());
+                    updated.getPropByRes().purge();
+                }
+                updated.getPerformedTasks().addAll(enableUpdate.getPerformedTasks());
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/42f78fee/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserStatusPropagationProcessor.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserStatusPropagationProcessor.java b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserStatusPropagationProcessor.java
new file mode 100644
index 0000000..eb1452f
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/processor/UserStatusPropagationProcessor.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.provisioning.camel.processor;
+
+import java.util.AbstractMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.server.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.server.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.server.persistence.api.entity.user.User;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserStatusPropagationProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserStatusPropagationProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        WorkflowResult<Long> updated = (WorkflowResult) exchange.getIn().getBody();
+
+        User user = exchange.getProperty("user", User.class);
+        StatusMod statusMod = exchange.getProperty("statusMod", StatusMod.class);
+
+        Set<String> resourcesToBeExcluded = new HashSet<>(user.getResourceNames());
+        resourcesToBeExcluded.removeAll(statusMod.getResourceNames());
+
+        List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(
+                user, statusMod.getType() != StatusMod.ModType.SUSPEND, resourcesToBeExcluded);
+        PropagationReporter propReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.getOut().setBody(new AbstractMap.SimpleEntry<>(updated.getResult(), propReporter.getStatuses()));
+    }
+}