You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/01/08 14:17:33 UTC

[13/13] syncope git commit: [SYNCOPE-620] server logic in, tests missing

[SYNCOPE-620] server logic in, tests missing


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

Branch: refs/heads/2_0_X
Commit: 99369c3115b9feec77bebff5fbbb2813d72aedf5
Parents: fc8761c
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Jan 8 14:16:57 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Jan 8 14:16:57 2015 +0100

----------------------------------------------------------------------
 .../core/rest/controller/RoleController.java    |  12 +-
 syncope620/common/lib/pom.xml                   |  10 +
 .../syncope/common/lib/AbstractBaseBean.java    |   7 +-
 .../common/lib/AttributableOperations.java      | 508 ++++++++++
 .../lib/SyncopeClientCompositeException.java    |  96 ++
 .../common/lib/SyncopeClientException.java      |  97 ++
 .../common/lib/mod/AbstractAttributableMod.java |  18 +-
 .../syncope/common/lib/mod/MembershipMod.java   |  46 +
 .../syncope/common/lib/mod/ReferenceMod.java    |  53 ++
 .../common/lib/mod/ResourceAssociationMod.java  |  80 ++
 .../apache/syncope/common/lib/mod/RoleMod.java  | 300 ++++++
 .../syncope/common/lib/mod/StatusMod.java       | 108 +++
 .../apache/syncope/common/lib/mod/UserMod.java  | 123 +++
 .../syncope/common/lib/mod/package-info.java    |  23 +
 .../common/lib/report/RoleReportletConf.java    |   2 +-
 .../common/lib/report/UserReportletConf.java    |   2 +-
 .../common/lib/search/OrderByClauseBuilder.java |  45 +
 .../search/RoleFiqlSearchConditionBuilder.java  |  90 ++
 .../syncope/common/lib/search/RoleProperty.java |  29 +
 .../common/lib/search/SearchableFields.java     |  67 ++
 .../syncope/common/lib/search/SpecialAttr.java  |  50 +
 .../SyncopeFiqlSearchConditionBuilder.java      | 110 +++
 .../common/lib/search/SyncopeProperty.java      |  37 +
 .../search/UserFiqlSearchConditionBuilder.java  |  95 ++
 .../syncope/common/lib/search/UserProperty.java |  29 +
 .../common/lib/to/AbstractAttributableTO.java   |  10 +-
 .../syncope/common/lib/to/AbstractExecTO.java   |  87 ++
 .../syncope/common/lib/to/AbstractPolicyTO.java |  89 ++
 .../lib/to/AbstractProvisioningTaskTO.java      | 117 +++
 .../syncope/common/lib/to/AbstractSchemaTO.java |  44 +
 .../syncope/common/lib/to/AbstractTaskTO.java   |  98 ++
 .../syncope/common/lib/to/AccountPolicyTO.java  |  68 ++
 .../syncope/common/lib/to/BulkAction.java       |  70 ++
 .../syncope/common/lib/to/BulkActionResult.java | 134 +++
 .../apache/syncope/common/lib/to/ConfTO.java    |  30 +
 .../syncope/common/lib/to/ConnBundleTO.java     |  95 ++
 .../syncope/common/lib/to/ConnInstanceTO.java   | 177 ++++
 .../syncope/common/lib/to/DerSchemaTO.java      |  39 +
 .../apache/syncope/common/lib/to/ErrorTO.java   |  66 ++
 .../syncope/common/lib/to/EventCategoryTO.java  |  89 ++
 .../apache/syncope/common/lib/to/LoggerTO.java  |  51 ++
 .../syncope/common/lib/to/MappingItemTO.java    | 134 +++
 .../apache/syncope/common/lib/to/MappingTO.java | 120 +++
 .../syncope/common/lib/to/NotificationTO.java   | 175 ++++
 .../common/lib/to/NotificationTaskTO.java       | 105 +++
 .../syncope/common/lib/to/PagedResult.java      |  98 ++
 .../syncope/common/lib/to/PasswordPolicyTO.java |  54 ++
 .../syncope/common/lib/to/PlainSchemaTO.java    | 156 ++++
 .../common/lib/to/PropagationTaskTO.java        | 123 +++
 .../syncope/common/lib/to/PushTaskTO.java       |  49 +
 .../syncope/common/lib/to/ReportExecTO.java     |  40 +
 .../apache/syncope/common/lib/to/ReportTO.java  | 151 +++
 .../syncope/common/lib/to/ResourceTO.java       | 270 ++++++
 .../apache/syncope/common/lib/to/RoleTO.java    |   2 +-
 .../syncope/common/lib/to/SchedTaskTO.java      | 101 ++
 .../common/lib/to/SecurityQuestionTO.java       |  51 ++
 .../syncope/common/lib/to/SyncPolicyTO.java     |  54 ++
 .../syncope/common/lib/to/SyncTaskTO.java       |  59 ++
 .../syncope/common/lib/to/TaskExecTO.java       |  39 +
 .../syncope/common/lib/to/VirSchemaTO.java      |  38 +
 .../common/lib/to/WorkflowFormPropertyTO.java   | 119 +++
 .../syncope/common/lib/to/WorkflowFormTO.java   | 162 ++++
 .../syncope/common/lib/to/package-info.java     |  23 +
 .../syncope/common/lib/types/AuditElements.java |  61 ++
 .../common/lib/types/AuditLoggerName.java       | 222 +++++
 .../common/lib/types/ClientExceptionType.java   | 107 +++
 .../syncope/common/lib/types/PolicyType.java    |   4 +
 .../lib/types/ReportExecExportFormat.java       |  32 +
 .../syncope/common/lib/types/SchemaType.java    |  68 ++
 .../lib/types/WorkflowFormPropertyType.java     |  32 +
 .../syncope/common/lib/types/WorkflowTasks.java |  47 +
 .../common/lib/wrap/AbstractWrappable.java      |  46 +
 .../common/lib/wrap/CorrelationRuleClass.java   |  30 +
 .../syncope/common/lib/wrap/EntitlementTO.java  |  30 +
 .../syncope/common/lib/wrap/JobClass.java       |  30 +
 .../syncope/common/lib/wrap/MailTemplate.java   |  30 +
 .../common/lib/wrap/PropagationActionClass.java |  30 +
 .../common/lib/wrap/PushActionClass.java        |  30 +
 .../common/lib/wrap/ReportletConfClass.java     |  30 +
 .../syncope/common/lib/wrap/ResourceName.java   |  30 +
 .../syncope/common/lib/wrap/SubjectId.java      |  25 +
 .../common/lib/wrap/SyncActionClass.java        |  30 +
 .../syncope/common/lib/wrap/Validator.java      |  30 +
 .../syncope/common/lib/wrap/package-info.java   |  23 +
 syncope620/pom.xml                              | 146 ++-
 syncope620/server/logic/pom.xml                 | 127 +++
 .../syncope/server/logic/AbstractLogic.java     |  58 ++
 .../logic/AbstractResourceAssociator.java       |  37 +
 .../server/logic/AbstractSubjectLogic.java      |  43 +
 .../logic/AbstractTransactionalLogic.java       |  31 +
 .../server/logic/ConfigurationLogic.java        | 157 ++++
 .../syncope/server/logic/ConnectorLogic.java    | 341 +++++++
 .../syncope/server/logic/EntitlementLogic.java  |  58 ++
 .../syncope/server/logic/LoggerLogic.java       | 307 +++++++
 .../server/logic/LogicInvocationHandler.java    | 108 +++
 .../server/logic/NotificationController.java    | 127 +++
 .../syncope/server/logic/PolicyController.java  | 197 ++++
 .../syncope/server/logic/ReportLogic.java       | 348 +++++++
 .../syncope/server/logic/ResourceLogic.java     | 301 ++++++
 .../apache/syncope/server/logic/RoleLogic.java  | 405 ++++++++
 .../syncope/server/logic/SchemaLogic.java       | 328 +++++++
 .../server/logic/SecurityQuestionLogic.java     | 150 +++
 .../apache/syncope/server/logic/TaskLogic.java  | 408 +++++++++
 .../logic/UnresolvedReferenceException.java     |  35 +
 .../apache/syncope/server/logic/UserLogic.java  | 534 +++++++++++
 .../syncope/server/logic/UserWorkflowLogic.java | 131 +++
 .../syncope/server/logic/WorkflowLogic.java     | 115 +++
 .../logic/audit/AuditConnectionFactory.java     | 159 ++++
 .../server/logic/audit/AuditManager.java        | 107 +++
 .../data/AbstractAttributableDataBinder.java    | 918 +++++++++++++++++++
 .../logic/data/ConfigurationDataBinder.java     |  75 ++
 .../logic/data/ConnInstanceDataBinder.java      | 246 +++++
 .../logic/data/NotificationDataBinder.java      |  62 ++
 .../server/logic/data/PolicyDataBinder.java     | 186 ++++
 .../server/logic/data/ReportDataBinder.java     | 175 ++++
 .../server/logic/data/ResourceDataBinder.java   | 389 ++++++++
 .../server/logic/data/RoleDataBinder.java       | 429 +++++++++
 .../server/logic/data/SchemaDataBinder.java     | 163 ++++
 .../logic/data/SecurityQuestionDataBinder.java  |  51 ++
 .../server/logic/data/TaskDataBinder.java       | 338 +++++++
 .../server/logic/data/UserDataBinder.java       | 479 ++++++++++
 .../init/ImplementationClassNamesLoader.java    | 141 +++
 .../server/logic/init/JobInstanceLoader.java    | 287 ++++++
 .../logic/init/WorkflowAdapterLoader.java       |  88 ++
 .../logic/notification/NotificationJob.java     | 280 ++++++
 .../logic/notification/NotificationManager.java | 441 +++++++++
 .../server/logic/report/AbstractReportlet.java  |  66 ++
 .../server/logic/report/ReportException.java    |  32 +
 .../syncope/server/logic/report/ReportJob.java  | 206 +++++
 .../server/logic/report/ReportXMLConst.java     |  44 +
 .../syncope/server/logic/report/Reportlet.java  |  47 +
 .../server/logic/report/ReportletConfClass.java |  32 +
 .../server/logic/report/RoleReportlet.java      | 327 +++++++
 .../server/logic/report/StaticReportlet.java    | 120 +++
 .../server/logic/report/TextSerializer.java     | 101 ++
 .../server/logic/report/UserReportlet.java      | 359 ++++++++
 .../logic/search/SearchCondConverter.java       |  50 +
 .../server/logic/search/SearchCondVisitor.java  | 203 ++++
 .../persistence/api/dao/DuplicateException.java |  35 +
 .../syncope/persistence/api/dao/RoleDAO.java    |   2 +
 .../syncope/persistence/api/dao/UserDAO.java    |   3 +
 .../api/entity/AttributableUtil.java            |   5 +
 .../api/entity/AttributableUtilFactory.java     |  33 +
 .../syncope/persistence/api/entity/Entity.java  |   4 +-
 .../persistence/api/entity/EntityFactory.java   |   2 +
 .../api/entity/ExternalResource.java            |   2 +-
 .../persistence/api/entity/role/Role.java       |   4 +-
 .../persistence/api/entity/task/TaskUtil.java   |  36 +
 .../api/entity/task/TaskUtilFactory.java        |  33 +
 syncope620/server/persistence-jpa/pom.xml       |   2 +-
 .../persistence/jpa/dao/AbstractSubjectDAO.java |  10 +-
 .../syncope/persistence/jpa/dao/JPAConfDAO.java |   7 +-
 .../syncope/persistence/jpa/dao/JPARoleDAO.java |  36 +-
 .../jpa/dao/JPASubjectSearchDAO.java            |  13 +-
 .../syncope/persistence/jpa/dao/JPAUserDAO.java |  69 +-
 .../persistence/jpa/entity/AbstractEntity.java  |   5 +-
 .../jpa/entity/JPAAttributableUtil.java         | 103 +--
 .../jpa/entity/JPAEntityFactory.java            |   9 +-
 .../persistence/jpa/entity/JPAPushPolicy.java   |   2 +-
 .../jpa/entity/JPASecurityQuestion.java         |   2 +-
 .../jpa/entity/JPAttributableUtilFactory.java   |  85 ++
 .../jpa/entity/conf/JPACPlainAttr.java          |   2 +-
 .../entity/conf/JPACPlainAttrUniqueValue.java   |   2 +-
 .../jpa/entity/conf/JPACPlainAttrValue.java     |   2 +-
 .../persistence/jpa/entity/conf/JPAConf.java    |   2 +-
 .../entity/membership/JPAMDerAttrTemplate.java  |   2 +-
 .../membership/JPAMPlainAttrTemplate.java       |   2 +-
 .../entity/membership/JPAMVirAttrTemplate.java  |   2 +-
 .../jpa/entity/role/JPARDerAttrTemplate.java    |   2 +-
 .../jpa/entity/role/JPARPlainAttrTemplate.java  |   2 +-
 .../jpa/entity/role/JPARVirAttrTemplate.java    |   2 +-
 .../persistence/jpa/entity/role/JPARole.java    |  16 +-
 .../jpa/entity/task/JPASchedTask.java           |   2 +-
 .../jpa/entity/task/JPATaskUtil.java            | 132 +++
 .../jpa/entity/task/JPATaskUtilFactory.java     |  91 ++
 .../persistence/jpa/entity/user/JPAUser.java    |   8 +-
 .../entity/ConnInstanceValidator.java           |   2 +-
 .../syncope/persistence/jpa/AbstractTest.java   |   4 +
 .../persistence/jpa/entity/AttrTest.java        |  14 +-
 .../persistence/jpa/entity/ConfTest.java        |   4 +-
 .../persistence/jpa/entity/DerSchemaTest.java   |   4 +-
 .../persistence/jpa/entity/PlainSchemaTest.java |   2 +-
 .../persistence/jpa/entity/VirSchemaTest.java   |   4 +-
 .../persistence/jpa/relationship/AttrTest.java  |   3 +-
 .../jpa/relationship/DerSchemaTest.java         |   3 +-
 .../jpa/relationship/PlainSchemaTest.java       |   7 +-
 .../jpa/relationship/SecurityQuestionTest.java  |   3 +
 .../src/test/resources/content.xml              |  26 +-
 .../src/test/resources/persistenceTestEnv.xml   |   5 +
 syncope620/server/pom.xml                       |   5 +-
 .../api/AttributableTransformer.java            |  33 +
 .../provisioning/api/ConnIdBundleManager.java   | 284 ++++++
 .../provisioning/api/ProvisioningManager.java   |  42 +
 .../api/RoleProvisioningManager.java            |  37 +
 .../syncope/provisioning/api/URIUtil.java       |  61 ++
 .../api/UserProvisioningManager.java            |  57 ++
 .../provisioning/api/WorkflowResult.java        |  87 ++
 .../provisioning/api/cache/VirAttrCache.java    |  65 ++
 .../provisioning/api/cache/VirAttrCacheKey.java |  79 ++
 .../api/cache/VirAttrCacheValue.java            |  86 ++
 .../api/propagation/PropagationByResource.java  | 365 ++++++++
 .../api/propagation/PropagationException.java   |  51 ++
 .../api/propagation/PropagationManager.java     | 248 +++++
 .../api/propagation/PropagationReporter.java    |  58 ++
 .../propagation/PropagationTaskExecutor.java    |  77 ++
 .../api/sync/SyncCorrelationRule.java           |  36 +
 syncope620/server/provisioning-common/pom.xml   |  44 +
 .../common/cache/DisabledVirAttrCache.java      |  52 ++
 .../common/cache/MemoryVirAttrCache.java        | 151 +++
 .../server/security/SecureRandomUtil.java       |  44 -
 .../security/UnauthorizedRoleException.java     |  42 +
 syncope620/server/utils/pom.xml                 |  17 +-
 .../syncope/server/utils/ConnObjectUtil.java    | 764 +++++++++++++++
 .../syncope/server/utils/ExceptionUtil.java     |  47 +
 .../InvalidPasswordPolicySpecException.java     |  37 +
 .../syncope/server/utils/MappingUtil.java       | 736 +++++++++++++++
 .../syncope/server/utils/PasswordGenerator.java | 320 +++++++
 .../syncope/server/utils/SecureRandomUtil.java  |  48 +
 .../apache/syncope/server/utils/URIUtil.java    |  61 --
 .../serialization/UnwrappedObjectMapper.java    |  95 ++
 syncope620/server/workflow-api/pom.xml          |  44 +
 .../workflow/api/RoleWorkflowAdapter.java       |  71 ++
 .../workflow/api/UserWorkflowAdapter.java       | 151 +++
 .../server/workflow/api/WorkflowAdapter.java    | 111 +++
 .../workflow/api/WorkflowDefinitionFormat.java  |  29 +
 .../server/workflow/api/WorkflowException.java  |  51 ++
 .../workflow/api/WorkflowInstanceLoader.java    |  28 +
 .../server/workflow/api/package-info.java       |  19 +
 228 files changed, 22689 insertions(+), 280 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java b/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
index 3a0f9d6..9b1220e 100644
--- a/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
+++ b/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
@@ -18,13 +18,10 @@
  */
 package org.apache.syncope.core.rest.controller;
 
-import static org.apache.syncope.core.rest.controller.AbstractController.LOG;
-
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -36,12 +33,10 @@ import org.apache.syncope.common.to.RoleTO;
 import org.apache.syncope.common.types.ClientExceptionType;
 import org.apache.syncope.common.SyncopeClientException;
 import org.apache.syncope.common.to.PropagationStatus;
-import org.apache.syncope.core.provisioning.ProvisioningManager;
 import org.apache.syncope.core.provisioning.RoleProvisioningManager;
 import org.apache.syncope.common.reqres.BulkAction;
 import org.apache.syncope.common.reqres.BulkActionResult;
 import org.apache.syncope.common.types.SubjectType;
-import org.apache.syncope.core.persistence.beans.PropagationTask;
 import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.persistence.dao.SubjectSearchDAO;
@@ -49,13 +44,10 @@ import org.apache.syncope.core.persistence.dao.NotFoundException;
 import org.apache.syncope.core.persistence.dao.RoleDAO;
 import org.apache.syncope.core.persistence.dao.UserDAO;
 import org.apache.syncope.core.persistence.dao.search.OrderByClause;
-import org.apache.syncope.core.propagation.PropagationException;
-import org.apache.syncope.core.propagation.PropagationReporter;
 import org.apache.syncope.core.propagation.PropagationTaskExecutor;
 import org.apache.syncope.core.propagation.impl.PropagationManager;
 import org.apache.syncope.core.rest.data.AttributableTransformer;
 import org.apache.syncope.core.rest.data.RoleDataBinder;
-import org.apache.syncope.core.util.ApplicationContextProvider;
 import org.apache.syncope.core.util.EntitlementUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -94,9 +86,9 @@ public class RoleController extends AbstractSubjectController<RoleTO, RoleMod> {
     protected AttributableTransformer attrTransformer;
 
     @Resource(name = "anonymousUser")
-    private String anonymousUser;
+    protected String anonymousUser;
 
-    @Resource(name = "roleProvisioningManager")
+    @Autowired
     protected RoleProvisioningManager provisioningManager;
 
     @PreAuthorize("hasAnyRole('ROLE_READ', T(org.apache.syncope.common.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/pom.xml b/syncope620/common/lib/pom.xml
index d52f136..ad51d98 100644
--- a/syncope620/common/lib/pom.xml
+++ b/syncope620/common/lib/pom.xml
@@ -35,6 +35,16 @@ under the License.
 
   <dependencies>
     <dependency>
+      <groupId>javax.ws.rs</groupId>
+      <artifactId>javax.ws.rs-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-rt-rs-extension-search</artifactId>
+    </dependency>
+
+    <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-annotations</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java
index 28bd4bd..8a6d9c4 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java
@@ -19,15 +19,20 @@
 package org.apache.syncope.common.lib;
 
 import java.io.Serializable;
+import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.ReportTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
 
 @XmlType
 // Reporting here only classes used via PagedResult
-//@XmlSeeAlso({ AbstractTaskTO.class, ReportTO.class, RoleTO.class, UserTO.class })
+@XmlSeeAlso({ AbstractTaskTO.class, ReportTO.class, RoleTO.class, UserTO.class })
 public abstract class AbstractBaseBean implements Serializable {
 
     private static final long serialVersionUID = 3119542005279892164L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
new file mode 100644
index 0000000..983cee4
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
@@ -0,0 +1,508 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
+import org.apache.syncope.common.lib.mod.AbstractSubjectMod;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.mod.MembershipMod;
+import org.apache.syncope.common.lib.mod.ReferenceMod;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+
+/**
+ * Utility class for manipulating classes extending AbstractAttributableTO and AbstractAttributableMod.
+ *
+ * @see AbstractAttributableTO
+ * @see AbstractAttributableMod
+ */
+public final class AttributableOperations {
+
+    private AttributableOperations() {
+        // empty constructor for static utility classes
+    }
+
+    private static void populate(final Map<String, AttrTO> updatedAttrs,
+            final Map<String, AttrTO> originalAttrs, final AbstractAttributableMod result) {
+
+        populate(updatedAttrs, originalAttrs, result, false);
+    }
+
+    private static void populate(final Map<String, AttrTO> updatedAttrs,
+            final Map<String, AttrTO> originalAttrs, final AbstractAttributableMod result,
+            final boolean virtuals) {
+
+        for (Map.Entry<String, AttrTO> entry : updatedAttrs.entrySet()) {
+            AttrMod mod = new AttrMod();
+            mod.setSchema(entry.getKey());
+
+            Set<String> updatedValues = new HashSet<String>(entry.getValue().getValues());
+
+            Set<String> originalValues = originalAttrs.containsKey(entry.getKey())
+                    ? new HashSet<String>(originalAttrs.get(entry.getKey()).getValues())
+                    : Collections.<String>emptySet();
+
+            if (!originalAttrs.containsKey(entry.getKey())) {
+                // SYNCOPE-459: take care of user virtual attributes without any value
+                updatedValues.remove("");
+                mod.getValuesToBeAdded().addAll(new ArrayList<String>(updatedValues));
+
+                if (virtuals) {
+                    result.getVirAttrsToUpdate().add(mod);
+                } else {
+                    result.getAttrsToUpdate().add(mod);
+                }
+            } else if (!updatedValues.equals(originalValues)) {
+                // avoid unwanted inputs
+                updatedValues.remove("");
+                if (!entry.getValue().isReadonly()) {
+                    mod.getValuesToBeAdded().addAll(updatedValues);
+
+                    if (!mod.isEmpty()) {
+                        if (virtuals) {
+                            result.getVirAttrsToRemove().add(mod.getSchema());
+                        } else {
+                            result.getAttrsToRemove().add(mod.getSchema());
+                        }
+                    }
+                }
+
+                mod.getValuesToBeRemoved().addAll(originalValues);
+
+                if (!mod.isEmpty()) {
+                    if (virtuals) {
+                        result.getVirAttrsToUpdate().add(mod);
+                    } else {
+                        result.getAttrsToUpdate().add(mod);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void diff(
+            final AbstractAttributableTO updated,
+            final AbstractAttributableTO original,
+            final AbstractAttributableMod result,
+            final boolean incremental) {
+
+        // 1. check same id
+        if (updated.getKey() != original.getKey()) {
+            throw new IllegalArgumentException("AttributableTO's id must be the same");
+        }
+        result.setKey(updated.getKey());
+
+        // 2. attributes
+        Map<String, AttrTO> updatedAttrs = new HashMap<>(updated.getAttrMap());
+        Map<String, AttrTO> originalAttrs = new HashMap<>(original.getAttrMap());
+
+        Set<String> originalAttrNames = new HashSet<>(originalAttrs.keySet());
+        originalAttrNames.removeAll(updatedAttrs.keySet());
+
+        if (!incremental) {
+            result.getAttrsToRemove().clear();
+            result.getAttrsToRemove().addAll(originalAttrNames);
+        }
+
+        Set<String> emptyUpdatedAttrs = new HashSet<>();
+        for (Map.Entry<String, AttrTO> entry : updatedAttrs.entrySet()) {
+            if (entry.getValue().getValues() == null || entry.getValue().getValues().isEmpty()) {
+
+                emptyUpdatedAttrs.add(entry.getKey());
+            }
+        }
+        for (String emptyUpdatedAttr : emptyUpdatedAttrs) {
+            updatedAttrs.remove(emptyUpdatedAttr);
+            result.getAttrsToRemove().add(emptyUpdatedAttr);
+        }
+
+        populate(updatedAttrs, originalAttrs, result);
+
+        // 3. derived attributes
+        updatedAttrs = updated.getDerAttrMap();
+        originalAttrs = original.getDerAttrMap();
+
+        originalAttrNames = new HashSet<>(originalAttrs.keySet());
+        originalAttrNames.removeAll(updatedAttrs.keySet());
+
+        if (!incremental) {
+            result.getDerAttrsToRemove().clear();
+            result.getDerAttrsToRemove().addAll(originalAttrNames);
+        }
+
+        Set<String> updatedAttrNames = new HashSet<>(updatedAttrs.keySet());
+        updatedAttrNames.removeAll(originalAttrs.keySet());
+        result.getDerAttrsToAdd().clear();
+        result.getDerAttrsToAdd().addAll(updatedAttrNames);
+
+        // 4. virtual attributes
+        updatedAttrs = updated.getVirAttrMap();
+        originalAttrs = original.getVirAttrMap();
+
+        originalAttrNames = new HashSet<>(originalAttrs.keySet());
+        originalAttrNames.removeAll(updatedAttrs.keySet());
+
+        if (!incremental) {
+            result.getVirAttrsToRemove().clear();
+            result.getVirAttrsToRemove().addAll(originalAttrNames);
+        }
+
+        populate(updatedAttrs, originalAttrs, result, true);
+
+        // 5. resources
+        if (original instanceof AbstractSubjectTO && updated instanceof AbstractSubjectTO
+                && result instanceof AbstractSubjectMod) {
+
+            Set<String> updatedRes = new HashSet<>(((AbstractSubjectTO) updated).getResources());
+            Set<String> originalRes = new HashSet<>(((AbstractSubjectTO) original).getResources());
+
+            updatedRes.removeAll(originalRes);
+            ((AbstractSubjectMod) result).getResourcesToAdd().clear();
+            ((AbstractSubjectMod) result).getResourcesToAdd().addAll(updatedRes);
+
+            originalRes.removeAll(((AbstractSubjectTO) updated).getResources());
+
+            if (!incremental) {
+                ((AbstractSubjectMod) result).getResourcesToRemove().clear();
+                ((AbstractSubjectMod) result).getResourcesToRemove().addAll(originalRes);
+            }
+        }
+    }
+
+    /**
+     * Calculate modifications needed by first in order to be equal to second.
+     *
+     * @param updated updated UserTO
+     * @param original original UserTO
+     * @return UserMod containing differences
+     */
+    public static UserMod diff(final UserTO updated, final UserTO original) {
+        return diff(updated, original, false);
+    }
+
+    /**
+     * Calculate modifications needed by first in order to be equal to second.
+     *
+     * @param updated updated UserTO
+     * @param original original UserTO
+     * @param incremental perform incremental diff (without removing existing info)
+     * @return UserMod containing differences
+     */
+    public static UserMod diff(final UserTO updated, final UserTO original, final boolean incremental) {
+        UserMod result = new UserMod();
+
+        diff(updated, original, result, incremental);
+
+        // 1. password
+        if (updated.getPassword() != null && (original.getPassword() == null
+                || !original.getPassword().equals(updated.getPassword()))) {
+
+            result.setPassword(updated.getPassword());
+        }
+
+        // 2. username
+        if (original.getUsername() != null && !original.getUsername().equals(updated.getUsername())) {
+            result.setUsername(updated.getUsername());
+        }
+
+        // 3. security question / answer
+        if (updated.getSecurityQuestion() == null) {
+            result.setSecurityQuestion(null);
+            result.setSecurityAnswer(null);
+        } else if (!updated.getSecurityQuestion().equals(original.getSecurityQuestion())
+                || StringUtils.isNotBlank(updated.getSecurityAnswer())) {
+
+            result.setSecurityQuestion(updated.getSecurityQuestion());
+            result.setSecurityAnswer(updated.getSecurityAnswer());
+        }
+
+        // 4. memberships
+        Map<Long, MembershipTO> updatedMembs = updated.getMembershipMap();
+        Map<Long, MembershipTO> originalMembs = original.getMembershipMap();
+
+        for (Map.Entry<Long, MembershipTO> entry : updatedMembs.entrySet()) {
+            MembershipMod membMod = new MembershipMod();
+            membMod.setRole(entry.getValue().getRoleId());
+
+            if (originalMembs.containsKey(entry.getKey())) {
+                // if memberships are actually same, just make the isEmpty() call below succeed
+                if (entry.getValue().equals(originalMembs.get(entry.getKey()))) {
+                    membMod.setRole(0);
+                } else {
+                    diff(entry.getValue(), originalMembs.get(entry.getKey()), membMod, false);
+                }
+            } else {
+                for (AttrTO attr : entry.getValue().getPlainAttrs()) {
+                    AttrMod attrMod = new AttrMod();
+                    attrMod.setSchema(attr.getSchema());
+                    attrMod.getValuesToBeAdded().addAll(attr.getValues());
+
+                    if (!attrMod.isEmpty()) {
+                        membMod.getAttrsToUpdate().add(attrMod);
+                        membMod.getAttrsToRemove().add(attrMod.getSchema());
+                    }
+                }
+                for (AttrTO attr : entry.getValue().getDerAttrs()) {
+                    membMod.getDerAttrsToAdd().add(attr.getSchema());
+                }
+                for (AttrTO attr : entry.getValue().getVirAttrs()) {
+                    AttrMod attrMod = new AttrMod();
+                    attrMod.setSchema(attr.getSchema());
+                    attrMod.getValuesToBeAdded().addAll(attr.getValues());
+
+                    if (!attrMod.isEmpty()) {
+                        membMod.getVirAttrsToUpdate().add(attrMod);
+                        membMod.getAttrsToRemove().add(attrMod.getSchema());
+                    }
+                }
+            }
+
+            if (!membMod.isEmpty()) {
+                result.getMembershipsToAdd().add(membMod);
+            }
+        }
+
+        if (!incremental) {
+            Set<Long> originalRoles = new HashSet<>(originalMembs.keySet());
+            originalRoles.removeAll(updatedMembs.keySet());
+            for (Long roleId : originalRoles) {
+                result.getMembershipsToRemove().add(originalMembs.get(roleId).getKey());
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Calculate modifications needed by first in order to be equal to second.
+     *
+     * @param updated updated RoleTO
+     * @param original original RoleTO
+     * @return RoleMod containing differences
+     */
+    public static RoleMod diff(final RoleTO updated, final RoleTO original) {
+        return diff(updated, original, false);
+    }
+
+    /**
+     * Calculate modifications needed by first in order to be equal to second.
+     *
+     * @param updated updated RoleTO
+     * @param original original RoleTO
+     * @param incremental perform incremental diff (without removing existing info)
+     * @return RoleMod containing differences
+     */
+    public static RoleMod diff(final RoleTO updated, final RoleTO original, final boolean incremental) {
+        RoleMod result = new RoleMod();
+
+        diff(updated, original, result, incremental);
+
+        // 1. inheritance
+        result.setInheritOwner(updated.isInheritOwner());
+        result.setInheritTemplates(updated.isInheritTemplates());
+        result.setInheritAccountPolicy(updated.isInheritAccountPolicy());
+        result.setInheritPasswordPolicy(updated.isInheritPasswordPolicy());
+        result.setInheritPlainAttrs(updated.isInheritAttrs());
+        result.setInheritDerAttrs(updated.isInheritDerAttrs());
+        result.setInheritVirAttrs(updated.isInheritVirAttrs());
+
+        // 2. policies
+        result.setAccountPolicy(new ReferenceMod(updated.getAccountPolicy()));
+        result.setPasswordPolicy(new ReferenceMod(updated.getPasswordPolicy()));
+
+        // 3. name
+        if (!original.getName().equals(updated.getName())) {
+            result.setName(updated.getName());
+        }
+
+        // 4. entitlements
+        Set<String> updatedEnts = new HashSet<>(updated.getEntitlements());
+        Set<String> originalEnts = new HashSet<>(original.getEntitlements());
+        if (updatedEnts.equals(originalEnts)) {
+            result.setModEntitlements(false);
+            result.getEntitlements().clear();
+        } else {
+            result.setModEntitlements(true);
+            result.getEntitlements().addAll(updated.getEntitlements());
+        }
+
+        // 5. templates
+        Set<String> updatedTemplates = new HashSet<>(updated.getRAttrTemplates());
+        Set<String> originalTemplates = new HashSet<>(original.getRAttrTemplates());
+        if (updatedTemplates.equals(originalTemplates)) {
+            result.setModRAttrTemplates(false);
+            result.getRPlainAttrTemplates().clear();
+        } else {
+            result.setModRAttrTemplates(true);
+            result.getRPlainAttrTemplates().addAll(updated.getRAttrTemplates());
+        }
+        updatedTemplates = new HashSet<>(updated.getRDerAttrTemplates());
+        originalTemplates = new HashSet<>(original.getRDerAttrTemplates());
+        if (updatedTemplates.equals(originalTemplates)) {
+            result.setModRDerAttrTemplates(false);
+            result.getRDerAttrTemplates().clear();
+        } else {
+            result.setModRDerAttrTemplates(true);
+            result.getRDerAttrTemplates().addAll(updated.getRDerAttrTemplates());
+        }
+        updatedTemplates = new HashSet<>(updated.getRVirAttrTemplates());
+        originalTemplates = new HashSet<>(original.getRVirAttrTemplates());
+        if (updatedTemplates.equals(originalTemplates)) {
+            result.setModRVirAttrTemplates(false);
+            result.getRVirAttrTemplates().clear();
+        } else {
+            result.setModRVirAttrTemplates(true);
+            result.getRVirAttrTemplates().addAll(updated.getRVirAttrTemplates());
+        }
+        updatedTemplates = new HashSet<>(updated.getMAttrTemplates());
+        originalTemplates = new HashSet<>(original.getMAttrTemplates());
+        if (updatedTemplates.equals(originalTemplates)) {
+            result.setModMAttrTemplates(false);
+            result.getMPlainAttrTemplates().clear();
+        } else {
+            result.setModMAttrTemplates(true);
+            result.getMPlainAttrTemplates().addAll(updated.getMAttrTemplates());
+        }
+        updatedTemplates = new HashSet<>(updated.getMDerAttrTemplates());
+        originalTemplates = new HashSet<>(original.getMDerAttrTemplates());
+        if (updatedTemplates.equals(originalTemplates)) {
+            result.setModMDerAttrTemplates(false);
+            result.getMDerAttrTemplates().clear();
+        } else {
+            result.setModMDerAttrTemplates(true);
+            result.getMDerAttrTemplates().addAll(updated.getMDerAttrTemplates());
+        }
+        updatedTemplates = new HashSet<>(updated.getMVirAttrTemplates());
+        originalTemplates = new HashSet<>(original.getMVirAttrTemplates());
+        if (updatedTemplates.equals(originalTemplates)) {
+            result.setModMVirAttrTemplates(false);
+            result.getMVirAttrTemplates().clear();
+        } else {
+            result.setModMVirAttrTemplates(true);
+            result.getMVirAttrTemplates().addAll(updated.getMVirAttrTemplates());
+        }
+
+        // 6. owner
+        result.setUserOwner(new ReferenceMod(updated.getUserOwner()));
+        result.setRoleOwner(new ReferenceMod(updated.getRoleOwner()));
+
+        return result;
+    }
+
+    private static List<AttrTO> getUpdateValues(final Map<String, AttrTO> attrs,
+            final Set<String> attrsToBeRemoved, final Set<AttrMod> attrsToBeUpdated) {
+
+        Map<String, AttrTO> rwattrs = new HashMap<>(attrs);
+        for (String attrName : attrsToBeRemoved) {
+            rwattrs.remove(attrName);
+        }
+        for (AttrMod attrMod : attrsToBeUpdated) {
+            if (rwattrs.containsKey(attrMod.getSchema())) {
+                AttrTO attrTO = rwattrs.get(attrMod.getSchema());
+                attrTO.getValues().removeAll(attrMod.getValuesToBeRemoved());
+                attrTO.getValues().addAll(attrMod.getValuesToBeAdded());
+            } else {
+                AttrTO attrTO = new AttrTO();
+                attrTO.setSchema(attrMod.getSchema());
+                attrTO.getValues().addAll(attrMod.getValuesToBeAdded());
+
+                rwattrs.put(attrMod.getSchema(), attrTO);
+            }
+        }
+
+        return new ArrayList<>(rwattrs.values());
+    }
+
+    private static <T extends AbstractAttributableTO, K extends AbstractAttributableMod> void apply(final T to,
+            final K mod, final T result) {
+
+        // 1. attributes
+        result.getPlainAttrs().addAll(getUpdateValues(to.getAttrMap(),
+                mod.getAttrsToRemove(), mod.getAttrsToUpdate()));
+
+        // 2. derived attributes
+        Map<String, AttrTO> attrs = to.getDerAttrMap();
+        for (String attrName : mod.getDerAttrsToRemove()) {
+            attrs.remove(attrName);
+        }
+        for (String attrName : mod.getDerAttrsToAdd()) {
+            AttrTO attrTO = new AttrTO();
+            attrTO.setSchema(attrName);
+
+            attrs.put(attrName, attrTO);
+        }
+        result.getDerAttrs().addAll(attrs.values());
+
+        // 3. virtual attributes
+        result.getVirAttrs().addAll(getUpdateValues(to.getVirAttrMap(),
+                mod.getVirAttrsToRemove(), mod.getVirAttrsToUpdate()));
+
+        // 4. resources
+        if (result instanceof AbstractSubjectTO && mod instanceof AbstractSubjectMod) {
+            ((AbstractSubjectTO) result).getResources().removeAll(((AbstractSubjectMod) mod).getResourcesToRemove());
+            ((AbstractSubjectTO) result).getResources().addAll(((AbstractSubjectMod) mod).getResourcesToAdd());
+        }
+    }
+
+    public static UserTO apply(final UserTO userTO, final UserMod userMod) {
+        // 1. check same id
+        if (userTO.getKey() != userMod.getKey()) {
+            throw new IllegalArgumentException("UserTO and UserMod ids must be the same");
+        }
+
+        UserTO result = SerializationUtils.clone(userTO);
+        apply(userTO, userMod, result);
+
+        // 1. password
+        result.setPassword(userMod.getPassword());
+
+        // 2. username
+        if (userMod.getUsername() != null) {
+            result.setUsername(userMod.getUsername());
+        }
+        // 3. memberships
+        Map<Long, MembershipTO> membs = result.getMembershipMap();
+        for (Long membId : userMod.getMembershipsToRemove()) {
+            result.getMemberships().remove(membs.get(membId));
+        }
+        for (MembershipMod membMod : userMod.getMembershipsToAdd()) {
+            MembershipTO membTO = new MembershipTO();
+            membTO.setRoleId(membMod.getRole());
+
+            apply(membTO, membMod, membTO);
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientCompositeException.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientCompositeException.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientCompositeException.java
new file mode 100644
index 0000000..7322cc8
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientCompositeException.java
@@ -0,0 +1,96 @@
+/*
+ * 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;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+
+public class SyncopeClientCompositeException extends SyncopeClientException {
+
+    private static final long serialVersionUID = 7882118041134372129L;
+
+    private final Set<SyncopeClientException> exceptions = new HashSet<>();
+
+    protected SyncopeClientCompositeException() {
+        super(ClientExceptionType.Composite);
+    }
+
+    public boolean hasExceptions() {
+        return !exceptions.isEmpty();
+    }
+
+    public boolean hasException(final ClientExceptionType exceptionType) {
+        return getException(exceptionType) != null;
+    }
+
+    public SyncopeClientException getException(final ClientExceptionType exceptionType) {
+        boolean found = false;
+        SyncopeClientException syncopeClientException = null;
+        for (Iterator<SyncopeClientException> itor = exceptions.iterator(); itor.hasNext() && !found;) {
+            syncopeClientException = itor.next();
+            if (syncopeClientException.getType().equals(exceptionType)) {
+                found = true;
+            }
+        }
+
+        return found
+                ? syncopeClientException
+                : null;
+    }
+
+    public Set<SyncopeClientException> getExceptions() {
+        return exceptions;
+    }
+
+    public boolean addException(final SyncopeClientException exception) {
+        if (exception.getType() == null) {
+            throw new IllegalArgumentException(exception + " does not have the right "
+                    + ClientExceptionType.class.getName() + " set");
+        }
+
+        return exceptions.add(exception);
+    }
+
+    @Override
+    public String getMessage() {
+        StringBuilder message = new StringBuilder();
+
+        message.append("{");
+        Iterator<SyncopeClientException> iter = getExceptions().iterator();
+        while (iter.hasNext()) {
+            SyncopeClientException e = iter.next();
+            message.append("[");
+            message.append(e.getMessage());
+            message.append("]");
+            if (iter.hasNext()) {
+                message.append(", ");
+            }
+        }
+        message.append("}");
+
+        return message.toString();
+    }
+
+    @Override
+    public String getLocalizedMessage() {
+        return getMessage();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientException.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientException.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientException.java
new file mode 100644
index 0000000..2243835
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientException.java
@@ -0,0 +1,97 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+
+public class SyncopeClientException extends RuntimeException {
+
+    private static final long serialVersionUID = 3380920886511913475L;
+
+    private ClientExceptionType type;
+
+    private final List<String> elements = new ArrayList<>();
+
+    public static SyncopeClientException build(final ClientExceptionType type) {
+        if (type == ClientExceptionType.Composite) {
+            throw new IllegalArgumentException("Composite exceptions must be obtained via buildComposite()");
+        }
+        return new SyncopeClientException(type);
+    }
+
+    public static SyncopeClientCompositeException buildComposite() {
+        return new SyncopeClientCompositeException();
+    }
+
+    protected SyncopeClientException(final ClientExceptionType type) {
+        super();
+        setType(type);
+    }
+
+    public boolean isComposite() {
+        return getType() == ClientExceptionType.Composite;
+    }
+
+    public SyncopeClientCompositeException asComposite() {
+        if (!isComposite()) {
+            throw new IllegalArgumentException("This is not a composite exception");
+        }
+
+        return (SyncopeClientCompositeException) this;
+    }
+
+    public ClientExceptionType getType() {
+        return type;
+    }
+
+    public final void setType(final ClientExceptionType type) {
+        this.type = type;
+    }
+
+    public List<String> getElements() {
+        return elements;
+    }
+
+    public boolean isEmpty() {
+        return elements.isEmpty();
+    }
+
+    public int size() {
+        return elements.size();
+    }
+
+    @Override
+    public String getMessage() {
+        StringBuilder message = new StringBuilder();
+
+        message.append(getType());
+        message.append(" ");
+        message.append(getElements());
+
+        return message.toString();
+    }
+
+    @Override
+    public String getLocalizedMessage() {
+        return getMessage();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
index 7339565..5d6b982 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
@@ -38,9 +38,9 @@ public abstract class AbstractAttributableMod extends AbstractBaseBean {
 
     protected long key;
 
-    protected final Set<AttrMod> attrsToUpdate = new HashSet<>();
+    protected final Set<AttrMod> plainAttrsToUpdate = new HashSet<>();
 
-    protected final Set<String> attrsToRemove = new HashSet<>();
+    protected final Set<String> plainAttrsToRemove = new HashSet<>();
 
     protected final Set<String> derAttrsToAdd = new HashSet<>();
 
@@ -58,18 +58,18 @@ public abstract class AbstractAttributableMod extends AbstractBaseBean {
         this.key = key;
     }
 
-    @XmlElementWrapper(name = "attributesToRemove")
+    @XmlElementWrapper(name = "plainAttrsToRemove")
     @XmlElement(name = "attribute")
-    @JsonProperty("attributesToRemove")
+    @JsonProperty("plainAttrsToRemove")
     public Set<String> getAttrsToRemove() {
-        return attrsToRemove;
+        return plainAttrsToRemove;
     }
 
-    @XmlElementWrapper(name = "attributesToUpdate")
+    @XmlElementWrapper(name = "plainAttrsToUpdate")
     @XmlElement(name = "attributeMod")
-    @JsonProperty("attributesToUpdate")
+    @JsonProperty("plainAttrsToUpdate")
     public Set<AttrMod> getAttrsToUpdate() {
-        return attrsToUpdate;
+        return plainAttrsToUpdate;
     }
 
     @XmlElementWrapper(name = "derAttrsToAdd")
@@ -104,7 +104,7 @@ public abstract class AbstractAttributableMod extends AbstractBaseBean {
      * @return true is all backing Sets are empty.
      */
     public boolean isEmpty() {
-        return attrsToUpdate.isEmpty() && attrsToRemove.isEmpty()
+        return plainAttrsToUpdate.isEmpty() && plainAttrsToRemove.isEmpty()
                 && derAttrsToAdd.isEmpty() && derAttrsToRemove.isEmpty()
                 && virAttrsToUpdate.isEmpty() && virAttrsToRemove.isEmpty();
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
new file mode 100644
index 0000000..bdcfcbf
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
@@ -0,0 +1,46 @@
+/*
+ * 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.mod;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement
+@XmlType
+public class MembershipMod extends AbstractAttributableMod {
+
+    private static final long serialVersionUID = 2511869129977331525L;
+
+    private long role;
+
+    public long getRole() {
+        return role;
+    }
+
+    public void setRole(final long role) {
+        this.role = role;
+    }
+
+    @JsonIgnore
+    @Override
+    public boolean isEmpty() {
+        return super.isEmpty() && role == 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ReferenceMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ReferenceMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ReferenceMod.java
new file mode 100644
index 0000000..e8356c2
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ReferenceMod.java
@@ -0,0 +1,53 @@
+/*
+ * 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.mod;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+/**
+ * This class is used to specify the willing to modify an external reference id. Use 'null' ReferenceMod to keep the
+ * current reference id; use a ReferenceMod with a null id to try to reset the reference id; use a ReferenceMod with a
+ * not null id to specify a new reference id.
+ */
+@XmlRootElement(name = "referenceMod")
+@XmlType
+public class ReferenceMod extends AbstractBaseBean {
+
+    private static final long serialVersionUID = -4188817853738067677L;
+
+    private Long key;
+
+    public ReferenceMod() {
+        this.key = null;
+    }
+
+    public ReferenceMod(final Long key) {
+        this.key = key;
+    }
+
+    public Long getKey() {
+        return key;
+    }
+
+    public void setKey(final Long key) {
+        this.key = key;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ResourceAssociationMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ResourceAssociationMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ResourceAssociationMod.java
new file mode 100644
index 0000000..6312349
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ResourceAssociationMod.java
@@ -0,0 +1,80 @@
+/*
+ * 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.mod;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.wrap.ResourceName;
+
+/**
+ * This class is used to specify the willing to create associations between user and external references.
+ * Password can be provided if required by an assign or provisioning operation.
+ *
+ * @see org.apache.syncope.common.types.ResourceAssociationActionType
+ */
+@XmlRootElement(name = "resourceAssociationMod")
+@XmlType
+public class ResourceAssociationMod extends AbstractBaseBean {
+
+    private static final long serialVersionUID = -4188817853738067678L;
+
+    /**
+     * Target external resources.
+     */
+    private final List<ResourceName> targetResources = new ArrayList<ResourceName>();
+
+    /**
+     * Indicate the willing to change password on target external resources.
+     */
+    private boolean changePwd;
+
+    /**
+     * Indicate the new password to be provisioned on target external resources.
+     */
+    private String password;
+
+    @XmlElementWrapper(name = "resources")
+    @XmlElement(name = "resource")
+    @JsonProperty("resources")
+    public List<ResourceName> getTargetResources() {
+        return targetResources;
+    }
+
+    public boolean isChangePwd() {
+        return changePwd;
+    }
+
+    public void setChangePwd(boolean changePwd) {
+        this.changePwd = changePwd;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/RoleMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/RoleMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/RoleMod.java
new file mode 100644
index 0000000..b1b8f4f
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/RoleMod.java
@@ -0,0 +1,300 @@
+/*
+ * 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.mod;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "roleMod")
+@XmlType
+public class RoleMod extends AbstractSubjectMod {
+
+    private static final long serialVersionUID = 7455805264680210747L;
+
+    private String name;
+
+    private ReferenceMod userOwner;
+
+    private ReferenceMod roleOwner;
+
+    private Boolean inheritOwner;
+
+    private Boolean inheritTemplates;
+
+    private Boolean inheritPlainAttrs;
+
+    private Boolean inheritDerAttrs;
+
+    private Boolean inheritVirAttrs;
+
+    private Boolean inheritAccountPolicy;
+
+    private Boolean inheritPasswordPolicy;
+
+    private boolean modEntitlements;
+
+    private final List<String> entitlements = new ArrayList<>();
+
+    private boolean modRAttrTemplates;
+
+    private final List<String> rPlainAttrTemplates = new ArrayList<>();
+
+    private boolean modRDerAttrTemplates;
+
+    private final List<String> rDerAttrTemplates = new ArrayList<>();
+
+    private boolean modRVirAttrTemplates;
+
+    private final List<String> rVirAttrTemplates = new ArrayList<>();
+
+    private boolean modMAttrTemplates;
+
+    private final List<String> mPlainAttrTemplates = new ArrayList<>();
+
+    private boolean modMDerAttrTemplates;
+
+    private final List<String> mDerAttrTemplates = new ArrayList<>();
+
+    private boolean modMVirAttrTemplates;
+
+    private final List<String> mVirAttrTemplates = new ArrayList<>();
+
+    private ReferenceMod passwordPolicy;
+
+    private ReferenceMod accountPolicy;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public ReferenceMod getUserOwner() {
+        return userOwner;
+    }
+
+    public void setUserOwner(final ReferenceMod userOwner) {
+        this.userOwner = userOwner;
+    }
+
+    public ReferenceMod getRoleOwner() {
+        return roleOwner;
+    }
+
+    public void setRoleOwner(final ReferenceMod roleOwner) {
+        this.roleOwner = roleOwner;
+    }
+
+    public Boolean getInheritOwner() {
+        return inheritOwner;
+    }
+
+    public void setInheritOwner(final Boolean inheritOwner) {
+        this.inheritOwner = inheritOwner;
+    }
+
+    public Boolean getInheritTemplates() {
+        return inheritTemplates;
+    }
+
+    public void setInheritTemplates(final Boolean inheritTemplates) {
+        this.inheritTemplates = inheritTemplates;
+    }
+
+    public Boolean getInheritPlainAttrs() {
+        return inheritPlainAttrs;
+    }
+
+    public void setInheritPlainAttrs(final Boolean inheritAttrs) {
+        this.inheritPlainAttrs = inheritAttrs;
+    }
+
+    public Boolean getInheritDerAttrs() {
+        return inheritDerAttrs;
+    }
+
+    public void setInheritDerAttrs(final Boolean inheritDerAttrs) {
+        this.inheritDerAttrs = inheritDerAttrs;
+    }
+
+    public Boolean getInheritVirAttrs() {
+        return inheritVirAttrs;
+    }
+
+    public void setInheritVirAttrs(final Boolean inheritVirAttrs) {
+        this.inheritVirAttrs = inheritVirAttrs;
+    }
+
+    public boolean isModEntitlements() {
+        return modEntitlements;
+    }
+
+    public void setModEntitlements(final boolean modEntitlements) {
+        this.modEntitlements = modEntitlements;
+    }
+
+    @XmlElementWrapper(name = "entitlements")
+    @XmlElement(name = "entitlement")
+    @JsonProperty("entitlements")
+    public List<String> getEntitlements() {
+        return entitlements;
+    }
+
+    public boolean isModRAttrTemplates() {
+        return modRAttrTemplates;
+    }
+
+    public void setModRAttrTemplates(final boolean modRAttrTemplates) {
+        this.modRAttrTemplates = modRAttrTemplates;
+    }
+
+    @XmlElementWrapper(name = "rPlainAttrTemplates")
+    @XmlElement(name = "rAttrTemplate")
+    @JsonProperty("rPlainAttrTemplates")
+    public List<String> getRPlainAttrTemplates() {
+        return rPlainAttrTemplates;
+    }
+
+    public boolean isModRDerAttrTemplates() {
+        return modRDerAttrTemplates;
+    }
+
+    public void setModRDerAttrTemplates(final boolean modRDerAttrTemplates) {
+        this.modRDerAttrTemplates = modRDerAttrTemplates;
+    }
+
+    @XmlElementWrapper(name = "rDerAttrTemplates")
+    @XmlElement(name = "rDerAttrTemplate")
+    @JsonProperty("rDerAttrTemplates")
+    public List<String> getRDerAttrTemplates() {
+        return rDerAttrTemplates;
+    }
+
+    public boolean isModRVirAttrTemplates() {
+        return modRVirAttrTemplates;
+    }
+
+    public void setModRVirAttrTemplates(final boolean modRVirAttrTemplates) {
+        this.modRVirAttrTemplates = modRVirAttrTemplates;
+    }
+
+    @XmlElementWrapper(name = "rVirAttrTemplates")
+    @XmlElement(name = "rVirAttrTemplate")
+    @JsonProperty("rVirAttrTemplates")
+    public List<String> getRVirAttrTemplates() {
+        return rVirAttrTemplates;
+    }
+
+    public boolean isModMAttrTemplates() {
+        return modMAttrTemplates;
+    }
+
+    public void setModMAttrTemplates(final boolean modMAttrTemplates) {
+        this.modMAttrTemplates = modMAttrTemplates;
+    }
+
+    @XmlElementWrapper(name = "mPlainAttrTemplates")
+    @XmlElement(name = "mAttrTemplate")
+    @JsonProperty("mPlainAttrTemplates")
+    public List<String> getMPlainAttrTemplates() {
+        return mPlainAttrTemplates;
+    }
+
+    public boolean isModMDerAttrTemplates() {
+        return modMDerAttrTemplates;
+    }
+
+    public void setModMDerAttrTemplates(final boolean modMDerAttrTemplates) {
+        this.modMDerAttrTemplates = modMDerAttrTemplates;
+    }
+
+    @XmlElementWrapper(name = "mDerAttrTemplates")
+    @XmlElement(name = "mDerAttrTemplate")
+    @JsonProperty("mDerAttrTemplates")
+    public List<String> getMDerAttrTemplates() {
+        return mDerAttrTemplates;
+    }
+
+    public boolean isModMVirAttrTemplates() {
+        return modMVirAttrTemplates;
+    }
+
+    public void setModMVirAttrTemplates(final boolean modMVirAttrTemplates) {
+        this.modMVirAttrTemplates = modMVirAttrTemplates;
+    }
+
+    @XmlElementWrapper(name = "mVirAttrTemplates")
+    @XmlElement(name = "mVirAttrTemplate")
+    @JsonProperty("mVirAttrTemplates")
+    public List<String> getMVirAttrTemplates() {
+        return mVirAttrTemplates;
+    }
+
+    public ReferenceMod getPasswordPolicy() {
+        return passwordPolicy;
+    }
+
+    public void setPasswordPolicy(final ReferenceMod passwordPolicy) {
+        this.passwordPolicy = passwordPolicy;
+    }
+
+    public Boolean getInheritPasswordPolicy() {
+        return inheritPasswordPolicy;
+    }
+
+    public void setInheritPasswordPolicy(final Boolean inheritPasswordPolicy) {
+        this.inheritPasswordPolicy = inheritPasswordPolicy;
+    }
+
+    public ReferenceMod getAccountPolicy() {
+        return accountPolicy;
+    }
+
+    public void setAccountPolicy(final ReferenceMod accountPolicy) {
+        this.accountPolicy = accountPolicy;
+    }
+
+    public Boolean getInheritAccountPolicy() {
+        return inheritAccountPolicy;
+    }
+
+    public void setInheritAccountPolicy(final Boolean inheritAccountPolicy) {
+        this.inheritAccountPolicy = inheritAccountPolicy;
+    }
+
+    @JsonIgnore
+    @Override
+    public boolean isEmpty() {
+        return super.isEmpty() && name == null && userOwner == null && roleOwner == null
+                && inheritTemplates == null && inheritOwner == null
+                && inheritAccountPolicy == null && inheritPasswordPolicy == null
+                && inheritPlainAttrs == null && inheritDerAttrs == null && inheritVirAttrs == null
+                && accountPolicy == null && passwordPolicy == null && entitlements.isEmpty()
+                && rPlainAttrTemplates.isEmpty() && rDerAttrTemplates.isEmpty() && rVirAttrTemplates.isEmpty()
+                && mPlainAttrTemplates.isEmpty() && mDerAttrTemplates.isEmpty() && mVirAttrTemplates.isEmpty();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
new file mode 100644
index 0000000..3ddf263
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
@@ -0,0 +1,108 @@
+/*
+ * 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.mod;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "statusMod")
+@XmlType
+public class StatusMod extends AbstractBaseBean {
+
+    private static final long serialVersionUID = 3230910033784302656L;
+
+    @XmlEnum
+    @XmlType(name = "statusModType")
+    public enum ModType {
+
+        ACTIVATE,
+        SUSPEND,
+        REACTIVATE;
+
+    }
+
+    /**
+     * Id of user to for which status update is requested.
+     */
+    private long id;
+
+    private ModType type;
+
+    /**
+     * Update token (if required).
+     */
+    private String token;
+
+    /**
+     * Whether update should be performed on internal storage.
+     */
+    private boolean onSyncope = true;
+
+    /**
+     * External resources for which update is needed to be propagated.
+     */
+    private final List<String> resourceNames = new ArrayList<>();
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public ModType getType() {
+        return type;
+    }
+
+    public void setType(final ModType type) {
+        this.type = type;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(final String token) {
+        this.token = token;
+    }
+
+    public boolean isOnSyncope() {
+        return onSyncope;
+    }
+
+    public void setOnSyncope(final boolean onSyncope) {
+        this.onSyncope = onSyncope;
+    }
+
+    @XmlElementWrapper(name = "resources")
+    @XmlElement(name = "resource")
+    @JsonProperty("resources")
+    public List<String> getResourceNames() {
+        return resourceNames;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
new file mode 100644
index 0000000..0f421be
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
@@ -0,0 +1,123 @@
+/*
+ * 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.mod;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.HashSet;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "userMod")
+@XmlType
+public class UserMod extends AbstractSubjectMod {
+
+    private static final long serialVersionUID = 3081848906558106204L;
+
+    private String password;
+
+    private String username;
+
+    private final Set<MembershipMod> membershipsToAdd;
+
+    private final Set<Long> membershipsToRemove;
+
+    private StatusMod pwdPropRequest;
+
+    private Long securityQuestion;
+
+    private String securityAnswer;
+
+    public UserMod() {
+        super();
+
+        membershipsToAdd = new HashSet<>();
+        membershipsToRemove = new HashSet<>();
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(final String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(final String password) {
+        this.password = password;
+    }
+
+    @XmlElementWrapper(name = "membershipsToAdd")
+    @XmlElement(name = "membership")
+    @JsonProperty("membershipsToAdd")
+    public Set<MembershipMod> getMembershipsToAdd() {
+        return membershipsToAdd;
+    }
+
+    @XmlElementWrapper(name = "membershipsToRemove")
+    @XmlElement(name = "membership")
+    @JsonProperty("membershipsToRemove")
+    public Set<Long> getMembershipsToRemove() {
+        return membershipsToRemove;
+    }
+
+    public StatusMod getPwdPropRequest() {
+        return pwdPropRequest;
+    }
+
+    public void setPwdPropRequest(final StatusMod pwdPropRequest) {
+        this.pwdPropRequest = pwdPropRequest;
+    }
+
+    public Long getSecurityQuestion() {
+        return securityQuestion;
+    }
+
+    public void setSecurityQuestion(final Long securityQuestion) {
+        this.securityQuestion = securityQuestion;
+    }
+
+    public String getSecurityAnswer() {
+        return securityAnswer;
+    }
+
+    public void setSecurityAnswer(final String securityAnswer) {
+        this.securityAnswer = securityAnswer;
+    }
+
+    @JsonIgnore
+    @Override
+    public boolean isEmpty() {
+        return super.isEmpty()
+                && password == null
+                && username == null
+                && membershipsToAdd.isEmpty()
+                && membershipsToRemove.isEmpty()
+                && pwdPropRequest == null
+                && securityQuestion == null
+                && securityAnswer == null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/package-info.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/package-info.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/package-info.java
new file mode 100644
index 0000000..866b275
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@XmlSchema(namespace = SyncopeConstants.NAMESPACE)
+package org.apache.syncope.common.lib.mod;
+
+import javax.xml.bind.annotation.XmlSchema;
+import org.apache.syncope.common.lib.SyncopeConstants;

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java
index 55e2da9..295316b 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java
@@ -39,7 +39,7 @@ public class RoleReportletConf extends AbstractReportletConf {
     @XmlType(name = "roleReportletConfFeature")
     public enum Feature {
 
-        id,
+        key,
         name,
         roleOwner,
         userOwner,

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
index 2c6ed17..afd806a 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
@@ -38,7 +38,7 @@ public class UserReportletConf extends AbstractReportletConf {
     @XmlType(name = "userReportletConfFeature")
     public enum Feature {
 
-        id,
+        key,
         username,
         workflowId,
         status,

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/OrderByClauseBuilder.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/OrderByClauseBuilder.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/OrderByClauseBuilder.java
new file mode 100644
index 0000000..41d152c
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/OrderByClauseBuilder.java
@@ -0,0 +1,45 @@
+/*
+ * 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.search;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Simple builder for generating <tt>orderby</tt> values.
+ */
+public class OrderByClauseBuilder {
+
+    private final StringBuilder builder = new StringBuilder();
+
+    public OrderByClauseBuilder asc(final String key) {
+        builder.append(key).append(" ASC,");
+        return this;
+    }
+
+    public OrderByClauseBuilder desc(final String key) {
+        builder.append(key).append(" DESC,");
+        return this;
+    }
+
+    public String build() {
+        return builder.length() == 0
+                ? StringUtils.EMPTY
+                : builder.deleteCharAt(builder.length() - 1).toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleFiqlSearchConditionBuilder.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleFiqlSearchConditionBuilder.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleFiqlSearchConditionBuilder.java
new file mode 100644
index 0000000..b6cbb6d
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleFiqlSearchConditionBuilder.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.common.lib.search;
+
+import java.util.Map;
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
+
+/**
+ * Extends <tt>SyncopeFiqlSearchConditionBuilder</tt> by providing some additional facilities for searching
+ * roles in Syncope.
+ */
+public class RoleFiqlSearchConditionBuilder extends SyncopeFiqlSearchConditionBuilder {
+
+    public RoleFiqlSearchConditionBuilder() {
+        super();
+    }
+
+    public RoleFiqlSearchConditionBuilder(final Map<String, String> properties) {
+        super(properties);
+    }
+
+    @Override
+    protected Builder newBuilderInstance() {
+        return new Builder(properties);
+    }
+
+    @Override
+    public RoleProperty is(final String property) {
+        return newBuilderInstance().is(property);
+    }
+
+    public CompleteCondition hasEntitlements(final String entitlement, final String... moreEntitlements) {
+        return newBuilderInstance().is(SpecialAttr.ENTITLEMENTS.toString()).
+                hasEntitlements(entitlement, moreEntitlements);
+    }
+
+    public CompleteCondition hasNotEntitlements(final String entitlement, final String... moreEntitlements) {
+        return newBuilderInstance().is(SpecialAttr.ENTITLEMENTS.toString()).
+                hasNotEntitlements(entitlement, moreEntitlements);
+    }
+
+    protected static class Builder extends SyncopeFiqlSearchConditionBuilder.Builder
+            implements RoleProperty, CompleteCondition {
+
+        public Builder(final Map<String, String> properties) {
+            super(properties);
+        }
+
+        public Builder(final Builder parent) {
+            super(parent);
+        }
+
+        @Override
+        public RoleProperty is(final String property) {
+            Builder b = new Builder(this);
+            b.result = property;
+            return b;
+        }
+
+        @Override
+        public CompleteCondition hasEntitlements(final String entitlement, final String... moreEntitlements) {
+            this.result = SpecialAttr.ENTITLEMENTS.toString();
+            return condition(FiqlParser.EQ, entitlement, (Object[]) moreEntitlements);
+        }
+
+        @Override
+        public CompleteCondition hasNotEntitlements(final String entitlement, final String... moreEntitlements) {
+            this.result = SpecialAttr.ENTITLEMENTS.toString();
+            return condition(FiqlParser.NEQ, entitlement, (Object[]) moreEntitlements);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleProperty.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleProperty.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleProperty.java
new file mode 100644
index 0000000..433ed11
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleProperty.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.search;
+
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+
+public interface RoleProperty extends SyncopeProperty {
+
+    CompleteCondition hasEntitlements(String entitlement, String... moreEntitlements);
+
+    CompleteCondition hasNotEntitlements(String entitlement, String... moreEntitlements);
+
+}