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/31 15:31:39 UTC

[4/4] syncope git commit: [SYNCOPE-620] Camel extension in: now time for IT

[SYNCOPE-620] Camel extension in: now time for IT


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

Branch: refs/heads/2_0_X
Commit: dae87ef8989ad20818e45a05ff7830d709286da1
Parents: cc922e6
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Sat Jan 31 15:31:25 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Sat Jan 31 15:31:25 2015 +0100

----------------------------------------------------------------------
 .../syncope/common/rest/api/RESTHeaders.java    |  21 --
 .../rest/api/service/WorkflowService.java       |  20 --
 syncope620/ext/camel/common-lib/pom.xml         |  60 ++++
 .../syncope/common/lib/to/CamelRouteTO.java     |  60 ++++
 syncope620/ext/camel/logic/pom.xml              |  65 ++++
 .../syncope/server/logic/CamelRouteLogic.java   |  88 +++++
 .../server/logic/init/CamelRouteLoader.java     | 141 ++++++++
 syncope620/ext/camel/persistence-api/pom.xml    |  60 ++++
 .../persistence/api/dao/CamelRouteDAO.java      |  37 ++
 .../api/entity/CamelEntityFactory.java          |  24 ++
 .../persistence/api/entity/CamelRoute.java      |  34 ++
 syncope620/ext/camel/persistence-jpa/pom.xml    | 138 ++++++++
 .../persistence/jpa/dao/JPACamelRouteDAO.java   |  71 ++++
 .../jpa/entity/JPACamelEntityFactory.java       |  33 ++
 .../persistence/jpa/entity/JPACamelRoute.java   |  79 +++++
 syncope620/ext/camel/pom.xml                    |  47 +++
 syncope620/ext/camel/provisioning-api/pom.xml   |  71 ++++
 .../api/data/CamelRouteDataBinder.java          |  29 ++
 syncope620/ext/camel/provisioning-camel/pom.xml |  78 +++++
 .../camel/AbstractCamelProvisioningManager.java | 103 ++++++
 .../camel/CamelRoleProvisioningManager.java     | 174 ++++++++++
 .../camel/CamelUserProvisioningManager.java     | 342 +++++++++++++++++++
 .../provisioning/camel/SyncopeCamelContext.java | 134 ++++++++
 .../camel/data/CamelRouteDataBinderImpl.java    |  48 +++
 .../src/main/resources/provisioning.properties  |  18 +
 .../src/main/resources/roleRoutes.xml           | 168 +++++++++
 .../src/main/resources/userRoutes.xml           | 304 +++++++++++++++++
 syncope620/ext/camel/rest-api/pom.xml           |  65 ++++
 .../rest/api/service/CamelRouteService.java     |  51 +++
 syncope620/ext/camel/rest-cxf/pom.xml           |  70 ++++
 .../rest/cxf/service/CamelRouteServiceImpl.java |  51 +++
 syncope620/ext/pom.xml                          |  40 +++
 .../src/main/resources/serverContext.xml        |   2 +
 syncope620/pom.xml                              |  22 ++
 .../logic/src/test/resources/logicTest.xml      |   1 +
 .../java/DefaultRoleProvisioningManager.java    |   2 -
 .../java/DefaultUserProvisioningManager.java    |   2 -
 .../java/data/ResourceDataBinderImpl.java       |   1 -
 .../src/main/resources/provisioning.properties  |  18 +
 .../src/main/resources/provisioningContext.xml  |   3 +
 .../src/test/resources/provisioningTest.xml     |   1 +
 .../rest/cxf/service/WorkflowServiceImpl.java   |  20 --
 42 files changed, 2730 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java
index 20e58c6..e1af7e5 100644
--- a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/RESTHeaders.java
@@ -49,27 +49,6 @@ public final class RESTHeaders {
     public static final String PWDRESET_NEEDS_SECURITYQUESTIONS = "Syncope.PasswordReset.SecurityQuestions";
 
     /**
-     * Option key stating if Activiti workflow adapter is in use for users.
-     */
-    public static final String ACTIVITI_USER_ENABLED = "Syncope.Activiti.User.Enabled";
-
-    /**
-     * Option key stating if Activiti workflow adapter is in use for roles.
-     */
-    public static final String ACTIVITI_ROLE_ENABLED = "Syncope.Activiti.Role.Enabled";
-    
-     /**
-     * Option key stating if Camel is the current provisioning manager engine.
-     */
-    public static final String CAMEL_USER_PROVISIONING_MANAGER ="Syncope.Provisioning.Camel.User.Enabled";
-    
-    /**
-     * Option key stating if Camel is the current provisioning manager engine.
-     */
-    public static final String CAMEL_ROLE_PROVISIONING_MANAGER ="Syncope.Provisioning.Camel.Role.Enabled";
-
-
-    /**
      * HTTP header key for object ID assigned to an object after its creation.
      */
     public static final String RESOURCE_ID = "Syncope.Id";

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java
----------------------------------------------------------------------
diff --git a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java
index 7b8aded..92aa86b 100644
--- a/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java
+++ b/syncope620/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/WorkflowService.java
@@ -21,16 +21,12 @@ package org.apache.syncope.common.rest.api.service;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
-import javax.ws.rs.OPTIONS;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import org.apache.cxf.jaxrs.model.wadl.Description;
-import org.apache.cxf.jaxrs.model.wadl.Descriptions;
-import org.apache.cxf.jaxrs.model.wadl.DocTarget;
 import org.apache.syncope.common.lib.types.SubjectType;
 import org.apache.syncope.common.rest.api.RESTHeaders;
 
@@ -41,22 +37,6 @@ import org.apache.syncope.common.rest.api.RESTHeaders;
 public interface WorkflowService extends JAXRSService {
 
     /**
-     * Checks whether Activiti is enabled (for users or roles).
-     *
-     * @param kind user or role
-     * @return <tt>Response</tt> contains special syncope HTTP header indicating if Activiti is enabled for
-     * users / roles
-     * @see org.apache.syncope.common.rest.api.RESTHeaders#ACTIVITI_USER_ENABLED
-     * @see org.apache.syncope.common.rest.api.RESTHeaders#ACTIVITI_ROLE_ENABLED
-     */
-    @Descriptions({
-        @Description(target = DocTarget.RESPONSE,
-                value = "Contains special syncope HTTP header indicating if Activiti is enabled for users / roles")
-    })
-    @OPTIONS
-    Response getOptions(@NotNull @PathParam("kind") SubjectType kind);
-
-    /**
      * Exports workflow definition for matching kind.
      *
      * @param kind user or role

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/common-lib/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/common-lib/pom.xml b/syncope620/ext/camel/common-lib/pom.xml
new file mode 100644
index 0000000..db81565
--- /dev/null
+++ b/syncope620/ext/camel/common-lib/pom.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope.ext</groupId>
+    <artifactId>syncope-ext-camel</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Extensions: Camel Common Lib</name>
+  <description>Apache Syncope Extensions: Camel Common Lib</description>
+  <groupId>org.apache.syncope.ext.camel</groupId>
+  <artifactId>syncope-ext-camel-common-lib</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.common</groupId>
+      <artifactId>syncope-common-lib</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/common-lib/src/main/java/org/apache/syncope/common/lib/to/CamelRouteTO.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/common-lib/src/main/java/org/apache/syncope/common/lib/to/CamelRouteTO.java b/syncope620/ext/camel/common-lib/src/main/java/org/apache/syncope/common/lib/to/CamelRouteTO.java
new file mode 100644
index 0000000..5572336
--- /dev/null
+++ b/syncope620/ext/camel/common-lib/src/main/java/org/apache/syncope/common/lib/to/CamelRouteTO.java
@@ -0,0 +1,60 @@
+package org.apache.syncope.common.lib.to;
+
+/*
+ * 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 javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.SubjectType;
+
+@XmlRootElement(name = "camelRoute")
+@XmlType
+public class CamelRouteTO extends AbstractBaseBean {
+
+    private String name;
+
+    private SubjectType subjectType;
+
+    private String content;
+
+    public String getKey() {
+        return name;
+    }
+
+    public void setKey(final String key) {
+        this.name = key;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(final String content) {
+        this.content = content;
+    }
+
+    public SubjectType getSubjectType() {
+        return subjectType;
+    }
+
+    public void setSubjectType(final SubjectType subjectType) {
+        this.subjectType = subjectType;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/logic/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/logic/pom.xml b/syncope620/ext/camel/logic/pom.xml
new file mode 100644
index 0000000..7e93f70
--- /dev/null
+++ b/syncope620/ext/camel/logic/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope.ext</groupId>
+    <artifactId>syncope-ext-camel</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Extensions: Camel Logic</name>
+  <description>Apache Syncope Extensions: Camel Logic</description>
+  <groupId>org.apache.syncope.ext.camel</groupId>
+  <artifactId>syncope-ext-camel-logic</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.server</groupId>
+      <artifactId>syncope-server-logic</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>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/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
new file mode 100644
index 0000000..4602b51
--- /dev/null
+++ b/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/CamelRouteLogic.java
@@ -0,0 +1,88 @@
+/*
+ * 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.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.common.lib.to.CamelRouteTO;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.server.persistence.api.dao.CamelRouteDAO;
+import org.apache.syncope.server.persistence.api.dao.NotFoundException;
+import org.apache.syncope.server.persistence.api.entity.CamelRoute;
+import org.apache.syncope.server.provisioning.api.data.CamelRouteDataBinder;
+import org.apache.syncope.server.provisioning.camel.SyncopeCamelContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class CamelRouteLogic extends AbstractTransactionalLogic<CamelRouteTO> {
+
+    @Autowired
+    private CamelRouteDAO routeDAO;
+
+    @Autowired
+    private CamelRouteDataBinder binder;
+
+    @Autowired
+    private SyncopeCamelContext context;
+
+    @PreAuthorize("hasRole('ROUTE_LIST')")
+    @Transactional(readOnly = true)
+    public List<CamelRouteTO> list(final SubjectType subjectType) {
+        List<CamelRouteTO> routes = new ArrayList<>();
+
+        for (CamelRoute route : routeDAO.find(subjectType)) {
+            routes.add(binder.getRouteTO(route));
+        }
+        return routes;
+    }
+
+    @PreAuthorize("hasRole('ROUTE_READ')")
+    @Transactional(readOnly = true)
+    public CamelRouteTO read(final String key) {
+        CamelRoute route = routeDAO.find(key);
+        if (route == null) {
+            throw new NotFoundException("CamelRoute with key=" + key);
+        }
+
+        return binder.getRouteTO(route);
+    }
+
+    @PreAuthorize("hasRole('ROUTE_UPDATE')")
+    public void update(final CamelRouteTO routeTO) {
+        CamelRoute route = routeDAO.find(routeTO.getKey());
+        if (route == null) {
+            throw new NotFoundException("CamelRoute with key=" + routeTO.getKey());
+        }
+
+        LOG.debug("Updating route {} with content {}", routeTO.getKey(), routeTO.getContent());
+        binder.update(route, routeTO);
+
+        context.reloadContext(routeTO.getKey());
+    }
+
+    @Override
+    protected CamelRouteTO resolveReference(Method method, Object... args) throws UnresolvedReferenceException {
+        throw new UnresolvedReferenceException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/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
new file mode 100644
index 0000000..865b4b1
--- /dev/null
+++ b/syncope620/ext/camel/logic/src/main/java/org/apache/syncope/server/logic/init/CamelRouteLoader.java
@@ -0,0 +1,141 @@
+/*
+ * 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.logic.init;
+
+import java.io.StringWriter;
+import java.util.List;
+import java.util.Map;
+import javax.sql.DataSource;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.server.persistence.api.SyncopeLoader;
+import org.apache.syncope.server.persistence.api.entity.CamelEntityFactory;
+import org.apache.syncope.server.persistence.api.entity.CamelRoute;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+@Component
+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();
+
+    @Autowired
+    private DataSource dataSource;
+
+    @Autowired
+    private CamelEntityFactory entityFactory;
+
+    private int size = 0;
+
+    private boolean loaded = false;
+
+    @Override
+    public Integer getPriority() {
+        return 1000;
+    }
+
+    @Transactional
+    public void load() {
+        synchronized (this) {
+            if (!loaded) {
+                loadRoutes("/userRoute.xml", SubjectType.USER);
+                loadRoutes("/roleRoute.xml", SubjectType.ROLE);
+                loadEntitlements();
+                loaded = true;
+            }
+        }
+    }
+
+    private boolean routesAvailable(final SubjectType subject) {
+        final String sql = String.format("SELECT * FROM %s WHERE SUBJECT = ?", 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();
+    }
+
+    private String nodeToString(final Node node) {
+        StringWriter sw = new StringWriter();
+        try {
+            Transformer transformer = T_FACTORY.newTransformer();
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+            transformer.transform(new DOMSource(node), new StreamResult(sw));
+        } catch (TransformerException te) {
+            LOG.debug("nodeToString Transformer Exception", te);
+        }
+        return sw.toString();
+    }
+
+    private void loadRoutes(final String path, final SubjectType subjectType) {
+        if (routesAvailable(subjectType)) {
+            final String query = String.format("INSERT INTO %s(ID, NAME, SUBJECT, ROUTECONTENT) VALUES (?, ?, ?, ?)",
+                    CamelRoute.class.getSimpleName());
+            try {
+                final DocumentBuilder dBuilder = DOC_FACTORY.newDocumentBuilder();
+                final Document doc = dBuilder.parse(getClass().getResourceAsStream(path));
+                doc.getDocumentElement().normalize();
+                final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
+                final NodeList listOfRoutes = doc.getElementsByTagName("route");
+                for (int s = 0; s < listOfRoutes.getLength(); s++) {
+                    //getting the route node element
+                    Node routeEl = listOfRoutes.item(s);
+                    //crate an instance of CamelRoute Entity
+                    CamelRoute route = entityFactory.newCamelRoute();
+                    route.setSubjectType(subjectType);
+                    route.setKey(((Element) routeEl).getAttribute("id"));
+                    route.setContent(nodeToString(listOfRoutes.item(s)));
+
+                    jdbcTemplate.update(query, new Object[] { size++, ((Element) routeEl).getAttribute("id"),
+                        subjectType.name(), nodeToString(listOfRoutes.item(s)) });
+                    LOG.debug("Route {} successfully registered", ((Element) routeEl).getAttribute("id"));
+                }
+            } catch (DataAccessException e) {
+                LOG.error("While trying to store queries {}", e);
+            } catch (Exception e) {
+                LOG.error("Route Registration failed {}", e.getMessage());
+            }
+        }
+    }
+
+    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')");
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/persistence-api/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/persistence-api/pom.xml b/syncope620/ext/camel/persistence-api/pom.xml
new file mode 100644
index 0000000..75f89af
--- /dev/null
+++ b/syncope620/ext/camel/persistence-api/pom.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope.ext</groupId>
+    <artifactId>syncope-ext-camel</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Extensions: Camel Persistence API</name>
+  <description>Apache Syncope Extensions: Camel Persistence API</description>
+  <groupId>org.apache.syncope.ext.camel</groupId>
+  <artifactId>syncope-ext-camel-persistence-api</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.server</groupId>
+      <artifactId>syncope-server-persistence-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/dao/CamelRouteDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/dao/CamelRouteDAO.java b/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/dao/CamelRouteDAO.java
new file mode 100644
index 0000000..dd39781
--- /dev/null
+++ b/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/dao/CamelRouteDAO.java
@@ -0,0 +1,37 @@
+/*
+ * 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.api.dao;
+
+import java.util.List;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.server.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.server.persistence.api.entity.CamelRoute;
+
+public interface CamelRouteDAO extends DAO<CamelRoute, String> {
+
+    CamelRoute find(String key);
+
+    List<CamelRoute> find(SubjectType subjectType);
+
+    List<CamelRoute> findAll();
+
+    CamelRoute save(CamelRoute route) throws InvalidEntityException;
+
+    void delete(String key);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/entity/CamelEntityFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/entity/CamelEntityFactory.java b/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/entity/CamelEntityFactory.java
new file mode 100644
index 0000000..49bd2cb
--- /dev/null
+++ b/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/entity/CamelEntityFactory.java
@@ -0,0 +1,24 @@
+/*
+ * 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.api.entity;
+
+public interface CamelEntityFactory {
+
+    CamelRoute newCamelRoute();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/entity/CamelRoute.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/entity/CamelRoute.java b/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/entity/CamelRoute.java
new file mode 100644
index 0000000..f2b166c
--- /dev/null
+++ b/syncope620/ext/camel/persistence-api/src/main/java/org/apache/syncope/server/persistence/api/entity/CamelRoute.java
@@ -0,0 +1,34 @@
+/*
+ * 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.api.entity;
+
+import org.apache.syncope.common.lib.types.SubjectType;
+
+public interface CamelRoute extends Entity<String> {
+
+    String getContent();
+
+    SubjectType getSubjectType();
+
+    void setKey(String name);
+
+    void setContent(String routeContent);
+
+    void setSubjectType(SubjectType subject);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/persistence-jpa/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/persistence-jpa/pom.xml b/syncope620/ext/camel/persistence-jpa/pom.xml
new file mode 100644
index 0000000..ab16419
--- /dev/null
+++ b/syncope620/ext/camel/persistence-jpa/pom.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope.ext</groupId>
+    <artifactId>syncope-ext-camel</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Extensions: Camel Persistence JPA</name>
+  <description>Apache Syncope Extensions: Camel Persistence JPA</description>
+  <groupId>org.apache.syncope.ext.camel</groupId>
+  <artifactId>syncope-ext-camel-persistence-jpa</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>    
+    <dependency>
+      <groupId>org.apache.syncope.server</groupId>
+      <artifactId>syncope-server-persistence-jpa</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.camel</groupId>
+      <artifactId>syncope-ext-camel-persistence-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.openjpa</groupId>
+        <artifactId>openjpa-maven-plugin</artifactId>
+        <inherited>true</inherited>
+        <dependencies>
+          <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>${h2.version}</version>
+          </dependency>
+        </dependencies>
+        <configuration>
+          <persistenceXmlFile>${rootpom.basedir}/server/persistence-jpa/src/main/resources/META-INF/spring-persistence.xml</persistenceXmlFile> 
+          <includes>org/apache/syncope/server/persistence/jpa/entity/**/*.class</includes>
+          <connectionDriverName>org.springframework.jdbc.datasource.DriverManagerDataSource</connectionDriverName>
+          <connectionProperties>
+            driverClassName=org.h2.Driver,
+            url=jdbc:h2:mem:syncopedb
+            username=sa,
+            password=
+          </connectionProperties>
+        </configuration>
+        <executions>
+          <execution>
+            <id>enhancer</id>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>enhance</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+    </plugins>
+
+    <testResources>
+      <testResource>
+        <directory>${rootpom.basedir}/server/persistence-jpa/src/main/resources</directory>
+        <filtering>true</filtering>        
+      </testResource>
+    </testResources>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>sqlgen</id>
+      
+      <properties>
+        <skipTests>true</skipTests>
+      </properties>
+      
+      <build>
+        <defaultGoal>clean verify</defaultGoal>
+        
+        <plugins>
+          <plugin>
+            <groupId>org.apache.openjpa</groupId>
+            <artifactId>openjpa-maven-plugin</artifactId>
+            <inherited>true</inherited>
+            <executions>
+              <execution>
+                <id>sqlgenr</id>
+                <phase>process-classes</phase>
+                <goals>
+                  <goal>sql</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>          
+        </plugins>
+      </build>
+        
+    </profile>
+  </profiles>
+
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/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
new file mode 100644
index 0000000..3302150
--- /dev/null
+++ b/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/dao/JPACamelRouteDAO.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.persistence.jpa.dao;
+
+import java.util.List;
+import javax.persistence.TypedQuery;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.server.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.server.persistence.api.dao.CamelRouteDAO;
+import org.apache.syncope.server.persistence.api.entity.CamelRoute;
+import org.apache.syncope.server.persistence.jpa.entity.JPACamelRoute;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+@Repository
+public class JPACamelRouteDAO extends AbstractDAO<CamelRoute, String> implements CamelRouteDAO {
+
+    @Override
+    public CamelRoute find(final String key) {
+        return entityManager.find(CamelRoute.class, key);
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public List<CamelRoute> find(final SubjectType subjectType) {
+        TypedQuery<CamelRoute> query = entityManager.createQuery(
+                "SELECT e FROM " + JPACamelRoute.class.getSimpleName()
+                + " e WHERE e.subjectType = :subjectType", CamelRoute.class);
+        query.setParameter("subjectType", subjectType);
+
+        return query.getResultList();
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public List<CamelRoute> findAll() {
+        TypedQuery<CamelRoute> query = entityManager.createQuery(
+                "SELECT e FROM " + JPACamelRoute.class.getSimpleName() + " e ", CamelRoute.class);
+        return query.getResultList();
+    }
+
+    @Override
+    public CamelRoute save(final CamelRoute route) throws InvalidEntityException {
+        return entityManager.merge(route);
+    }
+
+    @Override
+    public void delete(final String key) {
+        CamelRoute route = find(key);
+        if (route != null) {
+            entityManager.remove(route);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelEntityFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelEntityFactory.java b/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelEntityFactory.java
new file mode 100644
index 0000000..f4fee00
--- /dev/null
+++ b/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelEntityFactory.java
@@ -0,0 +1,33 @@
+/*
+ * 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.entity;
+
+import org.apache.syncope.server.persistence.api.entity.CamelEntityFactory;
+import org.apache.syncope.server.persistence.api.entity.CamelRoute;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JPACamelEntityFactory implements CamelEntityFactory {
+
+    @Override
+    public CamelRoute newCamelRoute() {
+        return new JPACamelRoute();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/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
new file mode 100644
index 0000000..d9d5fad
--- /dev/null
+++ b/syncope620/ext/camel/persistence-jpa/src/main/java/org/apache/syncope/server/persistence/jpa/entity/JPACamelRoute.java
@@ -0,0 +1,79 @@
+/*
+ * 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.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.server.persistence.api.entity.CamelRoute;
+
+@Entity
+@Table(name = JPACamelRoute.TABLE)
+public class JPACamelRoute extends AbstractEntity<String> implements CamelRoute {
+
+    private static final long serialVersionUID = -2767606675667839161L;
+
+    public static final String TABLE = "CamelRoute";
+
+    @Id
+    private String name;
+
+    @NotNull
+    @Enumerated(EnumType.STRING)
+    private SubjectType subject;
+
+    @Lob
+    private String content;
+
+    @Override
+    public String getKey() {
+        return name;
+    }
+
+    @Override
+    public void setKey(final String name) {
+        this.name = name;
+    }
+
+    @Override
+    public SubjectType getSubjectType() {
+        return subject;
+    }
+
+    @Override
+    public void setSubjectType(final SubjectType subject) {
+        this.subject = subject;
+    }
+
+    @Override
+    public String getContent() {
+        return content;
+    }
+
+    @Override
+    public void setContent(final String content) {
+        this.content = content;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/pom.xml b/syncope620/ext/camel/pom.xml
new file mode 100644
index 0000000..0a95c94
--- /dev/null
+++ b/syncope620/ext/camel/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope</groupId>
+    <artifactId>syncope-ext</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Extensions: Camel</name>
+  <description>Apache Syncope Extensions: Camel</description>
+  <groupId>org.apache.syncope.ext</groupId>
+  <artifactId>syncope-ext-camel</artifactId>
+  <packaging>pom</packaging>
+  
+  <modules>
+    <module>persistence-api</module>
+    <module>persistence-jpa</module>
+    <module>common-lib</module>
+    <module>provisioning-api</module>
+    <module>provisioning-camel</module>
+    <module>logic</module>
+    <module>rest-api</module>
+    <module>rest-cxf</module>
+  </modules>
+
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/provisioning-api/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-api/pom.xml b/syncope620/ext/camel/provisioning-api/pom.xml
new file mode 100644
index 0000000..b9bd6b9
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-api/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope.ext</groupId>
+    <artifactId>syncope-ext-camel</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Extensions: Camel Provisioning API</name>
+  <description>Apache Syncope Extensions: Camel Provisioning API</description>
+  <groupId>org.apache.syncope.ext.camel</groupId>
+  <artifactId>syncope-ext-camel-provisioning-api</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.server</groupId>
+      <artifactId>syncope-server-provisioning-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.camel</groupId>
+      <artifactId>syncope-ext-camel-persistence-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.camel</groupId>
+      <artifactId>syncope-ext-camel-common-lib</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/provisioning-api/src/main/java/org/apache/syncope/server/provisioning/api/data/CamelRouteDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-api/src/main/java/org/apache/syncope/server/provisioning/api/data/CamelRouteDataBinder.java b/syncope620/ext/camel/provisioning-api/src/main/java/org/apache/syncope/server/provisioning/api/data/CamelRouteDataBinder.java
new file mode 100644
index 0000000..4d8e4ec
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-api/src/main/java/org/apache/syncope/server/provisioning/api/data/CamelRouteDataBinder.java
@@ -0,0 +1,29 @@
+/*
+ * 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.api.data;
+
+import org.apache.syncope.common.lib.to.CamelRouteTO;
+import org.apache.syncope.server.persistence.api.entity.CamelRoute;
+
+public interface CamelRouteDataBinder {
+
+    CamelRouteTO getRouteTO(CamelRoute route);
+
+    void update(CamelRoute route, CamelRouteTO routeTO);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/syncope620/ext/camel/provisioning-camel/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/ext/camel/provisioning-camel/pom.xml b/syncope620/ext/camel/provisioning-camel/pom.xml
new file mode 100644
index 0000000..5218d62
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/pom.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope.ext</groupId>
+    <artifactId>syncope-ext-camel</artifactId>
+    <version>2.0.0-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Extensions: Camel Provisioning</name>
+  <description>Apache Syncope Extensions: Camel Provisioning</description>
+  <groupId>org.apache.syncope.ext.camel</groupId>
+  <artifactId>syncope-ext-camel-provisioning</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-spring</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-script</artifactId>
+    </dependency>
+      
+    <dependency>
+      <groupId>org.apache.syncope.server</groupId>
+      <artifactId>syncope-server-provisioning-java</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.syncope.ext.camel</groupId>
+      <artifactId>syncope-ext-camel-provisioning-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/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
new file mode 100644
index 0000000..b932d66
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/AbstractCamelProvisioningManager.java
@@ -0,0 +1,103 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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.DefaultExchange;
+import org.apache.camel.impl.DefaultMessage;
+import org.apache.camel.model.RoutesDefinition;
+import org.apache.camel.spring.SpringCamelContext;
+import org.apache.syncope.server.persistence.api.dao.CamelRouteDAO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+abstract class AbstractCamelProvisioningManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CamelUserProvisioningManager.class);
+
+    @Autowired
+    protected CamelRouteDAO routeDAO;
+
+    @Autowired
+    protected SyncopeCamelContext contextFactory;
+
+    protected SpringCamelContext camelContext;
+
+    protected RoutesDefinition routes;
+
+    protected final Map<String, PollingConsumer> consumerMap = new HashMap<>();
+
+    protected final List<String> knownURIs = new ArrayList<>();
+
+    protected SpringCamelContext getContext() {
+        return contextFactory.getContext();
+    }
+
+    protected void sendMessage(final String uri, final Object obj) {
+        Exchange exchange = new DefaultExchange(getContext());
+
+        DefaultMessage message = new DefaultMessage();
+        message.setBody(obj);
+        exchange.setIn(message);
+
+        ProducerTemplate template = getContext().createProducerTemplate();
+        template.send(uri, exchange);
+    }
+
+    protected void sendMessage(final String uri, final Object obj, final Map<String, Object> properties) {
+        Exchange exchange = new DefaultExchange(getContext());
+
+        for (Map.Entry<String, Object> property : properties.entrySet()) {
+            exchange.setProperty(property.getKey(), property.getValue());
+            LOG.debug("Added property {}", property.getKey());
+        }
+
+        DefaultMessage message = new DefaultMessage();
+        message.setBody(obj);
+        exchange.setIn(message);
+        ProducerTemplate template = getContext().createProducerTemplate();
+        template.send(uri, exchange);
+    }
+
+    protected PollingConsumer getConsumer(String uri) {
+        if (!knownURIs.contains(uri)) {
+            knownURIs.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);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/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
new file mode 100644
index 0000000..4dbe36a
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelRoleProvisioningManager.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.provisioning.camel;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.PollingConsumer;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.server.provisioning.api.RoleProvisioningManager;
+import org.apache.syncope.server.provisioning.api.propagation.PropagationException;
+
+public class CamelRoleProvisioningManager extends AbstractCamelProvisioningManager implements RoleProvisioningManager {
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(final RoleTO subject) {
+        return create(subject, Collections.<String>emptySet());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> create(final RoleTO roleTO, final Set<String> excludedResources) {
+        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) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> create(final RoleTO roleTO, final Map<Long, String> roleOwnerMap,
+            final Set<String> excludedResources) throws PropagationException {
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("roleOwnerMap", roleOwnerMap);
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:createRoleSync", roleTO, props);
+
+        String uri = "direct:createRoleSyncPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> update(final RoleMod subjectMod) {
+        return update(subjectMod, Collections.<String>emptySet());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> update(
+            final RoleMod subjectMod, final Set<String> excludedResources) {
+
+        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) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<PropagationStatus> delete(final Long roleKey) {
+        sendMessage("direct:deleteRole", roleKey);
+
+        String uri = "direct:deleteRolePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(List.class);
+    }
+
+    @Override
+    public Long unlink(final RoleMod roleMod) {
+        sendMessage("direct:unlinkRole", roleMod);
+
+        String uri = "direct:unlinkRolePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Long.class);
+    }
+
+    @Override
+    public Long link(final RoleMod roleMod) {
+        sendMessage("direct:linkRole", roleMod);
+
+        String uri = "direct:linkRolePort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Long.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<PropagationStatus> deprovision(final Long roleKey, Collection<String> resources) {
+        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) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(List.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/dae87ef8/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
new file mode 100644
index 0000000..1ed83fd
--- /dev/null
+++ b/syncope620/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/server/provisioning/camel/CamelUserProvisioningManager.java
@@ -0,0 +1,342 @@
+/*
+ * 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;
+
+import java.util.AbstractMap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.PollingConsumer;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.server.persistence.api.entity.user.User;
+import org.apache.syncope.server.provisioning.api.UserProvisioningManager;
+import org.apache.syncope.server.provisioning.api.WorkflowResult;
+import org.apache.syncope.server.provisioning.api.sync.ProvisioningResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CamelUserProvisioningManager extends AbstractCamelProvisioningManager implements UserProvisioningManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CamelUserProvisioningManager.class);
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO) {
+        return create(userTO, true, false, null, Collections.<String>emptySet());
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO, boolean storePassword) {
+        return create(userTO, storePassword, false, null, Collections.<String>emptySet());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> create(final UserTO userTO, final boolean storePassword,
+            boolean disablePwdPolicyCheck, Boolean enabled, Set<String> excludedResources) {
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("storePassword", storePassword);
+        props.put("disablePwdPolicyCheck", disablePwdPolicyCheck);
+        props.put("enabled", enabled);
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:createUser", userTO, props);
+
+        String uri = "direct:createPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public Map.Entry<Long, List<PropagationStatus>> update(final UserMod userMod) {
+        return update(userMod, false);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> update(UserMod userMod, boolean removeMemberships) {
+        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) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public List<PropagationStatus> delete(final Long userKey) {
+        return delete(userKey, Collections.<String>emptySet());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<PropagationStatus> delete(final Long userKey, final Set<String> excludedResources) {
+        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) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(List.class);
+    }
+
+    @Override
+    public Long unlink(final UserMod userMod) {
+        sendMessage("direct:unlinkUser", userMod);
+
+        String uri = "direct:unlinkPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        exchange.getIn().setBody((exchange.getIn().getBody(UserMod.class).getKey()));
+        return exchange.getIn().getBody(Long.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> activate(final User user, final StatusMod statusMod) {
+        Map<String, Object> props = new HashMap<>();
+        props.put("token", statusMod.getToken());
+        props.put("user", user);
+        props.put("statusMod", statusMod);
+
+        if (statusMod.isOnSyncope()) {
+            sendMessage("direct:activateUser", user.getKey(), props);
+        } else {
+            WorkflowResult<Long> updated =
+                    new WorkflowResult<>(user.getKey(), null, statusMod.getType().name().toLowerCase());
+            sendMessage("direct:statusUser", updated, props);
+        }
+
+        String uri = "direct:statusPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> reactivate(final User user, final StatusMod statusMod) {
+        Map<String, Object> props = new HashMap<>();
+        props.put("user", user);
+        props.put("statusMod", statusMod);
+
+        if (statusMod.isOnSyncope()) {
+            sendMessage("direct:reactivateUser", user.getKey(), props);
+        } else {
+            WorkflowResult<Long> updated =
+                    new WorkflowResult<>(user.getKey(), null, statusMod.getType().name().toLowerCase());
+            sendMessage("direct:statusUser", updated, props);
+        }
+
+        String uri = "direct:statusPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> suspend(final User user, final StatusMod statusMod) {
+        Map<String, Object> props = new HashMap<>();
+        props.put("user", user);
+        props.put("statusMod", statusMod);
+
+        if (statusMod.isOnSyncope()) {
+            sendMessage("direct:suspendUser", user.getKey(), props);
+        } else {
+            WorkflowResult<Long> updated =
+                    new WorkflowResult<>(user.getKey(), null, statusMod.getType().name().toLowerCase());
+            sendMessage("direct:statusUser", updated, props);
+        }
+
+        String uri = "direct:statusPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public Long link(final UserMod subjectMod) {
+        sendMessage("direct:linkUser", subjectMod);
+
+        String uri = "direct:linkPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        exchange.getIn().setBody((exchange.getIn().getBody(UserMod.class).getKey()));
+        return exchange.getIn().getBody(Long.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<PropagationStatus> deprovision(final Long user, final Collection<String> resources) {
+        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) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(List.class);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Map.Entry<Long, List<PropagationStatus>> update(
+            final UserMod userMod, Long id, final ProvisioningResult result,
+            final Boolean enabled, final Set<String> excludedResources) {
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("id", id);
+        props.put("result", result);
+        props.put("enabled", enabled);
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:updateSyncUser", 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);
+
+            result.setStatus(ProvisioningResult.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, false), new PropagationByResource(),
+                    new HashSet<String>());
+            sendMessage("direct:syncUserStatus", updated, props);
+            exchange = pollingConsumer.receive();
+        }
+
+        return exchange.getIn().getBody(Map.Entry.class);
+    }
+
+    @Override
+    public void innerSuspend(final User user, final boolean suspend) {
+        Map<String, Object> props = new HashMap<>();
+        props.put("suspend", suspend);
+
+        sendMessage("direct:suspendUserWF", user, props);
+
+        String uri = "direct:suspendWFPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+    }
+
+    @Override
+    public void requestPasswordReset(final Long userKey) {
+        sendMessage("direct:requestPwdReset", userKey);
+
+        String uri = "direct:requestPwdResetPort";
+        PollingConsumer pollingConsumer = getConsumer(uri);
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+    }
+
+    @Override
+    public void confirmPasswordReset(final User user, final String token, final String password) {
+        Map<String, Object> props = new HashMap<>();
+        props.put("user", user);
+        props.put("userId", 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) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+    }
+
+}