syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [09/11] syncope git commit: [SYNCOPE-694] Implementation completed
Date Fri, 18 Sep 2015 08:48:59 GMT
http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
index 6468dab..e20621b 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
@@ -28,7 +28,33 @@ public class RelationshipTO extends AbstractBaseBean {
 
     private static final long serialVersionUID = 360672942026613929L;
 
-    private String relationshipType;
+    public static class Builder {
+
+        private final RelationshipTO instance = new RelationshipTO();
+
+        public Builder type(final String type) {
+            instance.setType(type);
+            return this;
+        }
+
+        public Builder left(final String leftType, final long leftKey) {
+            instance.setLeftType(leftType);
+            instance.setLeftKey(leftKey);
+            return this;
+        }
+
+        public Builder right(final String rightType, final long rightKey) {
+            instance.setRightType(rightType);
+            instance.setRightKey(rightKey);
+            return this;
+        }
+
+        public RelationshipTO build() {
+            return instance;
+        }
+    }
+
+    private String type;
 
     private String leftType;
 
@@ -38,12 +64,12 @@ public class RelationshipTO extends AbstractBaseBean {
 
     private long rightKey;
 
-    public String getRelationshipType() {
-        return relationshipType;
+    public String getType() {
+        return type;
     }
 
-    public void setRelationshipType(final String relationshipType) {
-        this.relationshipType = relationshipType;
+    public void setType(final String type) {
+        this.type = type;
     }
 
     public String getLeftType() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/main/java/org/apache/syncope/common/lib/types/PatchOperation.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/PatchOperation.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/PatchOperation.java
new file mode 100644
index 0000000..9872cbf
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/PatchOperation.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.common.lib.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum
+public enum PatchOperation {
+
+    ADD_REPLACE,
+    DELETE;
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/main/java/org/apache/syncope/common/lib/types/ResourceDeassociationAction.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ResourceDeassociationAction.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ResourceDeassociationAction.java
new file mode 100644
index 0000000..c8d78ec
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ResourceDeassociationAction.java
@@ -0,0 +1,39 @@
+/*
+ * 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.common.lib.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum
+public enum ResourceDeassociationAction {
+
+    /**
+     * Remove association between user/group on Syncope and external resource(s) without any propagation.
+     */
+    UNLINK,
+    /**
+     * Remove user/group from external resource(s).
+     */
+    DEPROVISION,
+    /**
+     * Unassign (unlink + de-provision) external resource(s) from user/group.
+     */
+    UNASSIGN
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/main/java/org/apache/syncope/common/lib/types/ResourceDeassociationActionType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ResourceDeassociationActionType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/ResourceDeassociationActionType.java
deleted file mode 100644
index aea4fa3..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/ResourceDeassociationActionType.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.common.lib.types;
-
-import javax.xml.bind.annotation.XmlEnum;
-
-@XmlEnum
-public enum ResourceDeassociationActionType {
-
-    /**
-     * Remove association between user/group on Syncope and external resource(s) without any propagation.
-     */
-    UNLINK,
-    /**
-     * Remove user/group from external resource(s).
-     */
-    DEPROVISION,
-    /**
-     * Unassign (unlink + de-provision) external resource(s) from user/group.
-     */
-    UNASSIGN
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/main/java/org/apache/syncope/common/lib/types/StatusPatchType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/StatusPatchType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/StatusPatchType.java
new file mode 100644
index 0000000..00b88c5
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/StatusPatchType.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum
+public enum StatusPatchType {
+
+    ACTIVATE,
+    SUSPEND,
+    REACTIVATE;
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/BooleanWrap.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/BooleanWrap.java b/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/BooleanWrap.java
deleted file mode 100644
index 3be7643..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/BooleanWrap.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.common.lib.wrap;
-
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlRootElement(name = "booleanWrap")
-@XmlType
-public class BooleanWrap extends AbstractWrappable<Boolean> {
-
-    private static final long serialVersionUID = 3762310846902669241L;
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ResourceKey.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ResourceKey.java b/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ResourceKey.java
deleted file mode 100644
index 1b06c5b..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ResourceKey.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.common.lib.wrap;
-
-import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlRootElement(name = "resourceKey")
-@XmlType
-public class ResourceKey extends AbstractWrappable<String> {
-
-    private static final long serialVersionUID = -175720097924079573L;
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java
----------------------------------------------------------------------
diff --git a/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java b/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java
index bf8fcfb..9434b7f 100644
--- a/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java
+++ b/common/lib/src/test/java/org/apache/syncope/common/lib/JAXBTest.java
@@ -23,6 +23,8 @@ import static org.junit.Assert.fail;
 import java.io.StringWriter;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.Marshaller;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.report.UserReportletConf;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.junit.Test;
@@ -32,11 +34,12 @@ public class JAXBTest {
     @Test
     public void marshal() {
         try {
-            JAXBContext context = JAXBContext.newInstance(UserReportletConf.class);
+            JAXBContext context = JAXBContext.newInstance(UserTO.class, UserPatch.class, UserReportletConf.class);
             Marshaller marshaller = context.createMarshaller();
             marshaller.marshal(new UserTO(), new StringWriter());
+            marshaller.marshal(new UserPatch(), new StringWriter());
         } catch (Exception e) {
-            fail();
+            fail(ExceptionUtils.getStackTrace(e));
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java
----------------------------------------------------------------------
diff --git a/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java b/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java
index 008c226..711ce74 100644
--- a/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java
+++ b/common/lib/src/test/java/org/apache/syncope/common/lib/JSONTest.java
@@ -19,13 +19,21 @@
 package org.apache.syncope.common.lib;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
 import java.io.StringWriter;
+import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.patch.PasswordPatch;
+import org.apache.syncope.common.lib.patch.LongPatchItem;
+import org.apache.syncope.common.lib.patch.StringReplacePatchItem;
+import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.report.UserReportletConf;
+import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.ReportTO;
 import org.apache.syncope.common.lib.to.WorkflowFormPropertyTO;
+import org.apache.syncope.common.lib.types.PatchOperation;
 import org.junit.Test;
 
 public class JSONTest {
@@ -60,4 +68,31 @@ public class JSONTest {
         ReportTO actual = mapper.readValue(writer.toString(), ReportTO.class);
         assertEquals(report, actual);
     }
+
+    @Test
+    public void patch() throws IOException {
+        UserPatch patch = new UserPatch();
+        patch.setKey(12L);
+        patch.setUsername(new StringReplacePatchItem.Builder().value("newusername").build());
+        assertNotNull(patch.getUsername().getValue());
+        patch.setPassword(new PasswordPatch.Builder().
+                onSyncope(false).
+                resource("ext1").resource("ext2").
+                value("newpassword").
+                build());
+        assertNotNull(patch.getPassword().getValue());
+        patch.getRoles().add(new LongPatchItem.Builder().operation(PatchOperation.DELETE).value(7L).build());
+        patch.getDerAttrs().add(new AttrPatch.Builder().
+                operation(PatchOperation.ADD_REPLACE).
+                attrTO(new AttrTO.Builder().schema("derived").build()).
+                build());
+
+        ObjectMapper mapper = new ObjectMapper();
+
+        StringWriter writer = new StringWriter();
+        mapper.writeValue(writer, patch);
+
+        UserPatch actual = mapper.readValue(writer.toString(), UserPatch.class);
+        assertEquals(patch, actual);
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
index b460b54..904f854 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyObjectService.java
@@ -24,7 +24,7 @@ import javax.ws.rs.MatrixParam;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
-import org.apache.syncope.common.lib.mod.AnyObjectMod;
+import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.rest.api.beans.AnyListQuery;
@@ -33,7 +33,7 @@ import org.apache.syncope.common.rest.api.beans.AnyListQuery;
  * REST operations for anyObjects.
  */
 @Path("anyObjects")
-public interface AnyObjectService extends AnyService<AnyObjectTO, AnyObjectMod> {
+public interface AnyObjectService extends AnyService<AnyObjectTO, AnyObjectPatch> {
 
     /**
      * Returns a paged list of existing any objects matching the given query, for the given type.

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
index 71aa4b6..3e342a8 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AnyService.java
@@ -18,31 +18,30 @@
  */
 package org.apache.syncope.common.rest.api.service;
 
-import java.util.List;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.BeanParam;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+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.syncope.common.lib.mod.AnyMod;
-import org.apache.syncope.common.lib.mod.ResourceAssociationMod;
+import org.apache.cxf.jaxrs.ext.PATCH;
+import org.apache.syncope.common.lib.patch.AnyPatch;
+import org.apache.syncope.common.lib.patch.AssociationPatch;
+import org.apache.syncope.common.lib.patch.DeassociationPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
 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.types.ResourceAssociationAction;
-import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
-import org.apache.syncope.common.lib.wrap.ResourceKey;
 import org.apache.syncope.common.rest.api.beans.AnyListQuery;
 import org.apache.syncope.common.rest.api.beans.AnySearchQuery;
 
-public interface AnyService<TO extends AnyTO, MOD extends AnyMod> extends JAXRSService {
+public interface AnyService<TO extends AnyTO, P extends AnyPatch> extends JAXRSService {
 
     /**
      * Reads the any object matching the provided key.
@@ -91,15 +90,28 @@ public interface AnyService<TO extends AnyTO, MOD extends AnyMod> extends JAXRSS
     /**
      * Updates any object matching the provided key.
      *
-     * @param anyMod modification to be applied to any object matching the provided key
+     * @param anyPatch modification to be applied to any object matching the provided key
      * @return <tt>Response</tt> object featuring the updated any object enriched with propagation status information
      * - <tt>AnyTO</tt> as <tt>Entity</tt>
      */
-    @POST
+    @PATCH
+    @Path("{key}")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    Response update(@NotNull P anyPatch);
+
+    /**
+     * Updates any object matching the provided key.
+     *
+     * @param anyTO complete update
+     * @return <tt>Response</tt> object featuring the updated any object enriched with propagation status information
+     * - <tt>AnyTO</tt> as <tt>Entity</tt>
+     */
+    @PUT
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    Response update(@NotNull MOD anyMod);
+    Response update(@NotNull TO anyTO);
 
     /**
      * Deletes any object matching provided key.
@@ -117,36 +129,26 @@ public interface AnyService<TO extends AnyTO, MOD extends AnyMod> extends JAXRSS
     /**
      * Executes resource-related operations on given any object.
      *
-     * @param key any object id.
-     * @param type resource association action type
-     * @param resourceNames external resources to be used for propagation-related operations
+     * @param patch external resources to be used for propagation-related operations
      * @return <tt>Response</tt> object featuring <tt>BulkActionResult</tt> as <tt>Entity</tt>
      */
     @POST
-    @Path("{key}/deassociate/{type}")
+    @Path("{key}/deassociate/{action}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    Response deassociate(
-            @NotNull @PathParam("key") Long key,
-            @NotNull @PathParam("type") ResourceDeassociationActionType type,
-            @NotNull List<ResourceKey> resourceNames);
+    Response deassociate(@NotNull DeassociationPatch patch);
 
     /**
      * Executes resource-related operations on given any object.
      *
-     * @param key any object id.
-     * @param type resource association action type
-     * @param associationMod external resources to be used for propagation-related operations
+     * @param patch external resources to be used for propagation-related operations
      * @return <tt>Response</tt> object featuring <tt>BulkActionResult</tt> as <tt>Entity</tt>
      */
     @POST
-    @Path("{key}/associate/{type}")
+    @Path("{key}/associate/{action}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    Response associate(
-            @NotNull @PathParam("key") Long key,
-            @NotNull @PathParam("type") ResourceAssociationAction type,
-            @NotNull ResourceAssociationMod associationMod);
+    Response associate(@NotNull AssociationPatch patch);
 
     /**
      * Executes the provided bulk action.

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConnectorService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConnectorService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConnectorService.java
index b523758..68f6bdd 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConnectorService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ConnectorService.java
@@ -38,7 +38,6 @@ import org.apache.syncope.common.lib.to.ConnBundleTO;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
 import org.apache.syncope.common.lib.to.PlainSchemaTO;
 import org.apache.syncope.common.lib.types.ConnConfProperty;
-import org.apache.syncope.common.lib.wrap.BooleanWrap;
 import org.apache.syncope.common.lib.wrap.ConnIdObjectClass;
 
 /**
@@ -170,12 +169,11 @@ public interface ConnectorService extends JAXRSService {
 
     /**
      * @param connInstanceTO connector instance to be used for connection check
-     * @return true if connection could be established
      */
     @POST
     @Path("check")
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    BooleanWrap check(@NotNull ConnInstanceTO connInstanceTO);
+    void check(@NotNull ConnInstanceTO connInstanceTO);
 
     /**
      * Reload all connector bundles and instances.

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
index 569c0b6..934ceff 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/GroupService.java
@@ -23,14 +23,14 @@ import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
-import org.apache.syncope.common.lib.mod.GroupMod;
+import org.apache.syncope.common.lib.patch.GroupPatch;
 import org.apache.syncope.common.lib.to.GroupTO;
 
 /**
  * REST operations for groups.
  */
 @Path("groups")
-public interface GroupService extends AnyService<GroupTO, GroupMod> {
+public interface GroupService extends AnyService<GroupTO, GroupPatch> {
 
     /**
      * This method is similar to <tt>read()</tt>, but uses different authentication handling to ensure that a user

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java
index 14bb19f..bdf8411 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/ResourceService.java
@@ -36,9 +36,8 @@ import org.apache.syncope.common.lib.to.BulkActionResult;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedConnObjectTOResult;
 import org.apache.syncope.common.lib.to.ResourceTO;
-import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
+import org.apache.syncope.common.lib.types.ResourceDeassociationAction;
 import org.apache.syncope.common.lib.wrap.AnyKey;
-import org.apache.syncope.common.lib.wrap.BooleanWrap;
 import org.apache.syncope.common.rest.api.beans.ConnObjectTOListQuery;
 
 /**
@@ -134,13 +133,12 @@ public interface ResourceService extends JAXRSService {
      * Checks whether the connection to resource could be established.
      *
      * @param resourceTO resource to be checked
-     * @return true if connection to resource could be established
      */
     @POST
     @Path("check")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    BooleanWrap check(@NotNull ResourceTO resourceTO);
+    void check(@NotNull ResourceTO resourceTO);
 
     /**
      * De-associate any objects from the given resource.
@@ -152,12 +150,12 @@ public interface ResourceService extends JAXRSService {
      * @return <tt>Response</tt> object featuring <tt>BulkActionResult</tt> as <tt>Entity</tt>
      */
     @POST
-    @Path("{key}/bulkDeassociation/{anyTypeKey}/{type}")
+    @Path("{key}/bulkDeassociation/{anyTypeKey}/{action}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     BulkActionResult bulkDeassociation(@NotNull @PathParam("key") String key,
             @NotNull @PathParam("anyTypeKey") String anyTypeKey,
-            @NotNull @PathParam("type") ResourceDeassociationActionType type, @NotNull List<AnyKey> keys);
+            @NotNull @PathParam("action") ResourceDeassociationAction type, @NotNull List<AnyKey> keys);
 
     /**
      * Executes the provided bulk action.

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java
index 258a1b6..cd934be 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserSelfService.java
@@ -24,12 +24,14 @@ import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.cxf.jaxrs.ext.PATCH;
+import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.UserTO;
 
 /**
@@ -65,14 +67,26 @@ public interface UserSelfService extends JAXRSService {
     /**
      * Self-updates user.
      *
-     * @param userMod modification to be applied to self
+     * @param patch modification to be applied to self
      * @return <tt>Response</tt> object featuring the updated user - <tt>UserTO</tt> as <tt>Entity</tt>
      */
-    @POST
+    @PATCH
+    @Path("{key}")
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    Response update(@NotNull UserPatch patch);
+
+    /**
+     * Self-updates user.
+     *
+     * @param user complete update
+     * @return <tt>Response</tt> object featuring the updated user - <tt>UserTO</tt> as <tt>Entity</tt>
+     */
+    @PUT
     @Path("{key}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    Response update(@NotNull UserMod userMod);
+    Response update(@NotNull UserTO user);
 
     /**
      * Self-deletes user.

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
index fd0faac..0f54ace 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java
@@ -29,15 +29,15 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import org.apache.syncope.common.lib.mod.StatusMod;
-import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.patch.StatusPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.UserTO;
 
 /**
  * REST operations for users.
  */
 @Path("users")
-public interface UserService extends AnyService<UserTO, UserMod> {
+public interface UserService extends AnyService<UserTO, UserPatch> {
 
     /**
      * Gives the username for the provided user key.
@@ -77,7 +77,7 @@ public interface UserService extends AnyService<UserTO, UserMod> {
     /**
      * Performs a status update on given.
      *
-     * @param statusMod status update details
+     * @param statusPatch status update details
      * @return <tt>Response</tt> object featuring the updated user enriched with propagation status information
      * - <tt>UserTO</tt> as <tt>Entity</tt>
      */
@@ -85,5 +85,5 @@ public interface UserService extends AnyService<UserTO, UserMod> {
     @Path("{key}/status")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
-    Response status(@NotNull StatusMod statusMod);
+    Response status(@NotNull StatusPatch statusPatch);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
index cd40a6b..e85058c 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AbstractAnyLogic.java
@@ -25,11 +25,10 @@ import java.util.List;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Predicate;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.mod.AnyMod;
+import org.apache.syncope.common.lib.patch.AnyPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.UserTO;
@@ -49,7 +48,7 @@ import org.apache.syncope.core.provisioning.api.LogicActions;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
 
-public abstract class AbstractAnyLogic<TO extends AnyTO, MOD extends AnyMod>
+public abstract class AbstractAnyLogic<TO extends AnyTO, P extends AnyPatch>
         extends AbstractResourceAssociator<TO> {
 
     @Autowired
@@ -122,18 +121,15 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, MOD extends AnyMod>
         return any;
     }
 
-    protected Pair<MOD, List<LogicActions>> beforeUpdate(final MOD input, final String realmPath) {
-        if (StringUtils.isBlank(input.getRealm())) {
-            input.setRealm(realmPath);
-        }
-        Realm realm = realmDAO.find(input.getRealm());
+    protected Pair<P, List<LogicActions>> beforeUpdate(final P input, final String realmPath) {
+        Realm realm = realmDAO.find(realmPath);
         if (realm == null) {
             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidRealm);
-            sce.getElements().add(input.getRealm());
+            sce.getElements().add(realmPath);
             throw sce;
         }
 
-        MOD mod = input;
+        P mod = input;
 
         List<LogicActions> actions = getActions(realm);
         for (LogicActions action : actions) {
@@ -244,7 +240,7 @@ public abstract class AbstractAnyLogic<TO extends AnyTO, MOD extends AnyMod>
 
     public abstract TO create(TO anyTO);
 
-    public abstract TO update(MOD anyMod);
+    public abstract TO update(P anyPatch);
 
     public abstract TO delete(Long key);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
index 5e52b9e..5d1c9b8 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/AnyObjectLogic.java
@@ -34,12 +34,14 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.mod.AnyObjectMod;
+import org.apache.syncope.common.lib.patch.AnyObjectPatch;
+import org.apache.syncope.common.lib.patch.StringPatchItem;
 import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
@@ -61,7 +63,7 @@ import org.springframework.transaction.annotation.Transactional;
  * Spring's Transactional logic at class level.
  */
 @Component
-public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod> {
+public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectPatch> {
 
     @Autowired
     protected AnyObjectDAO anyObjectDAO;
@@ -182,24 +184,20 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
 
     @PreAuthorize("hasRole('" + Entitlement.ANY_OBJECT_UPDATE + "')")
     @Override
-    public AnyObjectTO update(final AnyObjectMod anyObjectMod) {
-        AnyObjectTO anyObjectTO = binder.getAnyObjectTO(anyObjectMod.getKey());
-        Pair<AnyObjectMod, List<LogicActions>> before = beforeUpdate(anyObjectMod, anyObjectTO.getRealm());
-
-        Set<String> requestedRealms = new HashSet<>();
-        requestedRealms.add(before.getLeft().getRealm());
-        if (StringUtils.isNotBlank(before.getLeft().getRealm())) {
-            requestedRealms.add(before.getLeft().getRealm());
-        }
-        Set<String> effectiveRealms = getEffectiveRealms(
-                AuthContextUtils.getAuthorizations().get(Entitlement.ANY_OBJECT_UPDATE),
-                requestedRealms);
-        securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
-        if (StringUtils.isNotBlank(before.getLeft().getRealm())) {
-            securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
+    public AnyObjectTO update(final AnyObjectPatch anyObjectPatch) {
+        AnyObjectTO anyObjectTO = binder.getAnyObjectTO(anyObjectPatch.getKey());
+        Pair<AnyObjectPatch, List<LogicActions>> before = beforeUpdate(anyObjectPatch, anyObjectTO.getRealm());
+
+        if (before.getLeft().getRealm() != null && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())) {
+            Set<String> requestedRealms = new HashSet<>();
+            requestedRealms.add(before.getLeft().getRealm().getValue());
+            Set<String> effectiveRealms = getEffectiveRealms(
+                    AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+                    requestedRealms);
+            securityChecks(effectiveRealms, before.getLeft().getRealm().getValue(), before.getLeft().getKey());
         }
 
-        Map.Entry<Long, List<PropagationStatus>> updated = provisioningManager.update(anyObjectMod);
+        Map.Entry<Long, List<PropagationStatus>> updated = provisioningManager.update(anyObjectPatch);
 
         AnyObjectTO updatedTO = binder.getAnyObjectTO(updated.getKey());
         updatedTO.getPropagationStatusTOs().addAll(updated.getValue());
@@ -237,11 +235,17 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
                 Collections.singleton(anyObject.getRealm()));
         securityChecks(effectiveRealms, anyObject.getRealm(), anyObject.getKey());
 
-        AnyObjectMod anyObjectMod = new AnyObjectMod();
-        anyObjectMod.setKey(key);
-        anyObjectMod.getResourcesToRemove().addAll(resources);
+        AnyObjectPatch patch = new AnyObjectPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
 
-        return binder.getAnyObjectTO(provisioningManager.unlink(anyObjectMod));
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.DELETE).value(resource).build();
+            }
+        }));
+
+        return binder.getAnyObjectTO(provisioningManager.unlink(patch));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.ANY_OBJECT_UPDATE + "')")
@@ -254,11 +258,17 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
                 Collections.singleton(anyObject.getRealm()));
         securityChecks(effectiveRealms, anyObject.getRealm(), anyObject.getKey());
 
-        AnyObjectMod anyObjectMod = new AnyObjectMod();
-        anyObjectMod.setKey(key);
-        anyObjectMod.getResourcesToAdd().addAll(resources);
+        AnyObjectPatch patch = new AnyObjectPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
 
-        return binder.getAnyObjectTO(provisioningManager.link(anyObjectMod));
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(resource).build();
+            }
+        }));
+
+        return binder.getAnyObjectTO(provisioningManager.link(patch));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.ANY_OBJECT_UPDATE + "')")
@@ -271,10 +281,17 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
                 Collections.singleton(anyObject.getRealm()));
         securityChecks(effectiveRealms, anyObject.getRealm(), anyObject.getKey());
 
-        AnyObjectMod anyObjectMod = new AnyObjectMod();
-        anyObjectMod.setKey(key);
-        anyObjectMod.getResourcesToRemove().addAll(resources);
-        return update(anyObjectMod);
+        AnyObjectPatch patch = new AnyObjectPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
+
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.DELETE).value(resource).build();
+            }
+        }));
+
+        return update(patch);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.ANY_OBJECT_UPDATE + "')")
@@ -292,11 +309,17 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
                 Collections.singleton(anyObject.getRealm()));
         securityChecks(effectiveRealms, anyObject.getRealm(), anyObject.getKey());
 
-        AnyObjectMod anyObjectMod = new AnyObjectMod();
-        anyObjectMod.setKey(key);
-        anyObjectMod.getResourcesToAdd().addAll(resources);
+        AnyObjectPatch patch = new AnyObjectPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
+
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(resource).build();
+            }
+        }));
 
-        return update(anyObjectMod);
+        return update(patch);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.ANY_OBJECT_UPDATE + "')")
@@ -347,8 +370,8 @@ public class AnyObjectLogic extends AbstractAnyLogic<AnyObjectTO, AnyObjectMod>
                     key = (Long) args[i];
                 } else if (args[i] instanceof AnyObjectTO) {
                     key = ((AnyObjectTO) args[i]).getKey();
-                } else if (args[i] instanceof AnyObjectMod) {
-                    key = ((AnyObjectMod) args[i]).getKey();
+                } else if (args[i] instanceof AnyObjectPatch) {
+                    key = ((AnyObjectPatch) args[i]).getKey();
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
index 3319579..870a4d0 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ConnectorLogic.java
@@ -259,20 +259,10 @@ public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
 
     @PreAuthorize("hasRole('" + Entitlement.CONNECTOR_READ + "')")
     @Transactional(readOnly = true)
-    public boolean check(final ConnInstanceTO connInstanceTO) {
-        final Connector connector = connFactory.createConnector(
+    public void check(final ConnInstanceTO connInstanceTO) {
+        Connector connector = connFactory.createConnector(
                 binder.getConnInstance(connInstanceTO), connInstanceTO.getConfiguration());
-
-        boolean result;
-        try {
-            connector.test();
-            result = true;
-        } catch (Exception ex) {
-            LOG.error("Test connection failure {}", ex);
-            result = false;
-        }
-
-        return result;
+        connector.test();
     }
 
     @PreAuthorize("hasRole('" + Entitlement.CONNECTOR_READ + "')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
index a8af2b9..0eb0d0c 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/GroupLogic.java
@@ -35,12 +35,14 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.common.lib.mod.GroupMod;
+import org.apache.syncope.common.lib.patch.GroupPatch;
+import org.apache.syncope.common.lib.patch.StringPatchItem;
 import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.core.misc.RealmUtils;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -65,7 +67,7 @@ import org.springframework.transaction.annotation.Transactional;
  * Spring's Transactional logic at class level.
  */
 @Component
-public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupMod> {
+public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupPatch> {
 
     @Autowired
     protected GroupDAO groupDAO;
@@ -202,24 +204,20 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupMod> {
 
     @PreAuthorize("hasRole('" + Entitlement.GROUP_UPDATE + "')")
     @Override
-    public GroupTO update(final GroupMod groupMod) {
-        GroupTO groupTO = binder.getGroupTO(groupMod.getKey());
-        Pair<GroupMod, List<LogicActions>> before = beforeUpdate(groupMod, groupTO.getRealm());
-
-        Set<String> requestedRealms = new HashSet<>();
-        requestedRealms.add(before.getLeft().getRealm());
-        if (StringUtils.isNotBlank(before.getLeft().getRealm())) {
-            requestedRealms.add(before.getLeft().getRealm());
-        }
-        Set<String> effectiveRealms = getEffectiveRealms(
-                AuthContextUtils.getAuthorizations().get(Entitlement.GROUP_UPDATE),
-                requestedRealms);
-        securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
-        if (StringUtils.isNotBlank(before.getLeft().getRealm())) {
-            securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
+    public GroupTO update(final GroupPatch groupPatch) {
+        GroupTO groupTO = binder.getGroupTO(groupPatch.getKey());
+        Pair<GroupPatch, List<LogicActions>> before = beforeUpdate(groupPatch, groupTO.getRealm());
+
+        if (before.getLeft().getRealm() != null && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())) {
+            Set<String> requestedRealms = new HashSet<>();
+            requestedRealms.add(before.getLeft().getRealm().getValue());
+            Set<String> effectiveRealms = getEffectiveRealms(
+                    AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
+                    requestedRealms);
+            securityChecks(effectiveRealms, before.getLeft().getRealm().getValue(), before.getLeft().getKey());
         }
 
-        Map.Entry<Long, List<PropagationStatus>> updated = provisioningManager.update(groupMod);
+        Map.Entry<Long, List<PropagationStatus>> updated = provisioningManager.update(groupPatch);
 
         GroupTO updatedTO = binder.getGroupTO(updated.getKey());
         updatedTO.getPropagationStatusTOs().addAll(updated.getValue());
@@ -270,11 +268,17 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupMod> {
                 Collections.singleton(group.getRealm()));
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
 
-        GroupMod groupMod = new GroupMod();
-        groupMod.setKey(key);
-        groupMod.getResourcesToRemove().addAll(resources);
+        GroupPatch patch = new GroupPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
 
-        return binder.getGroupTO(provisioningManager.unlink(groupMod));
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.DELETE).value(resource).build();
+            }
+        }));
+
+        return binder.getGroupTO(provisioningManager.unlink(patch));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.GROUP_UPDATE + "')")
@@ -287,11 +291,17 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupMod> {
                 Collections.singleton(group.getRealm()));
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
 
-        GroupMod groupMod = new GroupMod();
-        groupMod.setKey(key);
-        groupMod.getResourcesToAdd().addAll(resources);
+        GroupPatch patch = new GroupPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
 
-        return binder.getGroupTO(provisioningManager.link(groupMod));
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(resource).build();
+            }
+        }));
+
+        return binder.getGroupTO(provisioningManager.link(patch));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.GROUP_UPDATE + "')")
@@ -304,10 +314,17 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupMod> {
                 Collections.singleton(group.getRealm()));
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
 
-        GroupMod groupMod = new GroupMod();
-        groupMod.setKey(key);
-        groupMod.getResourcesToRemove().addAll(resources);
-        return update(groupMod);
+        GroupPatch patch = new GroupPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
+
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.DELETE).value(resource).build();
+            }
+        }));
+
+        return update(patch);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.GROUP_UPDATE + "')")
@@ -325,11 +342,17 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupMod> {
                 Collections.singleton(group.getRealm()));
         securityChecks(effectiveRealms, group.getRealm(), group.getKey());
 
-        GroupMod groupMod = new GroupMod();
-        groupMod.setKey(key);
-        groupMod.getResourcesToAdd().addAll(resources);
+        GroupPatch patch = new GroupPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
+
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(resource).build();
+            }
+        }));
 
-        return update(groupMod);
+        return update(patch);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.GROUP_UPDATE + "')")
@@ -378,8 +401,8 @@ public class GroupLogic extends AbstractAnyLogic<GroupTO, GroupMod> {
                     key = (Long) args[i];
                 } else if (args[i] instanceof GroupTO) {
                     key = ((GroupTO) args[i]).getKey();
-                } else if (args[i] instanceof GroupMod) {
-                    key = ((GroupMod) args[i]).getKey();
+                } else if (args[i] instanceof GroupPatch) {
+                    key = ((GroupPatch) args[i]).getKey();
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
index ce2fb2e..7defb27 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/ResourceLogic.java
@@ -270,20 +270,11 @@ public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
 
     @PreAuthorize("hasRole('" + Entitlement.CONNECTOR_READ + "')")
     @Transactional(readOnly = true)
-    public boolean check(final ResourceTO resourceTO) {
+    public void check(final ResourceTO resourceTO) {
         ConnInstance connInstance = binder.getConnInstance(resourceTO);
         Connector connector = connFactory.createConnector(connInstance, connInstance.getConfiguration());
 
-        boolean result;
-        try {
-            connector.test();
-            result = true;
-        } catch (Exception e) {
-            LOG.error("Test connection failure {}", e);
-            result = false;
-        }
-
-        return result;
+        connector.test();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
index f508b47..116f725 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
@@ -33,13 +33,17 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.mod.StatusMod;
-import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.patch.BooleanReplacePatchItem;
+import org.apache.syncope.common.lib.patch.PasswordPatch;
+import org.apache.syncope.common.lib.patch.StatusPatch;
+import org.apache.syncope.common.lib.patch.StringPatchItem;
+import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.PropagationStatus;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.Entitlement;
+import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -66,7 +70,7 @@ import org.springframework.transaction.annotation.Transactional;
  * Spring's Transactional logic at class level.
  */
 @Component
-public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
+public class UserLogic extends AbstractAnyLogic<UserTO, UserPatch> {
 
     @Autowired
     protected UserDAO userDAO;
@@ -215,35 +219,32 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
     }
 
     @PreAuthorize("isAuthenticated() and not(hasRole('" + Entitlement.ANONYMOUS + "'))")
-    public UserTO selfUpdate(final UserMod userMod) {
+    public UserTO selfUpdate(final UserPatch userPatch) {
         UserTO userTO = binder.getAuthenticatedUserTO();
-        userMod.setKey(userTO.getKey());
-        return doUpdate(userMod, true);
+        userPatch.setKey(userTO.getKey());
+        return doUpdate(userPatch, true);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
     @Override
-    public UserTO update(final UserMod userMod) {
-        return doUpdate(userMod, false);
+    public UserTO update(final UserPatch userPatch) {
+        return doUpdate(userPatch, false);
     }
 
-    protected UserTO doUpdate(final UserMod userMod, final boolean self) {
-        UserTO userTO = binder.getUserTO(userMod.getKey());
-        Pair<UserMod, List<LogicActions>> before = beforeUpdate(userMod, userTO.getRealm());
+    protected UserTO doUpdate(final UserPatch userPatch, final boolean self) {
+        UserTO userTO = binder.getUserTO(userPatch.getKey());
+        Pair<UserPatch, List<LogicActions>> before = beforeUpdate(userPatch, userTO.getRealm());
+
+        if (!self
+                && before.getLeft().getRealm() != null
+                && StringUtils.isNotBlank(before.getLeft().getRealm().getValue())) {
 
-        if (!self) {
             Set<String> requestedRealms = new HashSet<>();
-            requestedRealms.add(before.getLeft().getRealm());
-            if (StringUtils.isNotBlank(before.getLeft().getRealm())) {
-                requestedRealms.add(before.getLeft().getRealm());
-            }
+            requestedRealms.add(before.getLeft().getRealm().getValue());
             Set<String> effectiveRealms = getEffectiveRealms(
                     AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
                     requestedRealms);
-            securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
-            if (StringUtils.isNotBlank(before.getLeft().getRealm())) {
-                securityChecks(effectiveRealms, before.getLeft().getRealm(), before.getLeft().getKey());
-            }
+            securityChecks(effectiveRealms, before.getLeft().getRealm().getValue(), before.getLeft().getKey());
         }
 
         Map.Entry<Long, List<PropagationStatus>> updated = provisioningManager.update(before.getLeft());
@@ -254,21 +255,21 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
         return afterUpdate(updatedTO, before.getRight());
     }
 
-    protected Map.Entry<Long, List<PropagationStatus>> setStatusOnWfAdapter(final StatusMod statusMod) {
+    protected Map.Entry<Long, List<PropagationStatus>> setStatusOnWfAdapter(final StatusPatch statusPatch) {
         Map.Entry<Long, List<PropagationStatus>> updated;
 
-        switch (statusMod.getType()) {
+        switch (statusPatch.getType()) {
             case SUSPEND:
-                updated = provisioningManager.suspend(statusMod);
+                updated = provisioningManager.suspend(statusPatch);
                 break;
 
             case REACTIVATE:
-                updated = provisioningManager.reactivate(statusMod);
+                updated = provisioningManager.reactivate(statusPatch);
                 break;
 
             case ACTIVATE:
             default:
-                updated = provisioningManager.activate(statusMod);
+                updated = provisioningManager.activate(statusPatch);
                 break;
 
         }
@@ -277,25 +278,26 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
-    public UserTO status(final StatusMod statusMod) {
+    public UserTO status(final StatusPatch statusPatch) {
         // security checks
-        UserTO toUpdate = binder.getUserTO(statusMod.getKey());
+        UserTO toUpdate = binder.getUserTO(statusPatch.getKey());
         Set<String> effectiveRealms = getEffectiveRealms(
                 AuthContextUtils.getAuthorizations().get(Entitlement.USER_UPDATE),
                 Collections.singleton(toUpdate.getRealm()));
         securityChecks(effectiveRealms, toUpdate.getRealm(), toUpdate.getKey());
 
-        Map.Entry<Long, List<PropagationStatus>> updated = setStatusOnWfAdapter(statusMod);
+        Map.Entry<Long, List<PropagationStatus>> updated = setStatusOnWfAdapter(statusPatch);
         UserTO savedTO = binder.getUserTO(updated.getKey());
         savedTO.getPropagationStatusTOs().addAll(updated.getValue());
         return savedTO;
     }
 
     @PreAuthorize("hasRole('" + Entitlement.MUST_CHANGE_PASSWORD + "')")
-    public UserTO changePassword(final String password) {
-        UserMod userMod = new UserMod();
-        userMod.setPassword(password);
-        return selfUpdate(userMod);
+    public UserTO changePassword(final String password) { 
+        UserPatch userPatch = new UserPatch();
+        userPatch.setPassword(new PasswordPatch.Builder().value(password).build());
+        userPatch.setMustChangePassword(new BooleanReplacePatchItem.Builder().value(false).build());
+        return selfUpdate(userPatch);
     }
 
     @PreAuthorize("isAnonymous() or hasRole('" + Entitlement.ANONYMOUS + "')")
@@ -389,11 +391,17 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
                 Collections.singleton(user.getRealm()));
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
 
-        UserMod userMod = new UserMod();
-        userMod.setKey(key);
-        userMod.getResourcesToRemove().addAll(resources);
+        UserPatch patch = new UserPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
 
-        return binder.getUserTO(provisioningManager.unlink(userMod));
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.DELETE).value(resource).build();
+            }
+        }));
+
+        return binder.getUserTO(provisioningManager.unlink(patch));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
@@ -406,11 +414,17 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
                 Collections.singleton(user.getRealm()));
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
 
-        UserMod userMod = new UserMod();
-        userMod.setKey(key);
-        userMod.getResourcesToAdd().addAll(resources);
+        UserPatch patch = new UserPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
+
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(resource).build();
+            }
+        }));
 
-        return binder.getUserTO(provisioningManager.link(userMod));
+        return binder.getUserTO(provisioningManager.link(patch));
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
@@ -423,10 +437,17 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
                 Collections.singleton(user.getRealm()));
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
 
-        UserMod userMod = new UserMod();
-        userMod.setKey(key);
-        userMod.getResourcesToRemove().addAll(resources);
-        return update(userMod);
+        UserPatch patch = new UserPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
+
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.DELETE).value(resource).build();
+            }
+        }));
+
+        return update(patch);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
@@ -444,19 +465,22 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
                 Collections.singleton(user.getRealm()));
         securityChecks(effectiveRealms, user.getRealm(), user.getKey());
 
-        UserMod userMod = new UserMod();
-        userMod.setKey(key);
-        userMod.getResourcesToAdd().addAll(resources);
+        UserPatch patch = new UserPatch();
+        patch.setKey(key);
+        patch.getResources().addAll(CollectionUtils.collect(resources, new Transformer<String, StringPatchItem>() {
+
+            @Override
+            public StringPatchItem transform(final String resource) {
+                return new StringPatchItem.Builder().operation(PatchOperation.ADD_REPLACE).value(resource).build();
+            }
+        }));
 
         if (changepwd) {
-            StatusMod statusMod = new StatusMod();
-            statusMod.setOnSyncope(false);
-            statusMod.getResources().addAll(resources);
-            userMod.setPwdPropRequest(statusMod);
-            userMod.setPassword(password);
+            patch.setPassword(new PasswordPatch.Builder().
+                    value(password).onSyncope(false).resources(resources).build());
         }
 
-        return update(userMod);
+        return update(patch);
     }
 
     @PreAuthorize("hasRole('" + Entitlement.USER_UPDATE + "')")
@@ -507,8 +531,8 @@ public class UserLogic extends AbstractAnyLogic<UserTO, UserMod> {
                     key = (String) args[i];
                 } else if (args[i] instanceof UserTO) {
                     key = ((UserTO) args[i]).getKey();
-                } else if (args[i] instanceof UserMod) {
-                    key = ((UserMod) args[i]).getKey();
+                } else if (args[i] instanceof UserPatch) {
+                    key = ((UserPatch) args[i]).getKey();
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java
index 51d8b45..9e0b45b 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java
@@ -22,8 +22,8 @@ import java.lang.reflect.Method;
 import java.util.List;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.mod.AnyMod;
-import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.patch.AnyPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.types.Entitlement;
@@ -68,12 +68,12 @@ public class UserWorkflowLogic extends AbstractTransactionalLogic<WorkflowFormTO
     public UserTO executeWorkflowTask(final UserTO userTO, final String taskId) {
         WorkflowResult<Long> updated = uwfAdapter.execute(userTO, taskId);
 
-        UserMod userMod = new UserMod();
-        userMod.setKey(userTO.getKey());
+        UserPatch userPatch = new UserPatch();
+        userPatch.setKey(userTO.getKey());
 
         List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
-                new WorkflowResult<Pair<UserMod, Boolean>>(
-                        new ImmutablePair<UserMod, Boolean>(userMod, null),
+                new WorkflowResult<Pair<UserPatch, Boolean>>(
+                        new ImmutablePair<UserPatch, Boolean>(userPatch, null),
                         updated.getPropByRes(), updated.getPerformedTasks()));
 
         taskExecutor.execute(tasks);
@@ -104,16 +104,16 @@ public class UserWorkflowLogic extends AbstractTransactionalLogic<WorkflowFormTO
     @PreAuthorize("hasRole('" + Entitlement.WORKFLOW_FORM_SUBMIT + "')")
     @Transactional(rollbackFor = { Throwable.class })
     public UserTO submitForm(final WorkflowFormTO form) {
-        WorkflowResult<? extends AnyMod> updated = uwfAdapter.submitForm(form);
+        WorkflowResult<? extends AnyPatch> updated = uwfAdapter.submitForm(form);
 
         // propByRes can be made empty by the workflow definition if no propagation should occur 
         // (for example, with rejected users)
-        if (updated.getResult() instanceof UserMod
+        if (updated.getResult() instanceof UserPatch
                 && updated.getPropByRes() != null && !updated.getPropByRes().isEmpty()) {
 
             List<PropagationTask> tasks = propagationManager.getUserUpdateTasks(
-                    new WorkflowResult<Pair<UserMod, Boolean>>(
-                            new ImmutablePair<>((UserMod) updated.getResult(), Boolean.TRUE),
+                    new WorkflowResult<Pair<UserPatch, Boolean>>(
+                            new ImmutablePair<>((UserPatch) updated.getResult(), Boolean.TRUE),
                             updated.getPropByRes(),
                             updated.getPerformedTasks()));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java b/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java
index 91715a7..c11ca05 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/report/UserReportlet.java
@@ -285,11 +285,7 @@ public class UserReportlet extends AbstractReportlet {
                     handler.startElement("", "", "relationship", atts);
 
                     if (conf.getFeatures().contains(Feature.resources)) {
-                        URelationship actualRel = user.getRelationship(rel.getRightKey());
-                        if (actualRel == null) {
-                            LOG.warn("Unexpected: cannot find relationship for any object {} for user {}",
-                                    rel.getRightKey(), user);
-                        } else {
+                        for (URelationship actualRel : user.getRelationships(rel.getRightKey())) {
                             doExtractResources(
                                     handler, anyObjectDataBinder.getAnyObjectTO(actualRel.getRightEnd(), true));
                         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
index 02c6e62..7c39bb7 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
@@ -28,7 +28,7 @@ import java.util.List;
 import java.util.Map;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.AnyOperations;
-import org.apache.syncope.common.lib.mod.AnyMod;
+import org.apache.syncope.common.lib.patch.AnyPatch;
 import org.apache.syncope.common.lib.policy.PasswordRuleConf;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
@@ -144,7 +144,7 @@ public class ConnObjectUtils {
     }
 
     /**
-     * Build an UserMod out of connector object attributes and schema mapping.
+     * Build {@link AnyPatch} out of connector object attributes and schema mapping.
      *
      * @param key any object to be updated
      * @param obj connector object
@@ -157,7 +157,7 @@ public class ConnObjectUtils {
      */
     @SuppressWarnings("unchecked")
     @Transactional(readOnly = true)
-    public <T extends AnyMod> T getAnyMod(final Long key, final ConnectorObject obj,
+    public <T extends AnyPatch> T getAnyPatch(final Long key, final ConnectorObject obj,
             final AnyTO original, final SyncTask syncTask, final Provision provision, final AnyUtils anyUtils) {
 
         AnyTO updated = getAnyTOFromConnObject(obj, syncTask, provision, anyUtils);

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
index 3e7a802..2f0a0c5 100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
@@ -33,7 +33,7 @@ import org.apache.commons.jexl2.MapContext;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
-import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
 import org.apache.syncope.common.lib.types.IntMappingType;
 import org.apache.syncope.common.lib.types.MappingPurpose;
@@ -122,8 +122,7 @@ public final class MappingUtils {
      * @param any given any object
      * @param password clear-text password
      * @param changePwd whether password should be included for propagation attributes or not
-     * @param vAttrsToBeRemoved virtual attributes to be removed
-     * @param vAttrsToBeUpdated virtual attributes to be added
+     * @param vAttrs virtual attributes to be managed
      * @param enable whether any object must be enabled or not
      * @param provision provision information
      * @return connObjectLink + prepared attributes
@@ -132,8 +131,7 @@ public final class MappingUtils {
             final Any<?, ?, ?> any,
             final String password,
             final boolean changePwd,
-            final Set<String> vAttrsToBeRemoved,
-            final Map<String, AttrMod> vAttrsToBeUpdated,
+            final Map<String, AttrPatch> vAttrs,
             final Boolean enable,
             final Provision provision) {
 
@@ -160,7 +158,7 @@ public final class MappingUtils {
                 }
 
                 Pair<String, Attribute> preparedAttr = prepareAttr(
-                        provision, mapping, any, password, passwordGenerator, vAttrsToBeRemoved, vAttrsToBeUpdated);
+                        provision, mapping, any, password, passwordGenerator, vAttrs);
 
                 if (preparedAttr != null && preparedAttr.getKey() != null) {
                     connObjectKey = preparedAttr.getKey();
@@ -214,15 +212,14 @@ public final class MappingUtils {
      * @param any any object
      * @param password clear-text password
      * @param passwordGenerator password generator
-     * @param vAttrsToBeRemoved virtual attributes to be removed
-     * @param vAttrsToBeUpdated virtual attributes to be added
+     * @param vAttrs virtual attributes to be managed
      * @return connObjectLink + prepared attribute
      */
     @SuppressWarnings("unchecked")
     private static Pair<String, Attribute> prepareAttr(
             final Provision provision, final MappingItem mapItem,
             final Any<?, ?, ?> any, final String password, final PasswordGenerator passwordGenerator,
-            final Set<String> vAttrsToBeRemoved, final Map<String, AttrMod> vAttrsToBeUpdated) {
+            final Map<String, AttrPatch> vAttrs) {
 
         List<Any<?, ?, ?>> anys = new ArrayList<>();
 
@@ -258,8 +255,7 @@ public final class MappingUtils {
             default:
         }
 
-        List<PlainAttrValue> values = getIntValues(
-                provision, mapItem, anys, vAttrsToBeRemoved, vAttrsToBeUpdated);
+        List<PlainAttrValue> values = getIntValues(provision, mapItem, anys, vAttrs);
 
         Schema schema = null;
         boolean readOnlyVirSchema = false;
@@ -409,7 +405,7 @@ public final class MappingUtils {
 
     private static String getGroupOwnerValue(final Provision provision, final Any<?, ?, ?> any) {
         Pair<String, Attribute> preparedAttr = prepareAttr(provision, getConnObjectKeyItem(provision),
-                any, null, null, Collections.<String>emptySet(), Collections.<String, AttrMod>emptyMap());
+                any, null, null, Collections.<String, AttrPatch>emptyMap());
         String connObjectKey = preparedAttr.getKey();
 
         final Name groupOwnerName = evaluateNAME(any, provision, connObjectKey);
@@ -422,13 +418,11 @@ public final class MappingUtils {
      * @param provision provision information
      * @param mappingItem mapping item
      * @param anys any objects
-     * @param vAttrsToBeRemoved virtual attributes to be removed
-     * @param vAttrsToBeUpdated virtual attributes to be added
+     * @param vAttrs virtual attributes to be managed
      * @return attribute values.
      */
     public static List<PlainAttrValue> getIntValues(final Provision provision,
-            final MappingItem mappingItem, final List<Any<?, ?, ?>> anys,
-            final Set<String> vAttrsToBeRemoved, final Map<String, AttrMod> vAttrsToBeUpdated) {
+            final MappingItem mappingItem, final List<Any<?, ?, ?>> anys, final Map<String, AttrPatch> vAttrs) {
 
         LOG.debug("Get attributes for '{}' and mapping type '{}'", anys, mappingItem.getIntMappingType());
 
@@ -468,13 +462,11 @@ public final class MappingUtils {
                     AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
                     VirAttr<?> virAttr = any.getVirAttr(mappingItem.getIntAttrName());
                     if (virAttr != null) {
-                        if (vAttrsToBeRemoved != null && vAttrsToBeUpdated != null) {
-                            if (vAttrsToBeUpdated.containsKey(mappingItem.getIntAttrName())) {
+                        if (vAttrs != null) {
+                            if (vAttrs.containsKey(mappingItem.getIntAttrName())) {
                                 virAttr.getValues().clear();
                                 virAttr.getValues().addAll(
-                                        vAttrsToBeUpdated.get(mappingItem.getIntAttrName()).getValuesToBeAdded());
-                            } else if (vAttrsToBeRemoved.contains(mappingItem.getIntAttrName())) {
-                                virAttr.getValues().clear();
+                                        vAttrs.get(mappingItem.getIntAttrName()).getAttrTO().getValues());
                             } else {
                                 throw new IllegalArgumentException("Don't need to update virtual attribute '"
                                         + mappingItem.getIntAttrName() + "'");
@@ -595,7 +587,7 @@ public final class MappingUtils {
      */
     public static String getConnObjectKeyValue(final Any<?, ?, ?> any, final Provision provision) {
         List<PlainAttrValue> values = getIntValues(provision, provision.getMapping().getConnObjectKeyItem(),
-                Collections.<Any<?, ?, ?>>singletonList(any), null, null);
+                Collections.<Any<?, ?, ?>>singletonList(any), null);
         return values == null || values.isEmpty()
                 ? null
                 : values.get(0).getValueAsString();

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
index ffb61a3..2094269 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.persistence.api.entity.anyobject;
 
+import java.util.Collection;
 import java.util.List;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.RelationshipType;
@@ -28,9 +29,11 @@ public interface AnyObject extends Any<APlainAttr, ADerAttr, AVirAttr> {
 
     boolean remove(ARelationship relationship);
 
-    ARelationship getRelationship(RelationshipType relationshipType);
+    ARelationship getRelationship(RelationshipType relationshipType, Long anyObjectKey);
 
-    ARelationship getRelationship(Long relationshipKey);
+    Collection<? extends ARelationship> getRelationships(Long anyObjectKey);
+
+    Collection<? extends ARelationship> getRelationships(RelationshipType relationshipType);
 
     List<? extends ARelationship> getRelationships();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/9f73fa43/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
index f3da581..884e849 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.persistence.api.entity.user;
 
+import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
@@ -137,9 +138,11 @@ public interface User extends Any<UPlainAttr, UDerAttr, UVirAttr> {
 
     boolean remove(URelationship relationship);
 
-    URelationship getRelationship(Long anyObjectKey);
+    URelationship getRelationship(RelationshipType relationshipType, Long anyObjectKey);
 
-    URelationship getRelationship(RelationshipType relationshipType);
+    Collection<? extends URelationship> getRelationships(Long anyObjectKey);
+
+    Collection<? extends URelationship> getRelationships(RelationshipType relationshipType);
 
     List<? extends URelationship> getRelationships();
 


Mime
View raw message