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/05/25 16:51:04 UTC

[28/29] syncope git commit: [SYNCOPE-666] Initial commit, Travis CI builds disabled

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
new file mode 100644
index 0000000..cab3239
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
@@ -0,0 +1,375 @@
+/*
+ * 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.collections4.CollectionUtils;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.mod.AnyMod;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.mod.ReferenceMod;
+import org.apache.syncope.common.lib.mod.GroupMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
+
+/**
+ * Utility class for comparing manipulating {@link AnyTO} and {@link AnyMod}.
+ */
+public final class AnyOperations {
+
+    private AnyOperations() {
+        // empty constructor for static utility classes
+    }
+
+    private static void populate(final Map<String, AttrTO> updatedAttrs,
+            final Map<String, AttrTO> originalAttrs, final AnyMod result) {
+
+        populate(updatedAttrs, originalAttrs, result, false);
+    }
+
+    private static void populate(final Map<String, AttrTO> updatedAttrs,
+            final Map<String, AttrTO> originalAttrs, final AnyMod 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<>(entry.getValue().getValues());
+
+            Set<String> originalValues = originalAttrs.containsKey(entry.getKey())
+                    ? new HashSet<>(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<>(updatedValues));
+
+                if (virtuals) {
+                    result.getVirAttrsToUpdate().add(mod);
+                } else {
+                    result.getPlainAttrsToUpdate().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.getPlainAttrsToRemove().add(mod.getSchema());
+                        }
+                    }
+                }
+
+                mod.getValuesToBeRemoved().addAll(originalValues);
+
+                if (!mod.isEmpty()) {
+                    if (virtuals) {
+                        result.getVirAttrsToUpdate().add(mod);
+                    } else {
+                        result.getPlainAttrsToUpdate().add(mod);
+                    }
+                }
+            }
+        }
+    }
+
+    private static void diff(
+            final AnyTO updated,
+            final AnyTO original,
+            final AnyMod result,
+            final boolean incremental) {
+
+        // 1. check same id
+        if (updated.getKey() != original.getKey()) {
+            throw new IllegalArgumentException("AnyTO's id must be the same");
+        }
+        result.setKey(updated.getKey());
+
+        // 2. attributes
+        Map<String, AttrTO> updatedAttrs = new HashMap<>(updated.getPlainAttrMap());
+        Map<String, AttrTO> originalAttrs = new HashMap<>(original.getPlainAttrMap());
+
+        Set<String> originalAttrNames = new HashSet<>(originalAttrs.keySet());
+        originalAttrNames.removeAll(updatedAttrs.keySet());
+
+        if (!incremental) {
+            result.getPlainAttrsToRemove().clear();
+            result.getPlainAttrsToRemove().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.getPlainAttrsToRemove().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
+        Set<String> updatedRes = new HashSet<>(updated.getResources());
+        Set<String> originalRes = new HashSet<>(original.getResources());
+
+        updatedRes.removeAll(originalRes);
+        result.getResourcesToAdd().clear();
+        result.getResourcesToAdd().addAll(updatedRes);
+
+        originalRes.removeAll(updated.getResources());
+
+        if (!incremental) {
+            result.getResourcesToRemove().clear();
+            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);
+
+        // 0. realm
+        if (updated.getRealm() != null && (original.getRealm() == null
+                || !original.getRealm().equals(updated.getRealm()))) {
+
+            result.setRealm(updated.getRealm());
+        }
+
+        // 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. roles
+        result.getRolesToRemove().addAll(CollectionUtils.subtract(original.getRoles(), updated.getRoles()));
+        result.getRolesToAdd().addAll(CollectionUtils.subtract(updated.getRoles(), original.getRoles()));
+
+        return result;
+    }
+
+    /**
+     * Calculate modifications needed by first in order to be equal to second.
+     *
+     * @param updated updated GroupTO
+     * @param original original GroupTO
+     * @return GroupMod containing differences
+     */
+    public static GroupMod diff(final GroupTO updated, final GroupTO original) {
+        return diff(updated, original, false);
+    }
+
+    /**
+     * Calculate modifications needed by first in order to be equal to second.
+     *
+     * @param updated updated GroupTO
+     * @param original original GroupTO
+     * @param incremental perform incremental diff (without removing existing info)
+     * @return GroupMod containing differences
+     */
+    public static GroupMod diff(final GroupTO updated, final GroupTO original, final boolean incremental) {
+        GroupMod result = new GroupMod();
+
+        diff(updated, original, result, incremental);
+
+        // 1. name
+        if (!original.getName().equals(updated.getName())) {
+            result.setName(updated.getName());
+        }
+
+        // 2. owner
+        result.setUserOwner(new ReferenceMod(updated.getUserOwner()));
+        result.setGroupOwner(new ReferenceMod(updated.getGroupOwner()));
+
+        // 3. dynMembershipCond
+        result.setADynMembershipCond(updated.getADynMembershipCond());
+        result.setUDynMembershipCond(updated.getUDynMembershipCond());
+
+        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 AnyTO, K extends AnyMod> void apply(final T to,
+            final K mod, final T result) {
+
+        // 1. attributes
+        result.getPlainAttrs().addAll(getUpdateValues(to.getPlainAttrMap(),
+                mod.getPlainAttrsToRemove(), mod.getPlainAttrsToUpdate()));
+
+        // 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
+        result.getResources().removeAll(mod.getResourcesToRemove());
+        result.getResources().addAll(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);
+
+        // 0. realm
+        if (userMod.getRealm() != null) {
+            result.setRealm(userMod.getRealm());
+        }
+
+        // 1. password
+        result.setPassword(userMod.getPassword());
+
+        // 2. username
+        if (userMod.getUsername() != null) {
+            result.setUsername(userMod.getUsername());
+        }
+
+        // 3. roles
+        result.getRoles().removeAll(userMod.getRolesToRemove());
+        result.getRoles().addAll(userMod.getRolesToAdd());
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
deleted file mode 100644
index 6c250ef..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
+++ /dev/null
@@ -1,509 +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;
-
-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.collections4.CollectionUtils;
-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.GroupMod;
-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.GroupTO;
-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<>(entry.getValue().getValues());
-
-            Set<String> originalValues = originalAttrs.containsKey(entry.getKey())
-                    ? new HashSet<>(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<>(updatedValues));
-
-                if (virtuals) {
-                    result.getVirAttrsToUpdate().add(mod);
-                } else {
-                    result.getPlainAttrsToUpdate().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.getPlainAttrsToRemove().add(mod.getSchema());
-                        }
-                    }
-                }
-
-                mod.getValuesToBeRemoved().addAll(originalValues);
-
-                if (!mod.isEmpty()) {
-                    if (virtuals) {
-                        result.getVirAttrsToUpdate().add(mod);
-                    } else {
-                        result.getPlainAttrsToUpdate().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.getPlainAttrMap());
-        Map<String, AttrTO> originalAttrs = new HashMap<>(original.getPlainAttrMap());
-
-        Set<String> originalAttrNames = new HashSet<>(originalAttrs.keySet());
-        originalAttrNames.removeAll(updatedAttrs.keySet());
-
-        if (!incremental) {
-            result.getPlainAttrsToRemove().clear();
-            result.getPlainAttrsToRemove().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.getPlainAttrsToRemove().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);
-
-        // 0. realm
-        if (updated.getRealm() != null && (original.getRealm() == null
-                || !original.getRealm().equals(updated.getRealm()))) {
-
-            result.setRealm(updated.getRealm());
-        }
-
-        // 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. roles
-        result.getRolesToRemove().addAll(CollectionUtils.subtract(original.getRoles(), updated.getRoles()));
-        result.getRolesToAdd().addAll(CollectionUtils.subtract(updated.getRoles(), original.getRoles()));
-
-        // 5. 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.setGroup(entry.getValue().getGroupKey());
-
-            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.setGroup(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.getPlainAttrsToUpdate().add(attrMod);
-                        membMod.getPlainAttrsToRemove().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.getPlainAttrsToRemove().add(attrMod.getSchema());
-                    }
-                }
-            }
-
-            if (!membMod.isEmpty()) {
-                result.getMembershipsToAdd().add(membMod);
-            }
-        }
-
-        if (!incremental) {
-            Set<Long> originalGroups = new HashSet<>(originalMembs.keySet());
-            originalGroups.removeAll(updatedMembs.keySet());
-            for (Long groupId : originalGroups) {
-                result.getMembershipsToRemove().add(originalMembs.get(groupId).getKey());
-            }
-        }
-
-        return result;
-    }
-
-    /**
-     * Calculate modifications needed by first in order to be equal to second.
-     *
-     * @param updated updated GroupTO
-     * @param original original GroupTO
-     * @return GroupMod containing differences
-     */
-    public static GroupMod diff(final GroupTO updated, final GroupTO original) {
-        return diff(updated, original, false);
-    }
-
-    /**
-     * Calculate modifications needed by first in order to be equal to second.
-     *
-     * @param updated updated GroupTO
-     * @param original original GroupTO
-     * @param incremental perform incremental diff (without removing existing info)
-     * @return GroupMod containing differences
-     */
-    public static GroupMod diff(final GroupTO updated, final GroupTO original, final boolean incremental) {
-        GroupMod result = new GroupMod();
-
-        diff(updated, original, result, incremental);
-
-        // 1. name
-        if (!original.getName().equals(updated.getName())) {
-            result.setName(updated.getName());
-        }
-
-        // 2. templates
-        Set<String> updatedTemplates = new HashSet<>(updated.getGPlainAttrTemplates());
-        Set<String> originalTemplates = new HashSet<>(original.getGPlainAttrTemplates());
-        if (updatedTemplates.equals(originalTemplates)) {
-            result.setModGAttrTemplates(false);
-            result.getGPlainAttrTemplates().clear();
-        } else {
-            result.setModGAttrTemplates(true);
-            result.getGPlainAttrTemplates().addAll(updated.getGPlainAttrTemplates());
-        }
-        updatedTemplates = new HashSet<>(updated.getGDerAttrTemplates());
-        originalTemplates = new HashSet<>(original.getGDerAttrTemplates());
-        if (updatedTemplates.equals(originalTemplates)) {
-            result.setModGDerAttrTemplates(false);
-            result.getGDerAttrTemplates().clear();
-        } else {
-            result.setModGDerAttrTemplates(true);
-            result.getGDerAttrTemplates().addAll(updated.getGDerAttrTemplates());
-        }
-        updatedTemplates = new HashSet<>(updated.getGVirAttrTemplates());
-        originalTemplates = new HashSet<>(original.getGVirAttrTemplates());
-        if (updatedTemplates.equals(originalTemplates)) {
-            result.setModGVirAttrTemplates(false);
-            result.getGVirAttrTemplates().clear();
-        } else {
-            result.setModGVirAttrTemplates(true);
-            result.getGVirAttrTemplates().addAll(updated.getGVirAttrTemplates());
-        }
-        updatedTemplates = new HashSet<>(updated.getMPlainAttrTemplates());
-        originalTemplates = new HashSet<>(original.getMPlainAttrTemplates());
-        if (updatedTemplates.equals(originalTemplates)) {
-            result.setModMAttrTemplates(false);
-            result.getMPlainAttrTemplates().clear();
-        } else {
-            result.setModMAttrTemplates(true);
-            result.getMPlainAttrTemplates().addAll(updated.getMPlainAttrTemplates());
-        }
-        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());
-        }
-
-        // 3. owner
-        result.setUserOwner(new ReferenceMod(updated.getUserOwner()));
-        result.setGroupOwner(new ReferenceMod(updated.getGroupOwner()));
-
-        // 4. dynMembershipCond
-        result.setDynMembershipCond(updated.getDynMembershipCond());
-
-        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.getPlainAttrMap(),
-                mod.getPlainAttrsToRemove(), mod.getPlainAttrsToUpdate()));
-
-        // 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);
-
-        // 0. realm
-        if (userMod.getRealm() != null) {
-            result.setRealm(userMod.getRealm());
-        }
-
-        // 1. password
-        result.setPassword(userMod.getPassword());
-
-        // 2. username
-        if (userMod.getUsername() != null) {
-            result.setUsername(userMod.getUsername());
-        }
-
-        // 3. roles
-        result.getRoles().removeAll(userMod.getRolesToRemove());
-        result.getRoles().addAll(userMod.getRolesToAdd());
-
-        // 4. memberships
-        Map<Long, MembershipTO> membs = result.getMembershipMap();
-        for (Long membKey : userMod.getMembershipsToRemove()) {
-            result.getMemberships().remove(membs.get(membKey));
-        }
-        for (MembershipMod membMod : userMod.getMembershipsToAdd()) {
-            MembershipTO membTO = new MembershipTO();
-            membTO.setGroupKey(membMod.getGroup());
-
-            apply(membTO, membMod, membTO);
-        }
-
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/CollectionUtils2.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/CollectionUtils2.java b/common/lib/src/main/java/org/apache/syncope/common/lib/CollectionUtils2.java
deleted file mode 100644
index 69739b6..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/CollectionUtils2.java
+++ /dev/null
@@ -1,153 +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;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import org.apache.commons.collections4.Predicate;
-import org.apache.commons.collections4.SetUtils;
-import org.apache.commons.collections4.Transformer;
-
-public final class CollectionUtils2 {
-
-    /**
-     * Returns the next element in <tt>iterator</tt> or <tt>defaultValue</tt> if the iterator is empty.
-     *
-     * @param defaultValue the default value to return if the iterator is empty
-     * @return the next element of <tt>iterator</tt> or the default value
-     */
-    public static <T> T getNext(final Iterator<? extends T> iterator, final T defaultValue) {
-        return iterator.hasNext() ? iterator.next() : defaultValue;
-    }
-
-    /**
-     * Returns the first element in <tt>iterable</tt> or <tt>defaultValue</tt> if the iterable is empty.
-     *
-     * <p/>
-     * If no default value is desired (and the caller instead wants a {@link java.util.NoSuchElementException} to be
-     * thrown), it is recommended that <tt>iterable.iterator().next()}</tt> is used instead.
-     *
-     * @param defaultValue the default value to return if the iterable is empty
-     * @return the first element of <tt>iterable</tt> or the default value
-     */
-    public static <T> T getFirst(final Iterable<? extends T> iterable, final T defaultValue) {
-        return getNext(iterable.iterator(), defaultValue);
-    }
-
-    /**
-     * Returns the first element in <tt>iterable</tt> or <tt>null</tt> if the iterable is empty.
-     *
-     * @return the first element of <tt>iterable</tt> or <tt>null</tt>
-     */
-    public static <T> T getFirstOrNull(final Iterable<? extends T> iterable) {
-        return getNext(iterable.iterator(), null);
-    }
-
-    /**
-     * Transforms all elements from inputCollection with the given transformer
-     * and adds them to the outputCollection if the provided predicate is verified.
-     * <p/>
-     * If the input collection or transformer is null, there is no change to the
-     * output collection.
-     *
-     * @param <I> the type of object in the input collection
-     * @param <O> the type of object in the output collection
-     * @param <R> the output type of the transformer - this extends O.
-     * @param inputCollection the collection to get the input from, may be null
-     * @param transformer the transformer to use, may be null
-     * @param predicate the predicate to use, may be null
-     * @param outputCollection the collection to output into, may not be null if the inputCollection
-     * and transformer are not null
-     * @return the outputCollection with the transformed input added
-     * @throws NullPointerException if the output collection is null and both, inputCollection and
-     * transformer are not null
-     */
-    public static <I, O, R extends Collection<? super O>> R collect(final Iterable<? extends I> inputCollection,
-            final Transformer<? super I, ? extends O> transformer, final Predicate<? super I> predicate,
-            final R outputCollection) {
-
-        if (inputCollection != null) {
-            return collect(inputCollection.iterator(), transformer, predicate, outputCollection);
-        }
-        return outputCollection;
-    }
-
-    /**
-     * Transforms all elements from the inputIterator with the given transformer
-     * and adds them to the outputCollection.
-     * <p/>
-     * If the input iterator or transformer is null, there is no change to the
-     * output collection.
-     *
-     * @param inputIterator the iterator to get the input from, may be null
-     * @param transformer the transformer to use, may be null
-     * @param predicate the predicate to use, may be null
-     * @param outputCollection the collection to output into, may not be null if the inputCollection
-     * and transformer are not null
-     * @param <I> the type of object in the input collection
-     * @param <O> the type of object in the output collection
-     * @param <R> the output type of the transformer - this extends O.
-     * @return the outputCollection with the transformed input added
-     * @throws NullPointerException if the output collection is null and both, inputCollection and
-     * transformer are not null
-     */
-    public static <I, O, R extends Collection<? super O>> R collect(final Iterator<? extends I> inputIterator,
-            final Transformer<? super I, ? extends O> transformer, final Predicate<? super I> predicate,
-            final R outputCollection) {
-
-        if (inputIterator != null && transformer != null) {
-            while (inputIterator.hasNext()) {
-                final I item = inputIterator.next();
-                final O value = transformer.transform(item);
-                if (predicate == null || predicate.evaluate(item)) {
-                    outputCollection.add(value);
-                }
-            }
-        }
-        return outputCollection;
-    }
-
-    /**
-     * Gets elements in the input collection that match the predicate.
-     * <p/>
-     * A <code>null</code> collection or predicate matches no elements.
-     *
-     * @param <C> the type of object the {@link Iterable} contains
-     * @param input the {@link Iterable} to get the input from, may be null
-     * @param predicate the predicate to use, may be null
-     * @return the matches for the predicate in the collection
-     */
-    public static <C> Collection<C> find(final Iterable<C> input, final Predicate<? super C> predicate) {
-        Set<C> result = SetUtils.predicatedSet(new HashSet<C>(), predicate);
-        if (input != null && predicate != null) {
-            for (final C o : input) {
-                if (predicate.evaluate(o)) {
-                    result.add(o);
-                }
-            }
-        }
-        return SetUtils.unmodifiableSet(result);
-    }
-
-    private CollectionUtils2() {
-        // private constructor for static utility class
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
deleted file mode 100644
index aa5d442..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
+++ /dev/null
@@ -1,111 +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.mod;
-
-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.XmlType;
-import org.apache.syncope.common.lib.AbstractBaseBean;
-
-/**
- * Abstract base class for objects that can have attributes removed, added or updated.
- *
- * Attributes can be regular attributes, derived attributes, virtual attributes and resources.
- */
-@XmlType
-public abstract class AbstractAttributableMod extends AbstractBaseBean {
-
-    private static final long serialVersionUID = 3241118574016303198L;
-
-    protected long key;
-
-    protected final Set<AttrMod> plainAttrsToUpdate = new HashSet<>();
-
-    protected final Set<String> plainAttrsToRemove = new HashSet<>();
-
-    protected final Set<String> derAttrsToAdd = new HashSet<>();
-
-    protected final Set<String> derAttrsToRemove = new HashSet<>();
-
-    protected final Set<AttrMod> virAttrsToUpdate = new HashSet<>();
-
-    protected final Set<String> virAttrsToRemove = new HashSet<>();
-
-    public long getKey() {
-        return key;
-    }
-
-    public void setKey(final long key) {
-        this.key = key;
-    }
-
-    @XmlElementWrapper(name = "plainAttrsToRemove")
-    @XmlElement(name = "attribute")
-    @JsonProperty("plainAttrsToRemove")
-    public Set<String> getPlainAttrsToRemove() {
-        return plainAttrsToRemove;
-    }
-
-    @XmlElementWrapper(name = "plainAttrsToUpdate")
-    @XmlElement(name = "attributeMod")
-    @JsonProperty("plainAttrsToUpdate")
-    public Set<AttrMod> getPlainAttrsToUpdate() {
-        return plainAttrsToUpdate;
-    }
-
-    @XmlElementWrapper(name = "derAttrsToAdd")
-    @XmlElement(name = "attribute")
-    @JsonProperty("derAttrsToAdd")
-    public Set<String> getDerAttrsToAdd() {
-        return derAttrsToAdd;
-    }
-
-    @XmlElementWrapper(name = "derAttrsToRemove")
-    @XmlElement(name = "attribute")
-    @JsonProperty("derAttrsToRemove")
-    public Set<String> getDerAttrsToRemove() {
-        return derAttrsToRemove;
-    }
-
-    @XmlElementWrapper(name = "virAttrsToRemove")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrsToRemove")
-    public Set<String> getVirAttrsToRemove() {
-        return virAttrsToRemove;
-    }
-
-    @XmlElementWrapper(name = "virAttrsToUpdate")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrsToUpdate")
-    public Set<AttrMod> getVirAttrsToUpdate() {
-        return virAttrsToUpdate;
-    }
-
-    /**
-     * @return true is all backing Sets are empty.
-     */
-    public boolean isEmpty() {
-        return plainAttrsToUpdate.isEmpty() && plainAttrsToRemove.isEmpty()
-                && derAttrsToAdd.isEmpty() && derAttrsToRemove.isEmpty()
-                && virAttrsToUpdate.isEmpty() && virAttrsToRemove.isEmpty();
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractSubjectMod.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractSubjectMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractSubjectMod.java
deleted file mode 100644
index 3671785..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractSubjectMod.java
+++ /dev/null
@@ -1,66 +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.mod;
-
-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.XmlType;
-
-@XmlType
-public abstract class AbstractSubjectMod extends AbstractAttributableMod {
-
-    private static final long serialVersionUID = -6404459635536484024L;
-
-    private String realm;
-
-    protected final Set<String> resourcesToAdd = new HashSet<>();
-
-    protected final Set<String> resourcesToRemove = new HashSet<>();
-
-    public String getRealm() {
-        return realm;
-    }
-
-    public void setRealm(final String realm) {
-        this.realm = realm;
-    }
-
-    @XmlElementWrapper(name = "resourcesToAdd")
-    @XmlElement(name = "resource")
-    @JsonProperty("resourcesToAdd")
-    public Set<String> getResourcesToAdd() {
-        return resourcesToAdd;
-    }
-
-    @XmlElementWrapper(name = "resourcesToRemove")
-    @XmlElement(name = "resource")
-    @JsonProperty("resourcesToRemove")
-    public Set<String> getResourcesToRemove() {
-        return resourcesToRemove;
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return super.isEmpty() && resourcesToAdd.isEmpty() && resourcesToRemove.isEmpty();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AnyMod.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AnyMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AnyMod.java
new file mode 100644
index 0000000..ec508c9
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AnyMod.java
@@ -0,0 +1,135 @@
+/*
+ * 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.HashSet;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlType
+public abstract class AnyMod extends AbstractBaseBean {
+
+    private static final long serialVersionUID = 7366724481786360591L;
+
+    protected long key;
+
+    private String realm;
+
+    protected final Set<AttrMod> plainAttrsToUpdate = new HashSet<>();
+
+    protected final Set<String> plainAttrsToRemove = new HashSet<>();
+
+    protected final Set<String> derAttrsToAdd = new HashSet<>();
+
+    protected final Set<String> derAttrsToRemove = new HashSet<>();
+
+    protected final Set<AttrMod> virAttrsToUpdate = new HashSet<>();
+
+    protected final Set<String> virAttrsToRemove = new HashSet<>();
+
+    protected final Set<String> resourcesToAdd = new HashSet<>();
+
+    protected final Set<String> resourcesToRemove = new HashSet<>();
+
+    public long getKey() {
+        return key;
+    }
+
+    public void setKey(final long key) {
+        this.key = key;
+    }
+
+    public String getRealm() {
+        return realm;
+    }
+
+    public void setRealm(final String realm) {
+        this.realm = realm;
+    }
+
+    @XmlElementWrapper(name = "plainAttrsToRemove")
+    @XmlElement(name = "attribute")
+    @JsonProperty("plainAttrsToRemove")
+    public Set<String> getPlainAttrsToRemove() {
+        return plainAttrsToRemove;
+    }
+
+    @XmlElementWrapper(name = "plainAttrsToUpdate")
+    @XmlElement(name = "attributeMod")
+    @JsonProperty("plainAttrsToUpdate")
+    public Set<AttrMod> getPlainAttrsToUpdate() {
+        return plainAttrsToUpdate;
+    }
+
+    @XmlElementWrapper(name = "derAttrsToAdd")
+    @XmlElement(name = "attribute")
+    @JsonProperty("derAttrsToAdd")
+    public Set<String> getDerAttrsToAdd() {
+        return derAttrsToAdd;
+    }
+
+    @XmlElementWrapper(name = "derAttrsToRemove")
+    @XmlElement(name = "attribute")
+    @JsonProperty("derAttrsToRemove")
+    public Set<String> getDerAttrsToRemove() {
+        return derAttrsToRemove;
+    }
+
+    @XmlElementWrapper(name = "virAttrsToRemove")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrsToRemove")
+    public Set<String> getVirAttrsToRemove() {
+        return virAttrsToRemove;
+    }
+
+    @XmlElementWrapper(name = "virAttrsToUpdate")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrsToUpdate")
+    public Set<AttrMod> getVirAttrsToUpdate() {
+        return virAttrsToUpdate;
+    }
+
+    @XmlElementWrapper(name = "resourcesToAdd")
+    @XmlElement(name = "resource")
+    @JsonProperty("resourcesToAdd")
+    public Set<String> getResourcesToAdd() {
+        return resourcesToAdd;
+    }
+
+    @XmlElementWrapper(name = "resourcesToRemove")
+    @XmlElement(name = "resource")
+    @JsonProperty("resourcesToRemove")
+    public Set<String> getResourcesToRemove() {
+        return resourcesToRemove;
+    }
+
+    /**
+     * @return true is all backing collections are empty.
+     */
+    public boolean isEmpty() {
+        return plainAttrsToUpdate.isEmpty() && plainAttrsToRemove.isEmpty()
+                && derAttrsToAdd.isEmpty() && derAttrsToRemove.isEmpty()
+                && virAttrsToUpdate.isEmpty() && virAttrsToRemove.isEmpty()
+                && resourcesToAdd.isEmpty() && resourcesToRemove.isEmpty();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AnyObjectMod.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AnyObjectMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AnyObjectMod.java
new file mode 100644
index 0000000..b51a67b
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AnyObjectMod.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.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;
+
+@XmlRootElement(name = "anyObjectMod")
+@XmlType
+public class AnyObjectMod extends AnyMod {
+
+    private static final long serialVersionUID = -3474517624611170097L;
+
+    private final List<Long> relationshipsToAdd = new ArrayList<>();
+
+    private final List<Long> relationshipsToRemove = new ArrayList<>();
+
+    private final List<Long> membershipsToAdd = new ArrayList<>();
+
+    private final List<Long> membershipsToRemove = new ArrayList<>();
+
+    @XmlElementWrapper(name = "relationshipsToAdd")
+    @XmlElement(name = "relationship")
+    @JsonProperty("relationshipsToAdd")
+    public List<Long> getRelationshipsToAdd() {
+        return relationshipsToAdd;
+    }
+
+    @XmlElementWrapper(name = "urelationshipsToRemove")
+    @XmlElement(name = "urelationship")
+    @JsonProperty("urelationshipsToRemove")
+    public List<Long> getRelationshipsToRemove() {
+        return relationshipsToRemove;
+    }
+
+    @XmlElementWrapper(name = "membershipsToAdd")
+    @XmlElement(name = "membership")
+    @JsonProperty("membershipsToAdd")
+    public List<Long> getMembershipsToAdd() {
+        return membershipsToAdd;
+    }
+
+    @XmlElementWrapper(name = "membershipsToRemove")
+    @XmlElement(name = "membership")
+    @JsonProperty("membershipsToRemove")
+    public List<Long> getMembershipsToRemove() {
+        return membershipsToRemove;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java
index 5620fa1..3c948ea 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/GroupMod.java
@@ -19,17 +19,12 @@
 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 = "groupMod")
 @XmlType
-public class GroupMod extends AbstractSubjectMod {
+public class GroupMod extends AnyMod {
 
     private static final long serialVersionUID = 7455805264680210747L;
 
@@ -39,31 +34,9 @@ public class GroupMod extends AbstractSubjectMod {
 
     private ReferenceMod groupOwner;
 
-    private boolean modGAttrTemplates;
+    private String aDynMembershipCond;
 
-    private final List<String> gPlainAttrTemplates = new ArrayList<>();
-
-    private boolean modGDerAttrTemplates;
-
-    private final List<String> gDerAttrTemplates = new ArrayList<>();
-
-    private boolean modGVirAttrTemplates;
-
-    private final List<String> gVirAttrTemplates = 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 String dynMembershipCond;
+    private String uDynMembershipCond;
 
     public String getName() {
         return name;
@@ -89,110 +62,26 @@ public class GroupMod extends AbstractSubjectMod {
         this.groupOwner = groupOwner;
     }
 
-    public boolean isModGAttrTemplates() {
-        return modGAttrTemplates;
-    }
-
-    public void setModGAttrTemplates(final boolean modGAttrTemplates) {
-        this.modGAttrTemplates = modGAttrTemplates;
-    }
-
-    @XmlElementWrapper(name = "gPlainAttrTemplates")
-    @XmlElement(name = "gAttrTemplate")
-    @JsonProperty("gPlainAttrTemplates")
-    public List<String> getGPlainAttrTemplates() {
-        return gPlainAttrTemplates;
-    }
-
-    public boolean isModGDerAttrTemplates() {
-        return modGDerAttrTemplates;
-    }
-
-    public void setModGDerAttrTemplates(final boolean modGDerAttrTemplates) {
-        this.modGDerAttrTemplates = modGDerAttrTemplates;
-    }
-
-    @XmlElementWrapper(name = "gDerAttrTemplates")
-    @XmlElement(name = "gDerAttrTemplate")
-    @JsonProperty("gDerAttrTemplates")
-    public List<String> getGDerAttrTemplates() {
-        return gDerAttrTemplates;
-    }
-
-    public boolean isModGVirAttrTemplates() {
-        return modGVirAttrTemplates;
-    }
-
-    public void setModGVirAttrTemplates(final boolean modGVirAttrTemplates) {
-        this.modGVirAttrTemplates = modGVirAttrTemplates;
-    }
-
-    @XmlElementWrapper(name = "gVirAttrTemplates")
-    @XmlElement(name = "gVirAttrTemplate")
-    @JsonProperty("gVirAttrTemplates")
-    public List<String> getGVirAttrTemplates() {
-        return gVirAttrTemplates;
-    }
-
-    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;
+    public String getADynMembershipCond() {
+        return aDynMembershipCond;
     }
 
-    @XmlElementWrapper(name = "mVirAttrTemplates")
-    @XmlElement(name = "mVirAttrTemplate")
-    @JsonProperty("mVirAttrTemplates")
-    public List<String> getMVirAttrTemplates() {
-        return mVirAttrTemplates;
+    public void setADynMembershipCond(final String aDynMembershipCond) {
+        this.aDynMembershipCond = aDynMembershipCond;
     }
 
-    public String getDynMembershipCond() {
-        return dynMembershipCond;
+    public String getUDynMembershipCond() {
+        return uDynMembershipCond;
     }
 
-    public void setDynMembershipCond(final String dynMembershipCond) {
-        this.dynMembershipCond = dynMembershipCond;
+    public void setUDynMembershipCond(final String uDynMembershipCond) {
+        this.uDynMembershipCond = uDynMembershipCond;
     }
 
     @JsonIgnore
     @Override
     public boolean isEmpty() {
         return super.isEmpty() && name == null && userOwner == null && groupOwner == null
-                && gPlainAttrTemplates.isEmpty() && gDerAttrTemplates.isEmpty() && gVirAttrTemplates.isEmpty()
-                && mPlainAttrTemplates.isEmpty() && mDerAttrTemplates.isEmpty() && mVirAttrTemplates.isEmpty()
-                && dynMembershipCond == null;
+                && aDynMembershipCond == null && uDynMembershipCond == null;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
deleted file mode 100644
index d414011..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
+++ /dev/null
@@ -1,46 +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.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 group;
-
-    public long getGroup() {
-        return group;
-    }
-
-    public void setGroup(final long group) {
-        this.group = group;
-    }
-
-    @JsonIgnore
-    @Override
-    public boolean isEmpty() {
-        return super.isEmpty() && group == 0;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
index fe63b63..fe09eeb 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
@@ -20,7 +20,9 @@ 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.HashSet;
+import java.util.List;
 import java.util.Set;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
@@ -29,7 +31,7 @@ import javax.xml.bind.annotation.XmlType;
 
 @XmlRootElement(name = "userMod")
 @XmlType
-public class UserMod extends AbstractSubjectMod {
+public class UserMod extends AnyMod {
 
     private static final long serialVersionUID = 3081848906558106204L;
 
@@ -37,13 +39,17 @@ public class UserMod extends AbstractSubjectMod {
 
     private String password;
 
-    private final Set<Long> rolesToAdd = new HashSet<>();
+    private final List<Long> relationshipsToAdd = new ArrayList<>();
 
-    private final Set<Long> rolesToRemove = new HashSet<>();
+    private final List<Long> relationshipsToRemove = new ArrayList<>();
+
+    private final List<Long> membershipsToAdd = new ArrayList<>();
+
+    private final List<Long> membershipsToRemove = new ArrayList<>();
 
-    private final Set<MembershipMod> membershipsToAdd = new HashSet<>();
+    private final Set<Long> rolesToAdd = new HashSet<>();
 
-    private final Set<Long> membershipsToRemove = new HashSet<>();
+    private final Set<Long> rolesToRemove = new HashSet<>();
 
     private StatusMod pwdPropRequest;
 
@@ -67,34 +73,48 @@ public class UserMod extends AbstractSubjectMod {
         this.password = password;
     }
 
-    @XmlElementWrapper(name = "rolesToAdd")
-    @XmlElement(name = "role")
-    @JsonProperty("rolesToAdd")
-    public Set<Long> getRolesToAdd() {
-        return rolesToAdd;
+    @XmlElementWrapper(name = "relationshipsToAdd")
+    @XmlElement(name = "relationship")
+    @JsonProperty("relationshipsToAdd")
+    public List<Long> getRelationshipsToAdd() {
+        return relationshipsToAdd;
     }
 
-    @XmlElementWrapper(name = "rolesToRemove")
-    @XmlElement(name = "role")
-    @JsonProperty("rolesToRemove")
-    public Set<Long> getRolesToRemove() {
-        return rolesToRemove;
+    @XmlElementWrapper(name = "urelationshipsToRemove")
+    @XmlElement(name = "urelationship")
+    @JsonProperty("urelationshipsToRemove")
+    public List<Long> getRelationshipsToRemove() {
+        return relationshipsToRemove;
     }
 
     @XmlElementWrapper(name = "membershipsToAdd")
     @XmlElement(name = "membership")
     @JsonProperty("membershipsToAdd")
-    public Set<MembershipMod> getMembershipsToAdd() {
+    public List<Long> getMembershipsToAdd() {
         return membershipsToAdd;
     }
 
     @XmlElementWrapper(name = "membershipsToRemove")
     @XmlElement(name = "membership")
     @JsonProperty("membershipsToRemove")
-    public Set<Long> getMembershipsToRemove() {
+    public List<Long> getMembershipsToRemove() {
         return membershipsToRemove;
     }
 
+    @XmlElementWrapper(name = "rolesToAdd")
+    @XmlElement(name = "role")
+    @JsonProperty("rolesToAdd")
+    public Set<Long> getRolesToAdd() {
+        return rolesToAdd;
+    }
+
+    @XmlElementWrapper(name = "rolesToRemove")
+    @XmlElement(name = "role")
+    @JsonProperty("rolesToRemove")
+    public Set<Long> getRolesToRemove() {
+        return rolesToRemove;
+    }
+
     public StatusMod getPwdPropRequest() {
         return pwdPropRequest;
     }
@@ -125,8 +145,6 @@ public class UserMod extends AbstractSubjectMod {
         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/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/report/AbstractAnyReportletConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/report/AbstractAnyReportletConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/report/AbstractAnyReportletConf.java
new file mode 100644
index 0000000..e6949b6
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/report/AbstractAnyReportletConf.java
@@ -0,0 +1,84 @@
+/*
+ * 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.report;
+
+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.XmlType;
+import org.apache.syncope.common.lib.annotation.FormAttributeField;
+import org.apache.syncope.common.lib.types.IntMappingType;
+
+@XmlType
+public abstract class AbstractAnyReportletConf extends AbstractReportletConf {
+
+    private static final long serialVersionUID = -5388597116592877789L;
+
+    @FormAttributeField(userSearch = true)
+    protected String matchingCond;
+
+    @FormAttributeField(schema = IntMappingType.UserPlainSchema)
+    protected final List<String> plainAttrs = new ArrayList<>();
+
+    @FormAttributeField(schema = IntMappingType.UserDerivedSchema)
+    protected final List<String> derAttrs = new ArrayList<>();
+
+    @FormAttributeField(schema = IntMappingType.UserVirtualSchema)
+    protected final List<String> virAttrs = new ArrayList<>();
+
+    public AbstractAnyReportletConf() {
+        super();
+    }
+
+    public AbstractAnyReportletConf(final String name) {
+        super(name);
+    }
+
+    public String getMatchingCond() {
+        return matchingCond;
+    }
+
+    public void setMatchingCond(final String matchingCond) {
+        this.matchingCond = matchingCond;
+    }
+
+    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("plainAttrs")
+    public List<String> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @XmlElementWrapper(name = "derAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("derAttrs")
+    public List<String> getDerAttrs() {
+        return derAttrs;
+    }
+
+    @XmlElementWrapper(name = "virAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrs")
+    public List<String> getVirAttrs() {
+        return virAttrs;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/report/AbstractSubjectReportletConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/report/AbstractSubjectReportletConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/report/AbstractSubjectReportletConf.java
deleted file mode 100644
index 8b3da49..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/report/AbstractSubjectReportletConf.java
+++ /dev/null
@@ -1,84 +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.report;
-
-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.XmlType;
-import org.apache.syncope.common.lib.annotation.FormAttributeField;
-import org.apache.syncope.common.lib.types.IntMappingType;
-
-@XmlType
-public abstract class AbstractSubjectReportletConf extends AbstractReportletConf {
-
-    private static final long serialVersionUID = -5388597116592877789L;
-
-    @FormAttributeField(userSearch = true)
-    protected String matchingCond;
-
-    @FormAttributeField(schema = IntMappingType.UserPlainSchema)
-    protected final List<String> plainAttrs = new ArrayList<>();
-
-    @FormAttributeField(schema = IntMappingType.UserDerivedSchema)
-    protected final List<String> derAttrs = new ArrayList<>();
-
-    @FormAttributeField(schema = IntMappingType.UserVirtualSchema)
-    protected final List<String> virAttrs = new ArrayList<>();
-
-    public AbstractSubjectReportletConf() {
-        super();
-    }
-
-    public AbstractSubjectReportletConf(final String name) {
-        super(name);
-    }
-
-    public String getMatchingCond() {
-        return matchingCond;
-    }
-
-    public void setMatchingCond(final String matchingCond) {
-        this.matchingCond = matchingCond;
-    }
-
-    @XmlElementWrapper(name = "plainAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("plainAttrs")
-    public List<String> getPlainAttrs() {
-        return plainAttrs;
-    }
-
-    @XmlElementWrapper(name = "derAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("derAttrs")
-    public List<String> getDerAttrs() {
-        return derAttrs;
-    }
-
-    @XmlElementWrapper(name = "virAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrs")
-    public List<String> getVirAttrs() {
-        return virAttrs;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java
index de7bff3..861795c 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/report/GroupReportletConf.java
@@ -29,7 +29,7 @@ import javax.xml.bind.annotation.XmlType;
 
 @XmlRootElement(name = "groupReportletConf")
 @XmlType
-public class GroupReportletConf extends AbstractSubjectReportletConf {
+public class GroupReportletConf extends AbstractAnyReportletConf {
 
     private static final long serialVersionUID = -8488503068032439699L;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java b/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
index ce783ff..72daf7b 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
@@ -29,7 +29,7 @@ import javax.xml.bind.annotation.XmlType;
 
 @XmlRootElement(name = "userReportletConf")
 @XmlType
-public class UserReportletConf extends AbstractSubjectReportletConf {
+public class UserReportletConf extends AbstractAnyReportletConf {
 
     @XmlEnum
     @XmlType(name = "userReportletConfFeature")

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java b/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java
index 7a27a2b..9a68a8d 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java
@@ -25,10 +25,11 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import org.apache.commons.lang3.ArrayUtils;
-import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.UserTO;
-import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
 
 public final class SearchableFields {
 
@@ -36,17 +37,19 @@ public final class SearchableFields {
         "serialVersionUID", "password"
     };
 
-    public static List<String> get(final SubjectType subjectType) {
-        return get(subjectType == SubjectType.USER
+    public static List<String> get(final AnyTypeKind anyTypeKind) {
+        return get(anyTypeKind == AnyTypeKind.USER
                 ? UserTO.class
-                : GroupTO.class);
+                : anyTypeKind == AnyTypeKind.GROUP
+                        ? GroupTO.class
+                        : AnyObjectTO.class);
     }
 
-    public static List<String> get(final Class<? extends AbstractAttributableTO> attributableRef) {
+    public static List<String> get(final Class<? extends AnyTO> anyRef) {
         final List<String> fieldNames = new ArrayList<>();
 
         // loop on class and all superclasses searching for field
-        Class<?> clazz = attributableRef;
+        Class<?> clazz = anyRef;
         while (clazz != null && clazz != Object.class) {
             for (Field field : clazz.getDeclaredFields()) {
                 if (!ArrayUtils.contains(ATTRIBUTES_NOTINCLUDED, field.getName())

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java
deleted file mode 100644
index c724bb0..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java
+++ /dev/null
@@ -1,85 +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.to;
-
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlType
-public abstract class AbstractAttributableTO extends ConnObjectTO {
-
-    private static final long serialVersionUID = 4083884098736820255L;
-
-    private long key;
-
-    private final Set<AttrTO> derAttrs = new LinkedHashSet<>();
-
-    private final Set<AttrTO> virAttrs = new LinkedHashSet<>();
-
-    public long getKey() {
-        return key;
-    }
-
-    public void setKey(final long key) {
-        this.key = key;
-    }
-
-    @XmlElementWrapper(name = "derAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("derAttrs")
-    public Set<AttrTO> getDerAttrs() {
-        return derAttrs;
-    }
-
-    @JsonIgnore
-    public Map<String, AttrTO> getDerAttrMap() {
-        Map<String, AttrTO> result = new HashMap<>(derAttrs.size());
-        for (AttrTO attributeTO : derAttrs) {
-            result.put(attributeTO.getSchema(), attributeTO);
-        }
-
-        return Collections.unmodifiableMap(result);
-    }
-
-    @XmlElementWrapper(name = "virAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrs")
-    public Set<AttrTO> getVirAttrs() {
-        return virAttrs;
-    }
-
-    @JsonIgnore
-    public Map<String, AttrTO> getVirAttrMap() {
-        Map<String, AttrTO> result = new HashMap<>(virAttrs.size());
-        for (AttrTO attributeTO : virAttrs) {
-            result.put(attributeTO.getSchema(), attributeTO);
-        }
-
-        return Collections.unmodifiableMap(result);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractSubjectTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractSubjectTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractSubjectTO.java
deleted file mode 100644
index ae21f12..0000000
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractSubjectTO.java
+++ /dev/null
@@ -1,63 +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.to;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
-import javax.xml.bind.annotation.XmlType;
-
-@XmlType
-public abstract class AbstractSubjectTO extends AbstractAttributableTO {
-
-    private static final long serialVersionUID = 114668706977919206L;
-
-    private String realm;
-
-    private final Set<String> resources = new HashSet<>();
-
-    private final List<PropagationStatus> propagationStatusTOs = new ArrayList<>();
-
-    public String getRealm() {
-        return realm;
-    }
-
-    public void setRealm(final String realm) {
-        this.realm = realm;
-    }
-
-    @XmlElementWrapper(name = "resources")
-    @XmlElement(name = "resource")
-    @JsonProperty("resources")
-    public Set<String> getResources() {
-        return resources;
-    }
-
-    @XmlElementWrapper(name = "propagationStatuses")
-    @XmlElement(name = "propagationStatus")
-    @JsonProperty("propagationStatuses")
-    public List<PropagationStatus> getPropagationStatusTOs() {
-        return propagationStatusTOs;
-    }
-
-}