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/01/05 14:34:08 UTC

[03/53] [abbrv] syncope git commit: Initial running version, in order to fix #1

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/DefaultUserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/DefaultUserProvisioningManager.java b/core/src/main/java/org/apache/syncope/core/provisioning/DefaultUserProvisioningManager.java
new file mode 100644
index 0000000..86f6ebe
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/DefaultUserProvisioningManager.java
@@ -0,0 +1,347 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.mod.StatusMod;
+import org.apache.syncope.common.mod.UserMod;
+import org.apache.syncope.common.to.PropagationStatus;
+import org.apache.syncope.common.to.UserTO;
+import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
+import org.apache.syncope.core.persistence.dao.UserDAO;
+import org.apache.syncope.core.propagation.PropagationByResource;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationReporter;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.rest.data.UserDataBinder;
+import org.apache.syncope.core.sync.SyncResult;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.apache.syncope.core.workflow.user.UserWorkflowAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultUserProvisioningManager implements UserProvisioningManager{
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultUserProvisioningManager.class);
+
+    @Autowired
+    protected UserWorkflowAdapter uwfAdapter;
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+    
+    @Autowired
+    protected UserDataBinder binder;    
+
+    @Autowired
+    protected UserDAO userDAO;   
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO){
+        return create(userTO, true);
+    }
+    
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO, boolean storePassword) {
+        WorkflowResult<Map.Entry<Long, Boolean>> created;
+        try {
+            created = uwfAdapter.create(userTO,storePassword);
+        } catch (RuntimeException e) {
+            throw e;
+        }
+
+        List<PropagationTask> tasks = propagationManager.getUserCreateTaskIds(
+                created, userTO.getPassword(), userTO.getVirAttrs(), userTO.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);
+        }
+
+        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(
+                created.getResult().getKey(), propagationReporter.getStatuses());
+        return result;
+    }
+    
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(UserTO userTO, boolean storePassword, boolean disablePwdPolicyCheck, Boolean enabled, Set<String> excludedResources) {
+                WorkflowResult<Map.Entry<Long, Boolean>> created;
+        try {
+            created = uwfAdapter.create(userTO,storePassword);
+        } catch (RuntimeException e) {
+            throw e;
+        }
+
+        List<PropagationTask> tasks = propagationManager.getUserCreateTaskIds(
+                created, userTO.getPassword(), userTO.getVirAttrs(), excludedResources, null);
+        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);
+        }
+
+        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(
+                created.getResult().getKey(), propagationReporter.getStatuses());
+        return result;
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> update(final UserMod userMod) {
+        return update(userMod, false);
+    }
+    
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> update(UserMod userMod, boolean removeMemberships) {
+        WorkflowResult<Map.Entry<UserMod, Boolean>> updated;
+        try {
+            updated = uwfAdapter.update(userMod);
+        } catch (RuntimeException e) {
+            throw e;
+        }
+
+        List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(updated);
+
+        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);
+        }
+
+        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(
+                updated.getResult().getKey().getId(), propagationReporter.getStatuses());
+        return result;    
+    }
+       
+    @Override
+    public List<PropagationStatus> delete(final Long userId) {
+
+        return delete(userId, Collections.<String>emptySet());
+    }
+
+    @Override
+    public List<PropagationStatus> delete(Long subjectId, Set<String> excludedResources) {
+        List<PropagationTask> tasks = propagationManager.getUserDeleteTaskIds(subjectId,excludedResources);
+
+        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);
+        }
+
+        try {
+            uwfAdapter.delete(subjectId);
+        } catch (RuntimeException e) {
+            throw e;
+        }
+
+        return propagationReporter.getStatuses();
+    }
+
+    
+    @Override
+    public Long unlink(UserMod userMod) {
+        WorkflowResult<Map.Entry<UserMod, Boolean>> updated = uwfAdapter.update(userMod);
+        return updated.getResult().getKey().getId();
+    }
+
+    @Override
+    public Long link(UserMod subjectMod) {
+        return uwfAdapter.update(subjectMod).getResult().getKey().getId();
+    }
+    
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> activate(SyncopeUser user, StatusMod statusMod) {
+        WorkflowResult<Long> updated;
+        if (statusMod.isOnSyncope()) {
+            updated = uwfAdapter.activate(user.getId(), statusMod.getToken());
+        } else {
+            updated = new WorkflowResult<Long>(user.getId(), null, statusMod.getType().name().toLowerCase());
+        }
+  
+        List<PropagationStatus> statuses = propagateStatus(user, statusMod);
+        return new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(updated.getResult(), statuses);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> reactivate(SyncopeUser user, StatusMod statusMod) {
+        WorkflowResult<Long> updated;
+        if (statusMod.isOnSyncope()) {
+            updated = uwfAdapter.reactivate(user.getId());
+        } else {
+            updated = new WorkflowResult<Long>(user.getId(), null, statusMod.getType().name().toLowerCase());
+        }
+        
+        List<PropagationStatus> statuses = propagateStatus(user, statusMod);
+        return new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(updated.getResult(), statuses);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> suspend(SyncopeUser user, StatusMod statusMod) {
+        WorkflowResult<Long> updated;
+        if (statusMod.isOnSyncope()) {
+            updated = uwfAdapter.suspend(user.getId());
+        } else {
+            updated = new WorkflowResult<Long>(user.getId(), null, statusMod.getType().name().toLowerCase());
+        }
+        
+        List<PropagationStatus> statuses = propagateStatus(user, statusMod);
+        return new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(updated.getResult(), statuses);
+    }
+    
+    public List<PropagationStatus> propagateStatus(SyncopeUser user, StatusMod statusMod){
+                
+        Set<String> resourcesToBeExcluded = new HashSet<String>(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);
+        }
+        
+        return propReporter.getStatuses();
+        
+    }
+
+    @Override
+    public List<PropagationStatus> deprovision(Long userId, Collection<String> resources) {
+        
+        final SyncopeUser user = binder.getUserFromId(userId);        
+        
+        final Set<String> noPropResourceName = user.getResourceNames();
+        noPropResourceName.removeAll(resources);
+        
+        final List<PropagationTask> tasks =
+                propagationManager.getUserDeleteTaskIds(userId, new HashSet<String>(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);
+        }
+        
+        return propagationReporter.getStatuses();
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> updateInSync(final UserMod userMod,final Long id, final SyncResult result, Boolean enabled, 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);
+
+            result.setStatus(SyncResult.Status.FAILURE);
+            result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
+
+            updated = new WorkflowResult<Map.Entry<UserMod, Boolean>>(
+                    new AbstractMap.SimpleEntry<UserMod, Boolean>(userMod, false), new PropagationByResource(),
+                    new HashSet<String>());
+        }
+
+        if (enabled != null) {
+            SyncopeUser user = userDAO.find(id);
+
+            WorkflowResult<Long> enableUpdate = null;
+            if (user.isSuspended() == null) {
+                enableUpdate = uwfAdapter.activate(id, null);
+            } else if (enabled && user.isSuspended()) {
+                enableUpdate = uwfAdapter.reactivate(id);
+            } else if (!enabled && !user.isSuspended()) {
+                enableUpdate = uwfAdapter.suspend(id);
+            }
+
+            if (enableUpdate != null) {
+                if (enableUpdate.getPropByRes() != null) {
+                    updated.getPropByRes().merge(enableUpdate.getPropByRes());
+                    updated.getPropByRes().purge();
+                }
+                updated.getPerformedTasks().addAll(enableUpdate.getPerformedTasks());
+            }
+        }
+
+            PropagationReporter propagationReporter = ApplicationContextProvider.getApplicationContext().
+                    getBean(PropagationReporter.class);
+
+            List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(updated,updated.getResult().getKey().getPassword() != null,excludedResources);
+                
+            try {
+                    taskExecutor.execute(tasks, propagationReporter);
+            } catch (PropagationException e) {
+                    LOG.error("Error propagation primary resource", e);
+                    propagationReporter.onPrimaryResourceFailure(tasks);
+            }
+            
+            return new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(updated.getResult().getKey().getId(), propagationReporter.getStatuses());
+
+    }
+
+    @Override
+    public void innerSuspend(SyncopeUser user, boolean suspend) {
+        
+            final WorkflowResult<Long> updated = uwfAdapter.suspend(user);
+
+            // propagate suspension if and only if it is required by policy
+            if (suspend) {
+                UserMod userMod = new UserMod();
+                userMod.setId(updated.getResult());
+
+                final List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(
+                        new WorkflowResult<Map.Entry<UserMod, Boolean>>(
+                                new AbstractMap.SimpleEntry<UserMod, Boolean>(userMod, Boolean.FALSE),
+                                updated.getPropByRes(), updated.getPerformedTasks()));
+
+                taskExecutor.execute(tasks);
+            }            
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/RoleProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/RoleProvisioningManager.java b/core/src/main/java/org/apache/syncope/core/provisioning/RoleProvisioningManager.java
new file mode 100644
index 0000000..594bf5e
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/RoleProvisioningManager.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.syncope.core.provisioning;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.to.RoleTO;
+import org.apache.syncope.common.mod.RoleMod;
+import org.apache.syncope.common.to.PropagationStatus;
+import org.apache.syncope.core.propagation.PropagationException;
+
+public interface RoleProvisioningManager extends ProvisioningManager<RoleTO, RoleMod>{
+    
+    public Map.Entry<Long, List<PropagationStatus>> create(final RoleTO roleTO, Set<String> excludedResources);
+    
+    public Map.Entry<Long, List<PropagationStatus>> createInSync(final RoleTO roleTO, Map<Long, String> roleOwnerMap,Set<String> excludedResources) throws PropagationException;
+    
+    public Map.Entry<Long, List<PropagationStatus>> update(RoleMod subjectMod, Set<String> excludedResources);
+    
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/UserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/UserProvisioningManager.java b/core/src/main/java/org/apache/syncope/core/provisioning/UserProvisioningManager.java
new file mode 100644
index 0000000..da29a42
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/UserProvisioningManager.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2013 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.syncope.core.provisioning;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.mod.StatusMod;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.apache.syncope.common.to.UserTO;
+import org.apache.syncope.common.mod.UserMod;
+import org.apache.syncope.common.to.PropagationStatus;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
+import org.apache.syncope.core.sync.SyncResult;
+
+public interface UserProvisioningManager extends ProvisioningManager<UserTO, UserMod>{
+    
+    public Map.Entry<Long, List<PropagationStatus>> activate(SyncopeUser user, StatusMod statusMod);
+
+    public Map.Entry<Long, List<PropagationStatus>> reactivate(SyncopeUser user, StatusMod statusMod);
+
+    public Map.Entry<Long, List<PropagationStatus>> suspend(SyncopeUser user, StatusMod statusMod);
+    
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword);
+    
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword, boolean disablePwdPolicyCheck, Boolean enabled,Set<String> excludedResources);
+    
+    public Map.Entry<Long, List<PropagationStatus>> update(final UserMod userMod, final boolean removeMemberships);
+    
+    public Map.Entry<Long, List<PropagationStatus>> updateInSync(final UserMod userMod,final Long id, final SyncResult result, Boolean enabled, Set<String> excludedResources);
+
+    public List<PropagationStatus> delete(Long subjectId, Set<String> excludedResources);    
+    
+    public void innerSuspend(SyncopeUser user, boolean suspend);
+    
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/CamelRoleProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/CamelRoleProvisioningManager.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/CamelRoleProvisioningManager.java
new file mode 100644
index 0000000..4857d2f
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/CamelRoleProvisioningManager.java
@@ -0,0 +1,307 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.syncope.core.provisioning.camel;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.PollingConsumer;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.impl.DefaultMessage;
+import org.apache.camel.model.Constants;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.RoutesDefinition;
+import org.apache.camel.spring.SpringCamelContext;
+import org.apache.syncope.common.mod.RoleMod;
+import org.apache.syncope.common.to.PropagationStatus;
+import org.apache.syncope.common.to.RoleTO;
+import org.apache.syncope.core.persistence.beans.CamelRoute;
+import org.apache.syncope.core.persistence.dao.RouteDAO;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.provisioning.RoleProvisioningManager;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class CamelRoleProvisioningManager implements RoleProvisioningManager{
+
+    private static final Logger LOG = LoggerFactory.getLogger(CamelRoleProvisioningManager.class);
+
+    private DefaultCamelContext camelContext;
+
+    private RoutesDefinition routes;
+
+    protected Map<String, PollingConsumer> consumerMap;
+
+    protected List<String> knownUri;
+    
+    @Autowired
+    protected RouteDAO routeDAO;
+
+    @Autowired
+    protected SyncopeCamelContext contextFactory;
+
+    public CamelRoleProvisioningManager() throws Exception {
+        knownUri = new ArrayList<String>();
+        consumerMap = new HashMap();
+    }
+
+    public void startContext() throws Exception {
+        camelContext.start();
+    }
+
+    public void stopContext() throws Exception {
+        camelContext.stop();
+    }
+
+    public CamelContext getContext() {
+        //ApplicationContext context = ApplicationContextProvider.getApplicationContext();
+        //return context.getBean("camel-context", DefaultCamelContext.class);        
+        return contextFactory.getContext(routeDAO);  
+    }
+
+    public void changeRoute(String routePath) {
+        try {
+            camelContext.removeRouteDefinitions(routes.getRoutes());
+            InputStream is = getClass().getResourceAsStream(routePath);
+            routes = getContext().loadRoutesDefinition(is);
+            camelContext.addRouteDefinitions(routes.getRoutes());
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            LOG.error("Unexpected error", e);
+        }
+    }
+
+    protected void sendMessage(String uri, Object obj) {
+        Exchange exc = new DefaultExchange(getContext());
+        DefaultMessage m = new DefaultMessage();
+        m.setBody(obj);
+        exc.setIn(m);
+        ProducerTemplate template = getContext().createProducerTemplate();
+        template.send(uri, exc);
+    }
+
+    protected void sendMessage(String uri, Object obj, Map<String, Object> properties) {
+        Exchange exc = new DefaultExchange(getContext());
+        
+        Iterator<Map.Entry<String, Object>> it = properties.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, Object> property = it.next();
+            exc.setProperty(property.getKey(), property.getValue());
+            LOG.info("Added property {}", property.getKey());            
+        }
+
+        DefaultMessage m = new DefaultMessage();
+        m.setBody(obj);
+        exc.setIn(m);
+        ProducerTemplate template = getContext().createProducerTemplate();
+        template.send(uri, exc);
+    }
+
+    protected PollingConsumer getConsumer(final String uri) {
+
+        if (!knownUri.contains(uri)) {
+            knownUri.add(uri);
+            Endpoint endpoint = getContext().getEndpoint(uri);
+            PollingConsumer pollingConsumer = null;
+            try {
+                pollingConsumer = endpoint.createPollingConsumer();
+                consumerMap.put(uri, pollingConsumer);
+                pollingConsumer.start();
+            } catch (Exception ex) {
+                LOG.error("Unexpected error in Consumer creation ", ex);
+            }
+            return pollingConsumer;
+        } else {
+            return consumerMap.get(uri);
+        }
+    }
+    
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(RoleTO subject) {
+        
+        return create(subject, Collections.<String>emptySet());        
+    }
+    
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(RoleTO roleTO, Set<String> excludedResources) {
+        
+        String uri = "direct:createRolePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("excludedResources", excludedResources);
+        
+        sendMessage("direct:createRole", roleTO, props);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Map.Entry.class);
+    }
+    
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> createInSync(RoleTO roleTO, Map<Long, String> roleOwnerMap, Set<String> excludedResources) throws PropagationException {
+        
+        String uri = "direct:createRoleSyncPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map<String, Object> props = new HashMap<String, Object>();        
+        props.put("roleOwnerMap", roleOwnerMap);
+        props.put("excludedResources", excludedResources);
+           
+        sendMessage("direct:createRoleSync", roleTO, props);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {            
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+        
+        return o.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> update(RoleMod subjectMod) {
+                
+        return update(subjectMod, Collections.<String>emptySet());
+    }
+    
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> update(RoleMod subjectMod, Set<String> excludedResources) {
+
+        String uri = "direct:updateRolePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:updateRole",subjectMod, props);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Map.Entry.class);        
+    }
+
+    @Override
+    public List<PropagationStatus> delete(Long subjectId) {
+        
+        String uri = "direct:deleteRolePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        sendMessage("direct:deleteRole", subjectId);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(List.class);
+    }
+
+    @Override
+    public Long unlink(RoleMod subjectMod) {
+        String uri = "direct:unlinkRolePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        sendMessage("direct:unlinkRole", subjectMod);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Long.class);
+    }
+
+    @Override
+    public Long link(RoleMod subjectMod) {
+        
+        String uri = "direct:linkRolePort";
+        
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        sendMessage("direct:linkRole", subjectMod);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Long.class);  
+    }
+
+    @Override
+    public List<PropagationStatus> deprovision(final Long roleId, Collection<String> resources) {
+                
+        String uri = "direct:deprovisionRolePort";
+        
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        
+        Map props = new HashMap<String, Object>();
+        props.put("resources", resources);
+
+        sendMessage("direct:deprovisionRole", roleId, props);
+        
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+        
+        return o.getIn().getBody(List.class);
+    }
+   
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java
new file mode 100644
index 0000000..dc0c552
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java
@@ -0,0 +1,456 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.camel;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.URLDecoder;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.PollingConsumer;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.DefaultExchange;
+import org.apache.camel.impl.DefaultMessage;
+import org.apache.camel.model.Constants;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.model.RoutesDefinition;
+import org.apache.camel.spring.SpringCamelContext;
+import org.apache.syncope.common.mod.StatusMod;
+import org.apache.syncope.common.mod.UserMod;
+import org.apache.syncope.common.to.PropagationStatus;
+import org.apache.syncope.common.to.UserTO;
+import org.apache.syncope.core.persistence.beans.CamelRoute;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
+import org.apache.syncope.core.persistence.dao.RouteDAO;
+import org.apache.syncope.core.propagation.PropagationByResource;
+import org.apache.syncope.core.provisioning.UserProvisioningManager;
+import org.apache.syncope.core.sync.SyncResult;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class CamelUserProvisioningManager implements UserProvisioningManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CamelUserProvisioningManager.class);
+
+    private DefaultCamelContext camelContext;
+
+    private RoutesDefinition routes;
+
+    protected Map<String, PollingConsumer> consumerMap;
+
+    protected List<String> knownUri;
+
+    @Autowired
+    protected RouteDAO routeDAO;
+    
+    @Autowired
+    protected SyncopeCamelContext contextFactory;
+
+    public CamelUserProvisioningManager() throws Exception {
+        knownUri = new ArrayList<String>();
+        consumerMap = new HashMap();
+    }
+
+    public String readerToString(Reader reader, int size) throws IOException {
+        StringBuffer content = new StringBuffer();
+        char[] buffer = new char[size];
+        int n;
+
+        while ((n = reader.read(buffer)) != -1) {
+            content.append(buffer, 0, n);
+        }
+
+        return content.toString();
+    }
+    
+    public void startContext() throws Exception {
+        getContext().start();
+    }
+
+    public void stopContext() throws Exception {
+        camelContext.stop();
+    }
+
+    public CamelContext getContext() {
+        //ApplicationContext context = ApplicationContextProvider.getApplicationContext();
+        //return context.getBean("camel-context", DefaultCamelContext.class);                    
+        return contextFactory.getContext(routeDAO);
+    }
+
+    protected List<CamelRoute> getRoutes() {
+        return routeDAO.findAll();
+    }
+
+    public void changeRoute(String routePath) {
+        try {
+            camelContext.removeRouteDefinitions(routes.getRoutes());
+            InputStream is = getClass().getResourceAsStream(routePath);
+            routes = getContext().loadRoutesDefinition(is);
+            camelContext.addRouteDefinitions(routes.getRoutes());
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            LOG.error("Unexpected error", e);
+        }
+    }
+
+    protected void sendMessage(String uri, Object obj) {
+        Exchange exc = new DefaultExchange(getContext());
+        DefaultMessage m = new DefaultMessage();
+        m.setBody(obj);
+        exc.setIn(m);
+        ProducerTemplate template = getContext().createProducerTemplate();
+        template.send(uri, exc);
+    }
+
+    protected void sendMessage(String uri, Object obj, Map<String, Object> properties) {
+        Exchange exc = new DefaultExchange(getContext());
+
+        Iterator<Map.Entry<String, Object>> it = properties.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, Object> property = it.next();
+            exc.setProperty(property.getKey(), property.getValue());
+            LOG.info("Added property {}", property.getKey());
+        }
+
+        DefaultMessage m = new DefaultMessage();
+        m.setBody(obj);
+        exc.setIn(m);
+        ProducerTemplate template = getContext().createProducerTemplate();
+        template.send(uri, exc);
+    }
+
+    protected PollingConsumer getConsumer(String uri) {
+        if (!knownUri.contains(uri)) {
+            knownUri.add(uri);
+            Endpoint endpoint = getContext().getEndpoint(uri);
+            PollingConsumer pollingConsumer = null;
+            try {
+                pollingConsumer = endpoint.createPollingConsumer();
+                consumerMap.put(uri, pollingConsumer);
+                pollingConsumer.start();
+            } catch (Exception ex) {
+                LOG.error("Unexpected error in Consumer creation ", ex);
+            }
+            return pollingConsumer;
+        } else {
+            return consumerMap.get(uri);
+        }
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO) {
+
+        return create(userTO, true, false, null, Collections.<String>emptySet());
+    }
+    
+    
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO, boolean storePassword) {
+
+        return create(userTO, storePassword, false, null, Collections.<String>emptySet());
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword, boolean disablePwdPolicyCheck, Boolean enabled, Set<String> excludedResources) {
+        String uri = "direct:createPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("storePassword", storePassword);
+        props.put("disablePwdPolicyCheck", disablePwdPolicyCheck);
+        props.put("enabled", enabled);
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:createUser", userTO, props);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Map.Entry.class);
+    }
+
+    /**
+     *
+     * @param userMod
+     * @return
+     * @throws RuntimeException if problems arise on workflow update
+     */
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> update(final UserMod userMod) {
+        return update(userMod, false);
+    }
+    
+    
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> update(UserMod userMod, boolean removeMemberships) {
+        String uri = "direct:updatePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("removeMemberships", removeMemberships);
+
+        sendMessage("direct:updateUser", userMod, props);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Map.Entry.class);    
+    }
+
+
+    @Override
+    public List<PropagationStatus> delete(final Long userId) {
+
+        return delete(userId, Collections.<String>emptySet());
+    }
+
+    @Override
+    public List<PropagationStatus> delete(final Long userId, Set<String> excludedResources) {
+        String uri = "direct:deletePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:deleteUser", userId, props);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(List.class);
+    }
+
+    @Override
+    public Long unlink(final UserMod userMod) {
+        String uri = "direct:unlinkPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        sendMessage("direct:unlinkUser", userMod);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        o.getIn().setBody((o.getIn().getBody(UserMod.class).getId()));
+        return o.getIn().getBody(Long.class);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> activate(SyncopeUser user, StatusMod statusMod) {
+        String uri = "direct:statusPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map props = new HashMap<String, Object>();
+        props.put("token", statusMod.getToken());
+        props.put("user", user);
+        props.put("statusMod", statusMod);
+
+        if (statusMod.isOnSyncope()) {
+            sendMessage("direct:activateUser", user.getId(), props);
+        } else {
+            WorkflowResult<Long> updated = new WorkflowResult<Long>(user.getId(), null, statusMod.getType().name().toLowerCase());
+            sendMessage("direct:statusUser", updated, props);
+        }
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> reactivate(SyncopeUser user, StatusMod statusMod) {
+        String uri = "direct:statusPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map props = new HashMap<String, Object>();
+        props.put("user", user);
+        props.put("statusMod", statusMod);
+
+        if (statusMod.isOnSyncope()) {
+            sendMessage("direct:reactivateUser", user.getId(), props);
+        } else {
+            WorkflowResult<Long> updated = new WorkflowResult<Long>(user.getId(), null, statusMod.getType().name().toLowerCase());
+            sendMessage("direct:statusUser", updated, props);
+        }
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> suspend(SyncopeUser user, StatusMod statusMod) {
+
+        String uri = "direct:statusPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map props = new HashMap<String, Object>();
+        props.put("user", user);
+        props.put("statusMod", statusMod);
+
+        if (statusMod.isOnSyncope()) {
+            sendMessage("direct:suspendUser", user.getId(), props);
+        } else {
+            WorkflowResult<Long> updated = new WorkflowResult<Long>(user.getId(), null, statusMod.getType().name().toLowerCase());
+            sendMessage("direct:statusUser", updated, props);
+        }
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public Long link(UserMod subjectMod) {
+        String uri = "direct:linkPort";
+
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        sendMessage("direct:linkUser", subjectMod);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        o.getIn().setBody((o.getIn().getBody(UserMod.class).getId()));
+        return o.getIn().getBody(Long.class);
+    }
+
+    @Override
+    public List<PropagationStatus> deprovision(Long user, Collection<String> resources) {
+        String uri = "direct:deprovisionPort";
+
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map props = new HashMap<String, Object>();
+        props.put("resources", resources);
+
+        sendMessage("direct:deprovisionUser", user, props);
+
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return o.getIn().getBody(List.class);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> updateInSync(UserMod userMod, Long id, SyncResult result, Boolean enabled, Set<String> excludedResources) {
+
+        String uri = "direct:updateSyncPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("id", id);
+        props.put("result", result);
+        props.put("enabled", enabled);
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:updateSyncUser", userMod, props);
+
+        Exchange o = pollingConsumer.receive();
+        Exception e;
+        if ((e = (Exception) o.getProperty(Exchange.EXCEPTION_CAUGHT)) != null) {
+
+            LOG.error("Update of user {} failed, trying to sync its status anyway (if configured)", id, e);
+
+            result.setStatus(SyncResult.Status.FAILURE);
+            result.setMessage("Update failed, trying to sync status anyway (if configured)\n" + e.getMessage());
+
+            WorkflowResult<Map.Entry<UserMod, Boolean>> updated = new WorkflowResult<Map.Entry<UserMod, Boolean>>(
+                    new AbstractMap.SimpleEntry<UserMod, Boolean>(userMod, false), new PropagationByResource(),
+                    new HashSet<String>());
+            sendMessage("direct:syncUserStatus", updated, props);
+            o = pollingConsumer.receive();
+        }
+
+        return o.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public void innerSuspend(SyncopeUser user, boolean suspend) {
+
+        String uri = "direct:suspendWFPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+
+        Map<String, Object> props = new HashMap<String, Object>();
+        props.put("suspend", suspend);
+
+        sendMessage("direct:suspendUserWF", user, props);
+        Exchange o = pollingConsumer.receive();
+
+        if (o.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) o.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/SyncopeCamelContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/SyncopeCamelContext.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/SyncopeCamelContext.java
new file mode 100644
index 0000000..6381649
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/SyncopeCamelContext.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.syncope.core.provisioning.camel;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.camel.CamelContext;
+import org.apache.camel.model.Constants;
+import org.apache.camel.model.RouteDefinition;
+import org.apache.camel.spring.SpringCamelContext;
+import org.apache.syncope.core.persistence.beans.CamelRoute;
+import org.apache.syncope.core.persistence.dao.RouteDAO;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+
+@Component
+public class SyncopeCamelContext{
+
+    private static final Logger LOG = LoggerFactory.getLogger(SyncopeCamelContext.class);
+
+    private CamelContext camelContext = null;                   
+    
+    public SyncopeCamelContext() { 
+    }
+    
+    public CamelContext getContext(RouteDAO routeDAO){
+
+        if(camelContext == null) camelContext = new SpringCamelContext(ApplicationContextProvider.getApplicationContext());              
+        if(camelContext.getRouteDefinitions().isEmpty()){            
+            
+            List<CamelRoute> crl = routeDAO.findAll();
+            LOG.info("{} route(s) are going to be loaded ", crl.size());                
+            loadContext(routeDAO, crl);
+                
+            try {
+                camelContext.start();
+            } catch (Exception ex) {
+                LOG.error("Error during staring camel context {}", ex);
+            }
+        }
+        
+        return camelContext;
+    }
+    
+    public void loadContext(RouteDAO routeDAO, List<CamelRoute> crl){
+        
+        try {
+            DocumentBuilder dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+            JAXBContext jaxbContext = JAXBContext.newInstance(Constants.JAXB_CONTEXT_PACKAGES);
+            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+            List rds = new ArrayList();
+
+            for (int s = 0; s < crl.size(); s++) {
+
+                InputStream is = new ByteArrayInputStream( URLDecoder.decode(crl.get(s).getRouteContent(), "UTF-8").getBytes());
+                Document doc = dBuilder.parse(is);
+                doc.getDocumentElement().normalize();
+                Node routeEl = doc.getElementsByTagName("route").item(0);
+                JAXBElement obj = unmarshaller.unmarshal(routeEl, RouteDefinition.class);
+                //adding route definition to list                        
+                rds.add(obj.getValue());
+            }
+            camelContext.addRouteDefinitions(rds);
+        } catch (Exception ex) {
+            LOG.error("Error during loading camel context {}", ex);
+        }
+    
+    }
+    
+    public void reloadContext(RouteDAO routeDAO){
+        
+        List<CamelRoute> crl = routeDAO.findAll();
+        if(camelContext == null) getContext(routeDAO);
+        else {            
+            if( ! camelContext.getRouteDefinitions().isEmpty()){                    
+                for (Iterator<RouteDefinition> it = camelContext.getRouteDefinitions().iterator(); it.hasNext(); ) {
+                    RouteDefinition ard = it.next();
+                    it.remove();                       
+                }                    
+            }
+
+            loadContext(routeDAO, crl);
+        }
+    }
+    
+    public void reloadContext(RouteDAO routeDAO, Long routeId){
+        
+        if(camelContext == null) getContext(routeDAO);
+        else {            
+            if( ! camelContext.getRouteDefinitions().isEmpty()){
+                                
+                camelContext.getRouteDefinitions().remove(routeId.intValue());
+                List<CamelRoute> crl = new ArrayList<CamelRoute>();
+                crl.add(routeDAO.find(routeId));
+                loadContext(routeDAO, crl);
+            }
+                
+        }
+            
+    }
+    
+    public List<RouteDefinition> getDefinitions(){
+        return camelContext.getRouteDefinitions();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleCreatePropagation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleCreatePropagation.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleCreatePropagation.java
new file mode 100644
index 0000000..a6b40fb
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleCreatePropagation.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.core.provisioning.camel.processors;
+
+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.to.PropagationStatus;
+import org.apache.syncope.common.to.RoleTO;
+import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationReporter;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.apache.syncope.core.util.EntitlementUtil;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultRoleCreatePropagation  implements Processor{
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultRoleCreatePropagation.class);
+    
+    @Autowired
+    protected PropagationManager propagationManager;
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+    
+    @Override
+    public void process(Exchange exchange){
+        
+        WorkflowResult<Long> created = (WorkflowResult) exchange.getIn().getBody();
+        RoleTO subject = exchange.getProperty("subject", RoleTO.class);
+        Set<String> excludedResource = exchange.getProperty("excludedResources", Set.class);            
+                
+        EntitlementUtil.extendAuthContext(created.getResult());
+
+        List<PropagationTask> tasks = propagationManager.getRoleCreateTaskIds(created, subject.getVirAttrs());
+        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);
+        }
+        
+        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(
+                created.getResult(), propagationReporter.getStatuses());
+        
+        exchange.getOut().setBody(result);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleCreateSyncPropagation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleCreateSyncPropagation.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleCreateSyncPropagation.java
new file mode 100644
index 0000000..ea8df72
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleCreateSyncPropagation.java
@@ -0,0 +1,79 @@
+package org.apache.syncope.core.provisioning.camel.processors;
+
+/*
+ * 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.Collections;
+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.to.RoleTO;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.to.AttributeTO;
+import org.apache.syncope.common.to.PropagationStatus;
+import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.util.EntitlementUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DefaultRoleCreateSyncPropagation implements Processor{
+
+        
+    @Autowired
+    protected PropagationManager propagationManager;
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+    
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultRoleCreateSyncPropagation.class);
+    
+    @Override
+    public void process(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);
+        
+        AttributeTO roleOwner = actual.getAttrMap().get(StringUtils.EMPTY);
+
+        if (roleOwner != null) {
+            roleOwnerMap.put(created.getResult(), roleOwner.getValues().iterator().next());
+        }
+
+        EntitlementUtil.extendAuthContext(created.getResult());
+
+        List<PropagationTask> tasks = propagationManager.getRoleCreateTaskIds(created,
+                actual.getVirAttrs(), excludedResource);
+
+        taskExecutor.execute(tasks);
+        
+        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(
+                created.getResult(), Collections.<PropagationStatus>emptyList());
+        
+        exchange.getOut().setBody(result);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleDeletePropagation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleDeletePropagation.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleDeletePropagation.java
new file mode 100644
index 0000000..1d2c20e
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleDeletePropagation.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.syncope.core.provisioning.camel.processors;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
+import org.apache.syncope.core.persistence.dao.RoleDAO;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationReporter;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.rest.data.RoleDataBinder;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.apache.syncope.core.workflow.role.RoleWorkflowAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultRoleDeletePropagation implements Processor{
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultRoleDeletePropagation.class);
+    @Autowired
+    protected RoleWorkflowAdapter rwfAdapter;
+    @Autowired
+    protected PropagationManager propagationManager;
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;    
+    @Autowired
+    protected RoleDAO roleDAO;
+    @Autowired
+    protected RoleDataBinder binder;
+    
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        
+        Long subjectId = exchange.getIn().getBody(Long.class);
+        
+        final List<SyncopeRole> toBeDeprovisioned = new ArrayList<SyncopeRole>();
+
+        final SyncopeRole syncopeRole = roleDAO.find(subjectId);
+
+        if (syncopeRole != null) {
+            toBeDeprovisioned.add(syncopeRole);
+
+            final List<SyncopeRole> descendants = roleDAO.findDescendants(toBeDeprovisioned.get(0));
+            if (descendants != null) {
+                toBeDeprovisioned.addAll(descendants);
+            }
+        }
+
+        final List<PropagationTask> tasks = new ArrayList<PropagationTask>();
+
+        for (SyncopeRole 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 (WorkflowResult<Long> wfResult : binder.getUsersOnResourcesOnlyBecauseOfRole(role.getId())) {
+                tasks.addAll(propagationManager.getUserDeleteTaskIds(wfResult));
+            }
+
+            // Generate propagation tasks for deleting this role from resources
+            tasks.addAll(propagationManager.getRoleDeleteTaskIds(role.getId()));
+        }
+
+        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/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleDeprovisionPropagation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleDeprovisionPropagation.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleDeprovisionPropagation.java
new file mode 100644
index 0000000..0f02258
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleDeprovisionPropagation.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.core.provisioning.camel.processors;
+
+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.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationReporter;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.rest.data.RoleDataBinder;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultRoleDeprovisionPropagation implements Processor{
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultUserDeprovisionPropagation.class);
+    
+    @Autowired
+    protected PropagationManager propagationManager;
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+    @Autowired
+    protected RoleDataBinder binder;
+    
+    @Override
+    public void process(Exchange exchange){
+        
+        Long roleId = exchange.getIn().getBody(Long.class);
+        List<String> resources = exchange.getProperty("resources", List.class);
+        
+        final SyncopeRole role = binder.getRoleFromId(roleId);
+        
+        final Set<String> noPropResourceName = role.getResourceNames();
+        noPropResourceName.removeAll(resources);
+        
+        final List<PropagationTask> tasks = propagationManager.getRoleDeleteTaskIds(roleId, new HashSet<String>(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/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleUpdatePropagation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleUpdatePropagation.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleUpdatePropagation.java
new file mode 100644
index 0000000..cc2fcc0
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultRoleUpdatePropagation.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.camel.processors;
+
+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.mod.RoleMod;
+import org.apache.syncope.common.to.PropagationStatus;
+import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationReporter;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.rest.data.UserDataBinder;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultRoleUpdatePropagation implements Processor{
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultUserUpdatePropagation.class);
+    
+    @Autowired
+    protected PropagationManager propagationManager;
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+    @Autowired
+    protected UserDataBinder binder;
+    
+    @Override
+    public void process(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);
+        }
+        
+        Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(
+                updated.getResult(), propagationReporter.getStatuses());
+        
+        exchange.getOut().setBody(result);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserCreatePropagation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserCreatePropagation.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserCreatePropagation.java
new file mode 100644
index 0000000..c71e3dc
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserCreatePropagation.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.core.provisioning.camel.processors;
+
+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.to.PropagationStatus;
+import org.apache.syncope.common.to.UserTO;
+import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationReporter;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.apache.syncope.core.workflow.WorkflowResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultUserCreatePropagation implements Processor{
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultUserCreatePropagation.class);
+    
+    @Autowired
+    protected PropagationManager propagationManager;
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+    
+    @Override
+    public void process(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);
+            }
+            
+            Map.Entry<Long, List<PropagationStatus>> result = new AbstractMap.SimpleEntry<Long, List<PropagationStatus>>(created.getResult().getKey(), propagationReporter.getStatuses());         
+            exchange.getOut().setBody(result);
+        }               
+    }
+    
+    
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserDeletePropagation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserDeletePropagation.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserDeletePropagation.java
new file mode 100644
index 0000000..1afef83
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserDeletePropagation.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.core.provisioning.camel.processors;
+
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationReporter;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+
+public class DefaultUserDeletePropagation implements Processor{
+    
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultUserDeletePropagation.class);
+    @Autowired
+    protected PropagationManager propagationManager;
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+    
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        
+        Long userId = (Long) exchange.getIn().getBody();       
+        LOG.info("UserId {} ", userId);
+        
+        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(userId,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/5b3b124a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserDeprovisionPropagation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserDeprovisionPropagation.java b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserDeprovisionPropagation.java
new file mode 100644
index 0000000..f62e4b6
--- /dev/null
+++ b/core/src/main/java/org/apache/syncope/core/provisioning/camel/processors/DefaultUserDeprovisionPropagation.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.core.provisioning.camel.processors;
+
+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.core.persistence.beans.PropagationTask;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
+import org.apache.syncope.core.propagation.PropagationException;
+import org.apache.syncope.core.propagation.PropagationReporter;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.propagation.impl.PropagationManager;
+import org.apache.syncope.core.rest.data.UserDataBinder;
+import org.apache.syncope.core.util.ApplicationContextProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class DefaultUserDeprovisionPropagation implements Processor{
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultUserDeprovisionPropagation.class);
+    
+    @Autowired
+    protected PropagationManager propagationManager;
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+    @Autowired
+    protected UserDataBinder binder;
+    
+    @Override
+    public void process(Exchange exchange){
+        
+        Long userId = exchange.getIn().getBody(Long.class);
+        List<String> resources = exchange.getProperty("resources", List.class);
+        
+        final SyncopeUser user = binder.getUserFromId(userId);        
+        
+        final Set<String> noPropResourceName = user.getResourceNames();
+        noPropResourceName.removeAll(resources);
+        
+        final List<PropagationTask> tasks =
+                propagationManager.getUserDeleteTaskIds(userId, new HashSet<String>(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());
+    }
+    
+}