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/06/11 16:17:46 UTC

[56/70] syncope git commit: [SYNCOPE-666] Any* tests added

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
index 98a23a6..2d6c6e4 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/GroupServiceImpl.java
@@ -19,98 +19,23 @@
 package org.apache.syncope.core.rest.cxf.service;
 
 import java.util.List;
-import javax.ws.rs.core.Response;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.mod.GroupMod;
-import org.apache.syncope.common.lib.to.BulkAction;
-import org.apache.syncope.common.lib.to.BulkActionResult;
-import org.apache.syncope.common.lib.to.PagedResult;
-import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.GroupTO;
-import org.apache.syncope.common.lib.types.ResourceAssociationActionType;
-import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
-import org.apache.syncope.common.lib.wrap.ResourceKey;
-import org.apache.syncope.common.rest.api.CollectionWrapper;
-import org.apache.syncope.common.rest.api.beans.AnyListQuery;
-import org.apache.syncope.common.rest.api.beans.AnySearchQuery;
 import org.apache.syncope.common.rest.api.service.GroupService;
+import org.apache.syncope.core.logic.AbstractAnyLogic;
 import org.apache.syncope.core.logic.GroupLogic;
-import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 @Service
-public class GroupServiceImpl extends AbstractServiceImpl implements GroupService {
+public class GroupServiceImpl extends AbstractAnyService<GroupTO, GroupMod> implements GroupService {
 
     @Autowired
     private GroupLogic logic;
 
     @Override
-    public Response create(final GroupTO groupTO) {
-        GroupTO created = logic.create(groupTO);
-        return createResponse(created.getKey(), created);
-    }
-
-    @Override
-    public Response delete(final Long groupKey) {
-        GroupTO group = logic.read(groupKey);
-
-        checkETag(group.getETagValue());
-
-        GroupTO deleted = logic.delete(groupKey);
-        return modificationResponse(deleted);
-    }
-
-    @Override
-    public PagedResult<GroupTO> list(final AnyListQuery listQuery) {
-        CollectionUtils.transform(listQuery.getRealms(), new Transformer<String, String>() {
-
-            @Override
-            public String transform(final String input) {
-                return StringUtils.prependIfMissing(input, SyncopeConstants.ROOT_REALM);
-            }
-        });
-
-        return buildPagedResult(
-                logic.list(
-                        listQuery.getPage(),
-                        listQuery.getSize(),
-                        getOrderByClauses(listQuery.getOrderBy()),
-                        listQuery.getRealms()),
-                listQuery.getPage(),
-                listQuery.getSize(),
-                logic.count(listQuery.getRealms()));
-    }
-
-    @Override
-    public GroupTO read(final Long groupKey) {
-        return logic.read(groupKey);
-    }
-
-    @Override
-    public PagedResult<GroupTO> search(final AnySearchQuery searchQuery) {
-        CollectionUtils.transform(searchQuery.getRealms(), new Transformer<String, String>() {
-
-            @Override
-            public String transform(final String input) {
-                return StringUtils.prependIfMissing(input, SyncopeConstants.ROOT_REALM);
-            }
-        });
-
-        SearchCond cond = getSearchCond(searchQuery.getFiql());
-        return buildPagedResult(
-                logic.search(
-                        cond,
-                        searchQuery.getPage(),
-                        searchQuery.getSize(),
-                        getOrderByClauses(searchQuery.getOrderBy()),
-                        searchQuery.getRealms()),
-                searchQuery.getPage(),
-                searchQuery.getSize(),
-                logic.searchCount(cond, searchQuery.getRealms()));
+    protected AbstractAnyLogic<GroupTO, GroupMod> getAnyLogic() {
+        return logic;
     }
 
     @Override
@@ -118,126 +43,4 @@ public class GroupServiceImpl extends AbstractServiceImpl implements GroupServic
         return logic.own();
     }
 
-    @Override
-    public Response update(final Long groupKey, final GroupMod groupMod) {
-        GroupTO group = logic.read(groupKey);
-
-        checkETag(group.getETagValue());
-
-        groupMod.setKey(groupKey);
-        GroupTO updated = logic.update(groupMod);
-        return modificationResponse(updated);
-    }
-
-    @Override
-    public Response bulkDeassociation(
-            final Long groupKey, final ResourceDeassociationActionType type, final List<ResourceKey> resourceNames) {
-
-        GroupTO group = logic.read(groupKey);
-
-        checkETag(group.getETagValue());
-
-        GroupTO updated;
-        switch (type) {
-            case UNLINK:
-                updated = logic.unlink(groupKey, CollectionWrapper.unwrap(resourceNames));
-                break;
-
-            case UNASSIGN:
-                updated = logic.unassign(groupKey, CollectionWrapper.unwrap(resourceNames));
-                break;
-
-            case DEPROVISION:
-                updated = logic.deprovision(groupKey, CollectionWrapper.unwrap(resourceNames));
-                break;
-
-            default:
-                updated = logic.read(groupKey);
-        }
-
-        BulkActionResult result = new BulkActionResult();
-
-        if (type == ResourceDeassociationActionType.UNLINK) {
-            for (ResourceKey resourceName : resourceNames) {
-                result.getResults().put(resourceName.getElement(),
-                        updated.getResources().contains(resourceName.getElement())
-                                ? BulkActionResult.Status.FAILURE
-                                : BulkActionResult.Status.SUCCESS);
-            }
-        } else {
-            for (PropagationStatus propagationStatusTO : updated.getPropagationStatusTOs()) {
-                result.getResults().put(propagationStatusTO.getResource(),
-                        BulkActionResult.Status.valueOf(propagationStatusTO.getStatus().toString()));
-            }
-        }
-
-        return modificationResponse(result);
-    }
-
-    @Override
-    public Response bulkAssociation(
-            final Long groupKey, final ResourceAssociationActionType type, final List<ResourceKey> resourceNames) {
-
-        GroupTO group = logic.read(groupKey);
-
-        checkETag(group.getETagValue());
-
-        GroupTO updated;
-        switch (type) {
-            case LINK:
-                updated = logic.link(groupKey, CollectionWrapper.unwrap(resourceNames));
-                break;
-
-            case ASSIGN:
-                updated = logic.assign(groupKey, CollectionWrapper.unwrap(resourceNames), false, null);
-                break;
-
-            case PROVISION:
-                updated = logic.provision(groupKey, CollectionWrapper.unwrap(resourceNames), false, null);
-                break;
-
-            default:
-                updated = logic.read(groupKey);
-        }
-
-        BulkActionResult result = new BulkActionResult();
-
-        if (type == ResourceAssociationActionType.LINK) {
-            for (ResourceKey resourceName : resourceNames) {
-                result.getResults().put(resourceName.getElement(),
-                        updated.getResources().contains(resourceName.getElement())
-                                ? BulkActionResult.Status.FAILURE
-                                : BulkActionResult.Status.SUCCESS);
-            }
-        } else {
-            for (PropagationStatus propagationStatusTO : updated.getPropagationStatusTOs()) {
-                result.getResults().put(propagationStatusTO.getResource(),
-                        BulkActionResult.Status.valueOf(propagationStatusTO.getStatus().toString()));
-            }
-        }
-
-        return modificationResponse(result);
-    }
-
-    @Override
-    public BulkActionResult bulk(final BulkAction bulkAction) {
-        BulkActionResult result = new BulkActionResult();
-
-        if (bulkAction.getOperation() == BulkAction.Type.DELETE) {
-            for (String groupKey : bulkAction.getTargets()) {
-                try {
-                    result.getResults().put(
-                            String.valueOf(logic.delete(Long.valueOf(groupKey)).getKey()),
-                            BulkActionResult.Status.SUCCESS);
-                } catch (Exception e) {
-                    LOG.error("Error performing delete for group {}", groupKey, e);
-                    result.getResults().put(groupKey, BulkActionResult.Status.FAILURE);
-                }
-            }
-        } else {
-            LOG.warn("Unsupported bulk action: {}", bulkAction.getOperation());
-        }
-
-        return result;
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
index 192b4e0..391aea8 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java
@@ -18,44 +18,33 @@
  */
 package org.apache.syncope.core.rest.cxf.service;
 
-import java.util.List;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.mod.ResourceAssociationMod;
 import org.apache.syncope.common.lib.mod.StatusMod;
 import org.apache.syncope.common.lib.mod.UserMod;
-import org.apache.syncope.common.lib.to.BulkAction;
-import org.apache.syncope.common.lib.to.BulkActionResult;
-import org.apache.syncope.common.lib.to.PagedResult;
-import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.UserTO;
-import org.apache.syncope.common.lib.types.ResourceAssociationActionType;
-import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
-import org.apache.syncope.common.lib.wrap.ResourceKey;
-import org.apache.syncope.common.rest.api.CollectionWrapper;
 import org.apache.syncope.common.rest.api.RESTHeaders;
-import org.apache.syncope.common.rest.api.beans.AnyListQuery;
-import org.apache.syncope.common.rest.api.beans.AnySearchQuery;
 import org.apache.syncope.common.rest.api.service.UserService;
+import org.apache.syncope.core.logic.AbstractAnyLogic;
 import org.apache.syncope.core.logic.UserLogic;
-import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 @Service
-public class UserServiceImpl extends AbstractServiceImpl implements UserService {
+public class UserServiceImpl extends AbstractAnyService<UserTO, UserMod> implements UserService {
 
     @Autowired
     private UserLogic logic;
 
     @Override
-    public Response getUsername(final Long userKey) {
+    protected AbstractAnyLogic<UserTO, UserMod> getAnyLogic() {
+        return logic;
+    }
+
+    @Override
+    public Response getUsername(final Long key) {
         return Response.ok().header(HttpHeaders.ALLOW, OPTIONS_ALLOW).
-                header(RESTHeaders.USERNAME, logic.getUsername(userKey)).
+                header(RESTHeaders.USERNAME, logic.getUsername(key)).
                 build();
     }
 
@@ -73,237 +62,13 @@ public class UserServiceImpl extends AbstractServiceImpl implements UserService
     }
 
     @Override
-    public Response delete(final Long userKey) {
-        UserTO user = logic.read(userKey);
-
-        checkETag(user.getETagValue());
-
-        UserTO deleted = logic.delete(userKey);
-        return modificationResponse(deleted);
-    }
-
-    @Override
-    public PagedResult<UserTO> list(final AnyListQuery listQuery) {
-        CollectionUtils.transform(listQuery.getRealms(), new Transformer<String, String>() {
-
-            @Override
-            public String transform(final String input) {
-                return StringUtils.prependIfMissing(input, SyncopeConstants.ROOT_REALM);
-            }
-        });
-
-        return buildPagedResult(
-                logic.list(
-                        listQuery.getPage(),
-                        listQuery.getSize(),
-                        getOrderByClauses(listQuery.getOrderBy()),
-                        listQuery.getRealms()),
-                listQuery.getPage(),
-                listQuery.getSize(),
-                logic.count(listQuery.getRealms()));
-    }
-
-    @Override
-    public UserTO read(final Long userKey) {
-        return logic.read(userKey);
-    }
-
-    @Override
-    public PagedResult<UserTO> search(final AnySearchQuery searchQuery) {
-        CollectionUtils.transform(searchQuery.getRealms(), new Transformer<String, String>() {
-
-            @Override
-            public String transform(final String input) {
-                return StringUtils.prependIfMissing(input, SyncopeConstants.ROOT_REALM);
-            }
-        });
-
-        SearchCond cond = getSearchCond(searchQuery.getFiql());
-        return buildPagedResult(
-                logic.search(
-                        cond,
-                        searchQuery.getPage(),
-                        searchQuery.getSize(),
-                        getOrderByClauses(searchQuery.getOrderBy()),
-                        searchQuery.getRealms()),
-                searchQuery.getPage(),
-                searchQuery.getSize(),
-                logic.searchCount(cond, searchQuery.getRealms()));
-    }
-
-    @Override
-    public Response update(final Long userKey, final UserMod userMod) {
-        UserTO user = logic.read(userKey);
-
-        checkETag(user.getETagValue());
-
-        userMod.setKey(userKey);
-        UserTO updated = logic.update(userMod);
-        return modificationResponse(updated);
-    }
-
-    @Override
-    public Response status(final Long userKey, final StatusMod statusMod) {
-        UserTO user = logic.read(userKey);
+    public Response status(final Long key, final StatusMod statusMod) {
+        UserTO user = logic.read(key);
 
         checkETag(user.getETagValue());
 
-        statusMod.setKey(userKey);
+        statusMod.setKey(key);
         UserTO updated = logic.status(statusMod);
         return modificationResponse(updated);
     }
-
-    @Override
-    public Response bulkDeassociation(
-            final Long userKey, final ResourceDeassociationActionType type, final List<ResourceKey> resourceNames) {
-
-        final UserTO user = logic.read(userKey);
-
-        checkETag(user.getETagValue());
-
-        UserTO updated;
-        switch (type) {
-            case UNLINK:
-                updated = logic.unlink(userKey, CollectionWrapper.unwrap(resourceNames));
-                break;
-
-            case UNASSIGN:
-                updated = logic.unassign(userKey, CollectionWrapper.unwrap(resourceNames));
-                break;
-
-            case DEPROVISION:
-                updated = logic.deprovision(userKey, CollectionWrapper.unwrap(resourceNames));
-                break;
-
-            default:
-                updated = logic.read(userKey);
-        }
-
-        BulkActionResult result = new BulkActionResult();
-
-        if (type == ResourceDeassociationActionType.UNLINK) {
-            for (ResourceKey resourceName : resourceNames) {
-                result.getResults().put(
-                        resourceName.getElement(), updated.getResources().contains(resourceName.getElement())
-                                ? BulkActionResult.Status.FAILURE
-                                : BulkActionResult.Status.SUCCESS);
-            }
-        } else {
-            for (PropagationStatus propagationStatusTO : updated.getPropagationStatusTOs()) {
-                result.getResults().put(propagationStatusTO.getResource(),
-                        BulkActionResult.Status.valueOf(propagationStatusTO.getStatus().toString()));
-            }
-        }
-
-        return modificationResponse(result);
-    }
-
-    @Override
-    public Response bulkAssociation(
-            final Long userKey, final ResourceAssociationActionType type, final ResourceAssociationMod associationMod) {
-
-        final UserTO user = logic.read(userKey);
-
-        checkETag(user.getETagValue());
-
-        UserTO updated;
-        switch (type) {
-            case LINK:
-                updated = logic.link(
-                        userKey,
-                        CollectionWrapper.unwrap(associationMod.getTargetResources()));
-                break;
-
-            case ASSIGN:
-                updated = logic.assign(
-                        userKey,
-                        CollectionWrapper.unwrap(associationMod.getTargetResources()),
-                        associationMod.isChangePwd(),
-                        associationMod.getPassword());
-                break;
-
-            case PROVISION:
-                updated = logic.provision(
-                        userKey,
-                        CollectionWrapper.unwrap(associationMod.getTargetResources()),
-                        associationMod.isChangePwd(),
-                        associationMod.getPassword());
-                break;
-
-            default:
-                updated = logic.read(userKey);
-        }
-
-        BulkActionResult result = new BulkActionResult();
-
-        if (type == ResourceAssociationActionType.LINK) {
-            for (ResourceKey resourceName : associationMod.getTargetResources()) {
-                result.getResults().put(resourceName.getElement(),
-                        updated.getResources().contains(resourceName.getElement())
-                                ? BulkActionResult.Status.FAILURE
-                                : BulkActionResult.Status.SUCCESS);
-            }
-        } else {
-            for (PropagationStatus propagationStatusTO : updated.getPropagationStatusTOs()) {
-                result.getResults().put(propagationStatusTO.getResource(),
-                        BulkActionResult.Status.valueOf(propagationStatusTO.getStatus().toString()));
-            }
-        }
-
-        return modificationResponse(result);
-    }
-
-    @Override
-    public BulkActionResult bulk(final BulkAction bulkAction) {
-        BulkActionResult result = new BulkActionResult();
-
-        switch (bulkAction.getOperation()) {
-            case DELETE:
-                for (String key : bulkAction.getTargets()) {
-                    try {
-                        result.getResults().put(
-                                String.valueOf(logic.delete(Long.valueOf(key)).getKey()),
-                                BulkActionResult.Status.SUCCESS);
-                    } catch (Exception e) {
-                        LOG.error("Error performing delete for user {}", key, e);
-                        result.getResults().put(key, BulkActionResult.Status.FAILURE);
-                    }
-                }
-                break;
-
-            case SUSPEND:
-                for (String key : bulkAction.getTargets()) {
-                    StatusMod statusMod = new StatusMod();
-                    statusMod.setKey(Long.valueOf(key));
-                    statusMod.setType(StatusMod.ModType.SUSPEND);
-                    try {
-                        result.getResults().put(
-                                String.valueOf(logic.status(statusMod).getKey()), BulkActionResult.Status.SUCCESS);
-                    } catch (Exception e) {
-                        LOG.error("Error performing suspend for user {}", key, e);
-                        result.getResults().put(key, BulkActionResult.Status.FAILURE);
-                    }
-                }
-                break;
-
-            case REACTIVATE:
-                for (String key : bulkAction.getTargets()) {
-                    StatusMod statusMod = new StatusMod();
-                    statusMod.setKey(Long.valueOf(key));
-                    statusMod.setType(StatusMod.ModType.REACTIVATE);
-                    try {
-                        result.getResults().put(
-                                String.valueOf(logic.status(statusMod).getKey()), BulkActionResult.Status.SUCCESS);
-                    } catch (Exception e) {
-                        LOG.error("Error performing reactivate for user {}", key, e);
-                        result.getResults().put(key, BulkActionResult.Status.FAILURE);
-                    }
-                }
-                break;
-
-            default:
-        }
-
-        return result;
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java
----------------------------------------------------------------------
diff --git a/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java b/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java
index 3520a4a..4359e7b 100644
--- a/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java
+++ b/ext/camel/logic/src/main/java/org/apache/syncope/core/logic/init/CamelRouteLoader.java
@@ -56,6 +56,9 @@ public class CamelRouteLoader implements SyncopeLoader {
     @javax.annotation.Resource(name = "groupRoutes")
     private ResourceWithFallbackLoader groupRoutesLoader;
 
+    @javax.annotation.Resource(name = "anyObjectRoutes")
+    private ResourceWithFallbackLoader anyObjectRoutesLoader;
+
     @Autowired
     private DataSource dataSource;
 
@@ -76,6 +79,7 @@ public class CamelRouteLoader implements SyncopeLoader {
             if (!loaded) {
                 loadRoutes(userRoutesLoader.getResource(), AnyTypeKind.USER);
                 loadRoutes(groupRoutesLoader.getResource(), AnyTypeKind.GROUP);
+                loadRoutes(anyObjectRoutesLoader.getResource(), AnyTypeKind.ANY_OBJECT);
                 loaded = true;
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java
new file mode 100644
index 0000000..ae29501
--- /dev/null
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelAnyObjectProvisioningManager.java
@@ -0,0 +1,163 @@
+/*
+ * 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.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.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.mod.AnyObjectMod;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.core.provisioning.api.AnyObjectProvisioningManager;
+
+public class CamelAnyObjectProvisioningManager
+        extends AbstractCamelProvisioningManager implements AnyObjectProvisioningManager {
+
+    @Override
+    public Pair<Long, List<PropagationStatus>> create(final AnyObjectTO any) {
+        return create(any, Collections.<String>emptySet());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Pair<Long, List<PropagationStatus>> create(
+            final AnyObjectTO anyObjectTO, final Set<String> excludedResources) {
+
+        PollingConsumer pollingConsumer = getConsumer("direct:createAnyObjectPort");
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:createAnyObject", anyObjectTO, props);
+
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Pair.class);
+    }
+
+    @Override
+    public Pair<Long, List<PropagationStatus>> update(final AnyObjectMod anyMod) {
+        return update(anyMod, Collections.<String>emptySet());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Pair<Long, List<PropagationStatus>> update(
+            final AnyObjectMod anyMod, final Set<String> excludedResources) {
+
+        PollingConsumer pollingConsumer = getConsumer("direct:updateAnyObjectPort");
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:updateAnyObject", anyMod, props);
+
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(Pair.class);
+    }
+
+    @Override
+    public List<PropagationStatus> delete(final Long anyObjectObjectKey) {
+        return delete(anyObjectObjectKey, Collections.<String>emptySet());
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<PropagationStatus> delete(final Long anyObjectKey, final Set<String> excludedResources) {
+        PollingConsumer pollingConsumer = getConsumer("direct:deleteAnyObjectPort");
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("excludedResources", excludedResources);
+
+        sendMessage("direct:deleteAnyObject", anyObjectKey, props);
+
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(List.class);
+    }
+
+    @Override
+    public Long unlink(final AnyObjectMod anyObjectMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:unlinkAnyObjectPort");
+
+        sendMessage("direct:unlinkAnyObject", anyObjectMod);
+
+        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 AnyObjectMod anyObjectMod) {
+        PollingConsumer pollingConsumer = getConsumer("direct:linkAnyObjectPort");
+
+        sendMessage("direct:linkAnyObject", anyObjectMod);
+
+        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 anyObjectKey, final Collection<String> resources) {
+        PollingConsumer pollingConsumer = getConsumer("direct:deprovisionAnyObjectPort");
+
+        Map<String, Object> props = new HashMap<>();
+        props.put("resources", resources);
+
+        sendMessage("direct:deprovisionAnyObject", anyObjectKey, props);
+
+        Exchange exchange = pollingConsumer.receive();
+
+        if (exchange.getProperty(Exchange.EXCEPTION_CAUGHT) != null) {
+            throw (RuntimeException) exchange.getProperty(Exchange.EXCEPTION_CAUGHT);
+        }
+
+        return exchange.getIn().getBody(List.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectCreateProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectCreateProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectCreateProcessor.java
new file mode 100644
index 0000000..2f2e41e
--- /dev/null
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectCreateProcessor.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.core.provisioning.camel.processor;
+
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.provisioning.api.WorkflowResult;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AnyObjectCreateProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AnyObjectCreateProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        WorkflowResult<Long> created = (WorkflowResult) exchange.getIn().getBody();
+        AnyObjectTO any = exchange.getProperty("any", AnyObjectTO.class);
+        Set<String> excludedResource = exchange.getProperty("excludedResources", Set.class);
+
+        List<PropagationTask> tasks =
+                propagationManager.getAnyObjectCreateTasks(created, any.getVirAttrs(), excludedResource);
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.getOut().setBody(new ImmutablePair<>(created.getResult(), propagationReporter.getStatuses()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectDeleteProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectDeleteProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectDeleteProcessor.java
new file mode 100644
index 0000000..d1c9243
--- /dev/null
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectDeleteProcessor.java
@@ -0,0 +1,83 @@
+/*
+ * 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.processor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.core.workflow.api.AnyObjectWorkflowAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AnyObjectDeleteProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AnyObjectDeleteProcessor.class);
+
+    @Autowired
+    protected AnyObjectWorkflowAdapter gwfAdapter;
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    protected AnyObjectDAO anyObjectDAO;
+
+    @Override
+    public void process(final Exchange exchange) throws Exception {
+        Long anyKey = exchange.getIn().getBody(Long.class);
+        AnyObject anyObject = anyObjectDAO.find(anyKey);
+        @SuppressWarnings("unchecked")
+        Set<String> excludedResources = exchange.getProperty("excludedResources", Set.class);
+
+        List<PropagationTask> tasks = new ArrayList<>();
+
+        if (anyObject != null) {
+            // Generate propagation tasks for deleting this anyObject from resources
+            tasks.addAll(propagationManager.getAnyObjectDeleteTasks(anyObject.getKey(), 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);
+        }
+
+        exchange.setProperty("statuses", propagationReporter.getStatuses());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectDeprovisionProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectDeprovisionProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectDeprovisionProcessor.java
new file mode 100644
index 0000000..c56ab90
--- /dev/null
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectDeprovisionProcessor.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.camel.processor;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AnyObjectDeprovisionProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserDeprovisionProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    protected AnyObjectDAO anyObjectDAO;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        Long anyObjectKey = exchange.getIn().getBody(Long.class);
+        List<String> resources = exchange.getProperty("resources", List.class);
+
+        AnyObject anyObject = anyObjectDAO.authFind(anyObjectKey);
+
+        Collection<String> noPropResourceNames = CollectionUtils.removeAll(anyObject.getResourceNames(), resources);
+
+        List<PropagationTask> tasks =
+                propagationManager.getAnyObjectDeleteTasks(anyObjectKey, new HashSet<>(resources), noPropResourceNames);
+        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/a45a46bb/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
new file mode 100644
index 0000000..2979e97
--- /dev/null
+++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/AnyObjectUpdateProcessor.java
@@ -0,0 +1,90 @@
+/*
+ * 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.processor;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.syncope.common.lib.mod.AnyObjectMod;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.core.provisioning.api.VirAttrHandler;
+import org.apache.syncope.core.provisioning.api.WorkflowResult;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
+import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AnyObjectUpdateProcessor implements Processor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UserUpdateProcessor.class);
+
+    @Autowired
+    protected PropagationManager propagationManager;
+
+    @Autowired
+    protected PropagationTaskExecutor taskExecutor;
+
+    @Autowired
+    protected VirAttrHandler virtAttrHandler;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void process(final Exchange exchange) {
+        WorkflowResult<Long> updated = (WorkflowResult) exchange.getIn().getBody();
+        AnyObjectMod anyObjectMod = exchange.getProperty("anyMod", AnyObjectMod.class);
+        Set<String> excludedResources = exchange.getProperty("excludedResources", Set.class);
+
+        List<PropagationTask> tasks = propagationManager.getAnyObjectUpdateTasks(updated,
+                anyObjectMod.getVirAttrsToRemove(), anyObjectMod.getVirAttrsToUpdate(), excludedResources);
+        if (tasks.isEmpty()) {
+            // SYNCOPE-459: take care of user virtual attributes ...
+            PropagationByResource propByResVirAttr = virtAttrHandler.fillVirtual(
+                    updated.getResult(),
+                    AnyTypeKind.GROUP,
+                    anyObjectMod.getVirAttrsToRemove(),
+                    anyObjectMod.getVirAttrsToUpdate());
+            tasks.addAll(!propByResVirAttr.isEmpty()
+                    ? propagationManager.getAnyObjectUpdateTasks(updated, null, null, null)
+                    : Collections.<PropagationTask>emptyList());
+        }
+
+        PropagationReporter propagationReporter =
+                ApplicationContextProvider.getApplicationContext().getBean(PropagationReporter.class);
+        try {
+            taskExecutor.execute(tasks, propagationReporter);
+        } catch (PropagationException e) {
+            LOG.error("Error propagation primary resource", e);
+            propagationReporter.onPrimaryResourceFailure(tasks);
+        }
+
+        exchange.getOut().setBody(new ImmutablePair<>(updated.getResult(), propagationReporter.getStatuses()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/ext/camel/provisioning-camel/src/main/resources/anyObjectRoutes.xml
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/resources/anyObjectRoutes.xml b/ext/camel/provisioning-camel/src/main/resources/anyObjectRoutes.xml
new file mode 100644
index 0000000..de4df0b
--- /dev/null
+++ b/ext/camel/provisioning-camel/src/main/resources/anyObjectRoutes.xml
@@ -0,0 +1,121 @@
+<?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.
+-->
+<routes>
+     
+  <route id="createAnyObject">
+    <from uri="direct:createAnyObject"/>
+    <setProperty propertyName="any">
+      <simple>${body}</simple>
+    </setProperty>
+    <doTry>
+      <bean ref="awfAdapter" method="create(${body})"/>
+      <process ref="anyObjectCreateProcessor"/>
+      <to uri="direct:createAnyObjectPort"/>
+      <doCatch>        
+        <exception>java.lang.RuntimeException</exception>
+        <handled>
+          <constant>false</constant>
+        </handled>
+        <to uri="direct:createAnyObjectPort"/>
+      </doCatch>
+    </doTry>
+  </route>
+         
+  <route id="updateAnyObject">
+    <from uri="direct:updateAnyObject"/>
+    <setProperty propertyName="anyMod">
+      <simple>${body}</simple>
+    </setProperty>
+    <doTry>
+      <bean ref="awfAdapter" method="update(${body})"/>
+      <process ref="anyObjectUpdateProcessor"/>
+      <to uri="direct:updateAnyObjectPort"/>
+      <doCatch>        
+        <exception>java.lang.RuntimeException</exception>
+        <handled>
+          <constant>false</constant>
+        </handled>
+        <to uri="direct:updateAnyObjectPort"/>
+      </doCatch>
+    </doTry>
+  </route>
+
+  <route id="deleteAnyObject">
+    <from uri="direct:deleteAnyObject"/>
+    <doTry>
+      <process ref="anyObjectDeleteProcessor"/>
+      <bean ref="awfAdapter" method="delete(${body})"/>
+      <setBody>
+        <simple>${property.statuses}</simple>
+      </setBody>
+      <to uri="direct:deleteAnyObjectPort"/>
+      <doCatch>        
+        <exception>java.lang.RuntimeException</exception>
+        <handled>
+          <constant>false</constant>
+        </handled>
+        <to uri="direct:deleteAnyObjectPort"/>
+      </doCatch>
+    </doTry>
+  </route>
+
+  <route id="unlinkAnyObject">
+    <from uri="direct:unlinkAnyObject"/>
+    <doTry>
+      <bean ref="awfAdapter" method="update(${body})"/>
+      <setBody>
+        <simple>${body.getResult}</simple>
+      </setBody>
+      <to uri="direct:unlinkAnyObjectPort"/>
+      <doCatch>        
+        <exception>java.lang.RuntimeException</exception>
+        <handled>
+          <constant>false</constant>
+        </handled>
+        <to uri="direct:unlinkAnyObjectPort"/>
+      </doCatch>
+    </doTry>            
+  </route>
+        
+  <route id="linkAnyObject">
+    <from uri="direct:linkAnyObject"/>
+    <doTry>
+      <bean ref="awfAdapter" method="update(${body})"/>
+      <setBody>
+        <simple>${body.getResult}</simple>
+      </setBody>
+      <to uri="direct:linkAnyObjectPort"/>
+      <doCatch>        
+        <exception>java.lang.RuntimeException</exception>
+        <handled>
+          <constant>false</constant>
+        </handled>
+        <to uri="direct:linkAnyObjectPort"/>
+      </doCatch>
+    </doTry>            
+  </route>
+        
+  <route id="deprovisionAnyObject">
+    <from uri="direct:deprovisionAnyObject"/>            
+    <process ref="anyObjectDeprovisionProcessor"/>
+    <to uri="direct:deprovisionAnyObjectPort"/>              
+  </route>
+    
+</routes>

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/ext/camel/provisioning-camel/src/main/resources/provisioning.properties
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/resources/provisioning.properties b/ext/camel/provisioning-camel/src/main/resources/provisioning.properties
index 5061502..aa843ca 100644
--- a/ext/camel/provisioning-camel/src/main/resources/provisioning.properties
+++ b/ext/camel/provisioning-camel/src/main/resources/provisioning.properties
@@ -17,5 +17,5 @@
 camel.directory=${conf.directory}
 userProvisioningManager=org.apache.syncope.core.provisioning.camel.CamelUserProvisioningManager
 groupProvisioningManager=org.apache.syncope.core.provisioning.camel.CamelGroupProvisioningManager
-anyObjectProvisioningManager=org.apache.syncope.core.provisioning.java.DefaultAnyObjectProvisioningManager
+anyObjectProvisioningManager=org.apache.syncope.core.provisioning.camel.CamelAnObjectProvisioningManager
 virAttrCache=org.apache.syncope.core.provisioning.java.cache.MemoryVirAttrCache

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml
----------------------------------------------------------------------
diff --git a/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml b/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml
index 8eec14d..d334d75 100644
--- a/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml
+++ b/ext/camel/provisioning-camel/src/main/resources/provisioningCamelContext.xml
@@ -33,7 +33,11 @@ under the License.
     <property name="primary" value="file:${camel.directory}/groupRoutes.xml"/>
     <property name="fallback" value="classpath:groupRoutes.xml"/>
   </bean>
-    
+  <bean id="anyObjectRoutes" class="org.apache.syncope.core.misc.spring.ResourceWithFallbackLoader">
+    <property name="primary" value="file:${camel.directory}/anyObjectRoutes.xml"/>
+    <property name="fallback" value="classpath:anyObjectRoutes.xml"/>
+  </bean>
+      
   <context:component-scan base-package="org.apache.syncope.core.provisioning.camel"/>
 
 </beans>

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/build-tools/pom.xml
----------------------------------------------------------------------
diff --git a/fit/build-tools/pom.xml b/fit/build-tools/pom.xml
index bfae2f4..679eee6 100644
--- a/fit/build-tools/pom.xml
+++ b/fit/build-tools/pom.xml
@@ -85,10 +85,16 @@ under the License.
     <dependency>
       <groupId>net.tirasa.connid.bundles.db</groupId>
       <artifactId>net.tirasa.connid.bundles.db.table</artifactId>
-      <version>${connid.db.table.version}</version>
+      <version>${connid.database.version}</version>
       <scope>runtime</scope>
     </dependency>
-    
+    <dependency>
+      <groupId>net.tirasa.connid.bundles.db</groupId>
+      <artifactId>net.tirasa.connid.bundles.db.scriptedsql</artifactId>
+      <version>${connid.database.version}</version>
+      <scope>runtime</scope>
+    </dependency>
+        
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ConnIdStartStopListener.java
----------------------------------------------------------------------
diff --git a/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ConnIdStartStopListener.java b/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ConnIdStartStopListener.java
index 37adbd3..67567ec 100644
--- a/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ConnIdStartStopListener.java
+++ b/fit/build-tools/src/main/java/org/apache/syncope/fit/buildtools/ConnIdStartStopListener.java
@@ -49,7 +49,8 @@ public class ConnIdStartStopListener implements ServletContextListener {
 
         for (String bundleFile : new String[] {
             "testconnectorserver.soap.bundle",
-            "testconnectorserver.db.bundle",
+            "testconnectorserver.dbtable.bundle",
+            "testconnectorserver.scriptedsql.bundle",
             "testconnectorserver.csvdir.bundle",
             "testconnectorserver.ldap.bundle" }) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/build-tools/src/main/resources/buildToolsContext.xml
----------------------------------------------------------------------
diff --git a/fit/build-tools/src/main/resources/buildToolsContext.xml b/fit/build-tools/src/main/resources/buildToolsContext.xml
index 2b63ed6..e0f5678 100644
--- a/fit/build-tools/src/main/resources/buildToolsContext.xml
+++ b/fit/build-tools/src/main/resources/buildToolsContext.xml
@@ -45,8 +45,11 @@ under the License.
   <bean id="testconnectorserver.soap.bundle" class="java.lang.String">
     <constructor-arg value="net.tirasa.connid.bundles.soap-${connid.soap.version}.jar"/>
   </bean>  
-  <bean id="testconnectorserver.db.bundle" class="java.lang.String">
-    <constructor-arg value="net.tirasa.connid.bundles.db.table-${connid.db.table.version}.jar"/>
+  <bean id="testconnectorserver.dbtable.bundle" class="java.lang.String">
+    <constructor-arg value="net.tirasa.connid.bundles.db.table-${connid.database.version}.jar"/>
+  </bean>  
+  <bean id="testconnectorserver.scriptedsql.bundle" class="java.lang.String">
+    <constructor-arg value="net.tirasa.connid.bundles.db.scriptedsql-${connid.database.version}.jar"/>
   </bean>  
   <bean id="testconnectorserver.csvdir.bundle" class="java.lang.String">
     <constructor-arg value="net.tirasa.connid.bundles.csvdir-${connid.csvdir.version}.jar"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/build-tools/src/main/resources/testdb.sql
----------------------------------------------------------------------
diff --git a/fit/build-tools/src/main/resources/testdb.sql b/fit/build-tools/src/main/resources/testdb.sql
index ff4dd47..9202a87 100644
--- a/fit/build-tools/src/main/resources/testdb.sql
+++ b/fit/build-tools/src/main/resources/testdb.sql
@@ -37,10 +37,16 @@ INSERT INTO test2 VALUES ('verdi', 'password321', 'true');
 
 -- this table is for issueSYNCOPE230
 DROP TABLE testsync IF EXISTS;
-CREATE TABLE TESTSYNC (
+CREATE TABLE testsync (
 id NUMBER(10) PRIMARY KEY,
 username VARCHAR(80),
 surname VARCHAR(80),
 email VARCHAR(80));
 
 INSERT INTO testsync VALUES (965, 'issuesyncope230', 'Surname', 'syncope230@syncope.apache.org');
+
+DROP TABLE testPRINTER IF EXISTS;
+CREATE TABLE testPRINTER (
+id NUMBER(10) PRIMARY KEY,
+location VARCHAR(80),
+lastModification TIMESTAMP);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/main/resources/connid.properties
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/connid.properties b/fit/core-reference/src/main/resources/connid.properties
index a18252f..22ed0a8 100644
--- a/fit/core-reference/src/main/resources/connid.properties
+++ b/fit/core-reference/src/main/resources/connid.properties
@@ -20,5 +20,5 @@ connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}
 ## for test only
 testdb.url=${testdb.url}
 connid.soap.version=${connid.soap.version}
-connid.db.table.version=${connid.db.table.version}
+connid.database.version=${connid.database.version}
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/main/resources/scriptedsql/CreateScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/scriptedsql/CreateScript.groovy b/fit/core-reference/src/main/resources/scriptedsql/CreateScript.groovy
new file mode 100644
index 0000000..52c10f9
--- /dev/null
+++ b/fit/core-reference/src/main/resources/scriptedsql/CreateScript.groovy
@@ -0,0 +1,52 @@
+/*
+ * 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 groovy.sql.Sql;
+import groovy.sql.DataSet;
+
+// Parameters:
+// The connector sends us the following:
+// connection : SQL connection
+// action: String correponding to the action ("CREATE" here)
+// log: a handler to the Log facility
+// objectClass: a String describing the Object class (__ACCOUNT__ / __GROUP__ / other)
+// id: The entry identifier (OpenICF "Name" atribute. (most often matches the uid)
+// attributes: an Attribute Map, containg the <String> attribute name as a key
+// and the <List> attribute value(s) as value.
+// password: password string, clear text
+// options: a handler to the OperationOptions Map
+
+log.info("Entering " + action + " Script");
+
+def sql = new Sql(connection);
+
+switch ( objectClass ) {
+case "__PRINTER__":
+  sql.execute("INSERT INTO TESTPRINTER (id, location, lastmodification) values (?,?,?)",
+    [
+      id,
+      attributes.get("location").get(0),
+      new Date()
+    ])
+  break
+
+default:
+  id;
+}
+
+return id;

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/main/resources/scriptedsql/DeleteScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/scriptedsql/DeleteScript.groovy b/fit/core-reference/src/main/resources/scriptedsql/DeleteScript.groovy
new file mode 100644
index 0000000..cdd7f5b
--- /dev/null
+++ b/fit/core-reference/src/main/resources/scriptedsql/DeleteScript.groovy
@@ -0,0 +1,43 @@
+/*
+ * 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 groovy.sql.Sql;
+import groovy.sql.DataSet;
+
+// Parameters:
+// The connector sends the following:
+// connection: handler to the SQL connection
+// action: a string describing the action ("DELETE" here)
+// log: a handler to the Log facility
+// objectClass: a String describing the Object class (__ACCOUNT__ / __GROUP__ / other)
+// options: a handler to the OperationOptions Map
+// uid: String for the unique id that specifies the object to delete
+
+log.info("Entering " + action + " Script");
+def sql = new Sql(connection);
+
+assert uid != null
+
+switch ( objectClass ) {
+case "__PRINTER__":
+  sql.execute("DELETE FROM TESTPRINTER where id= ?",[uid])
+  break
+
+default:
+  uid;
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/main/resources/scriptedsql/SchemaScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/scriptedsql/SchemaScript.groovy b/fit/core-reference/src/main/resources/scriptedsql/SchemaScript.groovy
new file mode 100644
index 0000000..50f8a8a
--- /dev/null
+++ b/fit/core-reference/src/main/resources/scriptedsql/SchemaScript.groovy
@@ -0,0 +1,50 @@
+/*
+ * 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 org.identityconnectors.framework.common.objects.AttributeInfo;
+import org.identityconnectors.framework.common.objects.AttributeInfo.Flags;
+import org.identityconnectors.framework.common.objects.AttributeInfoBuilder;
+import org.identityconnectors.framework.common.objects.ObjectClassInfo;
+import org.identityconnectors.framework.common.objects.ObjectClassInfoBuilder;
+
+// Parameters:
+// The connector sends the following:
+// action: a string describing the action ("SCHEMA" here)
+// log: a handler to the Log facility
+// builder: SchemaBuilder instance for the connector
+//
+// The connector will make the final call to builder.build()
+// so the scipt just need to declare the different object types.
+
+// This sample shows how to create 3 basic ObjectTypes: __ACCOUNT__, __GROUP__ and organization.
+// Each of them contains one required attribute and normal String attributes
+
+
+log.info("Entering " + action + " Script");
+
+idAIB = new AttributeInfoBuilder("id", String.class);
+idAIB.setRequired(true);
+
+orgAttrsInfo = new HashSet<AttributeInfo>();
+orgAttrsInfo.add(idAIB.build());
+orgAttrsInfo.add(AttributeInfoBuilder.build("location", String.class));
+// Create the organization Object class
+ObjectClassInfo ociOrg = new ObjectClassInfoBuilder().setType("__PRINTER__").addAllAttributeInfo(orgAttrsInfo).build();
+builder.defineObjectClass(ociOrg);
+
+log.info("Schema script done");
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/main/resources/scriptedsql/SearchScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/scriptedsql/SearchScript.groovy b/fit/core-reference/src/main/resources/scriptedsql/SearchScript.groovy
new file mode 100644
index 0000000..cc0dd65
--- /dev/null
+++ b/fit/core-reference/src/main/resources/scriptedsql/SearchScript.groovy
@@ -0,0 +1,94 @@
+/*
+ * 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 groovy.sql.Sql;
+import groovy.sql.DataSet;
+
+// Parameters:
+// The connector sends the following:
+// connection: handler to the SQL connection
+// objectClass: a String describing the Object class (__ACCOUNT__ / __GROUP__ / other)
+// action: a string describing the action ("SEARCH" here)
+// log: a handler to the Log facility
+// options: a handler to the OperationOptions Map
+// query: a handler to the Query Map
+//
+// The Query map describes the filter used.
+//
+// query = [ operation: "CONTAINS", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "ENDSWITH", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "STARTSWITH", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "EQUALS", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "GREATERTHAN", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "GREATERTHANOREQUAL", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "LESSTHAN", left: attribute, right: "value", not: true/false ]
+// query = [ operation: "LESSTHANOREQUAL", left: attribute, right: "value", not: true/false ]
+// query = null : then we assume we fetch everything
+//
+// AND and OR filter just embed a left/right couple of queries.
+// query = [ operation: "AND", left: query1, right: query2 ]
+// query = [ operation: "OR", left: query1, right: query2 ]
+//
+// Returns: A list of Maps. Each map describing one row.
+// !!!! Each Map must contain a '__UID__' and '__NAME__' attribute.
+// This is required to build a ConnectorObject.
+
+log.info("Entering " + action + " Script");
+
+def sql = new Sql(connection);
+def result = []
+def where = "";
+
+if (query != null)  {
+  // Need to handle the __UID__ in queries
+  if (query.get("left").equalsIgnoreCase("__UID__") && objectClass.equalsIgnoreCase("__PRINTER__")) {
+    query.put("left","id")
+  }
+  
+  // We can use Groovy template engine to generate our custom SQL queries
+  def engine = new groovy.text.SimpleTemplateEngine();
+
+  def whereTemplates = [
+    CONTAINS:' WHERE $left ${not ? "NOT " : ""}LIKE "%$right%"',
+    ENDSWITH:' WHERE $left ${not ? "NOT " : ""}LIKE "%$right"',
+    STARTSWITH:' WHERE $left ${not ? "NOT " : ""}LIKE "$right%"',
+    EQUALS:' WHERE $left ${not ? "<>" : "="} \'$right\'',
+    GREATERTHAN:' WHERE $left ${not ? "<=" : ">"} "$right"',
+    GREATERTHANOREQUAL:' WHERE $left ${not ? "<" : ">="} "$right"',
+    LESSTHAN:' WHERE $left ${not ? ">=" : "<"} "$right"',
+    LESSTHANOREQUAL:' WHERE $left ${not ? ">" : "<="} "$right"'
+  ]
+
+  def wt = whereTemplates.get(query.get("operation"));
+  def binding = [left:query.get("left"),right:query.get("right"),not:query.get("not")];
+  def template = engine.createTemplate(wt).make(binding);
+  where = template.toString();
+  log.ok("Search WHERE clause is: "+ where)
+}
+
+switch ( objectClass ) {
+case "__PRINTER__":
+  sql.eachRow("SELECT * FROM TESTPRINTER " + where, 
+    {result.add([__UID__:it.id, __NAME__:it.id, location:it.location])} );
+  break
+
+default:
+  result;
+}
+
+return result;

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/main/resources/scriptedsql/SyncScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/scriptedsql/SyncScript.groovy b/fit/core-reference/src/main/resources/scriptedsql/SyncScript.groovy
new file mode 100644
index 0000000..6060870
--- /dev/null
+++ b/fit/core-reference/src/main/resources/scriptedsql/SyncScript.groovy
@@ -0,0 +1,98 @@
+/*
+ * 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 groovy.sql.Sql;
+import groovy.sql.DataSet;
+
+// Parameters:
+// The connector sends the following:
+// connection: handler to the SQL connection
+// objectClass: a String describing the Object class (__ACCOUNT__ / __GROUP__ / other)
+// action: a string describing the action ("SYNC" or "GET_LATEST_SYNC_TOKEN" here)
+// log: a handler to the Log facility
+// options: a handler to the OperationOptions Map (null if action = "GET_LATEST_SYNC_TOKEN")
+// token: a handler to an Object representing the sync token (null if action = "GET_LATEST_SYNC_TOKEN")
+//
+//
+// Returns:
+// if action = "GET_LATEST_SYNC_TOKEN", it must return an object representing the last known
+// sync token for the corresponding ObjectClass
+// 
+// if action = "SYNC":
+// A list of Maps . Each map describing one update:
+// Map should look like the following:
+//
+// [
+// "token": <Object> token object (could be Integer, Date, String) , [!! could be null]
+// "operation":<String> ("CREATE_OR_UPDATE"|"DELETE")  will always default to CREATE_OR_DELETE ,
+// "uid":<String> uid  (uid of the entry) ,
+// "previousUid":<String> prevuid (This is for rename ops) ,
+// "password":<String> password (optional... allows to pass clear text password if needed),
+// "attributes":Map<String,List> of attributes name/values
+// ]
+
+log.info("Entering " + action + " Script");
+def sql = new Sql(connection);
+
+if (action.equalsIgnoreCase("GET_LATEST_SYNC_TOKEN")) {
+  switch (objectClass) {
+  case "__PRINTER__":
+    row = sql.firstRow("SELECT lastmodification FROM TESTPRINTER ORDER BY lastmodification DESC");
+    log.ok("Get Latest Sync Token script: last token is: " + row["lastmodification"])
+    break;
+    
+  default:
+    row = null;
+  }
+
+  return row == null ? null : row["lastmodification"].getTime();
+} else if (action.equalsIgnoreCase("SYNC")) {
+  def result = [];
+  def lastmodification = null;
+  if (token != null) {
+    lastmodification = new Date(token);
+  } else {
+    lastmodification = new Date(0);
+  }
+
+  switch (objectClass) {
+  case "__PRINTER__":    
+    sql.eachRow("SELECT * FROM TESTPRINTER WHERE lastmodification > ${lastmodification}",
+      {
+        result.add([
+            operation:"CREATE_OR_UPDATE", 
+            uid:it.id.toString(), 
+            token:it.lastmodification.getTime(), 
+            attributes:[
+              __UID__:it.id.toString(),
+              __NAME__:it.id.toString(),
+              id:it.id.toString(),
+              location:it.location
+            ]
+          ]);
+      }
+    )
+    break;
+  }
+  
+  log.ok("Sync script: found " + result.size() + " events to sync");
+  return result;
+} else {
+  log.error("Sync script: action '" + action + "' is not implemented in this script");
+  return null;
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/main/resources/scriptedsql/TestScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/scriptedsql/TestScript.groovy b/fit/core-reference/src/main/resources/scriptedsql/TestScript.groovy
new file mode 100644
index 0000000..5b8f4b5
--- /dev/null
+++ b/fit/core-reference/src/main/resources/scriptedsql/TestScript.groovy
@@ -0,0 +1,31 @@
+/*
+ * 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 groovy.sql.Sql;
+import groovy.sql.DataSet;
+
+// Parameters:
+// The connector sends the following:
+// connection: handler to the SQL connection
+// action: a string describing the action ("TEST" here)
+// log: a handler to the Log facility
+
+log.info("Entering " + action + " Script");
+def sql = new Sql(connection);
+
+sql.eachRow("select * from TESTPRINTER", { println it.uid} );
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/main/resources/scriptedsql/UpdateScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/resources/scriptedsql/UpdateScript.groovy b/fit/core-reference/src/main/resources/scriptedsql/UpdateScript.groovy
new file mode 100644
index 0000000..f3155cb
--- /dev/null
+++ b/fit/core-reference/src/main/resources/scriptedsql/UpdateScript.groovy
@@ -0,0 +1,67 @@
+/*
+ * 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 groovy.sql.Sql;
+import groovy.sql.DataSet;
+
+// Parameters:
+// The connector sends us the following:
+// connection : SQL connection
+//
+// action: String correponding to the action (UPDATE/ADD_ATTRIBUTE_VALUES/REMOVE_ATTRIBUTE_VALUES)
+//   - UPDATE : For each input attribute, replace all of the current values of that attribute
+//     in the target object with the values of that attribute.
+//   - ADD_ATTRIBUTE_VALUES: For each attribute that the input set contains, add to the current values
+//     of that attribute in the target object all of the values of that attribute in the input set.
+//   - REMOVE_ATTRIBUTE_VALUES: For each attribute that the input set contains, remove from the current values
+//     of that attribute in the target object any value that matches one of the values of the attribute from the input set.
+
+// log: a handler to the Log facility
+//
+// objectClass: a String describing the Object class (__ACCOUNT__ / __GROUP__ / other)
+//
+// uid: a String representing the entry uid
+//
+// attributes: an Attribute Map, containg the <String> attribute name as a key
+// and the <List> attribute value(s) as value.
+//
+// password: password string, clear text (only for UPDATE)
+//
+// options: a handler to the OperationOptions Map
+
+log.info("Entering " + action + " Script");
+def sql = new Sql(connection);
+
+
+switch (action) {
+case "UPDATE":
+  if (attributes.get("location").get(0) != null) {
+    sql.executeUpdate("UPDATE TESTPRINTER SET location = ?, lastmodification = ? where id = ?", 
+      [attributes.get("location").get(0), new Date(), attributes.get("__NAME__").get(0)])
+    
+    return attributes.get("__NAME__").get(0);
+  }
+  break
+
+case "ADD_ATTRIBUTE_VALUES":
+  break
+
+
+default:
+  sql
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/a45a46bb/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractITCase.java
index 8cfec8b..efe1b16 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AbstractITCase.java
@@ -35,11 +35,13 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
+import org.apache.syncope.common.lib.mod.AnyObjectMod;
 import org.apache.syncope.common.lib.mod.AttrMod;
 import org.apache.syncope.common.lib.mod.GroupMod;
 import org.apache.syncope.common.lib.mod.UserMod;
 import org.apache.syncope.common.lib.to.AbstractPolicyTO;
 import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.GroupTO;
@@ -48,6 +50,7 @@ import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
 import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.AnyObjectService;
 import org.apache.syncope.common.rest.api.service.AnyTypeClassService;
 import org.apache.syncope.common.rest.api.service.AnyTypeService;
 import org.apache.syncope.common.rest.api.service.CamelRouteService;
@@ -141,6 +144,8 @@ public abstract class AbstractITCase {
 
     protected static final String RESOURCE_NAME_CREATE_NONE = "ws-target-resource-create-none";
 
+    protected static final String RESOURCE_NAME_DBSCRIPTED = "resource-db-scripted";
+
     protected static String ANONYMOUS_UNAME;
 
     protected static String ANONYMOUS_KEY;
@@ -155,6 +160,8 @@ public abstract class AbstractITCase {
 
     protected static RealmService realmService;
 
+    protected static AnyObjectService anyObjectService;
+
     protected static RoleService roleService;
 
     protected static UserService userService;
@@ -226,6 +233,7 @@ public abstract class AbstractITCase {
         anyTypeClassService = adminClient.getService(AnyTypeClassService.class);
         anyTypeService = adminClient.getService(AnyTypeService.class);
         realmService = adminClient.getService(RealmService.class);
+        anyObjectService = adminClient.getService(AnyObjectService.class);
         roleService = adminClient.getService(RoleService.class);
         userService = adminClient.getService(UserService.class);
         userSelfService = adminClient.getService(UserSelfService.class);
@@ -287,8 +295,8 @@ public abstract class AbstractITCase {
         return userService.update(userMod.getKey(), userMod).readEntity(UserTO.class);
     }
 
-    protected UserTO deleteUser(final Long id) {
-        return userService.delete(id).readEntity(UserTO.class);
+    protected UserTO deleteUser(final Long key) {
+        return userService.delete(key).readEntity(UserTO.class);
     }
 
     public <T> T getObject(final URI location, final Class<?> serviceClass, final Class<T> resultClass) {
@@ -322,6 +330,25 @@ public abstract class AbstractITCase {
         return getObject(response.getLocation(), RoleService.class, RoleTO.class);
     }
 
+    protected AnyObjectTO createAnyObject(final AnyObjectTO anyObjectTO) {
+        Response response = anyObjectService.create(anyObjectTO);
+        if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
+            Exception ex = clientFactory.getExceptionMapper().fromResponse(response);
+            if (ex != null) {
+                throw (RuntimeException) ex;
+            }
+        }
+        return getObject(response.getLocation(), AnyObjectService.class, AnyObjectTO.class);
+    }
+
+    protected AnyObjectTO updateAnyObject(final AnyObjectMod anyObjectMod) {
+        return anyObjectService.update(anyObjectMod.getKey(), anyObjectMod).readEntity(AnyObjectTO.class);
+    }
+
+    protected AnyObjectTO deleteAnyObject(final Long key) {
+        return anyObjectService.delete(key).readEntity(AnyObjectTO.class);
+    }
+
     protected GroupTO createGroup(final GroupTO groupTO) {
         Response response = groupService.create(groupTO);
         if (response.getStatusInfo().getStatusCode() != Response.Status.CREATED.getStatusCode()) {
@@ -337,8 +364,8 @@ public abstract class AbstractITCase {
         return groupService.update(groupMod.getKey(), groupMod).readEntity(GroupTO.class);
     }
 
-    protected GroupTO deleteGroup(final Long id) {
-        return groupService.delete(id).readEntity(GroupTO.class);
+    protected GroupTO deleteGroup(final Long key) {
+        return groupService.delete(key).readEntity(GroupTO.class);
     }
 
     @SuppressWarnings("unchecked")