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 2018/11/09 14:04:39 UTC

[syncope] branch 2_1_X updated (bbf47be -> 62d04f2)

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a change to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git.


    from bbf47be  Upgrading Tomcat
     new 540c8cc  [SYNCOPE-1395] Preliminary changes
     new 62d04f2  [SYNCOPE-1395] persistence-jpa-pgjsonb module, passing all persistence-jpa's unit tests

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../core/persistence/api/dao/AllowedSchemas.java   |    1 -
 .../core/persistence/api/dao/AnyObjectDAO.java     |    3 +
 .../core/persistence/api/dao/PlainAttrDAO.java     |   10 +-
 .../persistence/api/dao/PlainAttrValueDAO.java     |   17 +-
 .../syncope/core/persistence/api/dao/UserDAO.java  |    3 +
 .../core/persistence/api/entity/EntityFactory.java |   16 +
 .../persistence/api/entity/GroupableRelatable.java |    3 +-
 core/persistence-jpa-pgjsonb/pom.xml               |  302 +++
 .../core/persistence/api/dao/PGAnyDAO.java}        |   15 +-
 .../core/persistence/jpa/dao/PGJPAAnyDAO.java      |  355 +++
 .../persistence/jpa/dao/PGJPAAnyObjectDAO.java     |   81 +
 .../persistence/jpa/dao/PGJPAAnySearchDAO.java     |  231 ++
 .../core/persistence/jpa/dao/PGJPAGroupDAO.java    |   81 +
 .../persistence/jpa/dao/PGJPAPlainAttrDAO.java}    |   18 +-
 .../jpa/dao/PGJPAPlainAttrValueDAO.java            |   46 +
 .../persistence/jpa/dao/PGJPAPlainSchemaDAO.java}  |   20 +-
 .../core/persistence/jpa/dao/PGJPAUserDAO.java     |   89 +
 .../core/persistence/jpa/entity/PGJPAAny.java}     |   15 +-
 .../persistence/jpa/entity/PGJPAEntityFactory.java |  132 ++
 .../jpa/entity/PGJPAEntityListener.java            |   49 +
 .../core/persistence/jpa/entity/PGPlainAttr.java}  |   12 +-
 .../jpa/entity/anyobject/PGAPlainAttr.java         |  196 ++
 .../entity/anyobject/PGAPlainAttrUniqueValue.java  |   60 +
 .../jpa/entity/anyobject/PGAPlainAttrValue.java    |   48 +
 .../jpa/entity/anyobject/PGJPAAnyObject.java       |   97 +
 .../entity/anyobject/PGJPAAnyObjectListener.java   |   49 +
 .../persistence/jpa/entity/conf/PGCPlainAttr.java  |  163 ++
 .../jpa/entity/conf/PGCPlainAttrUniqueValue.java   |   60 +
 .../jpa/entity/conf/PGCPlainAttrValue.java         |   48 +
 .../persistence/jpa/entity/conf/PGJPAConf.java     |   85 +
 .../jpa/entity/conf/PGJPAConfListener.java         |   49 +
 .../persistence/jpa/entity/group/PGGPlainAttr.java |  163 ++
 .../jpa/entity/group/PGGPlainAttrUniqueValue.java  |   60 +
 .../jpa/entity/group/PGGPlainAttrValue.java        |   48 +
 .../persistence/jpa/entity/group/PGJPAGroup.java   |   87 +
 .../jpa/entity/group/PGJPAGroupListener.java       |   49 +
 .../persistence/jpa/entity/user/PGJPAUser.java     |   90 +
 .../jpa/entity/user/PGJPAUserListener.java         |   49 +
 .../persistence/jpa/entity/user/PGUPlainAttr.java  |  196 ++
 .../jpa/entity/user/PGUPlainAttrUniqueValue.java   |   60 +
 .../jpa/entity/user/PGUPlainAttrValue.java         |   48 +
 .../jpa/validation/entity/PGJPAAnyCheck.java}      |   23 +-
 .../jpa/validation/entity/PGJPAAnyValidator.java   |   45 +
 .../main/resources/META-INF/spring-orm-pgjsonb.xml |   37 +
 .../src/main/resources/domains/Master.properties}  |   15 +-
 .../src/main/resources/indexes.xml                 |   63 +
 .../src/main/resources/persistence.properties      |    9 +-
 .../src/main/resources/views.xml                   |  154 ++
 .../src/test/resources/domains/MasterContent.xml   | 2410 ++++++++++++++++++++
 .../src/test/resources/persistenceTest.xml}        |   35 +-
 .../src/test/resources/simplelogger.properties     |    0
 .../core/persistence/jpa/dao/AbstractAnyDAO.java   |    8 +-
 .../persistence/jpa/dao/AbstractAnySearchDAO.java  |   12 +-
 .../core/persistence/jpa/dao/JPAAnyObjectDAO.java  |   23 +-
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  |    2 +-
 .../core/persistence/jpa/dao/JPAConfDAO.java       |   10 +-
 .../core/persistence/jpa/dao/JPADynRealmDAO.java   |   10 +-
 .../core/persistence/jpa/dao/JPAGroupDAO.java      |   31 +-
 .../core/persistence/jpa/dao/JPAPlainAttrDAO.java  |   19 +-
 .../persistence/jpa/dao/JPAPlainAttrValueDAO.java  |   55 +-
 .../persistence/jpa/dao/JPAPlainSchemaDAO.java     |   29 +-
 .../jpa/dao/JPARelationshipTypeDAO.java            |    5 +-
 .../core/persistence/jpa/dao/JPAUserDAO.java       |   29 +-
 .../core/persistence/jpa/entity/JPAAnyUtils.java   |    6 +-
 .../persistence/jpa/entity/JPAAnyUtilsFactory.java |    1 -
 .../persistence/jpa/entity/JPAEntityFactory.java   |   29 +-
 .../jpa/entity/anyobject/JPAAnyObject.java         |    6 +
 .../core/persistence/jpa/entity/conf/JPAConf.java  |    4 +-
 .../persistence/jpa/entity/group/JPAGroup.java     |    3 +-
 .../jpa/entity/resource/AbstractAnyTemplate.java   |    7 +-
 .../core/persistence/jpa/entity/user/JPAUser.java  |    6 +
 .../jpa/validation/entity/AnyValidator.java        |    8 +-
 .../jpa/validation/entity/PlainAttrValidator.java  |   27 +-
 .../validation/entity/PlainAttrValueValidator.java |   37 +-
 .../src/main/resources/persistence.properties      |    7 +
 .../src/main/resources/persistenceContext.xml      |    7 +
 .../syncope/core/persistence/jpa/AbstractTest.java |   12 +
 .../core/persistence/jpa/inner/ConfTest.java       |   11 +-
 .../persistence/jpa/inner/MultitenancyTest.java    |    2 +
 .../core/persistence/jpa/inner/PlainAttrTest.java  |   50 +-
 .../persistence/jpa/inner/PlainSchemaTest.java     |    2 +
 .../core/persistence/jpa/inner/UserTest.java       |   31 +-
 .../core/persistence/jpa/outer/ConfTest.java       |   11 +-
 .../core/persistence/jpa/outer/GroupTest.java      |   14 +-
 .../core/persistence/jpa/outer/PlainAttrTest.java  |   40 +-
 .../persistence/jpa/outer/PlainSchemaTest.java     |   10 +-
 .../core/persistence/jpa/outer/UserTest.java       |   16 +-
 .../jpa/outer/XMLContentExporterTest.java          |   10 +-
 core/pom.xml                                       |    1 +
 .../java/data/AbstractAnyDataBinder.java           |   10 +-
 .../java/data/AnyObjectDataBinderImpl.java         |    2 +-
 .../provisioning/java/data/UserDataBinderImpl.java |    2 +-
 .../core/src/main/resources/persistence.properties |    7 +
 .../src/main/resources/persistence.properties      |    7 +
 .../resources/elasticsearch/persistence.properties |    7 +
 95 files changed, 6296 insertions(+), 325 deletions(-)
 create mode 100644 core/persistence-jpa-pgjsonb/pom.xml
 copy core/{persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrValueDAO.java => persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/api/dao/PGAnyDAO.java} (56%)
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnyDAO.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnyObjectDAO.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnySearchDAO.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAGroupDAO.java
 copy core/{persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java => persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainAttrDAO.java} (63%)
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainAttrValueDAO.java
 copy core/{persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java => persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainSchemaDAO.java} (62%)
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAUserDAO.java
 copy core/{persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java => persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAAny.java} (68%)
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAEntityFactory.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAEntityListener.java
 copy core/{persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java => persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGPlainAttr.java} (73%)
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttr.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttrUniqueValue.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttrValue.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGJPAAnyObject.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGJPAAnyObjectListener.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttr.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttrUniqueValue.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttrValue.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGJPAConf.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGJPAConfListener.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttr.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttrUniqueValue.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttrValue.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGJPAGroup.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGJPAGroupListener.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGJPAUser.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGJPAUserListener.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttr.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttrUniqueValue.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttrValue.java
 copy core/{persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java => persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PGJPAAnyCheck.java} (54%)
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PGJPAAnyValidator.java
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/resources/META-INF/spring-orm-pgjsonb.xml
 copy core/{persistence-jpa/src/main/resources/persistence.properties => persistence-jpa-pgjsonb/src/main/resources/domains/Master.properties} (67%)
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/resources/indexes.xml
 copy core/{persistence-jpa => persistence-jpa-pgjsonb}/src/main/resources/persistence.properties (58%)
 create mode 100644 core/persistence-jpa-pgjsonb/src/main/resources/views.xml
 create mode 100644 core/persistence-jpa-pgjsonb/src/test/resources/domains/MasterContent.xml
 copy core/{persistence-jpa/src/main/resources/persistenceContext.xml => persistence-jpa-pgjsonb/src/test/resources/persistenceTest.xml} (60%)
 copy core/{persistence-jpa => persistence-jpa-pgjsonb}/src/test/resources/simplelogger.properties (100%)


[syncope] 01/02: [SYNCOPE-1395] Preliminary changes

Posted by il...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 540c8cc94729818e681b93c60f69e38ac5490cc8
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Thu Nov 8 10:30:38 2018 +0100

    [SYNCOPE-1395] Preliminary changes
---
 .../core/persistence/api/dao/AllowedSchemas.java   |  1 -
 .../core/persistence/api/dao/AnyObjectDAO.java     |  3 ++
 .../core/persistence/api/dao/PlainAttrDAO.java     | 10 ++--
 .../persistence/api/dao/PlainAttrValueDAO.java     | 17 +++----
 .../syncope/core/persistence/api/dao/UserDAO.java  |  3 ++
 .../core/persistence/api/entity/EntityFactory.java | 16 +++++++
 .../persistence/api/entity/GroupableRelatable.java |  3 +-
 .../core/persistence/jpa/dao/AbstractAnyDAO.java   |  8 +++-
 .../persistence/jpa/dao/AbstractAnySearchDAO.java  | 12 +----
 .../core/persistence/jpa/dao/JPAAnyObjectDAO.java  | 23 +++++----
 .../core/persistence/jpa/dao/JPAAnySearchDAO.java  |  2 +-
 .../core/persistence/jpa/dao/JPAConfDAO.java       | 10 ++--
 .../core/persistence/jpa/dao/JPADynRealmDAO.java   | 10 ++--
 .../core/persistence/jpa/dao/JPAGroupDAO.java      | 31 ++++++------
 .../core/persistence/jpa/dao/JPAPlainAttrDAO.java  | 19 +-------
 .../persistence/jpa/dao/JPAPlainAttrValueDAO.java  | 55 +++++++---------------
 .../persistence/jpa/dao/JPAPlainSchemaDAO.java     | 29 +++++++-----
 .../jpa/dao/JPARelationshipTypeDAO.java            |  5 +-
 .../core/persistence/jpa/dao/JPAUserDAO.java       | 29 +++++++-----
 .../core/persistence/jpa/entity/JPAAnyUtils.java   |  6 +--
 .../persistence/jpa/entity/JPAAnyUtilsFactory.java |  1 -
 .../persistence/jpa/entity/JPAEntityFactory.java   | 29 +++++++++++-
 .../jpa/entity/anyobject/JPAAnyObject.java         |  6 +++
 .../core/persistence/jpa/entity/conf/JPAConf.java  |  4 +-
 .../persistence/jpa/entity/group/JPAGroup.java     |  3 +-
 .../jpa/entity/resource/AbstractAnyTemplate.java   |  7 +--
 .../core/persistence/jpa/entity/user/JPAUser.java  |  6 +++
 .../jpa/validation/entity/AnyValidator.java        |  8 ++--
 .../jpa/validation/entity/PlainAttrValidator.java  | 27 +++++------
 .../validation/entity/PlainAttrValueValidator.java | 37 +++++++--------
 .../src/main/resources/persistence.properties      |  7 +++
 .../src/main/resources/persistenceContext.xml      |  7 +++
 .../syncope/core/persistence/jpa/AbstractTest.java | 12 +++++
 .../core/persistence/jpa/inner/ConfTest.java       | 11 +++--
 .../persistence/jpa/inner/MultitenancyTest.java    |  2 +
 .../core/persistence/jpa/inner/PlainAttrTest.java  | 50 ++++++++++++++++----
 .../persistence/jpa/inner/PlainSchemaTest.java     |  2 +
 .../core/persistence/jpa/inner/UserTest.java       | 31 +++++++++++-
 .../core/persistence/jpa/outer/ConfTest.java       | 11 +++--
 .../core/persistence/jpa/outer/GroupTest.java      | 14 +-----
 .../core/persistence/jpa/outer/PlainAttrTest.java  | 40 +++++++++-------
 .../persistence/jpa/outer/PlainSchemaTest.java     | 10 ++--
 .../core/persistence/jpa/outer/UserTest.java       | 16 ++-----
 .../jpa/outer/XMLContentExporterTest.java          | 10 ++--
 .../java/data/AbstractAnyDataBinder.java           | 10 ++--
 .../java/data/AnyObjectDataBinderImpl.java         |  2 +-
 .../provisioning/java/data/UserDataBinderImpl.java |  2 +-
 .../core/src/main/resources/persistence.properties |  7 +++
 .../src/main/resources/persistence.properties      |  7 +++
 .../resources/elasticsearch/persistence.properties |  7 +++
 50 files changed, 406 insertions(+), 272 deletions(-)

diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
index 54f5e51..aa3eee1 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
@@ -99,6 +99,5 @@ public class AllowedSchemas<S extends Schema> {
         public boolean test(final S object) {
             return object.getKey().equals(schema);
         }
-
     }
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
index f8f05f9..6fb8d79 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.Relationship;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
@@ -44,6 +45,8 @@ public interface AnyObjectDAO extends AnyDAO<AnyObject> {
 
     AnyObject findByName(String name);
 
+    AMembership findMembership(String key);
+
     List<Group> findDynGroups(String key);
 
     List<Relationship<Any<?>, AnyObject>> findAllRelationships(AnyObject anyObject);
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java
index 204aade..bce54f2 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrDAO.java
@@ -22,9 +22,11 @@ import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 
 public interface PlainAttrDAO extends DAO<PlainAttr<?>> {
 
-    <T extends PlainAttr<?>> T find(String key, Class<T> reference);
-
-    <T extends PlainAttr<?>> void delete(String key, Class<T> reference);
-
+    /**
+     * Deletes the given plain attribute and removes it from its owner.
+     *
+     * @param <T> actual plain attr class
+     * @param attr plain attribute
+     */
     <T extends PlainAttr<?>> void delete(T attr);
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrValueDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrValueDAO.java
index 26bfeaa..ec980d8 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrValueDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PlainAttrValueDAO.java
@@ -18,16 +18,17 @@
  */
 package org.apache.syncope.core.persistence.api.dao;
 
-import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 
 public interface PlainAttrValueDAO extends DAO<PlainAttrValue> {
 
-    <T extends PlainAttrValue> T find(String key, Class<T> reference);
-
-    <T extends PlainAttrValue> List<T> findAll(Class<T> reference);
-
-    <T extends PlainAttrValue> T save(T attributeValue);
-
-    <T extends PlainAttrValue> void delete(String key, Class<T> reference);
+    /**
+     * Deletes and remove all values of the given attribute.
+     *
+     * @param attr plain attribute
+     * @param anyUtils utility
+     */
+    void deleteAll(PlainAttr<?> attr, AnyUtils anyUtils);
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
index 13d7c77..bda2a8d 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java
@@ -27,6 +27,7 @@ import org.apache.syncope.core.persistence.api.entity.Role;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 
 public interface UserDAO extends AnyDAO<User> {
@@ -41,6 +42,8 @@ public interface UserDAO extends AnyDAO<User> {
 
     List<User> findBySecurityQuestion(SecurityQuestion securityQuestion);
 
+    UMembership findMembership(String key);
+
     List<Role> findDynRoles(String key);
 
     Collection<Role> findAllRoles(User user);
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/EntityFactory.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/EntityFactory.java
index 29be9ed..a756028 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/EntityFactory.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/EntityFactory.java
@@ -18,9 +18,25 @@
  */
 package org.apache.syncope.core.persistence.api.entity;
 
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.conf.Conf;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+
 public interface EntityFactory {
 
     <E extends Entity> E newEntity(Class<E> reference);
 
     ConnPoolConf newConnPoolConf();
+
+    Class<? extends User> userClass();
+
+    Class<? extends Group> groupClass();
+
+    Class<? extends AnyObject> anyObjectClass();
+
+    Class<? extends Conf> confClass();
+
+    Class<? extends AnySearchDAO> anySearchDAOClass();
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
index dd13b4a..daa8a4c 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
@@ -83,6 +83,8 @@ public interface GroupableRelatable<
 
     boolean add(M membership);
 
+    boolean remove(M membership);
+
     Optional<? extends M> getMembership(String groupKey);
 
     List<? extends M> getMemberships();
@@ -96,5 +98,4 @@ public interface GroupableRelatable<
     Collection<? extends REL> getRelationships(RelationshipType relationshipType);
 
     List<? extends REL> getRelationships();
-
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
index 568b007..531607b 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
@@ -47,6 +47,7 @@ import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.DynRealm;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
@@ -66,13 +67,16 @@ import org.springframework.transaction.annotation.Transactional;
 public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> implements AnyDAO<A> {
 
     @Autowired
+    protected AnyUtilsFactory anyUtilsFactory;
+
+    @Autowired
     protected ApplicationEventPublisher publisher;
 
     @Autowired
-    private PlainSchemaDAO plainSchemaDAO;
+    protected PlainSchemaDAO plainSchemaDAO;
 
     @Autowired
-    private DerSchemaDAO derSchemaDAO;
+    protected DerSchemaDAO derSchemaDAO;
 
     @Autowired
     protected DynRealmDAO dynRealmDAO;
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
index 0d35ccb..2a204cc 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnySearchDAO.java
@@ -353,17 +353,7 @@ public abstract class AbstractAnySearchDAO extends AbstractDAO<Any<?>> implement
             return Collections.<T>emptyList();
         }
 
-        List<OrderByClause> effectiveOrderBy;
-        if (orderBy.isEmpty()) {
-            OrderByClause keyClause = new OrderByClause();
-            keyClause.setField("key");
-            keyClause.setDirection(OrderByClause.Direction.ASC);
-            effectiveOrderBy = Collections.singletonList(keyClause);
-        } else {
-            effectiveOrderBy = orderBy;
-        }
-
-        return doSearch(adminRealms, cond, page, itemsPerPage, effectiveOrderBy, kind);
+        return doSearch(adminRealms, cond, page, itemsPerPage, orderBy, kind);
     }
 
     @Override
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index 278434f..f4aacd2 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -44,23 +44,22 @@ import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Relationship;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.user.URelationship;
-import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAARelationship;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAnyObject;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAURelationship;
 import org.apache.syncope.core.provisioning.api.event.AnyCreatedUpdatedEvent;
 import org.apache.syncope.core.provisioning.api.event.AnyDeletedEvent;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
-@Repository
 public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObjectDAO {
 
     @Autowired
@@ -71,7 +70,7 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
 
     @Override
     protected AnyUtils init() {
-        return new JPAAnyUtilsFactory().getInstance(AnyTypeKind.ANY_OBJECT);
+        return anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT);
     }
 
     @Transactional(readOnly = true)
@@ -89,7 +88,7 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     @Override
     public Map<AnyType, Integer> countByType() {
         Query query = entityManager().createQuery(
-                "SELECT e.type, COUNT(e) AS countByType FROM  " + JPAAnyObject.class.getSimpleName() + " e "
+                "SELECT e.type, COUNT(e) AS countByType FROM  " + anyUtils().anyClass().getSimpleName() + " e "
                 + "GROUP BY e.type ORDER BY countByType DESC");
         @SuppressWarnings("unchecked")
         List<Object[]> results = query.getResultList();
@@ -105,7 +104,7 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     @Override
     public Map<String, Integer> countByRealm(final AnyType anyType) {
         Query query = entityManager().createQuery(
-                "SELECT e.realm, COUNT(e) FROM  " + JPAAnyObject.class.getSimpleName() + " e "
+                "SELECT e.realm, COUNT(e) FROM  " + anyUtils().anyClass().getSimpleName() + " e "
                 + "WHERE e.type=:type GROUP BY e.realm");
         query.setParameter("type", anyType);
 
@@ -138,7 +137,7 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     @Override
     public AnyObject findByName(final String name) {
         TypedQuery<AnyObject> query = entityManager().createQuery(
-                "SELECT e FROM " + JPAAnyObject.class.getSimpleName() + " e WHERE e.name = :name", AnyObject.class);
+                "SELECT e FROM " + anyUtils().anyClass().getSimpleName() + " e WHERE e.name = :name", AnyObject.class);
         query.setParameter("name", name);
 
         AnyObject result = null;
@@ -152,6 +151,11 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     }
 
     @Override
+    public AMembership findMembership(final String key) {
+        return entityManager().find(JPAAMembership.class, key);
+    }
+
+    @Override
     public List<Relationship<Any<?>, AnyObject>> findAllRelationships(final AnyObject anyObject) {
         List<Relationship<Any<?>, AnyObject>> result = new ArrayList<>();
 
@@ -177,14 +181,14 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     @Override
     public int count() {
         Query query = entityManager().createQuery(
-                "SELECT COUNT(e) FROM  " + JPAAnyObject.class.getSimpleName() + " e");
+                "SELECT COUNT(e) FROM  " + anyUtils().anyClass().getSimpleName() + " e");
         return ((Number) query.getSingleResult()).intValue();
     }
 
     @Override
     public List<AnyObject> findAll(final int page, final int itemsPerPage) {
         TypedQuery<AnyObject> query = entityManager().createQuery(
-                "SELECT e FROM  " + JPAAnyObject.class.getSimpleName() + " e ORDER BY e.id", AnyObject.class);
+                "SELECT e FROM  " + anyUtils().anyClass().getSimpleName() + " e ORDER BY e.id", AnyObject.class);
         query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1));
         query.setMaxResults(itemsPerPage);
 
@@ -308,5 +312,4 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     public Collection<String> findAllResourceKeys(final String key) {
         return findAllResources(authFind(key)).stream().map(resource -> resource.getKey()).collect(Collectors.toList());
     }
-
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index 0a04ac0..53c52d9 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -223,7 +223,7 @@ public class JPAAnySearchDAO extends AbstractAnySearchDAO {
     }
 
     private StringBuilder buildSelect(final OrderBySupport obs) {
-        StringBuilder select = new StringBuilder("SELECT u.any_id");
+        StringBuilder select = new StringBuilder("SELECT DISTINCT u.any_id");
 
         obs.items.forEach(item -> {
             select.append(',').append(item.select);
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
index 35d07d2..ed065fe 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
@@ -22,9 +22,10 @@ import java.util.Optional;
 import java.util.Collections;
 import java.util.List;
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
-import org.apache.syncope.core.persistence.jpa.entity.conf.JPAConf;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -33,11 +34,14 @@ public class JPAConfDAO extends AbstractDAO<Conf> implements ConfDAO {
 
     private static final String KEY = "cd64d66f-6fff-4008-b966-a06b1cc1436d";
 
+    @Autowired
+    private EntityFactory entityFactory;
+
     @Override
     public Conf get() {
-        Conf instance = entityManager().find(JPAConf.class, KEY);
+        Conf instance = entityManager().find(entityFactory.confClass(), KEY);
         if (instance == null) {
-            instance = new JPAConf();
+            instance = entityFactory.newEntity(Conf.class);
             instance.setKey(KEY);
 
             instance = entityManager().merge(instance);
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADynRealmDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADynRealmDAO.java
index 7fc9585..d9c1775 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADynRealmDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADynRealmDAO.java
@@ -27,6 +27,7 @@ import org.apache.syncope.core.persistence.api.dao.DynRealmDAO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.DynRealm;
 import org.apache.syncope.core.persistence.api.entity.DynRealmMembership;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.search.SearchCondConverter;
 import org.apache.syncope.core.persistence.jpa.entity.JPADynRealm;
 import org.apache.syncope.core.provisioning.api.event.AnyCreatedUpdatedEvent;
@@ -48,6 +49,9 @@ public class JPADynRealmDAO extends AbstractDAO<DynRealm> implements DynRealmDAO
     private ApplicationEventPublisher publisher;
 
     @Autowired
+    private EntityFactory entityFactory;
+
+    @Autowired
     private AnySearchDAO searchDAO;
 
     private AnySearchDAO jpaAnySearchDAO;
@@ -55,11 +59,11 @@ public class JPADynRealmDAO extends AbstractDAO<DynRealm> implements DynRealmDAO
     private AnySearchDAO jpaAnySearchDAO() {
         synchronized (this) {
             if (jpaAnySearchDAO == null) {
-                if (AopUtils.getTargetClass(searchDAO).equals(JPAAnySearchDAO.class)) {
+                if (AopUtils.getTargetClass(searchDAO).equals(entityFactory.anySearchDAOClass())) {
                     jpaAnySearchDAO = searchDAO;
                 } else {
-                    jpaAnySearchDAO = (AnySearchDAO) ApplicationContextProvider.getBeanFactory().
-                            createBean(JPAAnySearchDAO.class, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
+                    jpaAnySearchDAO = (AnySearchDAO) ApplicationContextProvider.getBeanFactory().createBean(
+                            entityFactory.anySearchDAOClass(), AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
                 }
             }
         }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index b8125ef..a343ebc 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -54,6 +54,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
@@ -61,7 +62,6 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
 import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
-import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADynGroupMembership;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPATypeExtension;
@@ -73,10 +73,8 @@ import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.springframework.aop.support.AopUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
-import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
-@Repository
 public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
 
     public static final String UDYNMEMB_TABLE = "UDynGroupMembers";
@@ -84,6 +82,9 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     public static final String ADYNMEMB_TABLE = "ADynGroupMembers";
 
     @Autowired
+    private EntityFactory entityFactory;
+
+    @Autowired
     private PlainAttrDAO plainAttrDAO;
 
     @Autowired
@@ -100,11 +101,11 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     private AnySearchDAO jpaAnySearchDAO() {
         synchronized (this) {
             if (jpaAnySearchDAO == null) {
-                if (AopUtils.getTargetClass(searchDAO).equals(JPAAnySearchDAO.class)) {
+                if (AopUtils.getTargetClass(searchDAO).equals(entityFactory.anySearchDAOClass())) {
                     jpaAnySearchDAO = searchDAO;
                 } else {
-                    jpaAnySearchDAO = (AnySearchDAO) ApplicationContextProvider.getBeanFactory().
-                            createBean(JPAAnySearchDAO.class, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
+                    jpaAnySearchDAO = (AnySearchDAO) ApplicationContextProvider.getBeanFactory().createBean(
+                            entityFactory.anySearchDAOClass(), AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
                 }
             }
         }
@@ -113,7 +114,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
 
     @Override
     protected AnyUtils init() {
-        return new JPAAnyUtilsFactory().getInstance(AnyTypeKind.GROUP);
+        return anyUtilsFactory.getInstance(AnyTypeKind.GROUP);
     }
 
     @Transactional(readOnly = true)
@@ -131,14 +132,14 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     @Override
     public int count() {
         Query query = entityManager().createQuery(
-                "SELECT COUNT(e) FROM  " + JPAGroup.class.getSimpleName() + " e");
+                "SELECT COUNT(e) FROM  " + anyUtils().anyClass().getSimpleName() + " e");
         return ((Number) query.getSingleResult()).intValue();
     }
 
     @Override
     public Map<String, Integer> countByRealm() {
         Query query = entityManager().createQuery(
-                "SELECT e.realm, COUNT(e) FROM  " + JPAGroup.class.getSimpleName() + " e GROUP BY e.realm");
+                "SELECT e.realm, COUNT(e) FROM  " + anyUtils().anyClass().getSimpleName() + " e GROUP BY e.realm");
 
         @SuppressWarnings("unchecked")
         List<Object[]> results = query.getResultList();
@@ -170,7 +171,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     @Override
     public Group findByName(final String name) {
         TypedQuery<Group> query = entityManager().createQuery(
-                "SELECT e FROM " + JPAGroup.class.getSimpleName() + " e WHERE e.name = :name", Group.class);
+                "SELECT e FROM " + anyUtils().anyClass().getSimpleName() + " e WHERE e.name = :name", Group.class);
         query.setParameter("name", name);
 
         Group result = null;
@@ -191,7 +192,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
             return Collections.<Group>emptyList();
         }
 
-        StringBuilder queryString = new StringBuilder("SELECT e FROM ").append(JPAGroup.class.getSimpleName()).
+        StringBuilder queryString = new StringBuilder("SELECT e FROM ").append(anyUtils().anyClass().getSimpleName()).
                 append(" e WHERE e.userOwner=:owner ");
         userDAO.findAllGroupKeys(owner).forEach(groupKey -> {
             queryString.append("OR e.groupOwner.id='").append(groupKey).append("' ");
@@ -212,7 +213,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
         }
 
         TypedQuery<Group> query = entityManager().createQuery(
-                "SELECT e FROM " + JPAGroup.class.getSimpleName() + " e WHERE e.groupOwner=:owner", Group.class);
+                "SELECT e FROM " + anyUtils().anyClass().getSimpleName() + " e WHERE e.groupOwner=:owner", Group.class);
         query.setParameter("owner", owner);
 
         return query.getResultList();
@@ -241,7 +242,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     @Override
     public List<Group> findAll(final int page, final int itemsPerPage) {
         TypedQuery<Group> query = entityManager().createQuery(
-                "SELECT e FROM  " + JPAGroup.class.getSimpleName() + " e ORDER BY e.id", Group.class);
+                "SELECT e FROM  " + anyUtils().anyClass().getSimpleName() + " e ORDER BY e.id", Group.class);
         query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1));
         query.setMaxResults(itemsPerPage);
 
@@ -324,7 +325,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
 
         findAMemberships(group).forEach(membership -> {
             AnyObject leftEnd = membership.getLeftEnd();
-            leftEnd.getMemberships().remove(membership);
+            leftEnd.remove(membership);
             membership.setRightEnd(null);
             leftEnd.getPlainAttrs(membership).stream().map(attr -> {
                 leftEnd.remove(attr);
@@ -339,7 +340,7 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
 
         findUMemberships(group).forEach(membership -> {
             User leftEnd = membership.getLeftEnd();
-            leftEnd.getMemberships().remove(membership);
+            leftEnd.remove(membership);
             membership.setRightEnd(null);
             leftEnd.getPlainAttrs(membership).stream().map(attr -> {
                 leftEnd.remove(attr);
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
index d4ba926..5ca294c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
@@ -30,12 +30,10 @@ import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.conf.JPACPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttr;
-import org.springframework.stereotype.Repository;
 
-@Repository
 public class JPAPlainAttrDAO extends AbstractDAO<PlainAttr<?>> implements PlainAttrDAO {
 
-    public <T extends PlainAttr<?>> Class<? extends AbstractPlainAttr<?>> getEntityReference(
+    public static <T extends PlainAttr<?>> Class<? extends AbstractPlainAttr<?>> getEntityReference(
             final Class<T> reference) {
 
         return CPlainAttr.class.isAssignableFrom(reference)
@@ -50,21 +48,6 @@ public class JPAPlainAttrDAO extends AbstractDAO<PlainAttr<?>> implements PlainA
     }
 
     @Override
-    public <T extends PlainAttr<?>> T find(final String key, final Class<T> reference) {
-        return reference.cast(entityManager().find(getEntityReference(reference), key));
-    }
-
-    @Override
-    public <T extends PlainAttr<?>> void delete(final String key, final Class<T> reference) {
-        T attribute = find(key, reference);
-        if (attribute == null) {
-            return;
-        }
-
-        delete(attribute);
-    }
-
-    @Override
     @SuppressWarnings("unchecked")
     public <T extends PlainAttr<?>> void delete(final T plainAttr) {
         if (plainAttr.getOwner() != null) {
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java
index 9e24017..c0ede1d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrValueDAO.java
@@ -18,10 +18,11 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
-import java.util.List;
-import javax.persistence.TypedQuery;
+import java.util.stream.Collectors;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
-import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
@@ -40,13 +41,11 @@ import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttrUniqueV
 import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttrValue;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue;
-import org.springframework.stereotype.Repository;
 
-@Repository
 public class JPAPlainAttrValueDAO extends AbstractDAO<PlainAttrValue> implements PlainAttrValueDAO {
 
     @SuppressWarnings("unchecked")
-    private <T extends PlainAttrValue> Class<? extends AbstractPlainAttrValue> getEntityReference(
+    public static <T extends PlainAttrValue> Class<? extends AbstractPlainAttrValue> getEntityReference(
             final Class<T> reference) {
 
         return AbstractPlainAttrValue.class.isAssignableFrom(reference)
@@ -71,37 +70,19 @@ public class JPAPlainAttrValueDAO extends AbstractDAO<PlainAttrValue> implements
     }
 
     @Override
-    public <T extends PlainAttrValue> T find(final String key, final Class<T> reference) {
-        return reference.cast(entityManager().find(getEntityReference(reference), key));
-    }
-
-    @Override
-    public <T extends PlainAttrValue> List<T> findAll(final Class<T> reference) {
-        TypedQuery<T> query = entityManager().createQuery(
-                "SELECT e FROM " + getEntityReference(reference).getSimpleName() + " e", reference);
-        return query.getResultList();
-    }
-
-    @Override
-    public <T extends PlainAttrValue> T save(final T attributeValue) {
-        return entityManager().merge(attributeValue);
-    }
-
-    @Override
-    public <T extends PlainAttrValue> void delete(final String key, final Class<T> reference) {
-        T attrValue = find(key, reference);
-        if (attrValue == null) {
-            return;
+    public void deleteAll(final PlainAttr<?> attr, final AnyUtils anyUtils) {
+        if (attr.getUniqueValue() == null) {
+            attr.getValues().stream().map(Entity::getKey).collect(Collectors.toSet()).forEach(attrValueKey -> {
+                PlainAttrValue attrValue = anyUtils.plainAttrValueClass().cast(
+                        entityManager().find(getEntityReference(anyUtils.plainAttrValueClass()), attrValueKey));
+                if (attrValue != null) {
+                    entityManager().remove(attrValue);
+                    attr.getValues().remove(attrValue);
+                }
+            });
+        } else {
+            entityManager().remove(attr.getUniqueValue());
+            attr.setUniqueValue(null);
         }
-
-        if (attrValue.getAttr() != null) {
-            if (attrValue instanceof PlainAttrUniqueValue) {
-                attrValue.getAttr().setUniqueValue(null);
-            } else {
-                attrValue.getAttr().getValues().remove(attrValue);
-            }
-        }
-
-        entityManager().remove(attrValue);
     }
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainSchemaDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainSchemaDAO.java
index ef569d7..46df742 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainSchemaDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainSchemaDAO.java
@@ -31,15 +31,15 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
-import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
 import org.apache.syncope.core.persistence.jpa.entity.JPAPlainSchema;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Repository;
 
-@Repository
 public class JPAPlainSchemaDAO extends AbstractDAO<PlainSchema> implements PlainSchemaDAO {
 
     @Autowired
+    private AnyUtilsFactory anyUtilsFactory;
+
+    @Autowired
     private PlainAttrDAO plainAttrDAO;
 
     @Autowired
@@ -94,7 +94,7 @@ public class JPAPlainSchemaDAO extends AbstractDAO<PlainSchema> implements Plain
     @Override
     public <T extends PlainAttr<?>> List<T> findAttrs(final PlainSchema schema, final Class<T> reference) {
         TypedQuery<T> query = entityManager().createQuery(
-                "SELECT e FROM " + ((JPAPlainAttrDAO) plainAttrDAO).getEntityReference(reference).getSimpleName()
+                "SELECT e FROM " + JPAPlainAttrDAO.getEntityReference(reference).getSimpleName()
                 + " e WHERE e.schema=:schema", reference);
         query.setParameter("schema", schema);
 
@@ -106,6 +106,16 @@ public class JPAPlainSchemaDAO extends AbstractDAO<PlainSchema> implements Plain
         return entityManager().merge(schema);
     }
 
+    protected void deleteAttrs(final PlainSchema schema) {
+        for (AnyTypeKind anyTypeKind : AnyTypeKind.values()) {
+            AnyUtils anyUtils = anyUtilsFactory.getInstance(anyTypeKind);
+
+            findAttrs(schema, anyUtils.plainAttrClass()).forEach(attr -> {
+                plainAttrDAO.delete(attr);
+            });
+        }
+    }
+
     @Override
     public void delete(final String key) {
         PlainSchema schema = find(key);
@@ -115,16 +125,9 @@ public class JPAPlainSchemaDAO extends AbstractDAO<PlainSchema> implements Plain
 
         schema.getLabels().forEach(label -> label.setSchema(null));
 
-        AnyUtilsFactory anyUtilsFactory = new JPAAnyUtilsFactory();
-        for (AnyTypeKind anyTypeKind : AnyTypeKind.values()) {
-            AnyUtils anyUtils = anyUtilsFactory.getInstance(anyTypeKind);
-
-            findAttrs(schema, anyUtils.plainAttrClass()).forEach(attr -> {
-                plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass());
-            });
+        deleteAttrs(schema);
 
-            resourceDAO.deleteMapping(key);
-        }
+        resourceDAO.deleteMapping(key);
 
         if (schema.getAnyTypeClass() != null) {
             schema.getAnyTypeClass().getPlainSchemas().remove(schema);
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARelationshipTypeDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARelationshipTypeDAO.java
index fd1f731..4d7f64e 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARelationshipTypeDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPARelationshipTypeDAO.java
@@ -82,11 +82,11 @@ public class JPARelationshipTypeDAO extends AbstractDAO<RelationshipType> implem
             if (relationship instanceof URelationship) {
                 ((URelationship) relationship).getLeftEnd().getRelationships().remove((URelationship) relationship);
             } else if (relationship instanceof UMembership) {
-                ((UMembership) relationship).getLeftEnd().getMemberships().remove((UMembership) relationship);
+                ((UMembership) relationship).getLeftEnd().remove((UMembership) relationship);
             } else if (relationship instanceof ARelationship) {
                 ((ARelationship) relationship).getLeftEnd().getRelationships().remove((ARelationship) relationship);
             } else if (relationship instanceof AMembership) {
-                ((AMembership) relationship).getLeftEnd().getMemberships().remove((AMembership) relationship);
+                ((AMembership) relationship).getLeftEnd().remove((AMembership) relationship);
             }
             relationship.setLeftEnd(null);
             return relationship;
@@ -94,5 +94,4 @@ public class JPARelationshipTypeDAO extends AbstractDAO<RelationshipType> implem
 
         entityManager().remove(type);
     }
-
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
index a86ee8e..33bf9f7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -61,19 +61,18 @@ import org.apache.syncope.core.persistence.api.entity.policy.AccountPolicy;
 import org.apache.syncope.core.persistence.api.entity.policy.PasswordPolicy;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.persistence.api.entity.user.User;
-import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUMembership;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
 import org.apache.syncope.core.provisioning.api.event.AnyCreatedUpdatedEvent;
 import org.apache.syncope.core.provisioning.api.event.AnyDeletedEvent;
 import org.apache.syncope.core.spring.ImplementationManager;
 import org.apache.syncope.core.spring.security.Encryptor;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
-@Repository
 public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
 
     private static final Pattern USERNAME_PATTERN =
@@ -101,7 +100,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
 
     @Override
     protected AnyUtils init() {
-        return new JPAAnyUtilsFactory().getInstance(AnyTypeKind.USER);
+        return anyUtilsFactory.getInstance(AnyTypeKind.USER);
     }
 
     @Transactional(readOnly = true)
@@ -119,14 +118,14 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
     @Override
     public int count() {
         Query query = entityManager().createQuery(
-                "SELECT COUNT(e) FROM  " + JPAUser.class.getSimpleName() + " e");
+                "SELECT COUNT(e) FROM  " + anyUtils().anyClass().getSimpleName() + " e");
         return ((Number) query.getSingleResult()).intValue();
     }
 
     @Override
     public Map<String, Integer> countByRealm() {
         Query query = entityManager().createQuery(
-                "SELECT e.realm, COUNT(e) FROM  " + JPAUser.class.getSimpleName() + " e GROUP BY e.realm");
+                "SELECT e.realm, COUNT(e) FROM  " + anyUtils().anyClass().getSimpleName() + " e GROUP BY e.realm");
 
         @SuppressWarnings("unchecked")
         List<Object[]> results = query.getResultList();
@@ -138,7 +137,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
     @Override
     public Map<String, Integer> countByStatus() {
         Query query = entityManager().createQuery(
-                "SELECT e.status, COUNT(e) FROM  " + JPAUser.class.getSimpleName() + " e GROUP BY e.status");
+                "SELECT e.status, COUNT(e) FROM  " + anyUtils().anyClass().getSimpleName() + " e GROUP BY e.status");
 
         @SuppressWarnings("unchecked")
         List<Object[]> results = query.getResultList();
@@ -174,7 +173,8 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
 
     @Override
     public User findByUsername(final String username) {
-        TypedQuery<User> query = entityManager().createQuery("SELECT e FROM " + JPAUser.class.getSimpleName()
+        TypedQuery<User> query = entityManager().createQuery(
+                "SELECT e FROM " + anyUtils().anyClass().getSimpleName()
                 + " e WHERE e.username = :username", User.class);
         query.setParameter("username", username);
 
@@ -190,7 +190,8 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
 
     @Override
     public User findByToken(final String token) {
-        TypedQuery<User> query = entityManager().createQuery("SELECT e FROM " + JPAUser.class.getSimpleName()
+        TypedQuery<User> query = entityManager().createQuery(
+                "SELECT e FROM " + anyUtils().anyClass().getSimpleName()
                 + " e WHERE e.token LIKE :token", User.class);
         query.setParameter("token", token);
 
@@ -206,13 +207,19 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
 
     @Override
     public List<User> findBySecurityQuestion(final SecurityQuestion securityQuestion) {
-        TypedQuery<User> query = entityManager().createQuery("SELECT e FROM " + JPAUser.class.getSimpleName()
+        TypedQuery<User> query = entityManager().createQuery(
+                "SELECT e FROM " + anyUtils().anyClass().getSimpleName()
                 + " e WHERE e.securityQuestion = :securityQuestion", User.class);
         query.setParameter("securityQuestion", securityQuestion);
 
         return query.getResultList();
     }
 
+    @Override
+    public UMembership findMembership(final String key) {
+        return entityManager().find(JPAUMembership.class, key);
+    }
+
     private List<PasswordPolicy> getPasswordPolicies(final User user) {
         List<PasswordPolicy> policies = new ArrayList<>();
 
@@ -240,7 +247,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO {
     @Override
     public List<User> findAll(final int page, final int itemsPerPage) {
         TypedQuery<User> query = entityManager().createQuery(
-                "SELECT e FROM  " + JPAUser.class.getSimpleName() + " e ORDER BY e.id", User.class);
+                "SELECT e FROM  " + anyUtils().anyClass().getSimpleName() + " e ORDER BY e.id", User.class);
         query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1));
         query.setMaxResults(itemsPerPage);
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
index aa86519..4cc3058 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
@@ -141,16 +141,16 @@ public class JPAAnyUtils implements AnyUtils {
 
         switch (anyTypeKind) {
             case GROUP:
-                result = entityFactory.newEntity(Group.class).getClass();
+                result = entityFactory.groupClass();
                 break;
 
             case ANY_OBJECT:
-                result = entityFactory.newEntity(AnyObject.class).getClass();
+                result = entityFactory.anyObjectClass();
                 break;
 
             case USER:
             default:
-                result = entityFactory.newEntity(User.class).getClass();
+                result = entityFactory.userClass();
         }
 
         return result;
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java
index 1fa004b..7e5d282 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtilsFactory.java
@@ -67,5 +67,4 @@ public class JPAAnyUtilsFactory implements AnyUtilsFactory {
 
         return getInstance(type);
     }
-
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
index 79bc299..81be309 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAEntityFactory.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.persistence.jpa.entity;
 
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPASecurityQuestion;
 import org.apache.syncope.core.persistence.api.entity.AccessToken;
 import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPasswordPolicy;
@@ -122,7 +123,6 @@ import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrUniqueVa
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUPlainAttrValue;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAURelationship;
 import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
-import org.springframework.stereotype.Component;
 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
 import org.apache.syncope.core.persistence.api.entity.task.AnyTemplatePullTask;
 import org.apache.syncope.core.persistence.api.entity.policy.PullPolicy;
@@ -141,10 +141,10 @@ import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResour
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAOrgUnitItem;
 import org.apache.syncope.core.persistence.api.entity.policy.PullCorrelationRuleEntity;
 import org.apache.syncope.core.persistence.api.entity.policy.PushCorrelationRuleEntity;
+import org.apache.syncope.core.persistence.jpa.dao.JPAAnySearchDAO;
 import org.apache.syncope.core.persistence.jpa.entity.policy.JPAPushCorrelationRuleEntity;
 import org.apache.syncope.core.spring.security.SecureRandomUtils;
 
-@Component
 public class JPAEntityFactory implements EntityFactory {
 
     @SuppressWarnings("unchecked")
@@ -315,4 +315,29 @@ public class JPAEntityFactory implements EntityFactory {
     public ConnPoolConf newConnPoolConf() {
         return new JPAConnPoolConf();
     }
+
+    @Override
+    public Class<? extends User> userClass() {
+        return JPAUser.class;
+    }
+
+    @Override
+    public Class<? extends Group> groupClass() {
+        return JPAGroup.class;
+    }
+
+    @Override
+    public Class<? extends AnyObject> anyObjectClass() {
+        return JPAAnyObject.class;
+    }
+
+    @Override
+    public Class<? extends Conf> confClass() {
+        return JPAConf.class;
+    }
+
+    @Override
+    public Class<? extends AnySearchDAO> anySearchDAOClass() {
+        return JPAAnySearchDAO.class;
+    }
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
index d72e36a..0a04e01 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
@@ -175,6 +175,12 @@ public class JPAAnyObject
     }
 
     @Override
+    public boolean remove(final AMembership membership) {
+        checkType(membership, JPAAMembership.class);
+        return this.memberships.remove((JPAAMembership) membership);
+    }
+
+    @Override
     public List<? extends AMembership> getMemberships() {
         return memberships;
     }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
index b4be360..3911d28 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
@@ -59,12 +59,12 @@ public class JPAConf extends AbstractProvidedKeyEntity implements Conf {
     @Override
     public boolean remove(final CPlainAttr attr) {
         checkType(attr, JPACPlainAttr.class);
-        return plainAttrs.remove((JPACPlainAttr) attr);
+        return getPlainAttrs().remove((JPACPlainAttr) attr);
     }
 
     @Override
     public Optional<? extends CPlainAttr> getPlainAttr(final String plainSchema) {
-        return plainAttrs.stream().filter(plainAttr
+        return getPlainAttrs().stream().filter(plainAttr
                 -> plainAttr != null && plainAttr.getSchema() != null
                 && plainSchema.equals(plainAttr.getSchema().getKey())).findFirst();
     }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
index 53ef4fb..d10cb9a 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
@@ -164,7 +164,7 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     @Override
     public boolean remove(final GPlainAttr attr) {
         checkType(attr, JPAGPlainAttr.class);
-        return plainAttrs.remove((JPAGPlainAttr) attr);
+        return getPlainAttrs().remove((JPAGPlainAttr) attr);
     }
 
     @Override
@@ -236,5 +236,4 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     public List<? extends TypeExtension> getTypeExtensions() {
         return typeExtensions;
     }
-
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/AbstractAnyTemplate.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/AbstractAnyTemplate.java
index 2af788b..ce9dae3 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/AbstractAnyTemplate.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/AbstractAnyTemplate.java
@@ -25,9 +25,10 @@ import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
 import org.apache.syncope.core.persistence.api.entity.AnyTemplate;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractGeneratedKeyEntity;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyType;
-import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
 
 @MappedSuperclass
 public abstract class AbstractAnyTemplate extends AbstractGeneratedKeyEntity implements AnyTemplate {
@@ -56,7 +57,8 @@ public abstract class AbstractAnyTemplate extends AbstractGeneratedKeyEntity imp
         return template == null
                 ? anyType == null
                         ? null
-                        : new JPAAnyUtilsFactory().getInstance(anyType.getKind()).newAnyTO()
+                        : ApplicationContextProvider.getApplicationContext().getBean(AnyUtilsFactory.class).
+                                getInstance(anyType.getKind()).newAnyTO()
                 : anyType == null
                         ? null
                         : POJOHelper.deserialize(template, anyType.getKind().getTOClass());
@@ -70,5 +72,4 @@ public abstract class AbstractAnyTemplate extends AbstractGeneratedKeyEntity imp
             this.template = POJOHelper.serialize(template);
         }
     }
-
 }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
index 4ede8b7..4d91360 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
@@ -454,6 +454,12 @@ public class JPAUser
     }
 
     @Override
+    public boolean remove(final UMembership membership) {
+        checkType(membership, JPAUMembership.class);
+        return this.memberships.remove((JPAUMembership) membership);
+    }
+
+    @Override
     public List<? extends UMembership> getMemberships() {
         return memberships;
     }
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
index fba6674..fefb1e7 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
@@ -22,13 +22,14 @@ import javax.validation.ConstraintValidatorContext;
 import org.apache.syncope.common.lib.types.EntityViolationType;
 import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
-import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
 
 @SuppressWarnings("rawtypes")
 public class AnyValidator extends AbstractValidator<AnyCheck, Any> {
@@ -57,8 +58,9 @@ public class AnyValidator extends AbstractValidator<AnyCheck, Any> {
         context.disableDefaultConstraintViolation();
 
         if (!(any instanceof Conf)) {
-            AllowedSchemas<PlainSchema> allowedPlainSchemas = new JPAAnyUtilsFactory().
-                    getInstance(any.getType().getKind()).dao().findAllowedSchemas(any, PlainSchema.class);
+            AllowedSchemas<PlainSchema> allowedPlainSchemas =
+                    ApplicationContextProvider.getApplicationContext().getBean(AnyUtilsFactory.class).
+                            getInstance(any.getType().getKind()).dao().findAllowedSchemas(any, PlainSchema.class);
 
             for (PlainAttr<?> attr : ((Any<?>) any).getPlainAttrs()) {
                 if (attr != null && !allowedPlainSchemas.forSelfContains(attr.getSchema().getKey())) {
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
index d9975db..89ee1f8 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java
@@ -25,32 +25,31 @@ import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 public class PlainAttrValidator extends AbstractValidator<PlainAttrCheck, PlainAttr<?>> {
 
     @Override
-    public boolean isValid(final PlainAttr<?> object, final ConstraintValidatorContext context) {
-        boolean isValid;
+    public boolean isValid(final PlainAttr<?> attr, final ConstraintValidatorContext context) {
+        context.disableDefaultConstraintViolation();
 
-        if (object == null) {
+        boolean isValid;
+        if (attr == null) {
             isValid = true;
         } else {
-            if (object.getSchema().isUniqueConstraint()) {
-                isValid = object.getValues().isEmpty() && object.getUniqueValue() != null;
+            if (attr.getSchema().isUniqueConstraint()) {
+                isValid = attr.getValues().isEmpty() && attr.getUniqueValue() != null;
             } else {
-                isValid = !object.getValues().isEmpty() && object.getUniqueValue() == null;
+                isValid = !attr.getValues().isEmpty() && attr.getUniqueValue() == null;
 
-                if (!object.getSchema().isMultivalue()) {
-                    isValid &= object.getValues().size() == 1;
+                if (!attr.getSchema().isMultivalue()) {
+                    isValid &= attr.getValues().size() == 1;
                 }
             }
 
             if (!isValid) {
-                LOG.error("Invalid values for attribute " + object + ": " + "schema=" + object.getSchema().getKey()
-                        + ", values={}", object.getValuesAsStrings());
-
-                context.disableDefaultConstraintViolation();
+                LOG.error("Invalid values for attribute " + attr + ": "
+                        + "schema=" + attr.getSchema().getKey() + ", values={}", attr.getValuesAsStrings());
 
                 context.buildConstraintViolationWithTemplate(
                         getTemplate(EntityViolationType.InvalidValueList,
-                                "Invalid values " + object.getValuesAsStrings())).
-                        addPropertyNode(object.getSchema().getKey()).addConstraintViolation();
+                                "Invalid values " + attr.getValuesAsStrings())).
+                        addPropertyNode(attr.getSchema().getKey()).addConstraintViolation();
             }
         }
 
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
index 64ec693..fcb008d 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
@@ -27,56 +27,55 @@ import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 public class PlainAttrValueValidator extends AbstractValidator<PlainAttrValueCheck, PlainAttrValue> {
 
     @Override
-    public boolean isValid(final PlainAttrValue object, final ConstraintValidatorContext context) {
-        boolean isValid;
+    public boolean isValid(final PlainAttrValue value, final ConstraintValidatorContext context) {
+        context.disableDefaultConstraintViolation();
 
-        if (object == null) {
+        boolean isValid;
+        if (value == null) {
             isValid = true;
         } else {
             int nonNullVales = 0;
-            if (object.getBooleanValue() != null) {
+            if (value.getBooleanValue() != null) {
                 nonNullVales++;
             }
-            if (object.getDateValue() != null) {
+            if (value.getDateValue() != null) {
                 nonNullVales++;
             }
-            if (object.getDoubleValue() != null) {
+            if (value.getDoubleValue() != null) {
                 nonNullVales++;
             }
-            if (object.getLongValue() != null) {
+            if (value.getLongValue() != null) {
                 nonNullVales++;
             }
-            if (object.getBinaryValue() != null) {
+            if (value.getBinaryValue() != null) {
                 nonNullVales++;
             }
-            if (object.getStringValue() != null) {
+            if (value.getStringValue() != null) {
                 nonNullVales++;
             }
             isValid = nonNullVales == 1;
 
             if (!isValid) {
-                LOG.error("More than one non-null value for " + object);
+                LOG.error("More than one non-null value for " + value);
 
-                context.disableDefaultConstraintViolation();
                 context.buildConstraintViolationWithTemplate(
                         getTemplate(EntityViolationType.MoreThanOneNonNull, "More than one non-null value found")).
-                        addPropertyNode(object.getClass().getSimpleName().replaceAll("\\n", " ")).
+                        addPropertyNode(value.getClass().getSimpleName().replaceAll("\\n", " ")).
                         addConstraintViolation();
 
-            } else if (object instanceof PlainAttrUniqueValue) {
-                PlainSchema uniqueValueSchema = ((PlainAttrUniqueValue) object).getSchema();
-                PlainSchema attrSchema = object.getAttr().getSchema();
+            } else if (value instanceof PlainAttrUniqueValue) {
+                PlainSchema uniqueValueSchema = ((PlainAttrUniqueValue) value).getSchema();
+                PlainSchema attrSchema = value.getAttr().getSchema();
 
                 isValid = uniqueValueSchema.equals(attrSchema);
 
                 if (!isValid) {
-                    LOG.error("Unique value schema for " + object.getClass().getSimpleName() + "[" + object.getKey()
-                            + "]" + " is " + uniqueValueSchema + ", while owning attribute schema is " + attrSchema);
+                    LOG.error("Unique value schema for " + value + " is " + uniqueValueSchema
+                            + ", while owning attribute's schema is " + attrSchema);
 
-                    context.disableDefaultConstraintViolation();
                     context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidPlainAttr,
                             "Unique value schema is " + uniqueValueSchema
-                            + ", while owning attribute schema is " + attrSchema)).addPropertyNode("schema").
+                            + ", while owning attribute's schema is " + attrSchema)).addPropertyNode("schema").
                             addConstraintViolation();
                 }
             }
diff --git a/core/persistence-jpa/src/main/resources/persistence.properties b/core/persistence-jpa/src/main/resources/persistence.properties
index 946e588..0841aa0 100644
--- a/core/persistence-jpa/src/main/resources/persistence.properties
+++ b/core/persistence-jpa/src/main/resources/persistence.properties
@@ -15,5 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 content.directory=${conf.directory}
+entity.factory=org.apache.syncope.core.persistence.jpa.entity.JPAEntityFactory
+plainSchema.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainSchemaDAO
+plainAttr.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrDAO
+plainAttrValue.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrValueDAO
 any.search.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnySearchDAO
+user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO
+group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAGroupDAO
+anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnyObjectDAO
 openjpa.RemoteCommitProvider=sjvm
diff --git a/core/persistence-jpa/src/main/resources/persistenceContext.xml b/core/persistence-jpa/src/main/resources/persistenceContext.xml
index 50153a4..c7c54c2 100644
--- a/core/persistence-jpa/src/main/resources/persistenceContext.xml
+++ b/core/persistence-jpa/src/main/resources/persistenceContext.xml
@@ -30,7 +30,14 @@ under the License.
   <context:annotation-config/>
   
   <context:component-scan base-package="org.apache.syncope.core.persistence.jpa"/>
+  <bean class="${entity.factory}"/>
+  <bean class="${plainSchema.dao}"/>
+  <bean class="${plainAttr.dao}"/>
+  <bean class="${plainAttrValue.dao}"/>
   <bean class="${any.search.dao}"/>
+  <bean class="${user.dao}"/>
+  <bean class="${group.dao}"/>
+  <bean class="${anyObject.dao}"/>
 
   <bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
 
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/AbstractTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/AbstractTest.java
index d0151ba..a957b27 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/AbstractTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/AbstractTest.java
@@ -23,6 +23,10 @@ import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrDAO;
+import org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrValueDAO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.orm.jpa.EntityManagerFactoryUtils;
 import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
@@ -46,4 +50,12 @@ public abstract class AbstractTest {
 
         return entityManager;
     }
+
+    protected <T extends PlainAttr<?>> T findPlainAttr(final String key, final Class<T> reference) {
+        return reference.cast(entityManager().find(JPAPlainAttrDAO.getEntityReference(reference), key));
+    }
+
+    protected <T extends PlainAttrValue> T findPlainAttrValue(final String key, final Class<T> reference) {
+        return reference.cast(entityManager().find(JPAPlainAttrValueDAO.getEntityReference(reference), key));
+    }
 }
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConfTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConfTest.java
index 87c4f3f..55f0b6b 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConfTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/ConfTest.java
@@ -30,10 +30,12 @@ import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntit
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrValue;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
-import org.apache.syncope.core.persistence.jpa.entity.conf.JPACPlainAttrValue;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -62,12 +64,12 @@ public class ConfTest extends AbstractTest {
     }
 
     private void add(final CPlainAttr newAttr, final String value) {
-        JPACPlainAttrValue attrValue;
+        PlainAttrValue attrValue;
         if (newAttr.getSchema().isUniqueConstraint()) {
-            attrValue = new JPACPlainAttrValue();
+            attrValue = entityFactory.newEntity(CPlainAttrUniqueValue.class);
             ((PlainAttrUniqueValue) attrValue).setSchema(newAttr.getSchema());
         } else {
-            attrValue = new JPACPlainAttrValue();
+            attrValue = entityFactory.newEntity(CPlainAttrValue.class);
         }
         newAttr.add(value, attrValue);
     }
@@ -101,6 +103,7 @@ public class ConfTest extends AbstractTest {
 
         // 4. delete conf
         confDAO.delete("useless");
+        plainSchemaDAO.delete("useless");
         assertFalse(confDAO.find("useless").isPresent());
     }
 
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
index 8197a55..8af7240 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
@@ -37,6 +37,7 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -45,6 +46,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.transaction.annotation.Transactional;
 
 @Transactional("Two")
+@Tag("multitenancy")
 public class MultitenancyTest extends AbstractTest {
 
     @Autowired
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
index cc9281e..856e570 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
@@ -41,6 +41,7 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
 import org.apache.syncope.core.spring.security.Encryptor;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -57,17 +58,19 @@ public class PlainAttrTest extends AbstractTest {
     @Autowired
     private PlainSchemaDAO plainSchemaDAO;
 
+    @Tag("plainAttrTable")
     @Test
     public void findByKey() {
-        UPlainAttr attribute = plainAttrDAO.find("01f22fbd-b672-40af-b528-686d9b27ebc4", UPlainAttr.class);
+        UPlainAttr attribute = findPlainAttr("01f22fbd-b672-40af-b528-686d9b27ebc4", UPlainAttr.class);
         assertNotNull(attribute);
-        attribute = plainAttrDAO.find("9d0d9e40-1b18-488e-9482-37dab82163c9", UPlainAttr.class);
+        attribute = findPlainAttr("9d0d9e40-1b18-488e-9482-37dab82163c9", UPlainAttr.class);
         assertNotNull(attribute);
     }
 
+    @Tag("plainAttrTable")
     @Test
     public void read() {
-        UPlainAttr attribute = plainAttrDAO.find("01f22fbd-b672-40af-b528-686d9b27ebc4", UPlainAttr.class);
+        UPlainAttr attribute = findPlainAttr("01f22fbd-b672-40af-b528-686d9b27ebc4", UPlainAttr.class);
         assertNotNull(attribute);
         assertTrue(attribute.getValues().isEmpty());
         assertNotNull(attribute.getUniqueValue());
@@ -136,7 +139,36 @@ public class PlainAttrTest extends AbstractTest {
     }
 
     @Test
-    public void validateAndSave() {
+    public void invalidValueList() {
+        User user = userDAO.find("1417acbe-cbf6-4277-9372-e75e04f97000");
+
+        PlainSchema emailSchema = plainSchemaDAO.find("email");
+        assertNotNull(emailSchema);
+
+        PlainSchema fullnameSchema = plainSchemaDAO.find("fullname");
+        assertNotNull(fullnameSchema);
+
+        UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
+        attr.setOwner(user);
+        attr.setSchema(emailSchema);
+
+        user.add(attr);
+
+        InvalidEntityException iee = null;
+        try {
+            userDAO.save(user);
+            fail("This should not happen");
+        } catch (InvalidEntityException e) {
+            iee = e;
+        }
+        assertNotNull(iee);
+        // for attr because no values are set
+        assertTrue(iee.hasViolation(EntityViolationType.InvalidValueList));
+    }
+
+    @Tag("plainAttrTable")
+    @Test
+    public void invalidPlainAttr() {
         User user = userDAO.find("1417acbe-cbf6-4277-9372-e75e04f97000");
 
         PlainSchema emailSchema = plainSchemaDAO.find("email");
@@ -166,9 +198,9 @@ public class PlainAttrTest extends AbstractTest {
             iee = e;
         }
         assertNotNull(iee);
-        // for attribute
+        // for attr because no values are set
         assertTrue(iee.hasViolation(EntityViolationType.InvalidValueList));
-        // for uauv
+        // for uauv because uauv.schema and uauv.attr.schema are different
         assertTrue(iee.hasViolation(EntityViolationType.InvalidPlainAttr));
     }
 
@@ -222,13 +254,13 @@ public class PlainAttrTest extends AbstractTest {
         assertTrue(Arrays.equals(bytes, photo.getValues().get(0).getBinaryValue()));
     }
 
+    @Tag("plainAttrTable")
     @Test
     public void delete() {
-        UPlainAttr attribute = plainAttrDAO.find(
-                "9d0d9e40-1b18-488e-9482-37dab82163c9", UPlainAttr.class);
+        UPlainAttr attribute = findPlainAttr("9d0d9e40-1b18-488e-9482-37dab82163c9", UPlainAttr.class);
         String attrSchemaName = attribute.getSchema().getKey();
 
-        plainAttrDAO.delete(attribute.getKey(), UPlainAttr.class);
+        plainAttrDAO.delete(attribute);
 
         PlainSchema schema = plainSchemaDAO.find(attrSchemaName);
         assertNotNull(schema);
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
index ff46d62..d499652 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
@@ -37,6 +37,7 @@ import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -73,6 +74,7 @@ public class PlainSchemaTest extends AbstractTest {
         assertFalse(schema.getLabel(Locale.KOREAN).isPresent());
     }
 
+    @Tag("plainAttrTable")
     @Test
     public void findAttrs() {
         PlainSchema schema = plainSchemaDAO.find("icon");
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
index 01d379d..b35d83b 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/UserTest.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.core.persistence.jpa.inner;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -36,6 +37,8 @@ import org.apache.syncope.core.persistence.jpa.AbstractTest;
 import org.apache.syncope.core.provisioning.api.utils.policy.InvalidPasswordRuleConf;
 import org.apache.syncope.core.spring.security.PasswordGenerator;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrUniqueValue;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -56,6 +59,23 @@ public class UserTest extends AbstractTest {
     private ExternalResourceDAO resourceDAO;
 
     @Test
+    public void find() {
+        User user = userDAO.find("823074dc-d280-436d-a7dd-07399fae48ec");
+        assertNotNull(user);
+        assertEquals("puccini", user.getUsername());
+        assertFalse(user.isSuspended());
+        assertFalse(user.isMustChangePassword());
+        assertEquals("active", user.getStatus());
+        assertEquals(CipherAlgorithm.SHA1, user.getCipherAlgorithm());
+        assertEquals("e4c28e7a-9dbf-4ee7-9441-93812a0d4a28", user.getRealm().getKey());
+        assertNull(user.getSecurityQuestion());
+        assertNull(user.getSecurityAnswer());
+        assertEquals("admin", user.getCreator());
+        assertEquals("Giacomo", user.getPlainAttr("firstname").get().getValuesAsStrings().get(0));
+        assertEquals("Puccini", user.getPlainAttr("surname").get().getValuesAsStrings().get(0));
+    }
+
+    @Test
     public void findAll() {
         List<User> list = userDAO.findAll(1, 100);
         assertEquals(5, list.size());
@@ -110,8 +130,8 @@ public class UserTest extends AbstractTest {
     }
 
     @Test
-    public void findByPlainAttrValue() {
-        UPlainAttrValue fullnameValue = entityFactory.newEntity(UPlainAttrValue.class);
+    public void findByPlainAttrUniqueValue() {
+        UPlainAttrUniqueValue fullnameValue = entityFactory.newEntity(UPlainAttrUniqueValue.class);
         fullnameValue.setStringValue("Gioacchino Rossini");
 
         List<User> list = userDAO.findByPlainAttrValue("fullname", fullnameValue, false);
@@ -152,6 +172,13 @@ public class UserTest extends AbstractTest {
     }
 
     @Test
+    public void findMembership() {
+        UMembership memb = userDAO.findMembership("3d5e91f6-305e-45f9-ad30-4897d3d43bd9");
+        assertNotNull(memb);
+        assertEquals("1417acbe-cbf6-4277-9372-e75e04f97000", memb.getLeftEnd().getKey());
+    }
+
+    @Test
     public void saveInvalidPassword() {
         User user = entityFactory.newEntity(User.class);
         user.setUsername("username");
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
index 695bb87..17e35bb 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
@@ -24,9 +24,11 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrValue;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
-import org.apache.syncope.core.persistence.jpa.entity.conf.JPACPlainAttrValue;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -41,12 +43,12 @@ public class ConfTest extends AbstractTest {
     private PlainSchemaDAO plainSchemaDAO;
 
     private void add(final CPlainAttr newAttr, final String value) {
-        JPACPlainAttrValue attrValue;
+        PlainAttrValue attrValue;
         if (newAttr.getSchema().isUniqueConstraint()) {
-            attrValue = new JPACPlainAttrValue();
+            attrValue = entityFactory.newEntity(CPlainAttrUniqueValue.class);
             ((PlainAttrUniqueValue) attrValue).setSchema(newAttr.getSchema());
         } else {
-            attrValue = new JPACPlainAttrValue();
+            attrValue = entityFactory.newEntity(CPlainAttrValue.class);
         }
         newAttr.add(value, attrValue);
     }
@@ -68,5 +70,4 @@ public class ConfTest extends AbstractTest {
         CPlainAttr actual = confDAO.find("token.expireTime").get();
         assertEquals(expireTime, actual);
     }
-
 }
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
index 7f424fd..e596e2d 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
@@ -38,8 +38,6 @@ import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntit
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.RealmDAO;
@@ -84,12 +82,6 @@ public class GroupTest extends AbstractTest {
     private PlainSchemaDAO plainSchemaDAO;
 
     @Autowired
-    private PlainAttrDAO plainAttrDAO;
-
-    @Autowired
-    private PlainAttrValueDAO plainAttrValueDAO;
-
-    @Autowired
     private AnyTypeClassDAO anyTypeClassDAO;
 
     @Test
@@ -169,10 +161,8 @@ public class GroupTest extends AbstractTest {
 
         assertNull(groupDAO.find("b1f7c12d-ec83-441f-a50e-1691daaedf3b"));
         assertEquals(userDAO.findAllGroups(userDAO.findByUsername("verdi")).size(), 2);
-        assertNull(plainAttrDAO.find(
-                "f82fc61f-8e74-4a4b-9f9e-b8a41f38aad9", GPlainAttr.class));
-        assertNull(plainAttrValueDAO.find(
-                "49f35879-2510-4f11-a901-24152f753538", GPlainAttrValue.class));
+        assertNull(findPlainAttr("f82fc61f-8e74-4a4b-9f9e-b8a41f38aad9", GPlainAttr.class));
+        assertNull(findPlainAttrValue("49f35879-2510-4f11-a901-24152f753538", GPlainAttrValue.class));
         assertNotNull(plainSchemaDAO.find("icon"));
     }
 
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/PlainAttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/PlainAttrTest.java
index 8eb98af..58771ca 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/PlainAttrTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/PlainAttrTest.java
@@ -18,18 +18,23 @@
  */
 package org.apache.syncope.core.persistence.jpa.outer;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.fail;
 
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
 import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 
+@Tag("plainAttrTable")
 @Transactional("Master")
 public class PlainAttrTest extends AbstractTest {
 
@@ -40,30 +45,31 @@ public class PlainAttrTest extends AbstractTest {
     private PlainAttrValueDAO plainAttrValueDAO;
 
     @Test
-    public void deleteAttribute() {
-        plainAttrDAO.delete("35f407a2-d254-4890-9e45-5a7dd8c8df7d", UPlainAttr.class);
+    public void deleteAttr() {
+        plainAttrDAO.delete(findPlainAttr("35f407a2-d254-4890-9e45-5a7dd8c8df7d", UPlainAttr.class));
 
         plainAttrDAO.flush();
 
-        assertNull(plainAttrDAO.find("35f407a2-d254-4890-9e45-5a7dd8c8df7d", UPlainAttr.class));
-        assertNull(
-                plainAttrValueDAO.find("0c67225a-030a-4c56-b337-17cf7a311f0f", UPlainAttrValue.class));
+        assertNull(findPlainAttr("35f407a2-d254-4890-9e45-5a7dd8c8df7d", UPlainAttr.class));
+        assertNull(findPlainAttrValue("0c67225a-030a-4c56-b337-17cf7a311f0f", UPlainAttrValue.class));
     }
 
     @Test
-    public void deleteAttributeValue() {
-        UPlainAttrValue value = plainAttrValueDAO.find(
-                "7034de3b-3687-4db5-8454-363468f1a9de", UPlainAttrValue.class);
-        int attributeValueNumber = value.getAttr().getValues().size();
+    public void deleteAllAttValues() {
+        UPlainAttrValue value = findPlainAttrValue("7034de3b-3687-4db5-8454-363468f1a9de", UPlainAttrValue.class);
+        assertNotNull(value);
 
-        plainAttrValueDAO.delete(value.getKey(), UPlainAttrValue.class);
+        plainAttrValueDAO.deleteAll(value.getAttr(), anyUtilsFactory.getInstance(AnyTypeKind.USER));
 
-        plainAttrValueDAO.flush();
+        value = findPlainAttrValue("7034de3b-3687-4db5-8454-363468f1a9de", UPlainAttrValue.class);
+        assertNull(value);
 
-        assertNull(plainAttrValueDAO.find(value.getKey(), UPlainAttrValue.class));
-
-        UPlainAttr attribute = plainAttrDAO.find(
-                "9d0d9e40-1b18-488e-9482-37dab82163c9", UPlainAttr.class);
-        assertEquals(attribute.getValues().size(), attributeValueNumber - 1);
+        // by removing all values, the related attribute is not valid any more
+        try {
+            plainAttrValueDAO.flush();
+            fail();
+        } catch (InvalidEntityException e) {
+            assertNotNull(e);
+        }
     }
 }
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/PlainSchemaTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/PlainSchemaTest.java
index faaede5..39aa303 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/PlainSchemaTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/PlainSchemaTest.java
@@ -37,7 +37,6 @@ import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
@@ -74,9 +73,6 @@ public class PlainSchemaTest extends AbstractTest {
     private DerSchemaDAO derSchemaDAO;
 
     @Autowired
-    private PlainAttrDAO plainAttrDAO;
-
-    @Autowired
     private ExternalResourceDAO resourceDAO;
 
     @BeforeAll
@@ -110,7 +106,7 @@ public class PlainSchemaTest extends AbstractTest {
             plainSchemaDAO.flush();
             fail("This should not happen");
         } catch (Exception e) {
-            assertTrue(e instanceof EntityExistsException);
+            assertTrue(e instanceof EntityExistsException || e.getCause() instanceof EntityExistsException);
         }
     }
 
@@ -173,8 +169,8 @@ public class PlainSchemaTest extends AbstractTest {
         }
         assertTrue(mapItems.isEmpty());
 
-        assertNull(plainAttrDAO.find("01f22fbd-b672-40af-b528-686d9b27ebc4", UPlainAttr.class));
-        assertNull(plainAttrDAO.find(UUID.randomUUID().toString(), UPlainAttr.class));
+        assertNull(findPlainAttr("01f22fbd-b672-40af-b528-686d9b27ebc4", UPlainAttr.class));
+        assertNull(findPlainAttr(UUID.randomUUID().toString(), UPlainAttr.class));
         assertFalse(userDAO.findByUsername("rossini").getPlainAttr("fullname").isPresent());
         assertFalse(userDAO.findByUsername("vivaldi").getPlainAttr("fullname").isPresent());
     }
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
index 561e089..e6281b9 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
@@ -32,8 +32,6 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.RelationshipTypeDAO;
@@ -68,12 +66,6 @@ public class UserTest extends AbstractTest {
     private PlainSchemaDAO plainSchemaDAO;
 
     @Autowired
-    private PlainAttrDAO plainAttrDAO;
-
-    @Autowired
-    private PlainAttrValueDAO plainAttrValueDAO;
-
-    @Autowired
     private DerSchemaDAO derSchemaDAO;
 
     @Test
@@ -86,8 +78,8 @@ public class UserTest extends AbstractTest {
         userDAO.flush();
 
         assertNull(userDAO.findByUsername("bellini"));
-        assertNull(plainAttrDAO.find(UUID.randomUUID().toString(), UPlainAttr.class));
-        assertNull(plainAttrValueDAO.find(UUID.randomUUID().toString(), UPlainAttrValue.class));
+        assertNull(findPlainAttr(UUID.randomUUID().toString(), UPlainAttr.class));
+        assertNull(findPlainAttrValue(UUID.randomUUID().toString(), UPlainAttrValue.class));
         assertNotNull(plainSchemaDAO.find("loginDate"));
 
         memberships = groupDAO.findUMemberships(groupDAO.findByName("managingDirector"));
@@ -103,7 +95,7 @@ public class UserTest extends AbstractTest {
                 "bf825fe1-7320-4a54-bd64-143b5c18ab97",
                 user.getMemberships().get(0).getRightEnd().getKey());
 
-        user.getMemberships().remove(0);
+        user.remove(user.getMemberships().get(0));
 
         UMembership newM = entityFactory.newEntity(UMembership.class);
         newM.setLeftEnd(user);
@@ -202,7 +194,7 @@ public class UserTest extends AbstractTest {
         user = userDAO.findByUsername("vivaldi");
         assertEquals(1, user.getMemberships().size());
 
-        final UMembership newM = user.getMembership(groupDAO.findByName("additional").getKey()).get();
+        UMembership newM = user.getMembership(groupDAO.findByName("additional").getKey()).get();
         assertEquals(1, user.getPlainAttrs(newM).size());
 
         assertNull(user.getPlainAttr("obscure").get().getMembership());
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
index 7f2297c..4dfc322 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/XMLContentExporterTest.java
@@ -55,11 +55,11 @@ public class XMLContentExporterTest extends AbstractTest {
 
         List<String> realms = IOUtils.readLines(
                 IOUtils.toInputStream(exported, Charset.defaultCharset()), Charset.defaultCharset()).stream().
-                filter(row -> row.trim().startsWith("<REALM")).collect(Collectors.toList());
+                filter(row -> StringUtils.startsWithIgnoreCase(row.trim(), "<REALM")).collect(Collectors.toList());
         assertEquals(4, realms.size());
-        assertTrue(realms.get(0).contains("NAME=\"/\""));
-        assertTrue(realms.get(1).contains("NAME=\"odd\""));
-        assertTrue(realms.get(2).contains("NAME=\"even\""));
-        assertTrue(realms.get(3).contains("NAME=\"two\""));
+        assertTrue(StringUtils.containsIgnoreCase(realms.get(0), "NAME=\"/\""));
+        assertTrue(StringUtils.containsIgnoreCase(realms.get(1), "NAME=\"odd\""));
+        assertTrue(StringUtils.containsIgnoreCase(realms.get(2), "NAME=\"even\""));
+        assertTrue(StringUtils.containsIgnoreCase(realms.get(3), "NAME=\"two\""));
     }
 }
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index c7499a8..528b88c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -296,14 +296,10 @@ abstract class AbstractAnyDataBinder {
                             && !patch.getAttrTO().getValues().isEmpty()
                             && !patch.getAttrTO().getValues().get(0).equals(attr.getUniqueValue().getValueAsString())) {
 
-                        plainAttrValueDAO.delete(attr.getUniqueValue().getKey(), anyUtils.plainAttrUniqueValueClass());
+                        plainAttrValueDAO.deleteAll(attr, anyUtils);
                     }
                 } else {
-                    Collection<String> valuesToBeRemoved = attr.getValues().stream().
-                            map(value -> value.getKey()).collect(Collectors.toSet());
-                    valuesToBeRemoved.forEach(attrValueKey -> {
-                        plainAttrValueDAO.delete(attrValueKey, anyUtils.plainAttrValueClass());
-                    });
+                    plainAttrValueDAO.deleteAll(attr, anyUtils);
                 }
 
                 // 1.2 add values
@@ -324,7 +320,7 @@ abstract class AbstractAnyDataBinder {
             case DELETE:
             default:
                 any.remove(attr);
-                plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass());
+                plainAttrDAO.delete(attr);
         }
 
         resources.stream().
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index 3bab7fe..f772503 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -339,7 +339,7 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
         anyObjectPatch.getMemberships().stream().
                 filter((membPatch) -> (membPatch.getGroup() != null)).forEachOrdered(membPatch -> {
             anyObject.getMembership(membPatch.getGroup()).ifPresent(membership -> {
-                anyObject.getMemberships().remove(membership);
+                anyObject.remove(membership);
                 membership.setLeftEnd(null);
                 anyObject.getPlainAttrs(membership).forEach(attr -> {
                     anyObject.remove(attr);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index e50f59e..055f7aa 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -412,7 +412,7 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
         userPatch.getMemberships().stream().
                 filter(membPatch -> membPatch.getGroup() != null).forEachOrdered((membPatch) -> {
             user.getMembership(membPatch.getGroup()).ifPresent(membership -> {
-                user.getMemberships().remove(membership);
+                user.remove(membership);
                 membership.setLeftEnd(null);
                 user.getPlainAttrs(membership).forEach(attr -> {
                     user.remove(attr);
diff --git a/docker/core/src/main/resources/persistence.properties b/docker/core/src/main/resources/persistence.properties
index 6df8091..b656eb2 100644
--- a/docker/core/src/main/resources/persistence.properties
+++ b/docker/core/src/main/resources/persistence.properties
@@ -15,5 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 content.directory=/etc/apache-syncope
+entity.factory=org.apache.syncope.core.persistence.jpa.entity.JPAEntityFactory
+plainSchema.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainSchemaDAO
+plainAttr.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrDAO
+plainAttrValue.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrValueDAO
 any.search.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnySearchDAO
+user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO
+group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAGroupDAO
+anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnyObjectDAO
 openjpa.RemoteCommitProvider=${OPENJPA_REMOTE_COMMIT}
diff --git a/ext/elasticsearch/persistence-jpa/src/main/resources/persistence.properties b/ext/elasticsearch/persistence-jpa/src/main/resources/persistence.properties
index a3048a1..194c758 100644
--- a/ext/elasticsearch/persistence-jpa/src/main/resources/persistence.properties
+++ b/ext/elasticsearch/persistence-jpa/src/main/resources/persistence.properties
@@ -15,5 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 content.directory=${conf.directory}
+entity.factory=org.apache.syncope.core.persistence.jpa.entity.JPAEntityFactory
+plainSchema.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainSchemaDAO
+plainAttr.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrDAO
+plainAttrValue.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrValueDAO
 any.search.dao=org.apache.syncope.core.persistence.jpa.dao.ElasticsearchAnySearchDAO
+user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO
+group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAGroupDAO
+anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnyObjectDAO
 openjpa.RemoteCommitProvider=sjvm
diff --git a/fit/core-reference/src/main/resources/elasticsearch/persistence.properties b/fit/core-reference/src/main/resources/elasticsearch/persistence.properties
index a3048a1..194c758 100644
--- a/fit/core-reference/src/main/resources/elasticsearch/persistence.properties
+++ b/fit/core-reference/src/main/resources/elasticsearch/persistence.properties
@@ -15,5 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 content.directory=${conf.directory}
+entity.factory=org.apache.syncope.core.persistence.jpa.entity.JPAEntityFactory
+plainSchema.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainSchemaDAO
+plainAttr.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrDAO
+plainAttrValue.dao=org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrValueDAO
 any.search.dao=org.apache.syncope.core.persistence.jpa.dao.ElasticsearchAnySearchDAO
+user.dao=org.apache.syncope.core.persistence.jpa.dao.JPAUserDAO
+group.dao=org.apache.syncope.core.persistence.jpa.dao.JPAGroupDAO
+anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.JPAAnyObjectDAO
 openjpa.RemoteCommitProvider=sjvm


[syncope] 02/02: [SYNCOPE-1395] persistence-jpa-pgjsonb module, passing all persistence-jpa's unit tests

Posted by il...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 62d04f2c836c581a344ab7633d3bbab2ee8a6be0
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Fri Nov 9 14:33:18 2018 +0100

    [SYNCOPE-1395] persistence-jpa-pgjsonb module, passing all persistence-jpa's unit tests
---
 core/persistence-jpa-pgjsonb/pom.xml               |  302 +++
 .../syncope/core/persistence/api/dao/PGAnyDAO.java |   38 +
 .../core/persistence/jpa/dao/PGJPAAnyDAO.java      |  355 +++
 .../persistence/jpa/dao/PGJPAAnyObjectDAO.java     |   81 +
 .../persistence/jpa/dao/PGJPAAnySearchDAO.java     |  231 ++
 .../core/persistence/jpa/dao/PGJPAGroupDAO.java    |   81 +
 .../persistence/jpa/dao/PGJPAPlainAttrDAO.java     |   34 +
 .../jpa/dao/PGJPAPlainAttrValueDAO.java            |   46 +
 .../persistence/jpa/dao/PGJPAPlainSchemaDAO.java   |   38 +
 .../core/persistence/jpa/dao/PGJPAUserDAO.java     |   89 +
 .../core/persistence/jpa/entity/PGJPAAny.java      |   33 +
 .../persistence/jpa/entity/PGJPAEntityFactory.java |  132 ++
 .../jpa/entity/PGJPAEntityListener.java            |   49 +
 .../core/persistence/jpa/entity/PGPlainAttr.java   |   30 +
 .../jpa/entity/anyobject/PGAPlainAttr.java         |  196 ++
 .../entity/anyobject/PGAPlainAttrUniqueValue.java  |   60 +
 .../jpa/entity/anyobject/PGAPlainAttrValue.java    |   48 +
 .../jpa/entity/anyobject/PGJPAAnyObject.java       |   97 +
 .../entity/anyobject/PGJPAAnyObjectListener.java   |   49 +
 .../persistence/jpa/entity/conf/PGCPlainAttr.java  |  163 ++
 .../jpa/entity/conf/PGCPlainAttrUniqueValue.java   |   60 +
 .../jpa/entity/conf/PGCPlainAttrValue.java         |   48 +
 .../persistence/jpa/entity/conf/PGJPAConf.java     |   85 +
 .../jpa/entity/conf/PGJPAConfListener.java         |   49 +
 .../persistence/jpa/entity/group/PGGPlainAttr.java |  163 ++
 .../jpa/entity/group/PGGPlainAttrUniqueValue.java  |   60 +
 .../jpa/entity/group/PGGPlainAttrValue.java        |   48 +
 .../persistence/jpa/entity/group/PGJPAGroup.java   |   87 +
 .../jpa/entity/group/PGJPAGroupListener.java       |   49 +
 .../persistence/jpa/entity/user/PGJPAUser.java     |   90 +
 .../jpa/entity/user/PGJPAUserListener.java         |   49 +
 .../persistence/jpa/entity/user/PGUPlainAttr.java  |  196 ++
 .../jpa/entity/user/PGUPlainAttrUniqueValue.java   |   60 +
 .../jpa/entity/user/PGUPlainAttrValue.java         |   48 +
 .../jpa/validation/entity/PGJPAAnyCheck.java       |   41 +
 .../jpa/validation/entity/PGJPAAnyValidator.java   |   45 +
 .../main/resources/META-INF/spring-orm-pgjsonb.xml |   37 +
 .../src/main/resources/domains/Master.properties   |   28 +
 .../src/main/resources/indexes.xml                 |   63 +
 .../src/main/resources/persistence.properties      |   26 +
 .../src/main/resources/views.xml                   |  154 ++
 .../src/test/resources/domains/MasterContent.xml   | 2410 ++++++++++++++++++++
 .../src/test/resources/persistenceTest.xml         |   55 +
 .../src/test/resources/simplelogger.properties     |   22 +
 core/pom.xml                                       |    1 +
 45 files changed, 6126 insertions(+)

diff --git a/core/persistence-jpa-pgjsonb/pom.xml b/core/persistence-jpa-pgjsonb/pom.xml
new file mode 100644
index 0000000..de08084
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/pom.xml
@@ -0,0 +1,302 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.syncope</groupId>
+    <artifactId>syncope-core</artifactId>
+    <version>2.1.3-SNAPSHOT</version>
+  </parent>
+
+  <name>Apache Syncope Core Persistence JPA PostgreSQL jsonb</name>
+  <description>Apache Syncope Core Persistence JPA PostgreSQL jsonb</description>
+  <groupId>org.apache.syncope.core</groupId>
+  <artifactId>syncope-core-persistence-jpa-pgjsonb</artifactId>
+  <packaging>jar</packaging>
+  
+  <properties>
+    <rootpom.basedir>${basedir}/../..</rootpom.basedir>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.syncope.core</groupId>
+      <artifactId>syncope-core-persistence-jpa</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <!-- TEST -->
+    <dependency> 
+      <groupId>javax.servlet</groupId> 
+      <artifactId>javax.servlet-api</artifactId> 
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <version>${slf4j.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.h2database</groupId>
+      <artifactId>h2</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-engine</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.openjpa</groupId>
+        <artifactId>openjpa-maven-plugin</artifactId>
+        <inherited>true</inherited>
+        <dependencies>
+          <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>${h2.version}</version>
+          </dependency>
+        </dependencies>
+        <configuration>
+          <persistenceXmlFile>${project.basedir}/../persistence-jpa/src/main/resources/persistence-enhance.xml</persistenceXmlFile> 
+          <includes>org/apache/syncope/core/persistence/jpa/entity/**/*.class</includes>
+          <connectionDriverName>org.springframework.jdbc.datasource.DriverManagerDataSource</connectionDriverName>
+          <connectionProperties>
+            driverClassName=org.h2.Driver,
+            url=jdbc:h2:mem:syncopedb
+            username=sa,
+            password=
+          </connectionProperties>
+        </configuration>
+        <executions>
+          <execution>
+            <id>enhancer</id>
+            <phase>process-classes</phase>
+            <goals>
+              <goal>enhance</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+      </plugin>
+    </plugins>
+
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>ut</id>
+      
+      <dependencies>
+        <dependency>
+          <groupId>org.postgresql</groupId>
+          <artifactId>postgresql</artifactId>
+          <version>${jdbc.postgresql.version}</version>
+          <scope>test</scope>
+        </dependency>
+      </dependencies>
+
+      <build>
+        <defaultGoal>clean verify</defaultGoal>
+        
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>build-helper-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>add-test-source</id>
+                <phase>generate-test-sources</phase>
+                <goals>
+                  <goal>add-test-source</goal>
+                </goals>
+                <configuration>
+                  <sources>
+                    <source>${basedir}/../persistence-jpa/src/test/java</source>
+                  </sources>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+      
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <configuration>
+              <includes>
+                <include>**/*Test.java</include>
+              </includes>
+              <excludedGroups>multitenancy,plainAttrTable</excludedGroups>
+            </configuration>
+          </plugin>
+
+          <plugin>
+            <groupId>io.fabric8</groupId>
+            <artifactId>docker-maven-plugin</artifactId>
+            <configuration>
+              <images>
+                <image>
+                  <name>crunchydata/crunchy-postgres:centos7-10.5-2.1.0</name>
+                  <run>
+                    <env>
+                      <PG_ROOT_PASSWORD>postgres</PG_ROOT_PASSWORD>
+                      <PG_MODE>primary</PG_MODE>
+                      <PG_PRIMARY_USER>postgres</PG_PRIMARY_USER>
+                      <PG_PRIMARY_PASSWORD>postgres</PG_PRIMARY_PASSWORD>
+                      <PG_PRIMARY_HOST>localhost</PG_PRIMARY_HOST>
+                      <PG_PRIMARY_PORT>5432</PG_PRIMARY_PORT>
+                      <PG_DATABASE>syncope</PG_DATABASE>
+                      <PG_USER>syncope</PG_USER>
+                      <PG_PASSWORD>syncope</PG_PASSWORD>
+                    </env>
+                    <ports>
+                      <port>5432:5432</port>
+                    </ports>
+                  </run>
+                </image>
+              </images>
+            </configuration>
+            <executions>
+              <execution>
+                <id>start-postgres</id>
+                <phase>pre-integration-test</phase>
+                <goals>
+                  <goal>start</goal>
+                </goals>
+              </execution>
+              <execution>
+                <id>stop-postgres</id>
+                <phase>post-integration-test</phase>
+                <goals>
+                  <goal>stop</goal>
+                  <goal>remove</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+        
+        <testResources>
+          <testResource>
+            <directory>src/test/resources</directory>
+            <filtering>true</filtering>
+          </testResource>
+          <testResource>
+            <directory>src/main/resources</directory>
+            <filtering>true</filtering>
+          </testResource>
+        </testResources>
+      </build>
+    </profile>
+    
+    <profile>
+      <id>sqlgen</id>
+      
+      <properties>
+        <skipTests>true</skipTests>
+      </properties>
+      
+      <build>
+        <defaultGoal>clean verify</defaultGoal>
+        
+        <plugins>
+          <plugin>
+            <groupId>org.apache.openjpa</groupId>
+            <artifactId>openjpa-maven-plugin</artifactId>
+            <inherited>true</inherited>
+            <executions>
+              <execution>
+                <id>sqlgen</id>
+                <phase>process-classes</phase>
+                <goals>
+                  <goal>sql</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>          
+        </plugins>
+      </build>
+    </profile>
+    
+    <profile>
+      <id>schemagen</id>
+      
+      <properties>
+        <skipTests>true</skipTests>
+      </properties>
+      
+      <build>
+        <defaultGoal>clean verify</defaultGoal>
+        
+        <plugins>
+          <plugin>
+            <groupId>org.apache.openjpa</groupId>
+            <artifactId>openjpa-maven-plugin</artifactId>
+            <inherited>true</inherited>
+            <executions>
+              <execution>
+                <id>schemagen</id>
+                <phase>process-classes</phase>
+                <goals>
+                  <goal>schema</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>          
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/api/dao/PGAnyDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/api/dao/PGAnyDAO.java
new file mode 100644
index 0000000..2fecad7
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/api/dao/PGAnyDAO.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.dao;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+
+public interface PGAnyDAO {
+
+    <A extends Any<?>> List<A> findByDerAttrValue(
+            String table, AnyUtils anyUtils, String schemaKey, String value, boolean ignoreCaseMatch);
+
+    <A extends Any<?>> A findByPlainAttrUniqueValue(
+            String table, AnyUtils anyUtils, String schemaKey, PlainAttrValue attrUniqueValue, boolean ignoreCaseMatch);
+
+    <A extends Any<?>> List<A> findByPlainAttrValue(
+            String table, AnyUtils anyUtils, String schemaKey, PlainAttrValue attrValue, boolean ignoreCaseMatch);
+
+    <A extends Any<?>> void checkBeforeSave(String table, AnyUtils anyUtils, A any);
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnyDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnyDAO.java
new file mode 100644
index 0000000..030bba8
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnyDAO.java
@@ -0,0 +1,355 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.regex.Pattern;
+import javax.persistence.Query;
+import org.apache.commons.jexl3.parser.Parser;
+import org.apache.commons.jexl3.parser.ParserConstants;
+import org.apache.commons.jexl3.parser.Token;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.DuplicateException;
+import org.apache.syncope.core.persistence.api.dao.PGAnyDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractEntity;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+import org.apache.syncope.core.spring.security.AuthContextUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+@Repository
+public class PGJPAAnyDAO extends AbstractDAO<AbstractEntity> implements PGAnyDAO {
+
+    @Autowired
+    private PlainSchemaDAO plainSchemaDAO;
+
+    @Autowired
+    private DerSchemaDAO derSchemaDAO;
+
+    private String queryBegin(final String table) {
+        return "SELECT DISTINCT id FROM " + table + " u,"
+                + "jsonb_array_elements(u.plainAttrs) attrs,"
+                + "jsonb_array_elements(COALESCE(attrs -> 'values', '[{}]'::jsonb)) attrValues ";
+    }
+
+    private String attrValueMatch(
+            final AnyUtils anyUtils,
+            final PlainSchema schema,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        String key;
+        boolean lower = false;
+
+        switch (schema.getType()) {
+            case Boolean:
+                key = "booleanValue";
+                break;
+
+            case Date:
+                key = "dateValue";
+                break;
+
+            case Double:
+                key = "doubleValue";
+                break;
+
+            case Long:
+                key = "longValue";
+                break;
+
+            case Binary:
+                key = "binaryValue";
+                break;
+
+            default:
+                lower = ignoreCaseMatch;
+                key = "stringValue";
+        }
+
+        if (lower) {
+            return "attrs ->> 'schema' = ? "
+                    + "AND "
+                    + (lower ? "LOWER(" : "")
+                    + (schema.isUniqueConstraint() ? "attrs -> 'uniqueValue'" : "attrValues") + " ->> '" + key
+                    + "'" + (lower ? ")" : "")
+                    + " = "
+                    + (lower ? "LOWER(" : "")
+                    + "?"
+                    + (lower ? ")" : "");
+        } else {
+            PlainAttr<?> container = anyUtils.newPlainAttr();
+            container.setSchema(schema);
+            if (attrValue instanceof PlainAttrUniqueValue) {
+                container.setUniqueValue((PlainAttrUniqueValue) attrValue);
+            } else {
+                ((PGPlainAttr) container).add(attrValue);
+            }
+            return "plainAttrs @> '" + POJOHelper.serialize(Arrays.asList(container)) + "'::jsonb";
+        }
+    }
+
+    private <A extends Any<?>> List<A> buildResult(final AnyUtils anyUtils, final List<Object> queryResult) {
+        List<A> result = new ArrayList<>();
+        queryResult.forEach(anyKey -> {
+            A any = anyUtils.<A>dao().find(anyKey.toString());
+            if (any == null) {
+                LOG.error("Could not find any for key {}", anyKey);
+            } else {
+                result.add(any);
+            }
+        });
+        return result;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Transactional(readOnly = true)
+    @Override
+    public <A extends Any<?>> List<A> findByPlainAttrValue(
+            final String table,
+            final AnyUtils anyUtils,
+            final String schemaKey,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        PlainSchema schema = plainSchemaDAO.find(schemaKey);
+        if (schema == null) {
+            LOG.error("Invalid schema '{}'", schemaKey);
+            return Collections.<A>emptyList();
+        }
+
+        Query query = entityManager().createNativeQuery(
+                queryBegin(table)
+                + "WHERE " + attrValueMatch(anyUtils, schema, attrValue, ignoreCaseMatch));
+        query.setParameter(1, schemaKey);
+        query.setParameter(2, attrValue.getValue());
+
+        return buildResult(anyUtils, query.getResultList());
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public <A extends Any<?>> A findByPlainAttrUniqueValue(
+            final String table,
+            final AnyUtils anyUtils,
+            final String schemaKey,
+            final PlainAttrValue attrUniqueValue,
+            final boolean ignoreCaseMatch) {
+
+        PlainSchema schema = plainSchemaDAO.find(schemaKey);
+        if (schema == null) {
+            LOG.error("Invalid schema '{}'", schemaKey);
+            return null;
+        }
+        if (!schema.isUniqueConstraint()) {
+            LOG.error("This schema has not unique constraint: '{}'", schemaKey);
+            return null;
+        }
+
+        List<A> result = findByPlainAttrValue(table, anyUtils, schemaKey, attrUniqueValue, ignoreCaseMatch);
+        return result.isEmpty()
+                ? null
+                : result.get(0);
+    }
+
+    /**
+     * Split an attribute value recurring on provided literals/tokens.
+     *
+     * @param attrValue value to be split
+     * @param literals literals/tokens
+     * @return split value
+     */
+    private List<String> split(final String attrValue, final List<String> literals) {
+        final List<String> attrValues = new ArrayList<>();
+
+        if (literals.isEmpty()) {
+            attrValues.add(attrValue);
+        } else {
+            for (String token : attrValue.split(Pattern.quote(literals.get(0)))) {
+                if (!token.isEmpty()) {
+                    attrValues.addAll(split(token, literals.subList(1, literals.size())));
+                }
+            }
+        }
+
+        return attrValues;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Transactional(readOnly = true)
+    @Override
+    public <A extends Any<?>> List<A> findByDerAttrValue(
+            final String table,
+            final AnyUtils anyUtils,
+            final String schemaKey,
+            final String value,
+            final boolean ignoreCaseMatch) {
+
+        DerSchema derSchema = derSchemaDAO.find(schemaKey);
+        if (derSchema == null) {
+            LOG.error("Invalid schema '{}'", schemaKey);
+            return Collections.<A>emptyList();
+        }
+
+        Parser parser = new Parser(new StringReader(derSchema.getExpression()));
+
+        // Schema keys
+        List<String> identifiers = new ArrayList<>();
+
+        // Literals
+        List<String> literals = new ArrayList<>();
+
+        // Get schema keys and literals
+        for (Token token = parser.getNextToken(); token != null && StringUtils.isNotBlank(token.toString());
+                token = parser.getNextToken()) {
+
+            if (token.kind == ParserConstants.STRING_LITERAL) {
+                literals.add(token.toString().substring(1, token.toString().length() - 1));
+            }
+
+            if (token.kind == ParserConstants.IDENTIFIER) {
+                identifiers.add(token.toString());
+            }
+        }
+
+        // Sort literals in order to process later literals included into others
+        Collections.sort(literals, (l1, l2) -> {
+            if (l1 == null && l2 == null) {
+                return 0;
+            } else if (l1 != null && l2 == null) {
+                return -1;
+            } else if (l1 == null && l2 != null) {
+                return 1;
+            } else if (l1.length() == l2.length()) {
+                return 0;
+            } else if (l1.length() > l2.length()) {
+                return -1;
+            } else {
+                return 1;
+            }
+        });
+
+        // Split value on provided literals
+        List<String> attrValues = split(value, literals);
+
+        if (attrValues.size() != identifiers.size()) {
+            LOG.error("Ambiguous JEXL expression resolution: literals and values have different size");
+            return Collections.emptyList();
+        }
+
+        StringJoiner clauses = new StringJoiner(" AND id IN ");
+
+        // builder to build the clauses
+        StringBuilder bld = new StringBuilder();
+
+        // Contains used identifiers in order to avoid replications
+        Set<String> used = new HashSet<>();
+
+        List<Object> queryParams = new ArrayList<>();
+
+        // Create several clauses: one for eanch identifiers
+        for (int i = 0; i < identifiers.size(); i++) {
+            if (!used.contains(identifiers.get(i))) {
+                // verify schema existence and get schema type
+                PlainSchema schema = plainSchemaDAO.find(identifiers.get(i));
+                if (schema == null) {
+                    LOG.error("Invalid schema '{}', ignoring", identifiers.get(i));
+                } else {
+                    // clear builder
+                    bld.delete(0, bld.length());
+
+                    PlainAttrValue attrValue;
+                    if (schema.isUniqueConstraint()) {
+                        attrValue = anyUtils.newPlainAttrUniqueValue();
+                    } else {
+                        attrValue = anyUtils.newPlainAttrValue();
+                    }
+                    attrValue.setStringValue(attrValues.get(i));
+
+                    bld.append('(').
+                            append(queryBegin(table)).
+                            append("WHERE ").
+                            append(attrValueMatch(anyUtils, schema, attrValue, ignoreCaseMatch)).
+                            append(')');
+                    queryParams.add(schema.getKey());
+                    queryParams.add(attrValues.get(i));
+
+                    used.add(identifiers.get(i));
+
+                    clauses.add(bld.toString());
+                }
+            }
+        }
+
+        LOG.debug("Generated where clauses {}", clauses);
+
+        Query query = entityManager().createNativeQuery(
+                "SELECT DISTINCT id FROM " + table + " u WHERE id IN " + clauses.toString());
+        for (int i = 0; i < queryParams.size(); i++) {
+            query.setParameter(i + 1, queryParams.get(i));
+        }
+
+        return buildResult(anyUtils, query.getResultList());
+    }
+
+    @Transactional
+    @Override
+    public <A extends Any<?>> void checkBeforeSave(final String table, final AnyUtils anyUtils, final A any) {
+        // check UNIQUE constraints
+        any.getPlainAttrs().stream().
+                filter(attr -> attr.getUniqueValue() != null).
+                map(PGPlainAttr.class::cast).
+                forEach(attr -> {
+                    String schemaKey = attr.getSchemaKey();
+                    List<A> others = findByPlainAttrValue(table, anyUtils, schemaKey, attr.getUniqueValue(), false);
+                    if (others.isEmpty() || (others.size() == 1 && others.get(0).getKey().equals(any.getKey()))) {
+                        LOG.debug("No duplicate value found for {}", attr.getUniqueValue().getValueAsString());
+                    } else {
+                        throw new DuplicateException(
+                                "Value " + attr.getUniqueValue().getValueAsString() + " existing for " + schemaKey);
+                    }
+                });
+
+        // update sysInfo - as org.apache.syncope.core.persistence.jpa.entity.PlainAttrListener is not invoked
+        Date now = new Date();
+        String username = AuthContextUtils.getUsername();
+        LOG.debug("Set last change date '{}' and modifier '{}' for '{}'", now, username, any);
+        any.setLastModifier(username);
+        any.setLastChangeDate(now);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnyObjectDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnyObjectDAO.java
new file mode 100644
index 0000000..4879f26
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnyObjectDAO.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.dao.PGAnyDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.PGJPAAnyObject;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.springframework.transaction.annotation.Transactional;
+
+public class PGJPAAnyObjectDAO extends JPAAnyObjectDAO {
+
+    private PGAnyDAO anyDAO;
+
+    private PGAnyDAO anyDAO() {
+        if (anyDAO == null) {
+            anyDAO = ApplicationContextProvider.getApplicationContext().getBean(PGAnyDAO.class);
+        }
+        return anyDAO;
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public AnyObject find(final String key) {
+        return entityManager().find(PGJPAAnyObject.class, key);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<AnyObject> findByPlainAttrValue(
+            final String schemaKey,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByPlainAttrValue(PGJPAAnyObject.TABLE, anyUtils(), schemaKey, attrValue, ignoreCaseMatch);
+    }
+
+    @Override
+    public AnyObject findByPlainAttrUniqueValue(
+            final String schemaKey,
+            final PlainAttrValue attrUniqueValue,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByPlainAttrUniqueValue(PGJPAAnyObject.TABLE, anyUtils(),
+                schemaKey, attrUniqueValue, ignoreCaseMatch);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<AnyObject> findByDerAttrValue(
+            final String schemaKey,
+            final String value,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByDerAttrValue(PGJPAAnyObject.TABLE, anyUtils(), schemaKey, value, ignoreCaseMatch);
+    }
+
+    @Override
+    public AnyObject save(final AnyObject anyObject) {
+        anyDAO().checkBeforeSave(PGJPAAnyObject.TABLE, anyUtils(), anyObject);
+        return super.save(anyObject);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnySearchDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnySearchDAO.java
new file mode 100644
index 0000000..0fa44f0
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAAnySearchDAO.java
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+public class PGJPAAnySearchDAO extends JPAAnySearchDAO {
+
+    @Override
+    SearchSupport buildSearchSupport(final AnyTypeKind kind) {
+        return new SearchSupport(kind);
+    }
+
+    @Override
+    protected void processOBS(final SearchSupport svs, final OrderBySupport obs, final StringBuilder where) {
+        obs.views.forEach(searchView -> {
+            where.append(',').
+                    append(searchView.name).
+                    append(' ').append(searchView.alias);
+        });
+    }
+
+    @Override
+    protected void parseOrderByForPlainSchema(
+            final SearchSupport svs,
+            final OrderBySupport obs,
+            final OrderBySupport.Item item,
+            final OrderByClause clause,
+            final PlainSchema schema,
+            final String fieldName) {
+
+        // keep track of involvement of non-mandatory schemas in the order by clauses
+        obs.nonMandatorySchemas = !"true".equals(schema.getMandatoryCondition());
+
+        obs.views.add(svs.field());
+
+        item.select = svs.field().alias + ".attrValues ->> '" + fieldName + "' AS " + fieldName;
+        item.where = "attrs ->> 'schema' = '" + fieldName + "'";
+        item.orderBy = fieldName + " " + clause.getDirection().name();
+    }
+
+    private void fillAttrQuery(
+            final AnyUtils anyUtils,
+            final StringBuilder query,
+            final PlainAttrValue attrValue,
+            final PlainSchema schema,
+            final AttributeCond cond,
+            final boolean not,
+            final List<Object> parameters) {
+
+        String key;
+        boolean lower = false;
+        switch (schema.getType()) {
+            case Boolean:
+                key = "booleanValue";
+                break;
+
+            case Date:
+                key = "dateValue";
+                break;
+
+            case Double:
+                key = "doubleValue";
+                break;
+
+            case Long:
+                key = "longValue";
+                break;
+
+            case Binary:
+                key = "binaryValue";
+                break;
+
+            default:
+                lower = cond.getType() == AttributeCond.Type.IEQ || cond.getType() == AttributeCond.Type.ILIKE;
+                key = "stringValue";
+        }
+
+        if (!not && cond.getType() == AttributeCond.Type.EQ) {
+            PlainAttr<?> container = anyUtils.newPlainAttr();
+            container.setSchema(schema);
+            if (attrValue instanceof PlainAttrUniqueValue) {
+                container.setUniqueValue((PlainAttrUniqueValue) attrValue);
+            } else {
+                ((PGPlainAttr) container).add(attrValue);
+            }
+
+            query.append("plainAttrs @> '").
+                    append(POJOHelper.serialize(Arrays.asList(container))).
+                    append("'::jsonb");
+        } else {
+            query.append("attrs ->> 'schema' = ?").append(setParameter(parameters, cond.getSchema())).
+                    append(" AND ").
+                    append(lower ? "LOWER(" : "").
+                    append(schema.isUniqueConstraint()
+                            ? "attrs -> 'uniqueValue'" : "attrValues").
+                    append(" ->> '").append(key).append("'").
+                    append(lower ? ")" : "");
+
+            switch (cond.getType()) {
+                case LIKE:
+                case ILIKE:
+                    if (not) {
+                        query.append("NOT ");
+                    }
+                    query.append(" LIKE ");
+                    break;
+
+                case GE:
+                    if (not) {
+                        query.append('<');
+                    } else {
+                        query.append(">=");
+                    }
+                    break;
+
+                case GT:
+                    if (not) {
+                        query.append("<=");
+                    } else {
+                        query.append('>');
+                    }
+                    break;
+
+                case LE:
+                    if (not) {
+                        query.append('>');
+                    } else {
+                        query.append("<=");
+                    }
+                    break;
+
+                case LT:
+                    if (not) {
+                        query.append(">=");
+                    } else {
+                        query.append('<');
+                    }
+                    break;
+
+                case EQ:
+                case IEQ:
+                default:
+                    if (not) {
+                        query.append('!');
+                    }
+                    query.append('=');
+            }
+
+            query.append(lower ? "LOWER(" : "").
+                    append("?").append(setParameter(parameters, cond.getExpression())).
+                    append(lower ? ")" : "");
+        }
+    }
+
+    @Override
+    protected String getQuery(
+            final AttributeCond cond,
+            final boolean not,
+            final List<Object> parameters,
+            final SearchSupport svs) {
+
+        Pair<PlainSchema, PlainAttrValue> checked;
+        try {
+            checked = check(cond, svs.anyTypeKind);
+        } catch (IllegalArgumentException e) {
+            return EMPTY_QUERY;
+        }
+
+        // normalize NULL / NOT NULL checks
+        if (not) {
+            if (cond.getType() == AttributeCond.Type.ISNULL) {
+                cond.setType(AttributeCond.Type.ISNOTNULL);
+            } else if (cond.getType() == AttributeCond.Type.ISNOTNULL) {
+                cond.setType(AttributeCond.Type.ISNULL);
+            }
+        }
+
+        StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM ").
+                append(svs.field().name).append(" WHERE ");
+        switch (cond.getType()) {
+            case ISNOTNULL:
+                query.append("plainAttrs @> '[{\"schema\":\"").
+                        append(checked.getLeft().getKey()).
+                        append("\"}]'::jsonb");
+                break;
+
+            case ISNULL:
+                query.append("any_id NOT IN (").
+                        append("SELECT any_id FROM ").append(svs.field().name).
+                        append(" WHERE plainAttrs @> '[{\"schema\":\"").
+                        append(checked.getLeft().getKey()).
+                        append("\"}]'::jsonb)");
+                break;
+
+            default:
+                fillAttrQuery(anyUtilsFactory.getInstance(svs.anyTypeKind),
+                        query, checked.getRight(), checked.getLeft(), cond, not, parameters);
+        }
+
+        return query.toString();
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAGroupDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAGroupDAO.java
new file mode 100644
index 0000000..4c020c6
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAGroupDAO.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.dao.PGAnyDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.jpa.entity.group.PGJPAGroup;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.springframework.transaction.annotation.Transactional;
+
+public class PGJPAGroupDAO extends JPAGroupDAO {
+
+    private PGAnyDAO anyDAO;
+
+    private PGAnyDAO anyDAO() {
+        if (anyDAO == null) {
+            anyDAO = ApplicationContextProvider.getApplicationContext().getBean(PGAnyDAO.class);
+        }
+        return anyDAO;
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public Group find(final String key) {
+        return entityManager().find(PGJPAGroup.class, key);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<Group> findByPlainAttrValue(
+            final String schemaKey,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByPlainAttrValue(PGJPAGroup.TABLE, anyUtils(), schemaKey, attrValue, ignoreCaseMatch);
+    }
+
+    @Override
+    public Group findByPlainAttrUniqueValue(
+            final String schemaKey,
+            final PlainAttrValue attrUniqueValue,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByPlainAttrUniqueValue(PGJPAGroup.TABLE, anyUtils(),
+                schemaKey, attrUniqueValue, ignoreCaseMatch);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<Group> findByDerAttrValue(
+            final String schemaKey,
+            final String value,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByDerAttrValue(PGJPAGroup.TABLE, anyUtils(), schemaKey, value, ignoreCaseMatch);
+    }
+
+    @Override
+    public Group save(final Group group) {
+        anyDAO().checkBeforeSave(PGJPAGroup.TABLE, anyUtils(), group);
+        return super.save(group);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainAttrDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainAttrDAO.java
new file mode 100644
index 0000000..5ede5a6
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainAttrDAO.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+
+public class PGJPAPlainAttrDAO extends AbstractDAO<PlainAttr<?>> implements PlainAttrDAO {
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T extends PlainAttr<?>> void delete(final T plainAttr) {
+        if (plainAttr.getOwner() != null) {
+            ((Any<T>) plainAttr.getOwner()).remove(plainAttr);
+        }
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainAttrValueDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainAttrValueDAO.java
new file mode 100644
index 0000000..0b67612
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainAttrValueDAO.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.core.persistence.jpa.dao;
+
+import static org.apache.syncope.core.persistence.jpa.dao.JPAPlainAttrValueDAO.getEntityReference;
+
+import java.util.stream.Collectors;
+import org.apache.syncope.core.persistence.api.dao.PlainAttrValueDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+
+public class PGJPAPlainAttrValueDAO extends AbstractDAO<PlainAttrValue> implements PlainAttrValueDAO {
+
+    @Override
+    public void deleteAll(final PlainAttr<?> attr, final AnyUtils anyUtils) {
+        if (attr.getUniqueValue() == null) {
+            attr.getValues().stream().map(Entity::getKey).collect(Collectors.toSet()).forEach(attrValueKey -> {
+                PlainAttrValue attrValue = anyUtils.plainAttrValueClass().cast(
+                        entityManager().find(getEntityReference(anyUtils.plainAttrValueClass()), attrValueKey));
+                if (attrValue != null) {
+                    attr.getValues().remove(attrValue);
+                }
+            });
+        } else {
+            attr.setUniqueValue(null);
+        }
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainSchemaDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainSchemaDAO.java
new file mode 100644
index 0000000..ba8b97b
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAPlainSchemaDAO.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+
+public class PGJPAPlainSchemaDAO extends JPAPlainSchemaDAO {
+
+    @Override
+    public <T extends PlainAttr<?>> List<T> findAttrs(final PlainSchema schema, final Class<T> reference) {
+        // not possible
+        return Collections.emptyList();
+    }
+
+    @Override
+    protected void deleteAttrs(final PlainSchema schema) {
+        // nothing to do
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAUserDAO.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAUserDAO.java
new file mode 100644
index 0000000..340ba6e
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/dao/PGJPAUserDAO.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.core.persistence.api.dao.PGAnyDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.entity.user.PGJPAUser;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+import org.springframework.transaction.annotation.Transactional;
+
+public class PGJPAUserDAO extends JPAUserDAO {
+
+    private PGAnyDAO anyDAO;
+
+    private PGAnyDAO anyDAO() {
+        if (anyDAO == null) {
+            anyDAO = ApplicationContextProvider.getApplicationContext().getBean(PGAnyDAO.class);
+        }
+        return anyDAO;
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public User find(final String key) {
+        return entityManager().find(PGJPAUser.class, key);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<User> findByPlainAttrValue(
+            final String schemaKey,
+            final PlainAttrValue attrValue,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByPlainAttrValue(PGJPAUser.TABLE, anyUtils(), schemaKey, attrValue, ignoreCaseMatch);
+    }
+
+    @Override
+    public User findByPlainAttrUniqueValue(
+            final String schemaKey,
+            final PlainAttrValue attrUniqueValue,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByPlainAttrUniqueValue(PGJPAUser.TABLE, anyUtils(),
+                schemaKey, attrUniqueValue, ignoreCaseMatch);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public List<User> findByDerAttrValue(
+            final String schemaKey,
+            final String value,
+            final boolean ignoreCaseMatch) {
+
+        return anyDAO().findByDerAttrValue(PGJPAUser.TABLE, anyUtils(), schemaKey, value, ignoreCaseMatch);
+    }
+
+    @Override
+    public User save(final User user) {
+        anyDAO().checkBeforeSave(PGJPAUser.TABLE, anyUtils(), user);
+        return super.save(user);
+    }
+
+    @Override
+    public Pair<Set<String>, Set<String>> saveAndGetDynGroupMembs(final User user) {
+        anyDAO().checkBeforeSave(PGJPAUser.TABLE, anyUtils(), user);
+        return super.saveAndGetDynGroupMembs(user);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAAny.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAAny.java
new file mode 100644
index 0000000..005e616
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAAny.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Any;
+
+public interface PGJPAAny<A extends Any<?>> {
+
+    String getPlainAttrsJSON();
+
+    void setPlainAttrsJSON(String plainAttrs);
+
+    boolean add(PGPlainAttr<A> attr);
+
+    List<? extends PGPlainAttr<A>> getPlainAttrList();
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAEntityFactory.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAEntityFactory.java
new file mode 100644
index 0000000..0054d3f
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAEntityFactory.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.conf.Conf;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.dao.PGJPAAnySearchDAO;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.PGAPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.PGAPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.PGAPlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.anyobject.PGJPAAnyObject;
+import org.apache.syncope.core.persistence.jpa.entity.conf.PGCPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.conf.PGCPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.conf.PGCPlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.conf.PGJPAConf;
+import org.apache.syncope.core.persistence.jpa.entity.group.PGGPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.group.PGGPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.group.PGGPlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.group.PGJPAGroup;
+import org.apache.syncope.core.persistence.jpa.entity.user.PGJPAUser;
+import org.apache.syncope.core.persistence.jpa.entity.user.PGUPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.user.PGUPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.user.PGUPlainAttrValue;
+import org.apache.syncope.core.spring.security.SecureRandomUtils;
+
+public class PGJPAEntityFactory extends JPAEntityFactory {
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <E extends Entity> E newEntity(final Class<E> reference) {
+        E result;
+
+        if (reference.equals(User.class)) {
+            result = (E) new PGJPAUser();
+            ((PGJPAUser) result).setKey(SecureRandomUtils.generateRandomUUID().toString());
+        } else if (reference.equals(Group.class)) {
+            result = (E) new PGJPAGroup();
+            ((PGJPAGroup) result).setKey(SecureRandomUtils.generateRandomUUID().toString());
+        } else if (reference.equals(AnyObject.class)) {
+            result = (E) new PGJPAAnyObject();
+            ((PGJPAAnyObject) result).setKey(SecureRandomUtils.generateRandomUUID().toString());
+        } else if (reference.equals(Conf.class)) {
+            result = (E) new PGJPAConf();
+            ((PGJPAConf) result).setKey(SecureRandomUtils.generateRandomUUID().toString());
+        } else if (reference.equals(APlainAttr.class)) {
+            result = (E) new PGAPlainAttr();
+        } else if (reference.equals(APlainAttrValue.class)) {
+            result = (E) new PGAPlainAttrValue();
+        } else if (reference.equals(APlainAttrUniqueValue.class)) {
+            result = (E) new PGAPlainAttrUniqueValue();
+        } else if (reference.equals(CPlainAttr.class)) {
+            result = (E) new PGCPlainAttr();
+        } else if (reference.equals(CPlainAttrValue.class)) {
+            result = (E) new PGCPlainAttrValue();
+        } else if (reference.equals(CPlainAttrUniqueValue.class)) {
+            result = (E) new PGCPlainAttrUniqueValue();
+        } else if (reference.equals(GPlainAttr.class)) {
+            result = (E) new PGGPlainAttr();
+        } else if (reference.equals(GPlainAttrValue.class)) {
+            result = (E) new PGGPlainAttrValue();
+        } else if (reference.equals(GPlainAttrUniqueValue.class)) {
+            result = (E) new PGGPlainAttrUniqueValue();
+        } else if (reference.equals(UPlainAttr.class)) {
+            result = (E) new PGUPlainAttr();
+        } else if (reference.equals(UPlainAttrValue.class)) {
+            result = (E) new PGUPlainAttrValue();
+        } else if (reference.equals(UPlainAttrUniqueValue.class)) {
+            result = (E) new PGUPlainAttrUniqueValue();
+        } else {
+            result = super.newEntity(reference);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Class<? extends User> userClass() {
+        return PGJPAUser.class;
+    }
+
+    @Override
+    public Class<? extends Group> groupClass() {
+        return PGJPAGroup.class;
+    }
+
+    @Override
+    public Class<? extends AnyObject> anyObjectClass() {
+        return PGJPAAnyObject.class;
+    }
+
+    @Override
+    public Class<? extends Conf> confClass() {
+        return PGJPAConf.class;
+    }
+
+    @Override
+    public Class<? extends AnySearchDAO> anySearchDAOClass() {
+        return PGJPAAnySearchDAO.class;
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAEntityListener.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAEntityListener.java
new file mode 100644
index 0000000..ddbb13e
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGJPAEntityListener.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.List;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+public abstract class PGJPAEntityListener<A extends Any<?>> {
+
+    protected abstract List<? extends PGPlainAttr<A>> getValues(String plainAttrsJSON);
+
+    @SuppressWarnings("unchecked")
+    protected void read(final PGJPAAny<A> entity) {
+        if (entity.getPlainAttrsJSON() != null) {
+            getValues(entity.getPlainAttrsJSON()).stream().filter(attr -> attr.getSchema() != null).
+                    map(attr -> {
+                        attr.setOwner((A) entity);
+                        attr.getValues().forEach(value -> value.setAttr(attr));
+                        if (attr.getUniqueValue() != null) {
+                            attr.getUniqueValue().setAttr(attr);
+                        }
+                        return attr;
+                    }).forEach(attr -> entity.add(attr));
+        }
+    }
+
+    protected void save(final PGJPAAny<A> entity) {
+        entity.setPlainAttrsJSON(entity.getPlainAttrList().isEmpty()
+                ? "[{}]"
+                : POJOHelper.serialize(entity.getPlainAttrList()));
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGPlainAttr.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGPlainAttr.java
new file mode 100644
index 0000000..a802d3c
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/PGPlainAttr.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+
+public interface PGPlainAttr<A extends Any<?>> extends PlainAttr<A> {
+
+    String getSchemaKey();
+
+    boolean add(PlainAttrValue value);
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttr.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttr.java
new file mode 100644
index 0000000..292107e
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttr.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.anyobject;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.JPAPlainSchema;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+
+@JsonIgnoreProperties("valuesAsStrings")
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class PGAPlainAttr extends AbstractPlainAttr<AnyObject> implements APlainAttr, PGPlainAttr<AnyObject> {
+
+    private static final long serialVersionUID = 806271775349587902L;
+
+    /**
+     * The owner of this attribute.
+     */
+    @JsonIgnore
+    private PGJPAAnyObject owner;
+
+    @JsonProperty
+    private String schema;
+
+    /**
+     * The membership of this attribute; might be {@code NULL} if this attribute is not related to a membership.
+     */
+    @JsonProperty
+    private String membership;
+
+    /**
+     * Values of this attribute (if schema is not UNIQUE).
+     */
+    private final List<PGAPlainAttrValue> values = new ArrayList<>();
+
+    /**
+     * Value of this attribute (if schema is UNIQUE).
+     */
+    @JsonProperty
+    private PGAPlainAttrUniqueValue uniqueValue;
+
+    @Override
+    public AnyObject getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final AnyObject owner) {
+        checkType(owner, PGJPAAnyObject.class);
+        this.owner = (PGJPAAnyObject) owner;
+    }
+
+    @JsonIgnore
+    @Override
+    public String getSchemaKey() {
+        return schema;
+    }
+
+    @JsonIgnore
+    @Override
+    public JPAPlainSchema getSchema() {
+        return (JPAPlainSchema) ApplicationContextProvider.getBeanFactory().getBean(PlainSchemaDAO.class).find(schema);
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        if (schema != null) {
+            this.schema = schema.getKey();
+        }
+    }
+
+    @JsonSetter("schema")
+    public void setSchema(final String schema) {
+        this.schema = schema;
+    }
+
+    @JsonIgnore
+    public String getMembershipKey() {
+        return membership;
+    }
+
+    @JsonIgnore
+    @Override
+    public AMembership getMembership() {
+        return ApplicationContextProvider.getBeanFactory().getBean(AnyObjectDAO.class).findMembership(membership);
+    }
+
+    @Override
+    public void setMembership(final AMembership membership) {
+        if (membership != null) {
+            this.membership = membership.getKey();
+        }
+    }
+
+    @JsonSetter("membership")
+    public void setMembership(final String membership) {
+        this.membership = membership;
+    }
+
+    @Override
+    protected boolean addForMultiValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, PGAPlainAttrValue.class);
+        return values.add((PGAPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public boolean add(final PlainAttrValue value) {
+        return addForMultiValue(value);
+    }
+
+    @Override
+    public List<? extends APlainAttrValue> getValues() {
+        return values;
+    }
+
+    @JsonIgnore
+    public List<PGAPlainAttrValue> getPGValues() {
+        return values;
+    }
+
+    @Override
+    public PGAPlainAttrUniqueValue getUniqueValue() {
+        return uniqueValue;
+    }
+
+    @JsonIgnore
+    @Override
+    public void setUniqueValue(final PlainAttrUniqueValue uniqueValue) {
+        checkType(uniqueValue, PGAPlainAttrUniqueValue.class);
+        this.uniqueValue = (PGAPlainAttrUniqueValue) uniqueValue;
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder().
+                append(schema).
+                append(membership).
+                append(values).
+                append(uniqueValue).
+                build();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final PGAPlainAttr other = (PGAPlainAttr) obj;
+        return new EqualsBuilder().
+                append(schema, other.schema).
+                append(membership, other.membership).
+                append(values, other.values).
+                append(uniqueValue, other.uniqueValue).
+                build();
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttrUniqueValue.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttrUniqueValue.java
new file mode 100644
index 0000000..dd24599
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttrUniqueValue.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.anyobject;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@JsonIgnoreProperties({ "valueAsString", "value" })
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PGAPlainAttrUniqueValue extends AbstractPlainAttrValue implements APlainAttrUniqueValue {
+
+    private static final long serialVersionUID = -4053996864791245312L;
+
+    @JsonIgnore
+    private PGAPlainAttr attr;
+
+    @Override
+    public APlainAttr getAttr() {
+        return attr;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr<?> attr) {
+        checkType(attr, PGAPlainAttr.class);
+        this.attr = (PGAPlainAttr) attr;
+    }
+
+    @JsonIgnore
+    @Override
+    public PlainSchema getSchema() {
+        return getAttr() == null ? null : getAttr().getSchema();
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        // nothing to do
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttrValue.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttrValue.java
new file mode 100644
index 0000000..b3b76fd
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGAPlainAttrValue.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.anyobject;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@JsonIgnoreProperties({ "valueAsString", "value" })
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PGAPlainAttrValue extends AbstractPlainAttrValue implements APlainAttrValue {
+
+    private static final long serialVersionUID = 1832825176101443555L;
+
+    @JsonIgnore
+    private PGAPlainAttr attr;
+
+    @Override
+    public APlainAttr getAttr() {
+        return attr;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr<?> attr) {
+        checkType(attr, PGAPlainAttr.class);
+        this.attr = (PGAPlainAttr) attr;
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGJPAAnyObject.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGJPAAnyObject.java
new file mode 100644
index 0000000..dad8536
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGJPAAnyObject.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.core.persistence.jpa.entity.anyobject;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.Lob;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAAny;
+import org.apache.syncope.core.persistence.jpa.validation.entity.PGJPAAnyCheck;
+
+@Entity
+@Table(name = JPAAnyObject.TABLE)
+@EntityListeners({ PGJPAAnyObjectListener.class })
+@PGJPAAnyCheck
+public class PGJPAAnyObject extends JPAAnyObject implements PGJPAAny<AnyObject>, AnyObject {
+
+    private static final long serialVersionUID = -8543654943709531885L;
+
+    @Lob
+    @Column(columnDefinition = "jsonb")
+    private String plainAttrs;
+
+    @Transient
+    private final List<PGAPlainAttr> plainAttrList = new ArrayList<>();
+
+    @Override
+    public String getPlainAttrsJSON() {
+        return plainAttrs;
+    }
+
+    @Override
+    public void setPlainAttrsJSON(final String plainAttrs) {
+        this.plainAttrs = plainAttrs;
+    }
+
+    @Override
+    public List<PGAPlainAttr> getPlainAttrList() {
+        return plainAttrList;
+    }
+
+    @Override
+    public boolean add(final PGPlainAttr<AnyObject> attr) {
+        return add((APlainAttr) attr);
+    }
+
+    @Override
+    public boolean add(final APlainAttr attr) {
+        checkType(attr, PGAPlainAttr.class);
+        return plainAttrList.add((PGAPlainAttr) attr);
+    }
+
+    @Override
+    public boolean remove(final APlainAttr attr) {
+        return plainAttrList.removeIf(pgattr
+                -> pgattr.getSchemaKey().equals(attr.getSchema().getKey())
+                && attr.getOwner().getKey().equals(getKey())
+                && attr.getMembership() == null
+                ? true
+                : pgattr.getMembership() != null && pgattr.getMembershipKey().equals(attr.getMembership().getKey()));
+    }
+
+    @Override
+    protected List<? extends APlainAttr> internalGetPlainAttrs() {
+        return plainAttrList;
+    }
+
+    @Override
+    public boolean remove(final AMembership membership) {
+        plainAttrList.removeIf(attr -> attr.getMembership().getKey().equals(membership.getKey()));
+        return super.remove(membership);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGJPAAnyObjectListener.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGJPAAnyObjectListener.java
new file mode 100644
index 0000000..61b201f
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/PGJPAAnyObjectListener.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.anyobject;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import java.util.List;
+import javax.persistence.PostLoad;
+import javax.persistence.PrePersist;
+import javax.persistence.PreUpdate;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAEntityListener;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+public class PGJPAAnyObjectListener extends PGJPAEntityListener<AnyObject> {
+
+    @Override
+    protected List<? extends PGPlainAttr<AnyObject>> getValues(final String plainAttrsJSON) {
+        return POJOHelper.deserialize(plainAttrsJSON, new TypeReference<List<PGAPlainAttr>>() {
+        });
+    }
+
+    @PostLoad
+    public void read(final PGJPAAnyObject anyObject) {
+        super.read(anyObject);
+    }
+
+    @PrePersist
+    @PreUpdate
+    public void save(final PGJPAAnyObject anyObject) {
+        super.save(anyObject);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttr.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttr.java
new file mode 100644
index 0000000..a45d7d5
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttr.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.conf;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.conf.Conf;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.JPAPlainSchema;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+
+@JsonIgnoreProperties("valuesAsStrings")
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class PGCPlainAttr extends AbstractPlainAttr<Conf> implements CPlainAttr, PGPlainAttr<Conf> {
+
+    private static final long serialVersionUID = 806271775349587902L;
+
+    /**
+     * The owner of this attribute.
+     */
+    @JsonIgnore
+    private PGJPAConf owner;
+
+    @JsonProperty
+    private String schema;
+
+    /**
+     * Values of this attribute (if schema is not UNIQUE).
+     */
+    private final List<PGCPlainAttrValue> values = new ArrayList<>();
+
+    /**
+     * Value of this attribute (if schema is UNIQUE).
+     */
+    @JsonProperty
+    private PGCPlainAttrUniqueValue uniqueValue;
+
+    @Override
+    public Conf getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Conf owner) {
+        checkType(owner, PGJPAConf.class);
+        this.owner = (PGJPAConf) owner;
+    }
+
+    @JsonIgnore
+    @Override
+    public String getSchemaKey() {
+        return schema;
+    }
+
+    @JsonIgnore
+    @Override
+    public JPAPlainSchema getSchema() {
+        return (JPAPlainSchema) ApplicationContextProvider.getBeanFactory().getBean(PlainSchemaDAO.class).find(schema);
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        if (schema != null) {
+            this.schema = schema.getKey();
+        }
+    }
+
+    @JsonSetter("schema")
+    public void setSchema(final String schema) {
+        this.schema = schema;
+    }
+
+    @Override
+    protected boolean addForMultiValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, PGCPlainAttrValue.class);
+        return values.add((PGCPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public boolean add(final PlainAttrValue value) {
+        return addForMultiValue(value);
+    }
+
+    @Override
+    public List<? extends CPlainAttrValue> getValues() {
+        return values;
+    }
+
+    @JsonIgnore
+    public List<PGCPlainAttrValue> getPGValues() {
+        return values;
+    }
+
+    @Override
+    public PGCPlainAttrUniqueValue getUniqueValue() {
+        return uniqueValue;
+    }
+
+    @JsonIgnore
+    @Override
+    public void setUniqueValue(final PlainAttrUniqueValue uniqueValue) {
+        checkType(uniqueValue, PGCPlainAttrUniqueValue.class);
+        this.uniqueValue = (PGCPlainAttrUniqueValue) uniqueValue;
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder().
+                append(schema).
+                append(values).
+                append(uniqueValue).
+                build();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final PGCPlainAttr other = (PGCPlainAttr) obj;
+        return new EqualsBuilder().
+                append(schema, other.schema).
+                append(values, other.values).
+                append(uniqueValue, other.uniqueValue).
+                build();
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttrUniqueValue.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttrUniqueValue.java
new file mode 100644
index 0000000..5877f1c
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttrUniqueValue.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.conf;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@JsonIgnoreProperties({ "valueAsString", "value" })
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PGCPlainAttrUniqueValue extends AbstractPlainAttrValue implements CPlainAttrUniqueValue {
+
+    private static final long serialVersionUID = -4326417972859745823L;
+
+    @JsonIgnore
+    private PGCPlainAttr attr;
+
+    @Override
+    public CPlainAttr getAttr() {
+        return attr;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr<?> attr) {
+        checkType(attr, PGCPlainAttr.class);
+        this.attr = (PGCPlainAttr) attr;
+    }
+
+    @JsonIgnore
+    @Override
+    public PlainSchema getSchema() {
+        return getAttr() == null ? null : getAttr().getSchema();
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        // nothing to do
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttrValue.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttrValue.java
new file mode 100644
index 0000000..a537f0f
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGCPlainAttrValue.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.conf;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@JsonIgnoreProperties({ "valueAsString", "value" })
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PGCPlainAttrValue extends AbstractPlainAttrValue implements CPlainAttrValue {
+
+    private static final long serialVersionUID = 1832825176101443555L;
+
+    @JsonIgnore
+    private PGCPlainAttr attr;
+
+    @Override
+    public CPlainAttr getAttr() {
+        return attr;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr<?> attr) {
+        checkType(attr, PGCPlainAttr.class);
+        this.attr = (PGCPlainAttr) attr;
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGJPAConf.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGJPAConf.java
new file mode 100644
index 0000000..a297d18
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGJPAConf.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.conf;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.Lob;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.conf.Conf;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAAny;
+import org.apache.syncope.core.persistence.jpa.validation.entity.PGJPAAnyCheck;
+
+@Entity
+@Table(name = JPAConf.TABLE)
+@EntityListeners({ PGJPAConfListener.class })
+@PGJPAAnyCheck
+public class PGJPAConf extends JPAConf implements PGJPAAny<Conf>, Conf {
+
+    private static final long serialVersionUID = -8543654943709531885L;
+
+    @Lob
+    @Column(columnDefinition = "jsonb")
+    private String plainAttrs;
+
+    @Transient
+    private final List<PGCPlainAttr> plainAttrList = new ArrayList<>();
+
+    @Override
+    public String getPlainAttrsJSON() {
+        return plainAttrs;
+    }
+
+    @Override
+    public void setPlainAttrsJSON(final String plainAttrs) {
+        this.plainAttrs = plainAttrs;
+    }
+
+    @Override
+    public List<PGCPlainAttr> getPlainAttrList() {
+        return plainAttrList;
+    }
+
+    @Override
+    public boolean add(final PGPlainAttr<Conf> attr) {
+        return add((CPlainAttr) attr);
+    }
+
+    @Override
+    public boolean add(final CPlainAttr attr) {
+        checkType(attr, PGCPlainAttr.class);
+        return plainAttrList.add((PGCPlainAttr) attr);
+    }
+
+    @Override
+    public boolean remove(final CPlainAttr attr) {
+        return plainAttrList.removeIf(pgattr -> pgattr.getSchemaKey().equals(attr.getSchema().getKey()));
+    }
+
+    @Override
+    public List<? extends CPlainAttr> getPlainAttrs() {
+        return plainAttrList;
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGJPAConfListener.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGJPAConfListener.java
new file mode 100644
index 0000000..f1a7198
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/PGJPAConfListener.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.conf;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import java.util.List;
+import javax.persistence.PostLoad;
+import javax.persistence.PrePersist;
+import javax.persistence.PreUpdate;
+import org.apache.syncope.core.persistence.api.entity.conf.Conf;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAEntityListener;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+public class PGJPAConfListener extends PGJPAEntityListener<Conf> {
+
+    @Override
+    protected List<? extends PGPlainAttr<Conf>> getValues(final String plainAttrsJSON) {
+        return POJOHelper.deserialize(plainAttrsJSON, new TypeReference<List<PGCPlainAttr>>() {
+        });
+    }
+
+    @PostLoad
+    public void read(final PGJPAConf conf) {
+        super.read(conf);
+    }
+
+    @PrePersist
+    @PreUpdate
+    public void save(final PGJPAConf conf) {
+        super.save(conf);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttr.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttr.java
new file mode 100644
index 0000000..9e78535
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttr.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.group;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.JPAPlainSchema;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+
+@JsonIgnoreProperties("valuesAsStrings")
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class PGGPlainAttr extends AbstractPlainAttr<Group> implements GPlainAttr, PGPlainAttr<Group> {
+
+    private static final long serialVersionUID = 806271775349587902L;
+
+    /**
+     * The owner of this attribute.
+     */
+    @JsonIgnore
+    private PGJPAGroup owner;
+
+    @JsonProperty
+    private String schema;
+
+    /**
+     * Values of this attribute (if schema is not UNIQUE).
+     */
+    private final List<PGGPlainAttrValue> values = new ArrayList<>();
+
+    /**
+     * Value of this attribute (if schema is UNIQUE).
+     */
+    @JsonProperty
+    private PGGPlainAttrUniqueValue uniqueValue;
+
+    @Override
+    public Group getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Group owner) {
+        checkType(owner, PGJPAGroup.class);
+        this.owner = (PGJPAGroup) owner;
+    }
+
+    @JsonIgnore
+    @Override
+    public String getSchemaKey() {
+        return schema;
+    }
+
+    @JsonIgnore
+    @Override
+    public JPAPlainSchema getSchema() {
+        return (JPAPlainSchema) ApplicationContextProvider.getBeanFactory().getBean(PlainSchemaDAO.class).find(schema);
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        if (schema != null) {
+            this.schema = schema.getKey();
+        }
+    }
+
+    @JsonSetter("schema")
+    public void setSchema(final String schema) {
+        this.schema = schema;
+    }
+
+    @Override
+    protected boolean addForMultiValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, PGGPlainAttrValue.class);
+        return values.add((PGGPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public boolean add(final PlainAttrValue value) {
+        return addForMultiValue(value);
+    }
+
+    @Override
+    public List<? extends GPlainAttrValue> getValues() {
+        return values;
+    }
+
+    @JsonIgnore
+    public List<PGGPlainAttrValue> getPGValues() {
+        return values;
+    }
+
+    @Override
+    public PGGPlainAttrUniqueValue getUniqueValue() {
+        return uniqueValue;
+    }
+
+    @JsonIgnore
+    @Override
+    public void setUniqueValue(final PlainAttrUniqueValue uniqueValue) {
+        checkType(uniqueValue, PGGPlainAttrUniqueValue.class);
+        this.uniqueValue = (PGGPlainAttrUniqueValue) uniqueValue;
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder().
+                append(schema).
+                append(values).
+                append(uniqueValue).
+                build();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final PGGPlainAttr other = (PGGPlainAttr) obj;
+        return new EqualsBuilder().
+                append(schema, other.schema).
+                append(values, other.values).
+                append(uniqueValue, other.uniqueValue).
+                build();
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttrUniqueValue.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttrUniqueValue.java
new file mode 100644
index 0000000..c6219a0
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttrUniqueValue.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.group;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@JsonIgnoreProperties({ "valueAsString", "value" })
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PGGPlainAttrUniqueValue extends AbstractPlainAttrValue implements GPlainAttrUniqueValue {
+
+    private static final long serialVersionUID = -4326417972859745823L;
+
+    @JsonIgnore
+    private PGGPlainAttr attr;
+
+    @Override
+    public GPlainAttr getAttr() {
+        return attr;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr<?> attr) {
+        checkType(attr, PGGPlainAttr.class);
+        this.attr = (PGGPlainAttr) attr;
+    }
+
+    @JsonIgnore
+    @Override
+    public PlainSchema getSchema() {
+        return getAttr() == null ? null : getAttr().getSchema();
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        // nothing to do
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttrValue.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttrValue.java
new file mode 100644
index 0000000..398e5b0
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGGPlainAttrValue.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.group;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@JsonIgnoreProperties({ "valueAsString", "value" })
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PGGPlainAttrValue extends AbstractPlainAttrValue implements GPlainAttrValue {
+
+    private static final long serialVersionUID = 1832825176101443555L;
+
+    @JsonIgnore
+    private PGGPlainAttr attr;
+
+    @Override
+    public GPlainAttr getAttr() {
+        return attr;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr<?> attr) {
+        checkType(attr, PGGPlainAttr.class);
+        this.attr = (PGGPlainAttr) attr;
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGJPAGroup.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGJPAGroup.java
new file mode 100644
index 0000000..6207dfc
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGJPAGroup.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.group;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.Lob;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAAny;
+import org.apache.syncope.core.persistence.jpa.validation.entity.PGJPAAnyCheck;
+
+@Entity
+@Table(name = JPAGroup.TABLE)
+@EntityListeners({ PGJPAGroupListener.class })
+@PGJPAAnyCheck
+public class PGJPAGroup extends JPAGroup implements PGJPAAny<Group>, Group {
+
+    private static final long serialVersionUID = -8543654943709531885L;
+
+    @Lob
+    @Column(columnDefinition = "jsonb")
+    private String plainAttrs;
+
+    @Transient
+    private final List<PGGPlainAttr> plainAttrList = new ArrayList<>();
+
+    @Override
+    public String getPlainAttrsJSON() {
+        return plainAttrs;
+    }
+
+    @Override
+    public void setPlainAttrsJSON(final String plainAttrs) {
+        this.plainAttrs = plainAttrs;
+    }
+
+    @Override
+    public List<PGGPlainAttr> getPlainAttrList() {
+        return plainAttrList;
+    }
+
+    @Override
+    public boolean add(final PGPlainAttr<Group> attr) {
+        return add((GPlainAttr) attr);
+    }
+
+    @Override
+    public boolean add(final GPlainAttr attr) {
+        checkType(attr, PGGPlainAttr.class);
+        return plainAttrList.add((PGGPlainAttr) attr);
+    }
+
+    @Override
+    public boolean remove(final GPlainAttr attr) {
+        return plainAttrList.removeIf(pgattr
+                -> pgattr.getSchemaKey().equals(attr.getSchema().getKey())
+                && attr.getOwner().getKey().equals(getKey()));
+    }
+
+    @Override
+    public List<? extends GPlainAttr> getPlainAttrs() {
+        return plainAttrList;
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGJPAGroupListener.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGJPAGroupListener.java
new file mode 100644
index 0000000..b32f471
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/PGJPAGroupListener.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.group;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import java.util.List;
+import javax.persistence.PostLoad;
+import javax.persistence.PrePersist;
+import javax.persistence.PreUpdate;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAEntityListener;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+public class PGJPAGroupListener extends PGJPAEntityListener<Group> {
+
+    @Override
+    protected List<? extends PGPlainAttr<Group>> getValues(final String plainAttrsJSON) {
+        return POJOHelper.deserialize(plainAttrsJSON, new TypeReference<List<PGGPlainAttr>>() {
+        });
+    }
+
+    @PostLoad
+    public void read(final PGJPAGroup group) {
+        super.read(group);
+    }
+
+    @PrePersist
+    @PreUpdate
+    public void save(final PGJPAGroup group) {
+        super.save(group);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGJPAUser.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGJPAUser.java
new file mode 100644
index 0000000..486ba1c
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGJPAUser.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.user;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.Lob;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAAny;
+import org.apache.syncope.core.persistence.jpa.validation.entity.PGJPAAnyCheck;
+
+@Entity
+@Table(name = JPAUser.TABLE)
+@EntityListeners({ PGJPAUserListener.class })
+@PGJPAAnyCheck
+public class PGJPAUser extends JPAUser implements PGJPAAny<User>, User {
+
+    private static final long serialVersionUID = -8543654943709531885L;
+
+    @Lob
+    @Column(columnDefinition = "jsonb")
+    private String plainAttrs;
+
+    @Transient
+    private final List<PGUPlainAttr> plainAttrList = new ArrayList<>();
+
+    @Override
+    public String getPlainAttrsJSON() {
+        return plainAttrs;
+    }
+
+    @Override
+    public void setPlainAttrsJSON(final String plainAttrs) {
+        this.plainAttrs = plainAttrs;
+    }
+
+    @Override
+    public List<PGUPlainAttr> getPlainAttrList() {
+        return plainAttrList;
+    }
+
+    @Override
+    public boolean add(final PGPlainAttr<User> attr) {
+        return add((UPlainAttr) attr);
+    }
+
+    @Override
+    public boolean add(final UPlainAttr attr) {
+        checkType(attr, PGUPlainAttr.class);
+        return plainAttrList.add((PGUPlainAttr) attr);
+    }
+
+    @Override
+    public boolean remove(final UPlainAttr attr) {
+        return plainAttrList.removeIf(pgattr
+                -> pgattr.getSchemaKey().equals(attr.getSchema().getKey())
+                && attr.getOwner().getKey().equals(getKey())
+                && attr.getMembership() == null
+                ? true
+                : pgattr.getMembership() != null && pgattr.getMembershipKey().equals(attr.getMembership().getKey()));
+    }
+
+    @Override
+    protected List<? extends UPlainAttr> internalGetPlainAttrs() {
+        return plainAttrList;
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGJPAUserListener.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGJPAUserListener.java
new file mode 100644
index 0000000..5baf4fc
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGJPAUserListener.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.user;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import java.util.List;
+import javax.persistence.PostLoad;
+import javax.persistence.PrePersist;
+import javax.persistence.PreUpdate;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAEntityListener;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
+
+public class PGJPAUserListener extends PGJPAEntityListener<User> {
+
+    @Override
+    protected List<? extends PGPlainAttr<User>> getValues(final String plainAttrsJSON) {
+        return POJOHelper.deserialize(plainAttrsJSON, new TypeReference<List<PGUPlainAttr>>() {
+        });
+    }
+
+    @PostLoad
+    public void read(final PGJPAUser user) {
+        super.read(user);
+    }
+
+    @PrePersist
+    @PreUpdate
+    public void save(final PGJPAUser user) {
+        super.save(user);
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttr.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttr.java
new file mode 100644
index 0000000..09abb26
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttr.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.user;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.JPAPlainSchema;
+import org.apache.syncope.core.persistence.jpa.entity.PGPlainAttr;
+import org.apache.syncope.core.spring.ApplicationContextProvider;
+
+@JsonIgnoreProperties("valuesAsStrings")
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class PGUPlainAttr extends AbstractPlainAttr<User> implements UPlainAttr, PGPlainAttr<User> {
+
+    private static final long serialVersionUID = 806271775349587902L;
+
+    /**
+     * The owner of this attribute.
+     */
+    @JsonIgnore
+    private PGJPAUser owner;
+
+    @JsonProperty
+    private String schema;
+
+    /**
+     * The membership of this attribute; might be {@code NULL} if this attribute is not related to a membership.
+     */
+    @JsonProperty
+    private String membership;
+
+    /**
+     * Values of this attribute (if schema is not UNIQUE).
+     */
+    private final List<PGUPlainAttrValue> values = new ArrayList<>();
+
+    /**
+     * Value of this attribute (if schema is UNIQUE).
+     */
+    @JsonProperty
+    private PGUPlainAttrUniqueValue uniqueValue;
+
+    @Override
+    public User getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final User owner) {
+        checkType(owner, PGJPAUser.class);
+        this.owner = (PGJPAUser) owner;
+    }
+
+    @JsonIgnore
+    @Override
+    public String getSchemaKey() {
+        return schema;
+    }
+
+    @JsonIgnore
+    @Override
+    public JPAPlainSchema getSchema() {
+        return (JPAPlainSchema) ApplicationContextProvider.getBeanFactory().getBean(PlainSchemaDAO.class).find(schema);
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        if (schema != null) {
+            this.schema = schema.getKey();
+        }
+    }
+
+    @JsonSetter("schema")
+    public void setSchema(final String schema) {
+        this.schema = schema;
+    }
+
+    @JsonIgnore
+    public String getMembershipKey() {
+        return membership;
+    }
+
+    @JsonIgnore
+    @Override
+    public UMembership getMembership() {
+        return ApplicationContextProvider.getBeanFactory().getBean(UserDAO.class).findMembership(membership);
+    }
+
+    @Override
+    public void setMembership(final UMembership membership) {
+        if (membership != null) {
+            this.membership = membership.getKey();
+        }
+    }
+
+    @JsonSetter("membership")
+    public void setMembership(final String membership) {
+        this.membership = membership;
+    }
+
+    @Override
+    protected boolean addForMultiValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, PGUPlainAttrValue.class);
+        return values.add((PGUPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public boolean add(final PlainAttrValue value) {
+        return addForMultiValue(value);
+    }
+
+    @Override
+    public List<? extends UPlainAttrValue> getValues() {
+        return values;
+    }
+
+    @JsonIgnore
+    public List<PGUPlainAttrValue> getPGValues() {
+        return values;
+    }
+
+    @Override
+    public PGUPlainAttrUniqueValue getUniqueValue() {
+        return uniqueValue;
+    }
+
+    @JsonIgnore
+    @Override
+    public void setUniqueValue(final PlainAttrUniqueValue uniqueValue) {
+        checkType(uniqueValue, PGUPlainAttrUniqueValue.class);
+        this.uniqueValue = (PGUPlainAttrUniqueValue) uniqueValue;
+    }
+
+    @Override
+    public int hashCode() {
+        return new HashCodeBuilder().
+                append(schema).
+                append(membership).
+                append(values).
+                append(uniqueValue).
+                build();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final PGUPlainAttr other = (PGUPlainAttr) obj;
+        return new EqualsBuilder().
+                append(schema, other.schema).
+                append(membership, other.membership).
+                append(values, other.values).
+                append(uniqueValue, other.uniqueValue).
+                build();
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttrUniqueValue.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttrUniqueValue.java
new file mode 100644
index 0000000..9b6cd3e
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttrUniqueValue.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.user;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@JsonIgnoreProperties({ "valueAsString", "value" })
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PGUPlainAttrUniqueValue extends AbstractPlainAttrValue implements UPlainAttrUniqueValue {
+
+    private static final long serialVersionUID = -4053996864791245312L;
+
+    @JsonIgnore
+    private PGUPlainAttr attr;
+
+    @Override
+    public UPlainAttr getAttr() {
+        return attr;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr<?> attr) {
+        checkType(attr, PGUPlainAttr.class);
+        this.attr = (PGUPlainAttr) attr;
+    }
+
+    @JsonIgnore
+    @Override
+    public PlainSchema getSchema() {
+        return getAttr() == null ? null : getAttr().getSchema();
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        // nothing to do
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttrValue.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttrValue.java
new file mode 100644
index 0000000..6ba15d5
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/PGUPlainAttrValue.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity.user;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@JsonIgnoreProperties({ "valueAsString", "value" })
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class PGUPlainAttrValue extends AbstractPlainAttrValue implements UPlainAttrValue {
+
+    private static final long serialVersionUID = 1832825176101443555L;
+
+    @JsonIgnore
+    private PGUPlainAttr attr;
+
+    @Override
+    public UPlainAttr getAttr() {
+        return attr;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr<?> attr) {
+        checkType(attr, PGUPlainAttr.class);
+        this.attr = (PGUPlainAttr) attr;
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PGJPAAnyCheck.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PGJPAAnyCheck.java
new file mode 100644
index 0000000..ef6f87d
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PGJPAAnyCheck.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.validation.entity;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = PGJPAAnyValidator.class)
+@Documented
+public @interface PGJPAAnyCheck {
+
+    String message() default "{org.apache.syncope.core.persistence.validation.any}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PGJPAAnyValidator.java b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PGJPAAnyValidator.java
new file mode 100644
index 0000000..089808c
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PGJPAAnyValidator.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.core.persistence.jpa.validation.entity;
+
+import java.util.concurrent.atomic.AtomicReference;
+import javax.validation.ConstraintValidatorContext;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.jpa.entity.PGJPAAny;
+
+public class PGJPAAnyValidator extends AbstractValidator<PGJPAAnyCheck, PGJPAAny<?>> {
+
+    @Override
+    public boolean isValid(final PGJPAAny<?> entity, final ConstraintValidatorContext context) {
+        context.disableDefaultConstraintViolation();
+
+        PlainAttrValidator attrValidator = new PlainAttrValidator();
+        PlainAttrValueValidator attrValueValidator = new PlainAttrValueValidator();
+
+        AtomicReference<Boolean> isValid = new AtomicReference<>(Boolean.TRUE);
+        entity.getPlainAttrList().forEach(attr -> {
+            PlainAttr<?> plainAttr = (PlainAttr<?>) attr;
+            isValid.getAndSet(isValid.get() && attrValidator.isValid(plainAttr, context));
+            plainAttr.getValues().forEach(value
+                    -> isValid.getAndSet(isValid.get() && attrValueValidator.isValid(value, context)));
+        });
+
+        return isValid.get();
+    }
+}
diff --git a/core/persistence-jpa-pgjsonb/src/main/resources/META-INF/spring-orm-pgjsonb.xml b/core/persistence-jpa-pgjsonb/src/main/resources/META-INF/spring-orm-pgjsonb.xml
new file mode 100644
index 0000000..3e5b103
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/resources/META-INF/spring-orm-pgjsonb.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
+                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm 
+                                     http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
+                 version="2.0">
+  
+  <persistence-unit-metadata>
+    <persistence-unit-defaults>
+      <entity-listeners>
+        <entity-listener class="org.apache.syncope.core.persistence.jpa.validation.entity.EntityValidationListener">
+          <pre-persist method-name="validate"/>
+          <pre-update method-name="validate"/>
+        </entity-listener>
+      </entity-listeners>
+    </persistence-unit-defaults>
+  </persistence-unit-metadata>
+  
+</entity-mappings>
diff --git a/core/persistence-jpa-pgjsonb/src/main/resources/domains/Master.properties b/core/persistence-jpa-pgjsonb/src/main/resources/domains/Master.properties
new file mode 100644
index 0000000..d9a648f
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/resources/domains/Master.properties
@@ -0,0 +1,28 @@
+# 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.
+Master.driverClassName=org.postgresql.Driver
+Master.url=jdbc:postgresql://localhost:5432/syncope?stringtype=unspecified
+Master.schema=
+Master.username=syncope
+Master.password=syncope
+Master.databasePlatform=org.apache.openjpa.jdbc.sql.PostgresDictionary
+Master.orm=META-INF/spring-orm-pgjsonb.xml
+
+Master.pool.maxActive=10
+Master.pool.minIdle=2
+
+Master.audit.sql=audit.sql
diff --git a/core/persistence-jpa-pgjsonb/src/main/resources/indexes.xml b/core/persistence-jpa-pgjsonb/src/main/resources/indexes.xml
new file mode 100644
index 0000000..3e5b92b
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/resources/indexes.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+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.
+-->
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+  <comment>Additional indexes (in respect to JPA's)</comment>
+
+  <entry key="SyncopeUser_plainAttrs_idx">CREATE INDEX SyncopeUser_plainAttrs_idx ON SyncopeUser USING gin ((plainAttrs) jsonb_path_ops)</entry>
+  <entry key="SyncopeGroup_plainAttrs_idx">CREATE INDEX SyncopeGroup_plainAttrs_idx ON SyncopeGroup USING gin ((plainAttrs) jsonb_path_ops)</entry>
+  <entry key="AnyObject_plainAttrs_idx">CREATE INDEX AnyObject_plainAttrs_idx ON AnyObject USING gin ((plainAttrs) jsonb_path_ops)</entry>
+  <entry key="SyncopeConf_plainAttrs_idx">CREATE INDEX SyncopeConf_plainAttrs_idx ON SyncopeConf USING gin ((plainAttrs) jsonb_path_ops)</entry>
+
+  <entry key="UDynGroupMembers_any_id">CREATE INDEX UDynGroupMembers_any_id ON UDynGroupMembers(any_id)</entry>
+  <entry key="UDynGroupMembers_group_id">CREATE INDEX UDynGroupMembers_group_id ON UDynGroupMembers(group_id)</entry>
+  <entry key="ADynGroupMembers_any_id">CREATE INDEX ADynGroupMembers_any_id ON ADynGroupMembers(any_id)</entry>
+  <entry key="ADynGroupMembers_group_id">CREATE INDEX ADynGroupMembers_group_id ON ADynGroupMembers(group_id)</entry>
+
+  <entry key="DynRoleMembers_any_id">CREATE INDEX DynRoleMembers_any_id ON DynRoleMembers(any_id)</entry>
+  <entry key="DynRoleMembers_role_id">CREATE INDEX DynRoleMembers_role_id ON DynRoleMembers(role_id)</entry>
+
+  <entry key="DynRealmMembers_any_id">CREATE INDEX DynRealmMembers_any_id ON DynRealmMembers(any_id)</entry>
+  <entry key="DynRealmMembers_realm_id">CREATE INDEX DynRealmMembers_dynRealm_id ON DynRealmMembers(dynRealm_id)</entry>
+
+  <entry key="CPlainAttrValue_stringvalueIndex">CREATE INDEX CAttrValue_stringvalueIndex ON CPlainAttrValue(stringvalue)</entry>
+  <entry key="CPlainAttrValue_datevalueIndex">CREATE INDEX CAttrValue_datevalueIndex ON CPlainAttrValue(datevalue)</entry>
+  <entry key="CPlainAttrValue_longvalueIndex">CREATE INDEX CAttrValue_longvalueIndex ON CPlainAttrValue(longvalue)</entry>
+  <entry key="CPlainAttrValue_doublevalueIndex">CREATE INDEX CAttrValue_doublevalueIndex ON CPlainAttrValue(doublevalue)</entry>
+  <entry key="CPlainAttrValue_booleanvalueIndex">CREATE INDEX CAttrValue_booleanvalueIndex ON CPlainAttrValue(booleanvalue)</entry>
+
+  <entry key="UMembership_GroupIndex">CREATE INDEX UMembership_GroupIndex ON UMembership(group_id)</entry>
+  <entry key="UMembership_UserIndex">CREATE INDEX UMembership_UserIndex ON UMembership(user_id)</entry>
+  <entry key="AMembership_GroupIndex">CREATE INDEX AMembership_GroupIndex ON AMembership(group_id)</entry>
+  <entry key="AMembership_AnyObjectIndex">CREATE INDEX AMembership_AnyObjectIndex ON AMembership(anyObject_id)</entry>
+
+  <entry key="URelationship_RightIndex">CREATE INDEX URelationship_RightIndex ON URelationship(anyObject_id)</entry>
+  <entry key="URelationship_LeftIndex">CREATE INDEX URelationship_LeftIndex ON URelationship(user_id)</entry>
+  <entry key="ARelationship_RightIndex">CREATE INDEX ARelationship_RightIndex ON ARelationship(right_anyObject_id)</entry>
+  <entry key="ARelationship_AnyObjectIndex">CREATE INDEX ARelationship_AnyObjectIndex ON ARelationship(left_anyObject_id)</entry>
+
+  <entry key="CPlainAttrValue_attrIndex">CREATE INDEX CPlainAttrValue_attrIndex on CPlainAttrValue(attribute_id)</entry>
+  <entry key="CPAttrUniqueValue_attrIndex">CREATE INDEX CPAttrUniqueValue_attrIndex on CPlainAttrUniqueValue(attribute_id)</entry>
+
+  <entry key="CPlainAttr_owner_Index">CREATE INDEX CPlainAttr_owner_Index on CPlainAttr(owner_id)</entry>
+  <entry key="CPlainAttr_schema_Index">CREATE INDEX CPlainAttr_schema_Index on CPlainAttr(schema_id)</entry>
+
+  <entry key="Task_executedIndex">CREATE INDEX Task_executedIndex ON Task(executed)</entry>
+</properties>
diff --git a/core/persistence-jpa-pgjsonb/src/main/resources/persistence.properties b/core/persistence-jpa-pgjsonb/src/main/resources/persistence.properties
new file mode 100644
index 0000000..c3196eb
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/resources/persistence.properties
@@ -0,0 +1,26 @@
+# 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.
+content.directory=${conf.directory}
+entity.factory=org.apache.syncope.core.persistence.jpa.entity.PGJPAEntityFactory
+plainSchema.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAPlainSchemaDAO
+plainAttr.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAPlainAttrDAO
+plainAttrValue.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAPlainAttrValueDAO
+any.search.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAAnySearchDAO
+user.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAUserDAO
+group.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAGroupDAO
+anyObject.dao=org.apache.syncope.core.persistence.jpa.dao.PGJPAAnyObjectDAO
+openjpa.RemoteCommitProvider=sjvm
diff --git a/core/persistence-jpa-pgjsonb/src/main/resources/views.xml b/core/persistence-jpa-pgjsonb/src/main/resources/views.xml
new file mode 100644
index 0000000..eb450be
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/main/resources/views.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+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.
+-->
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+  
+  <entry key="UDynGroupMembers">
+    CREATE TABLE UDynGroupMembers(
+    any_id CHAR(36),
+    group_id CHAR(36),
+    UNIQUE(any_id, group_id))
+  </entry>
+  <entry key="ADynGroupMembers">
+    CREATE TABLE ADynGroupMembers(
+    anyType_id VARCHAR(255),
+    any_id CHAR(36),
+    group_id CHAR(36),
+    UNIQUE(anyType_id, any_id, group_id))
+  </entry>
+  <entry key="DynRoleMembers">
+    CREATE TABLE DynRoleMembers(
+    any_id CHAR(36),
+    role_id VARCHAR(255),
+    UNIQUE(any_id, role_id))
+  </entry>
+  <entry key="DynRealmMembers">
+    CREATE TABLE DynRealmMembers(
+    any_id CHAR(36),
+    dynRealm_id VARCHAR(255),
+    UNIQUE(any_id, dynRealm_id))
+  </entry>
+
+  <!-- user -->
+  <entry key="user_search">
+    CREATE VIEW user_search AS
+
+    SELECT u.id as any_id, u.*,attrs,attrValues
+    FROM SyncopeUser u, jsonb_array_elements(COALESCE(u.plainAttrs, '[{}]'::jsonb)) attrs,
+    jsonb_array_elements(COALESCE(attrs -> 'values', '[{}]'::jsonb)) attrValues
+  </entry>
+  <entry key="user_search_urelationship">
+    CREATE VIEW user_search_urelationship AS
+
+    SELECT m.user_id AS any_id, m.anyObject_id AS right_any_id, m.type_id AS type
+    FROM URelationship m
+  </entry>
+  <entry key="user_search_umembership">
+    CREATE VIEW user_search_umembership AS
+
+    SELECT m.user_id AS any_id, g.id AS group_id, g.name AS group_name
+    FROM UMembership m, SyncopeGroup g
+    WHERE m.group_id = g.id
+  </entry>
+  <entry key="user_search_role">
+    CREATE VIEW user_search_role AS
+
+    SELECT ss.user_id AS any_id, ss.role_id AS role_id
+    FROM SyncopeUser_SyncopeRole ss
+  </entry>
+  <entry key="user_search_priv">
+    CREATE VIEW user_search_priv AS
+
+    SELECT ss.user_id AS any_id, sp.privilege_id AS privilege_id
+    FROM SyncopeUser_SyncopeRole ss, SyncopeRole_Privilege sp
+    WHERE ss.role_id = sp.role_id
+  </entry>
+  <entry key="user_search_dynpriv">
+    CREATE VIEW user_search_dynpriv AS
+
+    SELECT any_id, privilege_id
+    FROM DynRoleMembers drm, SyncopeRole_Privilege rp
+    WHERE drm.role_id = rp.role_id
+  </entry>
+  <entry key="user_search_resource">
+    CREATE VIEW user_search_resource AS
+
+    SELECT st.user_id AS any_id, st.resource_id AS resource_id
+    FROM SyncopeUser_ExternalResource st
+  </entry>
+  <entry key="user_search_group_res">
+    CREATE VIEW user_search_group_res AS
+
+    SELECT m.user_id AS any_id, st.resource_id AS resource_id
+    FROM UMembership m, SyncopeGroup r, SyncopeGroup_ExternalResource st
+    WHERE m.group_id = r.id AND st.group_id = r.id
+  </entry>
+
+  <!-- anyObject -->
+  <entry key="anyObject_search">
+    CREATE VIEW anyObject_search AS
+
+    SELECT a.id as any_id, a.*,attrs,attrValues
+    FROM AnyObject a, jsonb_array_elements(COALESCE(a.plainAttrs, '[{}]'::jsonb)) attrs,
+    jsonb_array_elements(COALESCE(attrs -> 'values', '[{}]'::jsonb)) attrValues
+  </entry>
+  <entry key="anyObject_search_arelationship">
+    CREATE VIEW anyObject_search_arelationship AS
+
+    SELECT m.left_anyObject_id AS any_id, m.right_anyObject_id AS right_any_id, m.type_id AS type
+    FROM ARelationship m
+  </entry>
+  <entry key="anyObject_search_amembership">
+    CREATE VIEW anyObject_search_amembership AS
+
+    SELECT m.anyObject_id AS any_id, g.id AS group_id, g.name AS group_name
+    FROM AMembership m, SyncopeGroup g
+    WHERE m.group_id = g.id
+  </entry>
+  <entry key="anyObject_search_resource">
+    CREATE VIEW anyObject_search_resource AS
+
+    SELECT st.anyObject_id AS any_id, st.resource_id AS resource_id
+    FROM AnyObject_ExternalResource st
+  </entry>
+  <entry key="anyObject_search_group_res">
+    CREATE VIEW anyObject_search_group_res AS
+
+    SELECT m.anyObject_id AS any_id, st.resource_id AS resource_id
+    FROM AMembership m, SyncopeGroup r, SyncopeGroup_ExternalResource st
+    WHERE m.group_id = r.id AND st.group_id = r.id
+  </entry>
+
+  <!-- group -->
+  <entry key="group_search">
+    CREATE VIEW group_search AS
+
+    SELECT g.id as any_id, g.*,attrs,attrValues
+    FROM SyncopeGroup g, jsonb_array_elements(COALESCE(g.plainAttrs, '[{}]'::jsonb)) attrs,
+    jsonb_array_elements(COALESCE(attrs -> 'values', '[{}]'::jsonb)) attrValues
+  </entry>
+  <entry key="group_search_resource">
+    CREATE VIEW group_search_resource AS
+
+    SELECT st.group_id AS any_id, st.resource_id AS resource_id
+    FROM SyncopeGroup_ExternalResource st
+  </entry>
+
+</properties>
diff --git a/core/persistence-jpa-pgjsonb/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa-pgjsonb/src/test/resources/domains/MasterContent.xml
new file mode 100644
index 0000000..32efc96
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/test/resources/domains/MasterContent.xml
@@ -0,0 +1,2410 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<dataset>
+  <SyncopeDomain id="Two" adminCipherAlgorithm="SHA" adminPwd="2AA60A8FF7FCD473D321E0146AFD9E26DF395147"/>  
+  
+  <SyncopeSchema id="password.cipher.algorithm"/>
+  <PlainSchema id="password.cipher.algorithm" type="String"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <!-- notificationjob.cronExpression:
+  + not existing: NotificationJob runs according to NotificationJob.DEFAULT_CRON_EXP
+  + provided as empty string: NotificationJob disabled
+  + provided as non-empty string: NotificationJob runs according to the given value -->
+  <SyncopeSchema id="notificationjob.cronExpression"/>
+  <PlainSchema id="notificationjob.cronExpression" type="String"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  
+  <SyncopeSchema id="notification.maxRetries"/>
+  <PlainSchema id="notification.maxRetries" type="Long"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="token.length"/>
+  <PlainSchema id="token.length" type="Long"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="token.expireTime"/>
+  <PlainSchema id="token.expireTime" type="Long"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="selfRegistration.allowed"/>
+  <PlainSchema id="selfRegistration.allowed" type="Boolean"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="passwordReset.allowed"/>
+  <PlainSchema id="passwordReset.allowed" type="Boolean"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="passwordReset.securityQuestion"/>
+  <PlainSchema id="passwordReset.securityQuestion" type="Boolean"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="authentication.attributes"/>
+  <PlainSchema id="authentication.attributes" type="String" multivalue="1" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="authentication.statuses"/>
+  <PlainSchema id="authentication.statuses" type="String" multivalue="1" uniqueConstraint="0" readonly="0"/>
+
+  <!-- Save user login date upon successful authentication -->
+  <SyncopeSchema id="log.lastlogindate"/>
+  <PlainSchema id="log.lastlogindate" type="Boolean"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <!-- Return hashed password values when reading users -->
+  <SyncopeSchema id="return.password.value"/>
+  <PlainSchema id="return.password.value" type="Boolean"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  
+  <!--  JWT lifetime in minutes -->                   
+  <SyncopeSchema id="jwt.lifetime.minutes"/>
+  <PlainSchema id="jwt.lifetime.minutes" type="Long"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+    
+  <!--  Connector and Resource configuration history -->                   
+  <SyncopeSchema id="connector.conf.history.size"/>
+  <PlainSchema id="connector.conf.history.size" type="Long"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  
+  <SyncopeSchema id="resource.conf.history.size"/>
+  <PlainSchema id="resource.conf.history.size" type="Long"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  
+  <SyncopeConf id="cd64d66f-6fff-4008-b966-a06b1cc1436d"
+               plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;SHA1&quot;}],&quot;schema&quot;:&quot;password.cipher.algorithm&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;0/20 * * * * ?&quot;}],&quot;schema&quot;:&quot;notificationjob.cronExpression&quot;},{&quot;values&quot;:[{&quot;longValue&quot;:3}],&quot;schema&quot;:&quot;notification.maxRetries&quot;},{&quot;values&quot;:[{&quot;longValue&quot;:256}],&quot;schema&quot;:&quot;token.length&quot;},{&qu [...]
+
+  <!-- sample policies -->
+  <PasswordPolicy id="ce93fcda-dc3a-4369-a7b0-a6108c261c85" description="a password policy"
+                  historyLength="1" allowNullPassword="1"/>
+  <Implementation id="DefaultPasswordRuleConf1" type="PASSWORD_RULE" engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf","maxLength":0,"minLength":8,"nonAlphanumericRequired":false,"alphanumericRequired":false,"digitRequired":false,"lowercaseRequired":false,"uppercaseRequired":false,"mustStartWithDigit":false,"mustntStartWithDigit":false,"mustEndWithDigit":false,"mustntEndWithDigit":false,"mustStartWithNonAlpha":false,"mustStartWithAlpha":false,"mustntStartWithNonAlpha":false,"mustntStartWithAlpha":false,"mustE [...]
+  <PasswordPolicyRule policy_id="ce93fcda-dc3a-4369-a7b0-a6108c261c85" implementation_id="DefaultPasswordRuleConf1"/>
+  <PasswordPolicy id="986d1236-3ac5-4a19-810c-5ab21d79cba1"
+                  description="sample password policy" historyLength="0" allowNullPassword="1"/> 
+  <Implementation id="DefaultPasswordRuleConf2" type="PASSWORD_RULE"  engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf","maxLength":0,"minLength":10,"nonAlphanumericRequired":false,"alphanumericRequired":false,"digitRequired":true,"lowercaseRequired":false,"uppercaseRequired":false,"mustStartWithDigit":false,"mustntStartWithDigit":false,"mustEndWithDigit":false,"mustntEndWithDigit":false,"mustStartWithNonAlpha":false,"mustStartWithAlpha":false,"mustntStartWithNonAlpha":false,"mustntStartWithAlpha":false,"mustE [...]
+  <PasswordPolicyRule policy_id="986d1236-3ac5-4a19-810c-5ab21d79cba1" implementation_id="DefaultPasswordRuleConf2"/>
+  <AccountPolicy id="20ab5a8c-4b0c-432c-b957-f7fb9784d9f7" description="an account policy"
+                 propagateSuspension="0" maxAuthenticationAttempts="0"/>
+  <Implementation id="DefaultAccountRuleConf1" type="ACCOUNT_RULE" engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.policy.DefaultAccountRuleConf","maxLength":0,"minLength":0,"pattern":null,"allUpperCase":false,"allLowerCase":false,"wordsNotPermitted":[],"schemasNotPermitted":[],"prefixesNotPermitted":[],"suffixesNotPermitted":[]}'/>
+  <AccountPolicyRule policy_id="20ab5a8c-4b0c-432c-b957-f7fb9784d9f7" implementation_id="DefaultAccountRuleConf1"/>
+  <AccountPolicy id="06e2ed52-6966-44aa-a177-a0ca7434201f" description="sample account policy"
+                 propagateSuspension="0" maxAuthenticationAttempts="3"/>
+  <Implementation id="DefaultAccountRuleConf2" type="ACCOUNT_RULE"  engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.policy.DefaultAccountRuleConf","maxLength":0,"minLength":4,"pattern":null,"allUpperCase":false,"allLowerCase":false,"wordsNotPermitted":[],"schemasNotPermitted":[],"prefixesNotPermitted":["notpermitted1","notpermitted2"],"suffixesNotPermitted":[]}'/>
+  <AccountPolicyRule policy_id="06e2ed52-6966-44aa-a177-a0ca7434201f" implementation_id="DefaultAccountRuleConf2"/>
+  <PasswordPolicy id="55e5de0b-c79c-4e66-adda-251b6fb8579a" description="sample password policy" historyLength="0" allowNullPassword="0"/> 
+  <Implementation id="DefaultPasswordRuleConf3" type="PASSWORD_RULE" engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf","maxLength":0,"minLength":10,"nonAlphanumericRequired":true,"alphanumericRequired":false,"digitRequired":true,"lowercaseRequired":true,"uppercaseRequired":true,"mustStartWithDigit":true,"mustntStartWithDigit":false,"mustEndWithDigit":true,"mustntEndWithDigit":false,"mustStartWithNonAlpha":false,"mustStartWithAlpha":false,"mustntStartWithNonAlpha":false,"mustntStartWithAlpha":false,"mustEndWit [...]
+  <PasswordPolicyRule policy_id="55e5de0b-c79c-4e66-adda-251b6fb8579a" implementation_id="DefaultPasswordRuleConf3"/>
+
+  <RelationshipType id="inclusion" description="Models the act that an object is included in another"/>
+  <RelationshipType id="neighborhood" description="Models the act that an object is near another"/>
+  
+  <AnyTypeClass id="generic membership"/>
+
+  <AnyType id="USER" kind="USER"/>
+  <AnyTypeClass id="minimal user"/>
+  <AnyType_AnyTypeClass anyType_id="USER" anyTypeClass_id="minimal user"/>
+  <AnyTypeClass id="other"/>
+  <AnyType_AnyTypeClass anyType_id="USER" anyTypeClass_id="other"/>
+
+  <AnyType id="GROUP" kind="GROUP"/>
+  <AnyTypeClass id="minimal group"/>
+  <AnyType_AnyTypeClass anyType_id="GROUP" anyTypeClass_id="minimal group"/>
+  
+  <AnyType id="PRINTER" kind="ANY_OBJECT"/>
+  <AnyTypeClass id="minimal printer"/>
+  <AnyType_AnyTypeClass anyType_id="PRINTER" anyTypeClass_id="minimal printer"/>
+      
+  <AnyTypeClass id="csv"/>
+
+  <SyncopeSchema id="fullname"/>
+  <PlainSchema id="fullname" type="String" anyTypeClass_id="minimal user"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="1" readonly="0"/>
+  <SyncopeSchema id="userId"/>
+  <Implementation id="EmailAddressValidator" type="VALIDATOR" engine="JAVA"
+                  body="org.apache.syncope.core.persistence.jpa.attrvalue.validation.EmailAddressValidator"/>
+  <PlainSchema id="userId" type="String" anyTypeClass_id="minimal user"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="1" readonly="0"
+               validator_id="EmailAddressValidator"/>
+  <SyncopeSchema id="loginDate"/>
+  <PlainSchema id="loginDate" type="Date" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"
+               conversionPattern="yyyy-MM-dd"/>
+  <SyncopeSchema id="firstname"/>
+  <PlainSchema id="firstname" type="String" anyTypeClass_id="minimal user"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SchemaLabel id="d90f90d0-cf15-407e-bac7-d46a8eb57c05" schema_id="firstname" locale="en" display="Firstname"/>
+  <SchemaLabel id="a9465ef0-b8b4-4af4-840d-77031a6b54a0" schema_id="firstname" locale="it" display="Nome"/>
+  <SchemaLabel id="ac8b7383-62df-490d-9364-88dbd3d301aa" schema_id="firstname" locale="pt_BR" display="Nome prĂłprio"/>
+  <SyncopeSchema id="surname"/>
+  <PlainSchema id="surname" type="String" anyTypeClass_id="minimal user"
+               mandatoryCondition="true" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SchemaLabel id="69712058-162a-4e2a-b07e-c78d82dc286d" schema_id="surname" locale="en" display="Surname"/>
+  <SchemaLabel id="77e7bbbb-d30c-47e1-b6d2-e0a9e8c11fe2" schema_id="surname" locale="it" display="Cognome"/>
+  <SyncopeSchema id="ctype"/>
+  <PlainSchema id="ctype" type="String" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SyncopeSchema id="email"/>
+  <PlainSchema id="email" type="String" anyTypeClass_id="minimal user"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"
+               validator_id="EmailAddressValidator"/>
+  <SyncopeSchema id="activationDate"/>
+  <PlainSchema id="activationDate" type="Date" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"
+               conversionPattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ"/>
+  <SyncopeSchema id="uselessReadonly"/>
+  <PlainSchema id="uselessReadonly" type="String" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="1"/>
+  <SyncopeSchema id="cool"/>
+  <PlainSchema id="cool" type="Boolean" anyTypeClass_id="other" 
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SyncopeSchema id="gender"/>
+  <PlainSchema id="gender" type="Enum" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"
+               enumerationValues="M;F"/>
+  <SyncopeSchema id="aLong"/>
+  <PlainSchema id="aLong" type="Long" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SyncopeSchema id="makeItDouble"/>
+  <PlainSchema id="makeItDouble" type="Long" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SyncopeSchema id="obscure"/>
+  <PlainSchema id="obscure" type="Encrypted" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"
+               secretKey="7abcdefghilmnopqrstuvz9#" cipherAlgorithm="SHA"/>
+  <SyncopeSchema id="photo"/>
+  <PlainSchema id="photo" type="Binary" anyTypeClass_id="other"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"
+               mimeType="image/jpeg"/>
+  
+  <Implementation id="BinaryValidator" type="VALIDATOR" engine="JAVA"
+                  body="org.apache.syncope.core.persistence.jpa.attrvalue.validation.BinaryValidator"/>
+
+  <SyncopeSchema id="csvuserid"/>
+  <DerSchema id="csvuserid" expression="firstname + ',' + surname" anyTypeClass_id="csv"/>
+  <SyncopeSchema id="cn"/>
+  <DerSchema id="cn" expression="surname + ', ' + firstname" anyTypeClass_id="minimal user"/>
+  <SyncopeSchema id="noschema"/>
+  <DerSchema id="noschema" expression="surname + ', ' + notfound" anyTypeClass_id="other"/>
+  <SyncopeSchema id="info"/>
+  <DerSchema id="info" expression="username + ' - ' + creationDate + '[' + failedLogins + ']'" anyTypeClass_id="minimal user"/>
+
+  <SyncopeSchema id="icon"/>
+  <PlainSchema id="icon" type="String" anyTypeClass_id="minimal group"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>                
+  <SyncopeSchema id="show"/>
+  <PlainSchema id="show" type="Boolean" anyTypeClass_id="minimal group"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SyncopeSchema id="rderived_sx"/>
+  <PlainSchema id="rderived_sx" type="String" anyTypeClass_id="minimal group"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SyncopeSchema id="rderived_dx"/>
+  <PlainSchema id="rderived_dx" type="String" anyTypeClass_id="minimal group"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>           
+  <SyncopeSchema id="title"/>
+  <PlainSchema id="title" type="String" anyTypeClass_id="minimal group"
+               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="rderiveddata"/>
+  <DerSchema id="rderiveddata" expression="rderived_sx + '-' + rderived_dx"
+             anyTypeClass_id="minimal group"/>
+  <SyncopeSchema id="displayProperty"/>
+  <DerSchema id="displayProperty" expression="icon + ': ' + show"
+             anyTypeClass_id="minimal group"/>
+  <SyncopeSchema id="rderToBePropagated"/>
+  <DerSchema id="rderToBePropagated" expression="rderived_sx + '-' + rderived_dx"
+             anyTypeClass_id="minimal group"/>
+
+  <SyncopeSchema id="rderivedschema"/>
+  <DerSchema id="rderivedschema" expression="rderived_sx + '-' + rderived_dx"  anyTypeClass_id="minimal group"/>
+
+  <SyncopeSchema id="subscriptionDate"/>
+  <PlainSchema id="subscriptionDate" type="Date" anyTypeClass_id="generic membership"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"
+               conversionPattern="yyyy-MM-dd'T'HH:mm:ss.SSSZ"/>
+  <SyncopeSchema id="mderived_sx"/>
+  <PlainSchema id="mderived_sx" type="String" anyTypeClass_id="generic membership"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SyncopeSchema id="mderived_dx"/>
+  <PlainSchema id="mderived_dx" type="String" anyTypeClass_id="generic membership"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>          
+  <SyncopeSchema id="postalAddress"/>
+  <PlainSchema id="postalAddress" type="String" anyTypeClass_id="generic membership"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <SyncopeSchema id="mderiveddata"/>
+  <DerSchema id="mderiveddata" expression="mderived_sx + '-' + mderived_dx"/>
+  <SyncopeSchema id="mderToBePropagated"/>
+  <DerSchema id="mderToBePropagated" expression="mderived_sx + '-' + mderived_dx" 
+             anyTypeClass_id="generic membership"/>
+         
+  <SyncopeSchema id="model"/>
+  <PlainSchema id="model" type="String" anyTypeClass_id="minimal printer"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+  <SyncopeSchema id="location"/>
+  <PlainSchema id="location" type="String" anyTypeClass_id="minimal printer"
+               mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"/>
+
+  <Realm id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" name="/" passwordPolicy_id="986d1236-3ac5-4a19-810c-5ab21d79cba1"/>
+  <Realm id="722f3d84-9c2b-4525-8f6e-e4b82c55a36c" name="odd" 
+         parent_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" accountPolicy_id="06e2ed52-6966-44aa-a177-a0ca7434201f"/>
+  <Realm id="c5b75db1-fce7-470f-b780-3b9934d82a9d" name="even" 
+         parent_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"/>
+  <Realm id="0679e069-7355-4b20-bd11-a5a0a5453c7c" name="two" 
+         parent_id="c5b75db1-fce7-470f-b780-3b9934d82a9d"
+         accountPolicy_id="20ab5a8c-4b0c-432c-b957-f7fb9784d9f7"
+         passwordPolicy_id="ce93fcda-dc3a-4369-a7b0-a6108c261c85"/>
+  
+  <AnyObject id="fc6dbc3a-6c07-4965-8781-921e7401a4a5" name="HP LJ 1300n"
+             realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" type_id="PRINTER"
+             creator="admin" lastModifier="admin" 
+             creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"
+             plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Canon MFC8030&quot;}],&quot;schema&quot;:&quot;model&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;1st floor&quot;}],&quot;schema&quot;:&quot;location&quot;}]"/>
+  <AnyObject id="8559d14d-58c2-46eb-a2d4-a7d35161e8f8" name="Canon MF 8030cn"
+             realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" type_id="PRINTER"
+             creator="admin" lastModifier="admin" 
+             creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"
+             plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;HP Laserjet 1300n&quot;}],&quot;schema&quot;:&quot;model&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;2nd floor&quot;}],&quot;schema&quot;:&quot;location&quot;}]"/>
+  <AnyObject id="9e1d130c-d6a3-48b1-98b3-182477ed0688" name="Epson Stylus Color"
+             realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c" type_id="PRINTER"
+             creator="admin" lastModifier="admin" 
+             creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  
+  <ARelationship id="11a0ec66-b59b-428a-af3d-f856950ff1c5" type_id="neighborhood"
+                 left_anyObject_id="fc6dbc3a-6c07-4965-8781-921e7401a4a5"
+                 right_anyObject_id="8559d14d-58c2-46eb-a2d4-a7d35161e8f8"/>
+  
+  <Application id="mightyApp" description="A cool application"/>
+  <Privilege id="postMighty" description="Ability to POST"
+             spec="{ &quot;method&quot;: &quot;POST&quot;, &quot;url&quot;: &quot;/a/b/c&quot; }"
+             application_id="mightyApp"/>
+  <Privilege id="getMighty" description="Ability to GET"
+             spec="{ &quot;method&quot;: &quot;GET&quot;, &quot;url&quot;: &quot;/a/b/c&quot; }"
+             application_id="mightyApp"/>
+
+  <SyncopeRole id="User reviewer"/>
+  <SyncopeRole_entitlements entitlement="USER_READ" role_id="User reviewer"/>
+  <SyncopeRole_entitlements entitlement="USER_LIST" role_id="User reviewer"/>
+  <SyncopeRole_entitlements entitlement="USER_SEARCH" role_id="User reviewer"/>
+  <SyncopeRole_entitlements entitlement="ANYTYPE_LIST" role_id="User reviewer"/>
+  <SyncopeRole_entitlements entitlement="ANYTYPE_READ" role_id="User reviewer"/>
+  <SyncopeRole_entitlements entitlement="ANYTYPECLASS_LIST" role_id="User reviewer"/>
+  <SyncopeRole_entitlements entitlement="ANYTYPECLASS_READ" role_id="User reviewer"/>
+  <SyncopeRole_Realm role_id="User reviewer" realm_id="722f3d84-9c2b-4525-8f6e-e4b82c55a36c"/>
+  <SyncopeRole_Realm role_id="User reviewer" realm_id="c5b75db1-fce7-470f-b780-3b9934d82a9d"/>
+  
+  <SyncopeRole id="User manager"/>
+  <SyncopeRole_entitlements entitlement="USER_READ" role_id="User manager"/>
+  <SyncopeRole_entitlements entitlement="USER_LIST" role_id="User manager"/>
+  <SyncopeRole_entitlements entitlement="USER_SEARCH" role_id="User manager"/>
+  <SyncopeRole_entitlements entitlement="ANYTYPE_LIST" role_id="User manager"/>
+  <SyncopeRole_entitlements entitlement="ANYTYPE_READ" role_id="User manager"/>
+  <SyncopeRole_entitlements entitlement="ANYTYPECLASS_LIST" role_id="User manager"/>
+  <SyncopeRole_entitlements entitlement="ANYTYPECLASS_READ" role_id="User manager"/>
+  <SyncopeRole_entitlements entitlement="USER_REQUEST_FORM_CLAIM" role_id="User manager"/>
+  <SyncopeRole_entitlements entitlement="USER_REQUEST_FORM_SUBMIT" role_id="User manager"/>
+  <SyncopeRole_Realm role_id="User manager" realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"/>
+
+  <SyncopeRole id="Other"/>
+  <SyncopeRole_entitlements entitlement="SCHEMA_READ" role_id="Other"/>
+  <SyncopeRole_entitlements entitlement="GROUP_READ" role_id="Other"/>
+  <SyncopeRole_entitlements entitlement="USER_REQUEST_FORM_CLAIM" role_id="Other"/>
+  <SyncopeRole_Realm role_id="Other" realm_id="722f3d84-9c2b-4525-8f6e-e4b82c55a36c"/>
+  <SyncopeRole_Privilege role_id="Other" privilege_id="postMighty"/>
+  
+  <SyncopeRole id="Search for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="USER_READ" role_id="Search for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="USER_SEARCH" role_id="Search for realm evenTwo"/>
+  <SyncopeRole_Realm role_id="Search for realm evenTwo" realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"/>
+
+  <SyncopeRole id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_READ" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_UPDATE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_DELETE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="CONNECTOR_LIST" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_READ" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_UPDATE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_DELETE" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_entitlements entitlement="RESOURCE_LIST" role_id="Connector and Resource for realm evenTwo"/>
+  <SyncopeRole_Realm role_id="Connector and Resource for realm evenTwo"
+                     realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"/>
+
+  <SyncopeUser mustChangePassword="0" id="1417acbe-cbf6-4277-9372-e75e04f97000" status="active"
+               password="5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" cipherAlgorithm="SHA1"
+               realm_id="c5b75db1-fce7-470f-b780-3b9934d82a9d"
+               username="rossini" creator="admin" lastModifier="admin"
+               creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00" suspended="0"
+               plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;G&quot;}],&quot;schema&quot;:&quot;ctype&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Gioacchino&quot;}],&quot;schema&quot;:&quot;firstname&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Rossini&quot;}],&quot;schema&quot;:&quot;surname&quot;},{&quot;values&quot;:[{&quot;dateValue&quot;:1243288800000},{&quot;dateValue&quot;:1274824800000}],&quot;schema&quot;:&quot;loginDate&quot;},{&q [...]
+  <SyncopeUser_SyncopeRole user_id="1417acbe-cbf6-4277-9372-e75e04f97000" role_id="Other"/>
+  <SyncopeUser mustChangePassword="0" id="74cd8ece-715a-44a4-a736-e17b46c4e7e6" status="active"
+               password="5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" cipherAlgorithm="SHA1"
+               realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+               username="verdi" creator="admin" lastModifier="admin"
+               creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00" suspended="0"
+               plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Giuseppe&quot;}],&quot;schema&quot;:&quot;firstname&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Verdi&quot;}],&quot;schema&quot;:&quot;surname&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;verdi@syncope.org&quot;}],&quot;schema&quot;:&quot;email&quot;},{&quot;uniqueValue&quot;:{&quot;stringValue&quot;:&quot;Giuseppe Verdi&quot;},&quot;schema&quot;:&quot;fullname&quot;},{&quot;uniqu [...]
+  <SyncopeUser mustChangePassword="0" id="b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee" status="active"
+               password="5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" cipherAlgorithm="SHA1"
+               realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+               username="vivaldi" creator="admin" lastModifier="admin"
+               creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00" suspended="0"
+               plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Antonio&quot;}],&quot;schema&quot;:&quot;firstname&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Vivaldi&quot;}],&quot;schema&quot;:&quot;surname&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;vivaldi@syncope.org&quot;}],&quot;schema&quot;:&quot;email&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;F&quot;}],&quot;schema&quot;:&quot;ctype&quot;},{&quot;uniqueValue&quot;:{&q [...]
+  <SyncopeUser mustChangePassword="0" id="c9b2dec2-00a7-4855-97c0-d854842b4b24" status="active"
+               password="5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" cipherAlgorithm="SHA1"
+               realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+               username="bellini" creator="admin" lastModifier="admin"
+               creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00" suspended="0"
+               plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Vincenzo&quot;}],&quot;schema&quot;:&quot;firstname&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Bellini&quot;}],&quot;schema&quot;:&quot;surname&quot;},{&quot;values&quot;:[{&quot;dateValue&quot;:1245794400000}],&quot;schema&quot;:&quot;loginDate&quot;},{&quot;values&quot;:[{&quot;booleanValue&quot;:true}],&quot;schema&quot;:&quot;cool&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot; [...]
+  <SyncopeUser_SyncopeRole user_id="c9b2dec2-00a7-4855-97c0-d854842b4b24" role_id="User reviewer"/>
+  <SyncopeUser_SyncopeRole user_id="c9b2dec2-00a7-4855-97c0-d854842b4b24" role_id="User manager"/>
+  <SyncopeUser mustChangePassword="0" id="823074dc-d280-436d-a7dd-07399fae48ec" status="active"
+               password="5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" cipherAlgorithm="SHA1"
+               realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+               username="puccini" creator="admin" lastModifier="admin" 
+               creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00" suspended="0"
+               plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Giacomo&quot;}],&quot;schema&quot;:&quot;firstname&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;Puccini&quot;}],&quot;schema&quot;:&quot;surname&quot;},{&quot;uniqueValue&quot;:{&quot;stringValue&quot;:&quot;Giacomo Puccini&quot;},&quot;schema&quot;:&quot;fullname&quot;},{&quot;uniqueValue&quot;:{&quot;stringValue&quot;:&quot;puccini@apache.org&quot;},&quot;schema&quot;:&quot;userId&quot;}]"/>
+  <SyncopeUser_SyncopeRole user_id="823074dc-d280-436d-a7dd-07399fae48ec" role_id="Search for realm evenTwo"/>
+  <SyncopeUser_SyncopeRole user_id="823074dc-d280-436d-a7dd-07399fae48ec" role_id="Connector and Resource for realm evenTwo"/>
+  
+  <SyncopeGroup id="37d15e4c-cdc1-460b-a591-8505c8133806" name="root"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"
+                plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;niceIcon&quot;}],&quot;schema&quot;:&quot;icon&quot;},{&quot;values&quot;:[{&quot;booleanValue&quot;:true}],&quot;schema&quot;:&quot;show&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;sx&quot;}],&quot;schema&quot;:&quot;rderived_sx&quot;},{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;dx&quot;}],&quot;schema&quot;:&quot;rderived_dx&quot;}]"/>
+  <SyncopeGroup id="b1f7c12d-ec83-441f-a50e-1691daaedf3b" name="child"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"
+                plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;badIcon&quot;}],&quot;schema&quot;:&quot;icon&quot;}]"/>
+  <SyncopeGroup id="29f96485-729e-4d31-88a1-6fc60e4677f3" name="citizen"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  <SyncopeGroup id="8fb2d51e-c605-4e80-a72b-13ffecf1aa9a" name="employee"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"
+                plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;icon4&quot;}],&quot;schema&quot;:&quot;icon&quot;}]"/>
+  <SyncopeGroup id="a3c1a693-a6be-483f-a2b3-5cfec146f4bf" name="secretary"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  <SyncopeGroup id="ebf97068-aa4b-4a85-9f01-680e8c4cf227" name="director"
+                userOwner_id="823074dc-d280-436d-a7dd-07399fae48ec"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"
+                plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;icon6&quot;}],&quot;schema&quot;:&quot;icon&quot;}]"/>
+  <SyncopeGroup id="bf825fe1-7320-4a54-bd64-143b5c18ab97" name="managingDirector"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  <SyncopeGroup id="f779c0d4-633b-4be5-8f57-32eb478a3ca5" name="otherchild"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  <SyncopeGroup id="0cbcabd2-4410-4b6b-8f05-a052b451d18f" name="groupForWorkflowApproval"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  <SyncopeGroup id="b8d38784-57e7-4595-859a-076222644b55" name="managingConsultant"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  <SyncopeGroup id="268fed79-f440-4390-9435-b273768eb5d6" name="groupForWorkflowOptIn"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  <SyncopeGroup id="0626100b-a4ba-4e00-9971-86fad52a6216" name="aGroupForPropagation"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"
+                plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;r12&quot;}],&quot;schema&quot;:&quot;title&quot;}]"/>
+  <SyncopeGroup_AnyTypeClass group_id="0626100b-a4ba-4e00-9971-86fad52a6216" anyTypeClass_id="csv"/>  
+  <SyncopeGroup id="ba9ed509-b1f5-48ab-a334-c8530a6422dc" name="bGroupForPropagation"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"
+                plainAttrs="[{&quot;values&quot;:[{&quot;stringValue&quot;:&quot;r13&quot;}],&quot;schema&quot;:&quot;title&quot;}]"/>
+  <SyncopeGroup_AnyTypeClass group_id="ba9ed509-b1f5-48ab-a334-c8530a6422dc" anyTypeClass_id="csv"/>  
+  <SyncopeGroup id="ece66293-8f31-4a84-8e8d-23da36e70846" name="artDirector"
+                realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>  
+  <SyncopeGroup id="034740a9-fa10-453b-af37-dc7897e98fb1" name="additional"
+                realm_id="c5b75db1-fce7-470f-b780-3b9934d82a9d"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  <TypeExtension id="84c1490c-a1d9-4b91-859c-fafbb0113a85"
+                 group_id="034740a9-fa10-453b-af37-dc7897e98fb1" anyType_id="USER"/>
+  <TypeExtension_AnyTypeClass typeExtension_id="84c1490c-a1d9-4b91-859c-fafbb0113a85" anyTypeClass_id="csv"/>
+  <TypeExtension_AnyTypeClass typeExtension_id="84c1490c-a1d9-4b91-859c-fafbb0113a85" anyTypeClass_id="other"/>
+  <SyncopeGroup id="e7ff94e8-19c9-4f0a-b8b7-28327edbf6ed" name="fake"
+                realm_id="722f3d84-9c2b-4525-8f6e-e4b82c55a36c"
+                creator="admin" lastModifier="admin" 
+                creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
+  
+  <URelationship id="ca20ffca-1305-442f-be9a-3723a0cd88ca"
+                 user_id="c9b2dec2-00a7-4855-97c0-d854842b4b24"
+                 anyObject_id="fc6dbc3a-6c07-4965-8781-921e7401a4a5" type_id="neighborhood"/>
+
+  <UMembership id="3d5e91f6-305e-45f9-ad30-4897d3d43bd9"
+               user_id="1417acbe-cbf6-4277-9372-e75e04f97000" group_id="37d15e4c-cdc1-460b-a591-8505c8133806"/>
+  <UMembership id="d53f7657-2b22-4e10-a2cd-c3379a4d1a31"
+               user_id="74cd8ece-715a-44a4-a736-e17b46c4e7e6" group_id="37d15e4c-cdc1-460b-a591-8505c8133806"/>
+  <UMembership id="8e42a132-55ae-4860-bebd-2ca00ba5e959"
+               user_id="74cd8ece-715a-44a4-a736-e17b46c4e7e6" group_id="b1f7c12d-ec83-441f-a50e-1691daaedf3b"/>
+  <UMembership id="40e409a4-d870-4792-b820-30668f1269b9"
+               user_id="c9b2dec2-00a7-4855-97c0-d854842b4b24" group_id="bf825fe1-7320-4a54-bd64-143b5c18ab97"/>
+  <UMembership id="6d8a7dc0-d4bc-4b7e-b058-abcd3df28f28"
+               user_id="1417acbe-cbf6-4277-9372-e75e04f97000" group_id="f779c0d4-633b-4be5-8f57-32eb478a3ca5"/>
+  <UMembership id="34f2d776-58b1-4640-8e64-e979b4242a18"
+               user_id="74cd8ece-715a-44a4-a736-e17b46c4e7e6" group_id="29f96485-729e-4d31-88a1-6fc60e4677f3"/>
+  <UMembership id="8cfb78fc-d0e7-4f08-a0ae-d7abf3223b6f"
+               user_id="823074dc-d280-436d-a7dd-07399fae48ec" group_id="ece66293-8f31-4a84-8e8d-23da36e70846"/>
+    
+  <!-- pull policies -->
+  <PullPolicy id="66691e96-285f-4464-bc19-e68384ea4c85" description="a pull policy" conflictResolutionAction="IGNORE"/>
+  <PullPolicy id="880f8553-069b-4aed-9930-2cd53873f544" description="another pull policy" conflictResolutionAction="ALL"/>
+  <Implementation id="TestPullCorrelationRule" type="PULL_CORRELATION_RULE" engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf","name":"org.apache.syncope.common.lib.policy.DefaultPullCorrelationRuleConf","schemas":["username","firstname"]}'/>
+  <PullCorrelationRuleEntity id="10e3d196-7486-4c88-aefd-59e40d93a0c1" pullPolicy_id="880f8553-069b-4aed-9930-2cd53873f544" 
+                             anyType_id="USER" implementation_id="TestPullCorrelationRule"/>
+  <PullPolicy id="4ad10d94-e002-4b3f-b771-16089cc71da9" description="pull policy 1" conflictResolutionAction="IGNORE"/>
+  <PullPolicy id="9454b0d7-2610-400a-be82-fc23cf553dd6" description="pull policy for java rule" conflictResolutionAction="IGNORE"/>
+
+  <!-- push policies -->
+  <PushPolicy id="fb6530e5-892d-4f47-a46b-180c5b6c5c83" description="a push policy" conflictResolutionAction="IGNORE"/>
+  <Implementation id="TestPushCorrelationRule" type="PUSH_CORRELATION_RULE" engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf","name":"org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf","schemas":["email"]}'/>
+  <PushCorrelationRuleEntity id="24463935-32a0-4272-bc78-04d6d0adc69e" pushPolicy_id="fb6530e5-892d-4f47-a46b-180c5b6c5c83" 
+                             anyType_id="USER" implementation_id="TestPushCorrelationRule"/>
+  
+  <ConnInstance id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" displayName="ConnInstance100"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                location="${connid.location}"
+                bundleName="net.tirasa.connid.bundles.soap"
+                connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
+                version="${connid.soap.version}"
+                jsonConf='[{"schema":{"name":"endpoint","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["http://localhost:${cargo.servlet.port}/syncope-fit-build-tools/cxf/soap/provisioning"]},{"schema":{"name":"servicename","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false [...]
+  <ConnInstance_capabilities connInstance_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" capability="UPDATE"/>
+  <ConnInstance_capabilities connInstance_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" capability="DELETE"/>
+  <ConnInstance_capabilities connInstance_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8" capability="SEARCH"/>
+
+  <ConnInstance id="5aa5b8be-7521-481a-9651-c557aea078c1" displayName="H2"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
+                bundleName="net.tirasa.connid.bundles.db.table"
+                connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector"
+                version="${connid.database.version}"
+                jsonConf='[{"schema":{"name":"disabledStatusValue","displayName":null,"helpMessage":null,"type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"user","displayName":null,"helpMessage":null,"type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["sa"]},{"schema":{"name":"keyColumn","displayName":null,"helpM [...]
+  <ConnInstance_capabilities connInstance_id="5aa5b8be-7521-481a-9651-c557aea078c1" capability="AUTHENTICATE"/>
+  <ConnInstance_capabilities connInstance_id="5aa5b8be-7521-481a-9651-c557aea078c1" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="5aa5b8be-7521-481a-9651-c557aea078c1" capability="UPDATE"/>
+  <ConnInstance_capabilities connInstance_id="5aa5b8be-7521-481a-9651-c557aea078c1" capability="DELETE"/>
+  <ConnInstance_capabilities connInstance_id="5aa5b8be-7521-481a-9651-c557aea078c1" capability="SEARCH"/>
+  <ConnInstance_capabilities connInstance_id="5aa5b8be-7521-481a-9651-c557aea078c1" capability="SYNC"/>
+
+  <ConnInstance id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" displayName="ConnInstance102"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                location="${connid.location}"
+                bundleName="net.tirasa.connid.bundles.soap"
+                connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
+                version="${connid.soap.version}"
+                connRequestTimeout="10"
+                jsonConf='[{"schema":{"name":"servicename","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["net.tirasa.connid.bundles.soap.provisioning.interfaces.Provisioning"]},{"schema":{"name":"endpoint","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":true,"values":["http:/ [...]
+  <ConnInstance_capabilities connInstance_id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" capability="UPDATE"/>
+  <ConnInstance_capabilities connInstance_id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" capability="DELETE"/>
+  <ConnInstance_capabilities connInstance_id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08" capability="SEARCH"/>
+
+  <ConnInstance id="fcf9f2b0-f7d6-42c9-84a6-61b28255a42b" displayName="ConnInstance103"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                location="${connid.location}"
+                bundleName="net.tirasa.connid.bundles.soap"
+                connectorName="net.tirasa.connid.bundles.soap.WebServiceConnector"
+                version="${connid.soap.version}"
+                jsonConf='[{"schema":{"name":"endpoint","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["http://localhost:${cargo.servlet.port}/syncope-fit-build-tools/cxf/soap/provisioning"]},{"schema":{"name":"servicename","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false [...]
+
+  <ConnInstance id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" displayName="CSVDir"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                location="${connid.location}"
+                bundleName="net.tirasa.connid.bundles.csvdir"
+                connectorName="net.tirasa.connid.bundles.csvdir.CSVDirConnector"
+                version="${connid.csvdir.version}"
+                jsonConf='[{"schema":{"name":"fields","displayName":"fields","helpMessage":"Column names separated by comma","type":"[Ljava.lang.String;","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["id","name","surname","email","password","theirgroup","membership","status","deleted"]},{"schema":{"name":"keyColumnNames","displayName":"Key column name","helpMessage":"Name of the column used to identify user uniquely","type":"[Ljava.lan [...]
+  <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="UPDATE"/>
+  <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="DELETE"/>
+  <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="SEARCH"/>
+  <ConnInstance_capabilities connInstance_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf" capability="SYNC"/>
+    
+  <ConnInstance id="74141a3b-0762-4720-a4aa-fc3e374ef3ef"
+                bundleName="net.tirasa.connid.bundles.ldap" displayName="ApacheDS"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                location="${connid.location}"
+                connectorName="net.tirasa.connid.bundles.ldap.LdapConnector"
+                version="${connid.ldap.version}" 
+                jsonConf='[{"schema":{"name":"synchronizePasswords","displayName":"Enable Password Synchronization","helpMessage":"If true, the connector will synchronize passwords. The Password Capture Plugin needs to be installed for password synchronization to work.","type":"boolean","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"maintainLdapGroupMembership","displayName":"Maintain LDAP Group Membership" [...]
+  <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="UPDATE"/>
+  <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="DELETE"/>
+  <ConnInstance_capabilities connInstance_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef" capability="SEARCH"/>
+  
+  <ConnInstance id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" displayName="H2-test2"
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
+                bundleName="net.tirasa.connid.bundles.db.table"
+                connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector"
+                version="${connid.database.version}"
+                jsonConf='[{"schema":{"name":"disabledStatusValue","displayName":null,"helpMessage":null,"type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["false"]},{"schema":{"name":"user","displayName":null,"helpMessage":null,"type":"java.lang.String","required":false,"order":0,"confidential":false,"defaultValues":null},"overridable":false,"values":["sa"]},{"schema":{"name":"keyColumn","displayName":null,"helpM [...]
+  <ConnInstance_capabilities connInstance_id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" capability="UPDATE"/>
+  <ConnInstance_capabilities connInstance_id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" capability="SEARCH"/>
+  <ConnInstance_capabilities connInstance_id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d" capability="SYNC"/>
+  
+  <ConnInstance id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" bundleName="net.tirasa.connid.bundles.db.table" 
+                adminRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+                location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
+                connectorName="net.tirasa.connid.bundles.db.table.DatabaseTableConnector" 
+                displayName="H2-testpull" version="${connid.database.version}"
+                jsonConf='[{"schema":{"name":"changeLogColumn","displayName":"Change Log Column (Sync)","helpMessage":"=&lt;b&gt;Change Log Column&lt;/b&gt;&lt;br&gt;The change log column store the latest change time. Providing this value the Pull capabilities are activated.","type":"java.lang.String","required":false,"order":21,"confidential":false,"defaultValues":null},"overridable":false,"values":[]},{"schema":{"name":"nativeTimestamps","displayName":"Native Timestamps ","helpMessage" [...]
+  <ConnInstance_capabilities connInstance_id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" capability="UPDATE"/>
+  <ConnInstance_capabilities connInstance_id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" capability="DELETE"/>
+  <ConnInstance_capabilities connInstance_id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c" capability="SEARCH"/>
+  
+  <ConnInstance id="a6d017fd-a705-4507-bb7c-6ab6a6745997" bundleName="net.tirasa.connid.bundles.db.scriptedsql" 
+                adminRealm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"
+                location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
+                connectorName="net.tirasa.connid.bundles.db.scriptedsql.ScriptedSQLConnector"
+                displayName="Scripted SQL" version="${connid.database.version}"
+                jsonConf='[{&quot;schema&quot;:{&quot;name&quot;:&quot;updateScriptFileName&quot;,&quot;displayName&quot;:&quot;updateScriptFileName&quot;,&quot;helpMessage&quot;:&quot;updateScriptFileName&quot;,&quot;type&quot;:&quot;java.lang.String&quot;,&quot;required&quot;:false,&quot;order&quot;:0,&quot;confidential&quot;:false,&quot;defaultValues&quot;:[]},&quot;overridable&quot;:false,&quot;values&quot;:[&quot;${conf.directory}/scriptedsql/UpdateScript.groovy&quot;]},{&quot;schem [...]
+  <ConnInstance_capabilities connInstance_id="a6d017fd-a705-4507-bb7c-6ab6a6745997" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="a6d017fd-a705-4507-bb7c-6ab6a6745997" capability="UPDATE"/>
+  <ConnInstance_capabilities connInstance_id="a6d017fd-a705-4507-bb7c-6ab6a6745997" capability="DELETE"/>
+  <ConnInstance_capabilities connInstance_id="a6d017fd-a705-4507-bb7c-6ab6a6745997" capability="SEARCH"/>
+  <ConnInstance_capabilities connInstance_id="a6d017fd-a705-4507-bb7c-6ab6a6745997" capability="SYNC"/>
+  
+  <ConnInstance id="44c02549-19c3-483c-8025-4919c3283c37" bundlename="net.tirasa.connid.bundles.rest"
+                adminRealm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c"
+                location="connid://${testconnectorserver.key}@localhost:${testconnectorserver.port}"
+                connectorname="net.tirasa.connid.bundles.rest.RESTConnector"
+                displayname="REST" version="${connid.rest.version}"
+                jsonconf="[{&quot;schema&quot;:{&quot;name&quot;:&quot;authenticateScript&quot;,&quot;displayName&quot;:&quot;authenticateScript&quot;,&quot;helpMessage&quot;:&quot;authenticateScript&quot;,&quot;type&quot;:&quot;java.lang.String&quot;,&quot;required&quot;:false,&quot;order&quot;:6,&quot;confidential&quot;:false,&quot;defaultValues&quot;:[&quot;&quot;]},&quot;overridable&quot;:false,&quot;values&quot;:[]},{&quot;schema&quot;:{&quot;name&quot;:&quot;contentType&quot;,&quot [...]
+  <ConnInstance_capabilities connInstance_id="44c02549-19c3-483c-8025-4919c3283c37" capability="AUTHENTICATE"/>
+  <ConnInstance_capabilities connInstance_id="44c02549-19c3-483c-8025-4919c3283c37" capability="SYNC"/>
+  <ConnInstance_capabilities connInstance_id="44c02549-19c3-483c-8025-4919c3283c37" capability="CREATE"/>
+  <ConnInstance_capabilities connInstance_id="44c02549-19c3-483c-8025-4919c3283c37" capability="DELETE"/>
+  <ConnInstance_capabilities connInstance_id="44c02549-19c3-483c-8025-4919c3283c37" capability="SEARCH"/>
+  <ConnInstance_capabilities connInstance_id="44c02549-19c3-483c-8025-4919c3283c37" capability="UPDATE"/>
+
+  <ExternalResource id="ws-target-resource-1" connector_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="0" overrideCapabilities="0"
+                    propagationPriority="1" createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="ws-target-resource-2" connector_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    createTraceLevel="FAILURES" deleteTraceLevel="NONE" updateTraceLevel="ALL" provisioningTraceLevel="ALL"
+                    pullPolicy_id="9454b0d7-2610-400a-be82-fc23cf553dd6"/>
+  <ExternalResource id="ws-target-resource-timeout" connector_id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    propagationPriority="1" createTraceLevel="FAILURES" deleteTraceLevel="NONE" updateTraceLevel="ALL" provisioningTraceLevel="ALL"
+                    jsonConf='[{"schema":{"name":"endpoint","displayName":null,"helpMessage":null,"type":"java.lang.String","required":true,"order":0,"confidential":false,"defaultValues":null},"overridable":true,"values":["http://localhost:${cargo.servlet.port}/syncope-fit-build-tools/services/provisioning"]}]'/>
+  <ExternalResource id="ws-target-resource-list-mappings-1" connector_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="0" overrideCapabilities="0"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="ws-target-resource-list-mappings-2" connector_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="ws-target-resource-delete" connector_id="5ffbb4ac-a8c3-4b44-b699-11b398a1ba08"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="0" overrideCapabilities="0"
+                    propagationPriority="2" createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="ws-target-resource-update" connector_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="resource-testdb" connector_id="5aa5b8be-7521-481a-9651-c557aea078c1"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="resource-testdb2" connector_id="a28abd9b-9f4a-4ef6-a7a8-d19ad2a8f29d"
+                    randomPwdIfNotProvided="1" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="resource-csv" connector_id="6c2acf1b-b052-46f0-8c56-7a8ad6905edf"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="0" overrideCapabilities="0"
+                    pullPolicy_id="880f8553-069b-4aed-9930-2cd53873f544"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="ws-target-resource-update-resetsynctoken" connector_id="88a7a819-dab5-46b4-9b90-0b9769eabdb8"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="resource-ldap" connector_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef"
+                    randomPwdIfNotProvided="1" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    propagationPriority="1"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <Implementation id="LDAPMembershipPropagationActions" type="PROPAGATION_ACTIONS" engine="JAVA"
+                  body="org.apache.syncope.core.provisioning.java.propagation.LDAPMembershipPropagationActions"/>
+  <ExternalResourcePropAction resource_id="resource-ldap" implementation_id="LDAPMembershipPropagationActions"/>
+  <ExternalResource id="resource-ldap-orgunit" connector_id="74141a3b-0762-4720-a4aa-fc3e374ef3ef"
+                    randomPwdIfNotProvided="1" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    propagationPriority="1"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"
+                    jsonConf='[{"schema":{"name":"uidAttribute","displayName":"Uid Attribute","helpMessage":"The name of the LDAP attribute which is mapped to the Uid attribute. Default is \"entryUUID\".","type":"java.lang.String","required":false,"order":21,"confidential":false,"defaultValues":["entryUUID"]},"overridable":true,"values":["l"]},{"schema":{"name":"baseContexts","displayName":"Base Contexts","helpMessage":"One or more starting points in the LDAP tree that will be used when  [...]
+  <OrgUnit id="599a59cf-9a23-4447-9a59-cf9a2334473a" connObjectLink="syncope:fullPath2Dn(fullPath, 'ou') + ',o=isp'"
+           objectClass="organizationalUnit" resource_id="resource-ldap-orgunit" ignoreCaseMatch="0"/>
+  <OrgUnitItem id="5d0e7ad0-9026-42ad-be8a-32539389e7bd" connObjectKey="1" extAttrName="l"
+               intAttrName="fullpath" mandatoryCondition="true" purpose="BOTH"
+               orgUnit_id="599a59cf-9a23-4447-9a59-cf9a2334473a"/>
+  <OrgUnitItem id="1df556d3-bc23-48b7-a09b-fc3794a00019" connObjectKey="0" extAttrName="ou"
+               intAttrName="name" mandatoryCondition="true" purpose="BOTH"
+               orgUnit_id="599a59cf-9a23-4447-9a59-cf9a2334473a"/>
+  
+  <ExternalResource id="ws-target-resource-nopropagation" connector_id="fcf9f2b0-f7d6-42c9-84a6-61b28255a42b"
+                    randomPwdIfNotProvided="0" enforceMandatoryCondition="1" overrideCapabilities="0"
+                    createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"
+                    passwordPolicy_id="986d1236-3ac5-4a19-810c-5ab21d79cba1"/>
+  
+  <!-- The following three resources have been added to verify the issue SYNCOPE-68 -->
+  <ExternalResource id="ws-target-resource-nopropagation2" connector_id="fcf9f2b0-f7d6-42c9-84a6-61b28255a42b" 
+                    enforceMandatoryCondition="1" overrideCapabilities="0"
+                    randomPwdIfNotProvided="0" createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="ws-target-resource-nopropagation3" connector_id="fcf9f2b0-f7d6-42c9-84a6-61b28255a42b" 
+                    enforceMandatoryCondition="1" overrideCapabilities="0"
+                    randomPwdIfNotProvided="0" createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+  <ExternalResource id="ws-target-resource-nopropagation4" connector_id="fcf9f2b0-f7d6-42c9-84a6-61b28255a42b" 
+                    enforceMandatoryCondition="1" overrideCapabilities="0"
+                    randomPwdIfNotProvided="0" createTraceLevel="ALL" deleteTraceLevel="ALL" updateTraceLevel="ALL" provisioningTraceLevel="ALL"/>
+                    
+  <!-- External resource for issue SYNCOPE-230 -->
+  <ExternalResource id="resource-db-pull" connector_id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c"
+                    randomPwdIfNotProvided="0" createTraceLevel="ALL" deleteTraceLevel="ALL" provisioningTraceLevel="ALL" updateTraceLevel="ALL"
+                    enforceMandatoryCondition="0" overrideCapabilities="0"/>
+                    
+  <!-- External resource for issue SYNCOPE-267 -->
+  <ExternalResource id="resource-db-virattr" connector_id="be24b061-019d-4e3e-baf0-0a6d0a45cb9c"
+                    randomPwdIfNotProvided="0" createTraceLevel="ALL" deleteTraceLevel="ALL" provisioningTraceLevel="ALL" updateTraceLevel="ALL"
+                    enforceMandatoryCondition="0" overrideCapabilities="0"/>
+
+  <ExternalResource id="resource-db-scripted" connector_id="a6d017fd-a705-4507-bb7c-6ab6a6745997"
+                    randomPwdIfNotProvided="0" createTraceLevel="ALL" deleteTraceLevel="ALL" provisioningTraceLevel="ALL" updateTraceLevel="ALL"
+                    enforceMandatoryCondition="0" overrideCapabilities="0"/>
+
+  <ExternalResource id="rest-target-resource" connector_id="44c02549-19c3-483c-8025-4919c3283c37"
+                    createTraceLevel="ALL" updateTraceLevel="ALL"  deleteTraceLevel="ALL" provisioningTraceLevel="ALL" 
+                    enforceMandatoryCondition="1" overrideCapabilities="0"
+                    propagationPriority="0" randomPwdIfNotProvided="0"/>
+
+  <!-- Use resource-testdb for passthrough authentication (SYNCOPE-164) -->
+  <AccountPolicy_ExternalResource accountPolicy_id="20ab5a8c-4b0c-432c-b957-f7fb9784d9f7" resource_id="resource-testdb"/>
+    
+  <SyncopeUser_ExternalResource user_id="1417acbe-cbf6-4277-9372-e75e04f97000" resource_id="resource-testdb2"/>
+  <SyncopeUser_ExternalResource user_id="b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee" resource_id="ws-target-resource-delete"/>
+  <SyncopeUser_ExternalResource user_id="b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee" resource_id="ws-target-resource-2"/>
+  <SyncopeUser_ExternalResource user_id="b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee" resource_id="ws-target-resource-1"/>
+  <SyncopeUser_ExternalResource user_id="823074dc-d280-436d-a7dd-07399fae48ec" resource_id="resource-testdb2"/>
+  <SyncopeGroup_ExternalResource group_id="29f96485-729e-4d31-88a1-6fc60e4677f3" resource_id="ws-target-resource-list-mappings-1"/>
+  <SyncopeGroup_ExternalResource group_id="f779c0d4-633b-4be5-8f57-32eb478a3ca5" resource_id="ws-target-resource-2"/>
+  <SyncopeGroup_ExternalResource group_id="29f96485-729e-4d31-88a1-6fc60e4677f3" resource_id="ws-target-resource-list-mappings-2"/>
+  <SyncopeGroup_ExternalResource group_id="bf825fe1-7320-4a54-bd64-143b5c18ab97" resource_id="ws-target-resource-nopropagation"/>
+  <SyncopeGroup_ExternalResource group_id="b8d38784-57e7-4595-859a-076222644b55" resource_id="ws-target-resource-nopropagation3"/>
+  <SyncopeGroup_ExternalResource group_id="0626100b-a4ba-4e00-9971-86fad52a6216" resource_id="resource-csv"/>
+  <SyncopeGroup_ExternalResource group_id="ba9ed509-b1f5-48ab-a334-c8530a6422dc" resource_id="resource-csv"/>
+     
+  <Provision ignoreCaseMatch="0" id="209ea85f-f964-49c7-a498-6c9c2baa3bd8" resource_id="ws-target-resource-1" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="bc0cf27b-16b7-4e83-a4b0-09af7ea4aacc" provision_id="209ea85f-f964-49c7-a498-6c9c2baa3bd8"/>
+  <MappingItem id="96aad4e0-2678-4903-a52f-0a7d090a2863" mapping_id="bc0cf27b-16b7-4e83-a4b0-09af7ea4aacc" extAttrName="userId"
+               intAttrName="username" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="7f55b09c-b573-41dc-a9eb-ccd80bd3ea7a" extAttrName="email" mapping_id="bc0cf27b-16b7-4e83-a4b0-09af7ea4aacc"
+               intAttrName="email" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="a9749641-0556-49e2-a519-9bec35a4e06e" extAttrName="surname" mapping_id="bc0cf27b-16b7-4e83-a4b0-09af7ea4aacc"
+               intAttrName="surname" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="d118671c-2e3e-4aa3-a3dd-fde2ba4c4ded" mapping_id="bc0cf27b-16b7-4e83-a4b0-09af7ea4aacc"
+               extAttrName="__PASSWORD__" intAttrName="password" mandatoryCondition="true"
+               connObjectKey="0" password="1" purpose="PROPAGATION"/>
+  <MappingItem id="dca9de4f-9a5a-4280-8e9a-357e321ba7a5" mapping_id="bc0cf27b-16b7-4e83-a4b0-09af7ea4aacc" 
+               extAttrName="fullname" intAttrName="surname" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="471f0e2e-2bde-4442-9abf-0effb533f2ee" mapping_id="bc0cf27b-16b7-4e83-a4b0-09af7ea4aacc"
+               extAttrName="type" intAttrName="ctype" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="72324cda-a66c-4ffe-b6b6-1d9b6cee9bf2" mapping_id="bc0cf27b-16b7-4e83-a4b0-09af7ea4aacc"
+               extAttrName="name" intAttrName="firstname" mandatoryCondition="false"
+               connObjectKey="0" password="0" purpose="NONE"/>
+  
+  <Provision ignoreCaseMatch="0" id="41a53a00-0b35-4047-831a-d5238f74c7ba" resource_id="ws-target-resource-list-mappings-1" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="bf8afa4a-1522-44b9-91d0-c7b035e4fd99" provision_id="41a53a00-0b35-4047-831a-d5238f74c7ba"/>
+  <MappingItem id="6f8d7b42-44f4-4697-aff5-1736c4b01ee4" mapping_id="bf8afa4a-1522-44b9-91d0-c7b035e4fd99"
+               extAttrName="email" intAttrName="email" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="8515e385-3bf1-4928-adc9-489dee65829a" extAttrName="surname"
+               mapping_id="bf8afa4a-1522-44b9-91d0-c7b035e4fd99"
+               intAttrName="surname" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+
+  <Provision ignoreCaseMatch="0" id="09a65250-d9de-44b1-9412-11ed996d356d" resource_id="ws-target-resource-list-mappings-2" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="b12c4fad-f0f1-406d-b143-f2d68ed28e3a" provision_id="09a65250-d9de-44b1-9412-11ed996d356d"/>
+  <MappingItem id="55a4cf7f-ac96-4e8b-931c-2d0eab6a6bca" mapping_id="b12c4fad-f0f1-406d-b143-f2d68ed28e3a"
+               extAttrName="userId" intAttrName="userId" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+
+  <Provision ignoreCaseMatch="0" id="3d75991b-caee-4993-8e46-afb13d1bfbd4" resource_id="ws-target-resource-2" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="240a0291-f89d-4557-a547-2a3b9aad625b" provision_id="3d75991b-caee-4993-8e46-afb13d1bfbd4"/>
+  <MappingItem id="d5c4d467-cd18-4148-8195-015808b4b3e6" mapping_id="240a0291-f89d-4557-a547-2a3b9aad625b"
+               extAttrName="fullname" intAttrName="fullname" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="BOTH"/>
+  <MappingItem id="370a8673-f3f7-4328-a9ce-acd946f687c5" mapping_id="240a0291-f89d-4557-a547-2a3b9aad625b"
+               extAttrName="__PASSWORD__" intAttrName="password" mandatoryCondition="true"
+               connObjectKey="0" password="1" purpose="BOTH"/>
+  <MappingItem id="c8d1a47a-1846-47b8-9f68-30aa21e94dcc" extAttrName="type" mapping_id="240a0291-f89d-4557-a547-2a3b9aad625b"
+               intAttrName="ctype" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="BOTH"/>
+  <MappingItem id="f0a06b24-7d4d-480e-8188-e53045885569" extAttrName="surname" mapping_id="240a0291-f89d-4557-a547-2a3b9aad625b"
+               intAttrName="surname" mandatoryCondition="type == 'F'"
+               connObjectKey="0" password="0" purpose="BOTH"/>
+  <MappingItem id="adc3c628-27b3-4740-be01-2f83c210ace9" extAttrName="name" mapping_id="240a0291-f89d-4557-a547-2a3b9aad625b"
+               intAttrName="virtualdata" mandatoryCondition="type == 'F'"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="6972a78b-2570-45d9-bc0b-31d2f2f9c860" extAttrName="fullname" mapping_id="240a0291-f89d-4557-a547-2a3b9aad625b"
+               intAttrName="cn" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+    
+  <Provision ignoreCaseMatch="0" id="9ebc3237-49fa-4dce-9a4c-3070e931812f" resource_id="ws-target-resource-update" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="c17813c0-4e90-4118-bb28-cd36ad6d5a4d" provision_id="9ebc3237-49fa-4dce-9a4c-3070e931812f"/>
+  <MappingItem id="cc973ed6-d031-4790-adab-fc059ac0c818" extAttrName="email" mapping_id="c17813c0-4e90-4118-bb28-cd36ad6d5a4d"
+               intAttrName="email" mandatoryCondition="false"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="7a72c812-1897-4db0-bed4-4e7e8ea51afe" extAttrName="userId" mapping_id="c17813c0-4e90-4118-bb28-cd36ad6d5a4d"
+               intAttrName="userId" mandatoryCondition="false"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="946a3c7f-6359-4ab7-8a5f-adb08bdb4b5b" extAttrName="test3" mapping_id="c17813c0-4e90-4118-bb28-cd36ad6d5a4d"
+               intAttrName="fullname" mandatoryCondition="false"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+    
+  <Provision ignoreCaseMatch="0" id="8680bc79-dfa1-4719-9886-1d582bf1124f" resource_id="ws-target-resource-nopropagation" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="63ddd4c8-efed-4a22-a4b4-1f4e6f47c8d0" provision_id="8680bc79-dfa1-4719-9886-1d582bf1124f"/>
+  <MappingItem id="ffcfbb5e-7bbd-489a-a69e-2dd84f00731a" mapping_id="63ddd4c8-efed-4a22-a4b4-1f4e6f47c8d0" extAttrName="fullname" 
+               intAttrName="fullname" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+                     
+  <Provision ignoreCaseMatch="0" id="0bfa7c3e-2bb3-43d7-ac0e-d57cff7a18c8" resource_id="ws-target-resource-nopropagation2" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="3f636292-6edb-4d20-ab24-fe0c5fc3dec3" provision_id="0bfa7c3e-2bb3-43d7-ac0e-d57cff7a18c8"/>
+  <MappingItem id="e34928b8-ca57-4b6c-81c1-70bc87ff3fdc" mapping_id="3f636292-6edb-4d20-ab24-fe0c5fc3dec3" extAttrName="fullname" 
+               intAttrName="fullname" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+                     
+  <Provision ignoreCaseMatch="0" id="5bd76fec-f8d7-4ab9-acd7-89e099d534e8" resource_id="ws-target-resource-nopropagation3" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="c2a0cec1-32c4-4493-8f01-d1176e557fc1" provision_id="5bd76fec-f8d7-4ab9-acd7-89e099d534e8"/>
+  <MappingItem id="f3ba0859-b0f0-44a5-abfd-4a1a5ca29fbf" mapping_id="c2a0cec1-32c4-4493-8f01-d1176e557fc1" extAttrName="fullname"
+               intAttrName="fullname" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+                     
+  <Provision ignoreCaseMatch="0" id="18de6376-7051-4216-96f0-26629076abb9" resource_id="ws-target-resource-nopropagation4" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="906452d9-3eeb-4ef7-ac90-5ffc14513fbf" provision_id="18de6376-7051-4216-96f0-26629076abb9"/>
+  <MappingItem id="118" mapping_id="906452d9-3eeb-4ef7-ac90-5ffc14513fbf"
+               extAttrName="fullname" intAttrName="fullname" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+                       
+  <Provision ignoreCaseMatch="0" id="779fefb5-dd25-4078-915d-3c199ee32158" resource_id="resource-testdb" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="cb624b93-874b-40a0-8021-3b8116b781ab" provision_id="779fefb5-dd25-4078-915d-3c199ee32158"/>
+  <MappingItem id="1e0d30cd-2569-4a80-b9dc-af1467bd1c0b" mapping_id="cb624b93-874b-40a0-8021-3b8116b781ab"
+               extAttrName="ID" intAttrName="username" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="BOTH"/>
+  <MappingItem id="7fd1a178-77a1-4c4c-aca2-3c3f1834b77b" mapping_id="cb624b93-874b-40a0-8021-3b8116b781ab"
+               extAttrName="__PASSWORD__" intAttrName="password" mandatoryCondition="true"
+               connObjectKey="0" password="1" purpose="BOTH"/>
+                     
+  <Provision ignoreCaseMatch="0" id="0359084d-68fe-4bf8-b42b-2ebe4f578ae7" resource_id="resource-testdb2" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="935a0fc2-4a0b-4d82-9931-3c5ce44a33c1" provision_id="0359084d-68fe-4bf8-b42b-2ebe4f578ae7"/>
+  <MappingItem id="6d90658a-f470-4450-912d-6fe7d3bcda46" mapping_id="935a0fc2-4a0b-4d82-9931-3c5ce44a33c1" extAttrName="ID" 
+               intAttrName="username" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="2fb9eb01-50df-456e-86c1-b55f68cde2da" mapping_id="935a0fc2-4a0b-4d82-9931-3c5ce44a33c1" extAttrName="__PASSWORD__" 
+               intAttrName="password" mandatoryCondition="true"
+               connObjectKey="0" password="1" purpose="PROPAGATION"/>
+                         
+  <Provision ignoreCaseMatch="0" id="2adb6537-e207-4d9b-804f-90bf18cd6f48" resource_id="resource-csv" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Provision_AnyTypeClass provision_id="2adb6537-e207-4d9b-804f-90bf18cd6f48" anyTypeClass_id="csv"/>
+  <Provision_AnyTypeClass provision_id="2adb6537-e207-4d9b-804f-90bf18cd6f48" anyTypeClass_id="generic membership"/>
+  <Provision_AnyTypeClass provision_id="2adb6537-e207-4d9b-804f-90bf18cd6f48" anyTypeClass_id="minimal group"/>
+  <Mapping id="538c27dc-d260-4c53-9fc8-bf02ee226911" provision_id="2adb6537-e207-4d9b-804f-90bf18cd6f48"/>
+  <MappingItem id="517dc983-99a2-43c9-b4b4-78fd838e5ad1" extAttrName="id" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               intAttrName="username" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="BOTH"/>
+  <MappingItem id="ba6fb125-466e-4109-8e5d-133936437674" extAttrName="id" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               intAttrName="fullname" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="BOTH"/>
+  <MappingItem id="c426b070-0290-42be-9ee1-4046c7649635" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               extAttrName="__PASSWORD__" intAttrName="password" mandatoryCondition="true"
+               connObjectKey="0" password="1" purpose="BOTH"/>
+  <MappingItem id="20dbe358-5b71-4edd-8670-2bbde982e5c4" extAttrName="name" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               intAttrName="firstname" mandatoryCondition="false"
+               connObjectKey="0" password="0" purpose="BOTH"/>
+  <MappingItem id="4d70850e-9fc5-4e75-83ea-432fe090e1c0" extAttrName="surname" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               intAttrName="surname" mandatoryCondition="false"
+               connObjectKey="0" password="0" purpose="BOTH"/>
+  <MappingItem id="4b2f4292-d8ab-4948-a341-3f8c9e23e72d" extAttrName="email" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               intAttrName="userId" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="PULL"/>
+  <MappingItem id="20d6c914-54e7-4968-b1fc-685ae9c2c4a4" extAttrName="email" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               intAttrName="email" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="PULL"/>
+  <MappingItem id="09237f39-0d45-4258-a7cc-2400f7536b72" extAttrName="__NAME__" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               intAttrName="csvuserid" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+  <MappingItem id="63151b89-2eb3-4980-a682-0215d54ab4a2" extAttrName="theirgroup" mapping_id="538c27dc-d260-4c53-9fc8-bf02ee226911"
+               intAttrName="groups[root].rderToBePropagated" mandatoryCondition="false"
+               connObjectKey="0" password="0" purpose="PROPAGATION"/>
+                         
+  <Provision ignoreCaseMatch="0" id="1b53c74e-6a63-49ef-b2f1-96eeb7f1bbb8" resource_id="ws-target-resource-update-resetsynctoken" anyType_id="USER" objectClass="__ACCOUNT__"
+             serializedSyncToken='{"value":null}'/>
+  <Mapping id="23e20ce6-1ff9-495e-aa59-a58e5127a008" provision_id="1b53c74e-6a63-49ef-b2f1-96eeb7f1bbb8"/>
+  <MappingItem id="608f01c5-eb7c-462a-b4d6-b7c3c9632a50" mapping_id="23e20ce6-1ff9-495e-aa59-a58e5127a008"
+               extAttrName="userId" intAttrName="userId" mandatoryCondition="false"
+               connObjectKey="1" password="0" purpose="BOTH"/>
+  <MappingItem id="79ada054-5f8b-4e77-b405-bfec58b06e7b" mapping_id="23e20ce6-1ff9-495e-aa59-a58e5127a008"
+               extAttrName="__PASSWORD__" intAttrName="fullname" mandatoryCondition="false"
+               connObjectKey="0" password="1" purpose="BOTH"/>
+
+  <Provision ignoreCaseMatch="0" id="8b938d63-aa92-448c-89a8-a685fc0a67c8" resource_id="resource-ldap" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Provision_AnyTypeClass provision_id="8b938d63-aa92-448c-89a8-a685fc0a67c8" anyTypeClass_id="generic membership"/>
+  <Provision_AnyTypeClass provision_id="8b938d63-aa92-448c-89a8-a685fc0a67c8" anyTypeClass_id="minimal group"/>
+  <Mapping id="ae1c77c3-2f1d-4258-ad06-710bb09041a9" provision_id="8b938d63-aa92-448c-89a8-a685fc0a67c8"
+           connObjectLink="&apos;uid=&apos; + username + &apos;,ou=people,o=isp&apos;"/>
+  <MappingItem id="9ff7d686-452c-4cec-a475-c1137c5d88c7" connObjectKey="1" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="cn" intAttrName="username"
+               mandatoryCondition="true" purpose="BOTH"/>
+  <MappingItem id="73d97083-cfda-44e6-be62-3f9ac558b5eb" connObjectKey="0" password="1" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="__PASSWORD__" intAttrName="password"
+               mandatoryCondition="true" purpose="BOTH"/>
+  <MappingItem id="cf0a222c-36ea-41e6-987c-7908614ccd23" connObjectKey="0" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="sn" intAttrName="surname"
+               mandatoryCondition="true" purpose="BOTH"/>
+  <MappingItem id="b3a12364-e471-4e37-83ad-476c33a43617" connObjectKey="0" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="cn" intAttrName="fullname"
+               mandatoryCondition="true" purpose="BOTH"/>
+  <MappingItem id="aad2b7d7-3201-4bba-b496-f6587b4b7518" connObjectKey="0" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="mail" intAttrName="email"
+               mandatoryCondition="false" purpose="BOTH"/>
+  <MappingItem id="81b83c98-127b-469b-a497-412ba50acbeb" connObjectKey="0" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="title" intAttrName="title"
+               mandatoryCondition="false" purpose="BOTH"/>
+  <MappingItem id="318e92a1-3acb-49c5-b2fd-dba819c40ef1" connObjectKey="0" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="postalAddress" intAttrName="postalAddress"
+               mandatoryCondition="false" purpose="BOTH"/>
+  <MappingItem id="78fa504f-213c-41ac-a922-7c9f98e5ce11" connObjectKey="0" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="mail" intAttrName="userId"
+               mandatoryCondition="false" purpose="BOTH"/>
+  <MappingItem id="af6085cb-d0e8-47c9-b5f9-4b7d491a9750" connObjectKey="0" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="registeredAddress" intAttrName="obscure"
+               mandatoryCondition="false" purpose="BOTH"/>
+  <MappingItem id="5bb62bd2-5007-4eb8-b4f9-9df8917dc767" connObjectKey="0" password="0" mapping_id="ae1c77c3-2f1d-4258-ad06-710bb09041a9"
+               extAttrName="jpegPhoto" intAttrName="photo"
+               mandatoryCondition="false" purpose="BOTH"/>
+        
+  <SyncopeSchema id="virtualReadOnly"/>
+  <VirSchema id="virtualReadOnly" READONLY="1" anyTypeClass_id="minimal user"
+             provision_id="8b938d63-aa92-448c-89a8-a685fc0a67c8" extAttrName="givenname"/>
+
+  <Provision ignoreCaseMatch="0" id="20a75199-3f2e-4b9a-9510-c68dd7fc7b3d" resource_id="resource-ldap" anyType_id="GROUP" objectClass="__GROUP__"/>
+  <Mapping id="128412c8-be4f-4d7b-8bed-5ab89134f718" provision_id="20a75199-3f2e-4b9a-9510-c68dd7fc7b3d"
+           connObjectLink="&apos;cn=&apos; + name + &apos;,ou=groups,o=isp&apos;"/>
+  <MappingItem id="a2bf43c8-74cb-4250-92cf-fb8889409ac1"
+               connObjectKey="1" password="0" mapping_id="128412c8-be4f-4d7b-8bed-5ab89134f718"
+               extAttrName="cn" intAttrName="name"
+               mandatoryCondition="true" purpose="BOTH"/>
+  <MappingItem id="da2a69bc-5ca0-4657-9a18-ec1f8c986046"
+               connObjectKey="0" password="0" mapping_id="128412c8-be4f-4d7b-8bed-5ab89134f718"
+               extAttrName="owner" intAttrName="userOwner"
+               mandatoryCondition="false" purpose="BOTH"/>
+  <MappingItem id="9dde8bd5-f158-499e-9d81-3d7fcf9ea1e8"
+               connObjectKey="0" password="0" mapping_id="128412c8-be4f-4d7b-8bed-5ab89134f718"
+               extAttrName="description" intAttrName="title"
+               mandatoryCondition="false" purpose="BOTH"/>
+  
+  <SyncopeSchema id="rvirtualdata"/>
+  <VirSchema id="rvirtualdata" READONLY="0" anyTypeClass_id="minimal group"
+             provision_id="20a75199-3f2e-4b9a-9510-c68dd7fc7b3d" extAttrName="businessCategory"/>
+
+  <Provision ignoreCaseMatch="0" id="46b54e2a-e43e-4cd7-8c13-1af1bd65c3d3" resource_id="resource-db-pull" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="cda910bd-fc28-4f63-890e-66edc62d428b" provision_id="46b54e2a-e43e-4cd7-8c13-1af1bd65c3d3"/>
+  <MappingItem id="1a345706-a498-41bb-a948-820307a4365e" connObjectKey="0" mapping_id="cda910bd-fc28-4f63-890e-66edc62d428b"
+               extAttrName="EMAIL" intAttrName="email" 
+               mandatoryCondition="false" password="0" purpose="BOTH"/>
+  <MappingItem id="a234bde8-b431-408c-8ec9-c986c5b7f98d" connObjectKey="0" mapping_id="cda910bd-fc28-4f63-890e-66edc62d428b"
+               extAttrName="SURNAME" intAttrName="fullname" 
+               mandatoryCondition="false" password="0" purpose="PULL"/>
+  <MappingItem id="51a856de-ae25-41cd-967a-86920c834b70" connObjectKey="1" mapping_id="cda910bd-fc28-4f63-890e-66edc62d428b"
+               extAttrName="ID" intAttrName="firstname" 
+               mandatoryCondition="false" password="0" purpose="BOTH"/>
+  <MappingItem id="f4e5178e-ef37-4949-933a-7ec7eaea64c6" connObjectKey="0" mapping_id="cda910bd-fc28-4f63-890e-66edc62d428b"
+               extAttrName="SURNAME" intAttrName="surname" 
+               mandatoryCondition="false" password="0" purpose="BOTH"/>
+  <MappingItem id="3ac0ecaf-d9a1-4fc1-9ae9-84dc34576810" connObjectKey="0" mapping_id="cda910bd-fc28-4f63-890e-66edc62d428b"
+               extAttrName="USERNAME" intAttrName="username" 
+               mandatoryCondition="false" password="0" purpose="BOTH"/>
+  <MappingItem id="e7215305-93c9-460b-b862-46f7b60de72d" connObjectKey="0" mapping_id="cda910bd-fc28-4f63-890e-66edc62d428b"
+               extAttrName="EMAIL" intAttrName="userId" 
+               mandatoryCondition="false" password="0" purpose="PULL"/>
+  <MappingItem id="fb59d169-cf59-43f6-a517-adfd9aacc609" connObjectKey="0" mapping_id="cda910bd-fc28-4f63-890e-66edc62d428b"
+               extAttrName="MUSTCHANGEPASSWORD" intAttrName="mustChangePassword" 
+               mandatoryCondition="false" password="0" purpose="PULL"/>
+              
+  <Provision ignoreCaseMatch="0" id="6d7cb60a-c4ad-4a70-94ae-e5b88eb24930" resource_id="resource-db-virattr" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="45280585-308f-4571-9788-c7a4734b3614" provision_id="6d7cb60a-c4ad-4a70-94ae-e5b88eb24930"/>
+  <MappingItem id="6cb2f9f0-5fb4-4686-a375-31e2c34a6cd8" mapping_id="45280585-308f-4571-9788-c7a4734b3614" connObjectKey="1" password="0"
+               extAttrName="ID" intAttrName="key" 
+               mandatoryCondition="true" purpose="BOTH"/>
+                
+  <SyncopeSchema id="virtualdata"/>
+  <VirSchema id="virtualdata" READONLY="0" anyTypeClass_id="minimal user"
+             provision_id="6d7cb60a-c4ad-4a70-94ae-e5b88eb24930" extAttrName="USERNAME"/>
+  
+  <Provision ignoreCaseMatch="0" id="cfa86cbe-94b6-4712-a40a-a4861be1d425" resource_id="ws-target-resource-timeout" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="c71d690a-3dd9-48a5-b76f-32805186c4dc" provision_id="cfa86cbe-94b6-4712-a40a-a4861be1d425"/>
+  <MappingItem id="321bc904-e1fc-4a54-bf7c-74c8cbcc0815" mapping_id="c71d690a-3dd9-48a5-b76f-32805186c4dc" connObjectKey="1" password="0"
+               extAttrName="fullname" intAttrName="fullname"
+               mandatoryCondition="true" purpose="PROPAGATION"/>
+  
+  <Provision ignoreCaseMatch="0" id="ac1659dc-3ea3-45eb-8ae6-626e3d916492" resource_id="ws-target-resource-delete" anyType_id="USER" objectClass="__ACCOUNT__"/>
+  <Mapping id="72f590ae-2754-456b-aabb-eda7d8459dd3" provision_id="ac1659dc-3ea3-45eb-8ae6-626e3d916492"/>
+  <MappingItem id="4c98536f-10df-4953-b2df-59d7cd057fd2" mapping_id="72f590ae-2754-456b-aabb-eda7d8459dd3" extAttrName="userId" 
+               intAttrName="username" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="PROPAGATION"/>
+
+  <Provision ignoreCaseMatch="0" id="f1b55b66-eb13-4a93-a49c-448e93756eb6" resource_id="resource-db-scripted" anyType_id="PRINTER" objectClass="__PRINTER__"/>
+  <Mapping id="16439b5f-50c3-4604-97e9-f4004933abd8" provision_id="f1b55b66-eb13-4a93-a49c-448e93756eb6"/>
+  <MappingItem id="23aa0299-ddbb-4e59-8918-0ab2a32465fa" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="ID" 
+               intAttrName="key" mandatoryCondition="true"
+               connObjectKey="1" password="0" purpose="BOTH"/>
+  <MappingItem id="3dc96af0-5d0a-4ec1-be84-244716d88401" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="PRINTERNAME" 
+               intAttrName="name" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="BOTH"/>
+  <MappingItem id="f3ef9f8b-e667-4b18-969f-ba98c3d78bc0" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="LOCATION" 
+               intAttrName="location"
+               mandatoryCondition="false" connObjectKey="0" password="0" purpose="BOTH"/>
+    
+  <Provision ignoreCaseMatch="0" id="2e372858-f43c-4e1c-b728-58f43c5e1c23" objectClass="__ACCOUNT__" anyType_id="USER" resource_id="rest-target-resource"/>
+  <Mapping id="e6b64584-94a2-4890-b645-8494a2089011" provision_id="2e372858-f43c-4e1c-b728-58f43c5e1c23"/>
+  <MappingItem id="14726efb-09e1-441e-b26e-fb09e1841eb2" connObjectKey="0"
+               extAttrName="firstName" intAttrName="firstname" mandatoryCondition="true" password="0" purpose="BOTH"
+               mapping_id="e6b64584-94a2-4890-b645-8494a2089011"/>
+  <MappingItem id="4cdd1fd5-80cd-4fc1-9d1f-d580cd1fc11e" connObjectKey="1"
+               extAttrName="key" intAttrName="key" mandatoryCondition="true" password="0" purpose="BOTH"
+               mapping_id="e6b64584-94a2-4890-b645-8494a2089011"/>
+  <MappingItem id="4d7581b5-fe9b-49e6-b581-b5fe9bf9e60b" connObjectKey="0"
+               extAttrName="__PASSWORD__" intAttrName="password" mandatoryCondition="true" password="1" purpose="BOTH"
+               mapping_id="e6b64584-94a2-4890-b645-8494a2089011"/>
+  <MappingItem id="98f96cf4-fba2-4c68-b96c-f4fba2fc6834" connObjectKey="0"
+               extAttrName="username" intAttrName="username" mandatoryCondition="true" password="0" purpose="BOTH"
+               mapping_id="e6b64584-94a2-4890-b645-8494a2089011"/>
+  <MappingItem id="f3312f8f-1c94-493a-b12f-8f1c94093aa9" connObjectKey="0"
+               extAttrName="email" intAttrName="email" mandatoryCondition="true" password="0" purpose="BOTH"
+               mapping_id="e6b64584-94a2-4890-b645-8494a2089011"/>
+  <MappingItem id="ff49e982-fe60-4c1e-89e9-82fe60dc1ef9" connObjectKey="0"
+               extAttrName="surname" intAttrName="surname" mandatoryCondition="true" password="0" PURPOSE="BOTH"
+               mapping_id="e6b64584-94a2-4890-b645-8494a2089011"/>
+
+  <Implementation id="PullJobDelegate" type="TASKJOB_DELEGATE" engine="JAVA"
+                  body="org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate"/>
+  <Implementation id="PushJobDelegate" type="TASKJOB_DELEGATE" engine="JAVA"
+                  body="org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate"/>
+  <Task DTYPE="PropagationTask" id="1e697572-b896-484c-ae7f-0c8f63fcbc6c" operation="UPDATE"
+        objectClassName="__ACCOUNT__" resource_id="ws-target-resource-2" anyTypeKind="USER" entityKey="1417acbe-cbf6-4277-9372-e75e04f97000"
+        attributes='[{"name":"__PASSWORD__","value":[{"readOnly":false,"disposed":false,"encryptedBytes":"m9nh2US0Sa6m+cXccCq0Xw==","base64SHA1Hash":"GFJ69qfjxEOdrmt+9q+0Cw2uz60="}]},{"name":"__NAME__","value":["userId"],"nameValue":"userId"},{"name":"fullname","value":["fullname"]},{"name":"type","value":["type"]}]'/>
+  <TaskExec id="e58ca1c7-178a-4012-8a71-8aa14eaf0655" task_id="1e697572-b896-484c-ae7f-0c8f63fcbc6c" startDate="2015-12-17 09:40:00.506" endDate="2015-12-17 09:42:00.506" status="SUCCESS"/>
+  <Task DTYPE="PropagationTask" id="b8870cfb-3c1e-4fc4-abcb-2559826232e6" operation="CREATE"
+        objectClassName="__ACCOUNT__" resource_id="ws-target-resource-2" anyTypeKind="USER" entityKey="1417acbe-cbf6-4277-9372-e75e04f97000"
+        attributes='[{"name":"__PASSWORD__","value":[{"readOnly":false,"disposed":false,"encryptedBytes":"m9nh2US0Sa6m+cXccCq0Xw==","base64SHA1Hash":"GFJ69qfjxEOdrmt+9q+0Cw2uz60="}]},{"name":"__NAME__","value":["userId"],"nameValue":"userId"},{"name":"fullname","value":["fullname"]},{"name":"type","value":["type"]}]'/>
+  <Task DTYPE="PropagationTask" id="316285cc-ae52-4ea2-a33b-7355e189ac3f" operation="DELETE"
+        objectClassName="__ACCOUNT__" resource_id="ws-target-resource-2" anyTypeKind="USER" entityKey="1417acbe-cbf6-4277-9372-e75e04f97000"
+        attributes='[{"name":"__PASSWORD__","value":[{"readOnly":false,"disposed":false,"encryptedBytes":"m9nh2US0Sa6m+cXccCq0Xw==","base64SHA1Hash":"GFJ69qfjxEOdrmt+9q+0Cw2uz60="}]},{"name":"__NAME__","value":["userId"],"nameValue":"userId"},{"name":"type","value":["type"]}]'/>
+  <Task DTYPE="PullTask" remediation="0" id="c41b9b71-9bfa-4f90-89f2-84787def4c5c" name="CSV (update matching; assign unmatching)" resource_id="resource-csv"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"
+        pullMode="INCREMENTAL" unmatchingRule="ASSIGN" matchingRule="UPDATE" active="1"
+        jobDelegate_id="PullJobDelegate"/>
+  <AnyTemplatePullTask id="3a6173a9-8c34-4e37-b3b1-0c2ea385fac0"
+                       pullTask_id="c41b9b71-9bfa-4f90-89f2-84787def4c5c" anyType_id="USER"
+                       template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":["csv"],"derAttrs":[{"schema":"cn","values":[""]}],"virAttrs":[],"resources":["resource-t [...]
+  <AnyTemplatePullTask id="b3772d66-ec06-4133-bf38-b3273845ac5b"
+                       pullTask_id="c41b9b71-9bfa-4f90-89f2-84787def4c5c" anyType_id="GROUP"
+                       template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"plainAttrs":[]}'/>
+  <Implementation id="TestSampleJobDelegate" type="TASKJOB_DELEGATE" engine="JAVA"
+                  body="org.apache.syncope.fit.core.reference.TestSampleJobDelegate"/>
+  <Task DTYPE="SchedTask" id="e95555d2-1b09-42c8-b25b-f4c4ec597979" name="SampleJob Task" active="1"
+        jobDelegate_id="TestSampleJobDelegate" cronExpression="0 0 0 1 * ?"/>
+  <Implementation id="ExpiredAccessTokenCleanup" type="TASKJOB_DELEGATE" engine="JAVA"
+                  body="org.apache.syncope.core.provisioning.java.job.ExpiredAccessTokenCleanup"/>
+  <Task DTYPE="SchedTask" id="89de5014-e3f5-4462-84d8-d97575740baf" name="Access Token Cleanup Task"  active="1"
+        jobDelegate_id="ExpiredAccessTokenCleanup" cronExpression="0 0/5 * * * ?"/>
+  <Task DTYPE="PropagationTask" id="d6c2d6d3-6329-44c1-9187-f1469ead1cfa" operation="UPDATE"
+        objectClassName="__ACCOUNT__" resource_id="ws-target-resource-nopropagation" anyTypeKind="USER" entityKey="1417acbe-cbf6-4277-9372-e75e04f97000"
+        attributes='[{"name":"__PASSWORD__","value":[{"readOnly":false,"disposed":false,"encryptedBytes":"m9nh2US0Sa6m+cXccCq0Xw==","base64SHA1Hash":"GFJ69qfjxEOdrmt+9q+0Cw2uz60="}]},{"name":"__NAME__","value":["userId"],"nameValue":"userId"},{"name":"fullname","value":["fullname"]},{"name":"type","value":["type"]}]'/>
+  <TaskExec id="d789462f-e395-424f-bd8e-0db44a93222f" task_id="d6c2d6d3-6329-44c1-9187-f1469ead1cfa" startDate="2015-12-17 09:40:00.506" endDate="2015-12-17 09:42:00.506" status="SUCCESS"/>
+  <Task DTYPE="PullTask" remediation="0" id="83f7e85d-9774-43fe-adba-ccd856312994" name="TestDB Task" resource_id="resource-testdb"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="0" syncStatus="1" pullMode="FULL_RECONCILIATION"
+        unmatchingRule="PROVISION" matchingRule="UPDATE" active="1" jobDelegate_id="PullJobDelegate"/>
+  <AnyTemplatePullTask id="6c3f578d-327b-4a7c-8037-6f5ba24eb770" pullTask_id="83f7e85d-9774-43fe-adba-ccd856312994" anyType_id="USER"
+                       template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"relationships":[],"memberships":[],"dynMem [...]
+  <AnyTemplatePullTask id="45b61137-c7c3-49ee-86e0-9efffa75ae68" pullTask_id="83f7e85d-9774-43fe-adba-ccd856312994" anyType_id="GROUP"
+                       template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"plainAttrs":[]}'/>
+  <Task DTYPE="PullTask" remediation="0" id="81d88f73-d474-4450-9031-605daa4e313f" name="TestDB2 Task" resource_id="resource-testdb2"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="0" syncStatus="1" pullMode="FULL_RECONCILIATION"
+        unmatchingRule="PROVISION" matchingRule="UPDATE" active="1" jobDelegate_id="PullJobDelegate"/>
+  <Task DTYPE="PullTask" remediation="0" id="7c2242f4-14af-4ab5-af31-cdae23783655" name="TestDB Pull Task" resource_id="resource-db-pull"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" pullMode="FULL_RECONCILIATION" performCreate="1" performDelete="1" performUpdate="1" syncStatus="0"
+        unmatchingRule="PROVISION" matchingRule="UPDATE" active="1" jobDelegate_id="PullJobDelegate"/>
+  <Task DTYPE="PullTask" remediation="0" id="1e419ca4-ea81-4493-a14f-28b90113686d" name="LDAP Pull Task" resource_id="resource-ldap"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" pullMode="FULL_RECONCILIATION" performCreate="1" performDelete="1" performUpdate="1" syncStatus="0"
+        unmatchingRule="PROVISION" matchingRule="UPDATE" active="1" jobDelegate_id="PullJobDelegate"/>
+  <AnyTemplatePullTask id="df655a2a-40c0-43b1-a157-3f4988802f58" pullTask_id="1e419ca4-ea81-4493-a14f-28b90113686d" anyType_id="USER"
+                       template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"USER","realm":"&apos;/&apos; + title","status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":["minimal group"],"derAttrs":[],"virAttrs":[{"schema":"virtualReadOnly [...]
+  <AnyTemplatePullTask id="fda22ff3-98f3-42e4-a2ae-cd9a28282d57" pullTask_id="1e419ca4-ea81-4493-a14f-28b90113686d" anyType_id="GROUP"
+                       template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"plainAttrs":[{"schema":"show","values":["true"]}]}'/>
+  <Implementation id="LDAPMembershipPullActions" type="PULL_ACTIONS"  engine="JAVA"
+                  body="org.apache.syncope.core.provisioning.java.pushpull.LDAPMembershipPullActions"/>
+  <PullTaskAction task_id="1e419ca4-ea81-4493-a14f-28b90113686d" implementation_id="LDAPMembershipPullActions"/>
+  <Task DTYPE="PullTask" remediation="0" id="38abbf9e-a1a3-40a1-a15f-7d0ac02f47f1" name="VirAttrCache test" resource_id="resource-csv"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="0" performUpdate="1" performDelete="0" syncStatus="0" pullMode="FULL_RECONCILIATION"
+        unmatchingRule="PROVISION" matchingRule="UPDATE" active="1" jobDelegate_id="PullJobDelegate"/>
+  <Task DTYPE="PushTask" id="af558be4-9d2f-4359-bf85-a554e6e90be1" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"         
+        unmatchingRule="ASSIGN" matchingRule="IGNORE" active="1" jobDelegate_id="PushJobDelegate"/>  
+  <PushTaskAnyFilter id="1fdcff65-765f-4a6e-98a7-13ef7cca47e2" anyType_id="USER" pushTask_id="af558be4-9d2f-4359-bf85-a554e6e90be1" fiql="surname==Vivaldi"/>
+  <PushTaskAnyFilter id="3b564c51-5d64-48b3-8da5-fd4ebc10e0a8" anyType_id="GROUP" pushTask_id="af558be4-9d2f-4359-bf85-a554e6e90be1" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="97f327b6-2eff-4d35-85e8-d581baaab855" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"         
+        unmatchingRule="PROVISION" matchingRule="IGNORE" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="199efd21-5e89-46ac-95de-f47e9d0569fc" anyType_id="USER" pushTask_id="97f327b6-2eff-4d35-85e8-d581baaab855" fiql="surname==Bellini"/>
+  <PushTaskAnyFilter id="7672a167-77d6-4639-8b1d-0af561293c7d" anyType_id="GROUP" pushTask_id="97f327b6-2eff-4d35-85e8-d581baaab855" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="03aa2a04-4881-4573-9117-753f81b04865" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"        
+        unmatchingRule="UNLINK" matchingRule="IGNORE" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="39a11ba6-397a-4c94-8bfe-1f4f757d6501" anyType_id="USER" pushTask_id="03aa2a04-4881-4573-9117-753f81b04865" fiql="surname==Puccini"/>
+  <PushTaskAnyFilter id="5bd7501e-8a18-4fbd-a3fe-a1e731ba95db" anyType_id="GROUP" pushTask_id="03aa2a04-4881-4573-9117-753f81b04865" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="5e5f7c7e-9de7-4c6a-99f1-4df1af959807" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"         
+        unmatchingRule="IGNORE" matchingRule="IGNORE" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="0d0371a3-5772-4b4c-ad14-139adf1d346a" anyType_id="USER" pushTask_id="5e5f7c7e-9de7-4c6a-99f1-4df1af959807" fiql="surname==Verdi"/>
+  <PushTaskAnyFilter id="2e7488ae-a2fc-4657-a93b-159b8433c0e7" anyType_id="GROUP" pushTask_id="5e5f7c7e-9de7-4c6a-99f1-4df1af959807" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="0bc11a19-6454-45c2-a4e3-ceef84e5d79b" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"        
+        unmatchingRule="ASSIGN" matchingRule="UPDATE" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="41bf22fe-a014-41af-9a75-402b987eb433" anyType_id="USER" pushTask_id="0bc11a19-6454-45c2-a4e3-ceef84e5d79b" fiql="username==_NO_ONE_"/>
+  <PushTaskAnyFilter id="fa983fde-795e-4c89-a6f7-1ccd80a8adeb" anyType_id="GROUP" pushTask_id="0bc11a19-6454-45c2-a4e3-ceef84e5d79b" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="ec674143-480a-4816-98ad-b61fa090821e" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"        
+        unmatchingRule="IGNORE" matchingRule="DEPROVISION" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="e238a6dc-0b04-46cf-9bfa-be68bd9f2da0" anyType_id="USER" pushTask_id="ec674143-480a-4816-98ad-b61fa090821e" fiql="surname==Verdi"/>
+  <PushTaskAnyFilter id="0eaa643e-0add-4c46-8273-539f9d6abec5" anyType_id="GROUP" pushTask_id="ec674143-480a-4816-98ad-b61fa090821e" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="c46edc3a-a18b-4af2-b707-f4a415507496" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"        
+        unmatchingRule="IGNORE" matchingRule="UNASSIGN" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="335b4f11-589a-44c5-80b0-ba94892f0c62" anyType_id="USER" pushTask_id="c46edc3a-a18b-4af2-b707-f4a415507496" fiql="surname==Rossini"/>
+  <PushTaskAnyFilter id="b32eecc2-aa4f-43c6-a501-a692c3e93113" anyType_id="GROUP" pushTask_id="c46edc3a-a18b-4af2-b707-f4a415507496" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="51318433-cce4-4f71-8f45-9534b6c9c819" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"        
+        unmatchingRule="IGNORE" matchingRule="LINK" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="9f974a0d-87d8-4cae-9ea9-1fc245bc1dbf" anyType_id="USER" pushTask_id="51318433-cce4-4f71-8f45-9534b6c9c819" fiql="surname==Verdi"/>
+  <PushTaskAnyFilter id="0dc46ba4-1270-4fa9-b3e1-79f940d4308f" anyType_id="GROUP" pushTask_id="51318433-cce4-4f71-8f45-9534b6c9c819" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="24b1be9c-7e3b-443a-86c9-798ebce5eaf2" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"        
+        unmatchingRule="IGNORE" matchingRule="UNLINK" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="3aa3b0b8-7469-4859-89d5-476ae5915101" anyType_id="USER" pushTask_id="24b1be9c-7e3b-443a-86c9-798ebce5eaf2" fiql="surname==Verdi"/>
+  <PushTaskAnyFilter id="f054810e-6842-4017-8f60-5b4031fa2c72" anyType_id="GROUP" pushTask_id="24b1be9c-7e3b-443a-86c9-798ebce5eaf2" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="375c7b7f-9e3a-4833-88c9-b7787b0a69f2" name="Export on resource-testdb2" resource_id="resource-testdb2"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"        
+        unmatchingRule="IGNORE" matchingRule="UPDATE"  active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="95f047fc-1a8a-45f4-b56c-6e04d8ca5567" anyType_id="USER" pushTask_id="375c7b7f-9e3a-4833-88c9-b7787b0a69f2" fiql="surname==Verdi"/>
+  <PushTaskAnyFilter id="013a4298-4b14-4f8b-9f59-191c2d53dbd8" anyType_id="GROUP" pushTask_id="375c7b7f-9e3a-4833-88c9-b7787b0a69f2" fiql="name==_NO_ONE_"/>
+  <Task DTYPE="PushTask" id="fd905ba5-9d56-4f51-83e2-859096a67b75" name="Export on resource-ldap" resource_id="resource-ldap"
+        sourceRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28"
+        performCreate="1" performUpdate="1" performDelete="1" syncStatus="1"        
+        unmatchingRule="ASSIGN" matchingRule="UNLINK" active="1" jobDelegate_id="PushJobDelegate"/>
+  <PushTaskAnyFilter id="30842acc-f2dd-4d47-b359-20db06c30803" anyType_id="USER" pushTask_id="fd905ba5-9d56-4f51-83e2-859096a67b75" fiql="username==_NO_ONE_"/>
+  <PushTaskAnyFilter id="9e4c0233-440e-4b5b-9563-11ec0f55a334" anyType_id="GROUP" pushTask_id="fd905ba5-9d56-4f51-83e2-859096a67b75" fiql="name==citizen"/>
+  <Task DTYPE="PullTask" remediation="0" id="986867e2-993b-430e-8feb-aa9abb4c1dcd" name="CSV Task (update matching; provision unmatching)" resource_id="resource-csv"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" pullMode="INCREMENTAL"
+        unmatchingRule="PROVISION" matchingRule="UPDATE" active="1" jobDelegate_id="PullJobDelegate"/>
+  <AnyTemplatePullTask id="8bc41ba1-cc1d-4ee0-bb43-61cd148b414f" pullTask_id="986867e2-993b-430e-8feb-aa9abb4c1dcd" anyType_id="USER"
+                       template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":["resource-testdb"],"roles":[],"dynRoles":[]," [...]
+  <AnyTemplatePullTask id="9af0e343-8a37-42d2-9bc7-6e2e3b103219" pullTask_id="986867e2-993b-430e-8feb-aa9abb4c1dcd" anyType_id="GROUP"
+                       template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"plainAttrs":[]}'/>
+  <Task DTYPE="PullTask" remediation="0" id="feae4e57-15ca-40d9-b973-8b9015efca49" name="CSV (unlink matching; ignore unmatching)" resource_id="resource-csv"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" pullMode="FULL_RECONCILIATION"
+        unmatchingRule="IGNORE" matchingRule="UNLINK" active="1" jobDelegate_id="PullJobDelegate"/>
+  <Task DTYPE="PullTask" remediation="0" id="55d5e74b-497e-4bc0-9156-73abef4b9adc" name="CSV (ignore matching; assign unmatching)" resource_id="resource-csv"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" pullMode="FULL_RECONCILIATION"
+        unmatchingRule="ASSIGN" matchingRule="IGNORE" active="1" jobDelegate_id="PullJobDelegate"/>
+  <Task DTYPE="PropagationTask" id="0f618183-17ce-48bc-80bc-cc535f38983a" operation="CREATE"
+        objectClassName="__ACCOUNT__" resource_id="resource-testdb" anyTypeKind="USER" entityKey="1417acbe-cbf6-4277-9372-e75e04f97000"
+        attributes='[{"name":"__PASSWORD__","value":[{"readOnly":false,"disposed":false,"encryptedBytes":"m9nh2US0Sa6m+cXccCq0Xw==","base64SHA1Hash":"GFJ69qfjxEOdrmt+9q+0Cw2uz60="}]},{"name":"__NAME__","value":["userId"],"nameValue":"userId"},{"name":"fullname","value":["fullname"]},{"name":"type","value":["type"]}]'/>
+  <Task DTYPE="PullTask" remediation="0" id="30cfd653-257b-495f-8665-281281dbcb3d" name="Scripted SQL" resource_id="resource-db-scripted"
+        destinationRealm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" performCreate="1" performUpdate="1" performDelete="0" syncStatus="0" pullMode="INCREMENTAL"
+        unmatchingRule="PROVISION" matchingRule="UPDATE" active="1" jobDelegate_id="PullJobDelegate"/>
+  <Implementation id="ExpiredBatchCleanup" type="TASKJOB_DELEGATE" engine="JAVA"
+                  body="org.apache.syncope.core.provisioning.java.job.ExpiredBatchCleanup"/>
+  <Task DTYPE="SchedTask" id="8ea0ea51-ce08-4fe3-a0c8-c281b31b5893" name="Expired Batch Operations Cleanup Task"  active="1"
+        jobDelegate_id="ExpiredBatchCleanup" cronExpression="0 0/5 * * * ?"/>
+
+  <MailTemplate id="requestPasswordReset"
+                textTemplate="Hi,
+a password reset was request for ${user.getUsername()}.
+
+In order to complete this request, you need to visit this link:
+
+http://localhost:9080/syncope-enduser/app/#!/confirmpasswordreset?token=${input.get(0).replaceAll(' ', '%20')}
+
+If you did not request this reset, just ignore the present e-mail.
+
+Best regards."
+                htmlTemplate="&lt;html&gt;
+&lt;body&gt;
+&lt;p&gt;Hi,
+a password reset was request for ${user.getUsername()}.&lt;/p&gt;
+
+&lt;p&gt;In order to complete this request, you need to visit this 
+&lt;a href=&quot;http://localhost:9080/syncope-enduser/app/#!/confirmpasswordreset?token=${input.get(0).replaceAll(' ', '%20')}&quot;&gt;link&lt;/a&gt;&lt;/p&gt;.
+
+&lt;p&gt;If you did not request this reset, just ignore the present e-mail.&lt;/p&gt;
+
+&lt;p&gt;Best regards.&lt;/p&gt;
+&lt;/body&gt;
+&lt;/html&gt;"/>
+  <MailTemplate id="confirmPasswordReset"
+                textTemplate="Hi,
+we are happy to inform you that the password request was successfully executed for your account.
+
+Best regards."
+                htmlTemplate="&lt;html&gt;
+&lt;body&gt;
+&lt;p&gt;Hi,&lt;br/&gt;
+we are happy to inform you that the password request was successfully executed for your account.&lt;/p&gt;
+
+&lt;p&gt;Best regards.&lt;/p&gt;
+&lt;/body&gt;
+&lt;/html&gt;"/>
+  <MailTemplate id="test"/>
+  <MailTemplate id="optin"
+                textTemplate="Hi ${user.getPlainAttr(&quot;firstname&quot;).get().values[0]} ${user.getPlainAttr(&quot;surname&quot;).get().values[0]}, welcome to Syncope!
+
+Your username is ${user.username}.
+Your email address is ${user.getPlainAttr(&quot;email&quot;).get().values[0]}.
+Your email address inside a link: http://localhost/?email=${user.getPlainAttr(&quot;email&quot;).get().values[0].replace('@', '%40')}
+
+This message was sent to the following recipients:&#10;
+$$ for (recipient: recipients) {&#10;
+  * ${recipient.getPlainAttr(&quot;email&quot;).get().values[0]}&#10;
+$$ }&#10;
+&#10;
+because one of the following events occurred:&#10;
+$$ for (event: events) {&#10;
+  * ${event}&#10;
+$$ }&#10;
+&#10;
+$$ if (!empty(user.memberships)) {&#10;
+You have been provided with the following groups:&#10;
+$$ for(membership : user.memberships) {&#10;
+  * ${membership.groupName}&#10;
+$$ }&#10;
+$$ }&#10;"
+                htmlTemplate="&lt;html&gt;
+&lt;body&gt;
+&lt;h3&gt;Hi ${user.getPlainAttr(&quot;firstname&quot;).get().values[0]} ${user.getPlainAttr(&quot;surname&quot;).get().values[0]}, welcome to Syncope!&lt;/h3&gt;
+
+&lt;p&gt;
+   Your username is ${user.username}.&lt;br/&gt;
+   Your email address is ${user.getPlainAttr(&quot;email&quot;).get().values[0]}.
+   Your email address inside a &lt;a href=&quot;http://localhost/?email=${user.getPlainAttr(&quot;email&quot;).get().values[0].replace('@', '%40')}&quot;&gt;link&lt;/a&gt;.
+&lt;/p&gt;
+
+&lt;p&gt;
+    This message was sent to the following recipients:
+&lt;ul&gt;&#10;
+$$ for (recipient: recipients) {&#10;Na
+  &lt;li&gt;${recipient.getPlainAttr(&quot;email&quot;).get().values[0]}&lt;/li&gt;&#10;
+$$ }&#10;
+&lt;/ul&gt;&#10;
+
+because one of the following events occurred:
+&lt;ul&gt;&#10;
+$$ for (event: events) {&#10;
+  &lt;li&gt;${event}&lt;/li&gt;&#10;
+$$ }&#10;
+&lt;/ul&gt;&#10;
+&lt;/p&gt;
+&#10;
+$$ if (!empty(user.memberships)) {&#10;
+You have been provided with the following groups:&#10;
+&lt;ul&gt;&#10;
+$$ for(membership : user.memberships) {&#10;
+  &lt;li&gt;${membership.groupName}&lt;/li&gt;&#10;
+$$ }&#10;
+&lt;/ul&gt;&#10;
+$$ }&#10;
+&lt;/body&gt;
+&lt;/html&gt;"/>
+
+  <Notification id="e00945b5-1184-4d43-8e45-4318a8dcdfd4" active="1" recipientAttrName="email" selfAsRecipient="1" 
+                sender="admin@syncope.apache.org" subject="Password Reset request" template_id="requestPasswordReset" 
+                traceLevel="FAILURES"/> 
+  <AnyAbout id="a328f2e6-25e9-4cc1-badf-7425d7be4b39" anyType_id="USER" notification_id="e00945b5-1184-4d43-8e45-4318a8dcdfd4" filter="token!=$null"/>
+  <Notification_events notification_id="e00945b5-1184-4d43-8e45-4318a8dcdfd4" event="[CUSTOM]:[]:[]:[requestPasswordReset]:[SUCCESS]"/>
+  <Task DTYPE="NotificationTask" id="e1e520f0-2cbd-4e11-9a89-ea58a0f957e7" notification_id="e00945b5-1184-4d43-8e45-4318a8dcdfd4"
+        sender="admin@prova.org" subject="Notification for SYNCOPE-81" executed="0"
+        textBody="NOTIFICATION-81" htmlBody="NOTIFICATION-81" traceLevel="ALL"/>
+  <NotificationTask_recipients notificationTask_id="e1e520f0-2cbd-4e11-9a89-ea58a0f957e7" address="recipient@prova.org"/>  
+  
+  <Notification id="bef0c250-e8a7-4848-bb63-2564fc409ce2" active="1" recipientAttrName="email" selfAsRecipient="1" 
+                sender="admin@syncope.apache.org" subject="Password Reset successful" template_id="confirmPasswordReset" 
+                traceLevel="FAILURES"/> 
+  <Notification_events notification_id="bef0c250-e8a7-4848-bb63-2564fc409ce2" event="[CUSTOM]:[]:[]:[confirmPasswordReset]:[SUCCESS]"/>
+
+  <Notification id="9e2b911c-25de-4c77-bcea-b86ed9451050" sender="test@syncope.apache.org" subject="Test subject" template_id="test" selfAsRecipient="0" 
+                traceLevel="FAILURES"
+                recipientsFIQL="$groups==7"
+                recipientAttrName="email" active="1"/>
+  <AnyAbout id="2e2ee845-2abf-43c6-b543-49243a84e2f1" anyType_id="USER" notification_id="9e2b911c-25de-4c77-bcea-b86ed9451050" filter="fullname==*o*;fullname==*i*"/>
+  <Notification_events notification_id="9e2b911c-25de-4c77-bcea-b86ed9451050" event="[CUSTOM]:[]:[]:[unexisting1]:[FAILURE]"/>
+  <Notification_events notification_id="9e2b911c-25de-4c77-bcea-b86ed9451050" event="[CUSTOM]:[]:[]:[unexisting2]:[SUCCESS]"/>
+
+  <ReportTemplate id="empty"/>  
+  <ReportTemplate id="sample"
+                  htmlTemplate="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;
+&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&#10;
+                version=&quot;1.0&quot;&gt;&#10;
+&#10;
+  &lt;xsl:param name=&quot;status&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;message&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;start&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;end&quot;/&gt;&#10;
+  &#10;
+  &lt;xsl:template match=&quot;/&quot;&gt;&#10;
+    &lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;&#10;
+      &lt;head&gt;&#10;
+        &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;&#10;
+        &lt;title&gt;Apache Syncope Report - &lt;xsl:value-of select=&quot;report/@name&quot;/&gt;&lt;/title&gt;&#10;
+      &lt;/head&gt;&#10;
+      &lt;body&gt;&#10;
+        &lt;table style=&quot;border: 1px solid black;&quot;&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;h1&gt;Report Name:&lt;/h1&gt;&#10;
+            &lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;h1&gt;&#10;
+                &lt;xsl:value-of select=&quot;report/@name&quot;/&gt;&#10;
+              &lt;/h1&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;h2&gt;Start Date:&lt;/h2&gt;&#10;
+            &lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;h2&gt;&#10;
+                &lt;xsl:value-of select=&quot;$start&quot;/&gt;&#10;
+              &lt;/h2&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;h2&gt;End Date:&lt;/h2&gt;&#10;
+            &lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;h2&gt;&#10;
+                &lt;xsl:value-of select=&quot;$end&quot;/&gt;&#10;
+              &lt;/h2&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+        &lt;/table&gt;&#10;
+&#10;
+        &lt;xsl:apply-templates/&gt;&#10;
+      &lt;/body&gt;&#10;
+    &lt;/html&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+&#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.StaticReportlet']&quot;&gt;&#10;
+    &lt;h2&gt;Reportlet: &#10;
+      &lt;xsl:value-of select=&quot;@name&quot;/&gt;&#10;
+    &lt;/h2&gt;&#10;
+        &#10;
+    &lt;xsl:if test=&quot;string-length(string/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;p&gt;String value:                 &#10;
+        &lt;xsl:value-of select=&quot;string/text()&quot;/&gt;&#10;
+      &lt;/p&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(long/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;p&gt;Long value: &#10;
+        &lt;xsl:value-of select=&quot;long/text()&quot;/&gt;&#10;
+      &lt;/p&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(double/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;p&gt;Double value: &#10;
+        &lt;xsl:value-of select=&quot;double/text()&quot;/&gt;&#10;
+      &lt;/p&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(date/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;p&gt;Date value: &#10;
+        &lt;xsl:value-of select=&quot;date/text()&quot;/&gt;&#10;
+      &lt;/p&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(enum/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;p&gt;Enum value: &#10;
+        &lt;xsl:value-of select=&quot;enum/text()&quot;/&gt;&#10;
+      &lt;/p&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(list) &amp;gt; 0&quot;&gt;&#10;
+      &lt;p&gt;List values:&lt;/p&gt;&#10;
+            &#10;
+      &lt;ul&gt;&#10;
+        &lt;xsl:for-each select=&quot;list/string&quot;&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(string/text()) &amp;gt; 0&quot;&gt;&#10;
+            &lt;li&gt;&#10;
+              &lt;xsl:value-of select=&quot;text()&quot;/&gt;&#10;
+            &lt;/li&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+        &lt;/xsl:for-each&gt;&#10;
+      &lt;/ul&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.UserReportlet']&quot;&gt;&#10;
+    &#10;
+    &lt;h3&gt;Reportlet: &lt;xsl:value-of select=&quot;@name&quot;/&gt;&lt;/h3&gt;&#10;
+    &#10;
+    &lt;xsl:for-each select=&quot;user&quot;&gt;&#10;
+      &lt;h4&gt;User &lt;xsl:value-of select=&quot;@username&quot;/&gt;&lt;/h4&gt;&#10;
+      &#10;
+      &lt;table style=&quot;border: 1px solid black;&quot;&gt;&#10;
+        &lt;tr&gt;&#10;
+          &lt;td&gt;Status:&lt;/td&gt;&#10;
+          &lt;td&gt;&#10;
+            &lt;xsl:value-of select=&quot;@status&quot;/&gt;&#10;
+          &lt;/td&gt;&#10;
+        &lt;/tr&gt;&#10;
+        &lt;xsl:if test=&quot;string-length(@creationDate) &amp;gt; 0&quot;&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;Creation Date:&lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;xsl:value-of select=&quot;@creationDate&quot;/&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+        &lt;/xsl:if&gt;&#10;
+        &lt;xsl:if test=&quot;string-length(@lastLoginDate) &amp;gt; 0&quot;&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;Last Login Date:&lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;xsl:value-of select=&quot;@lastLoginDate&quot;/&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+        &lt;/xsl:if&gt;&#10;
+        &lt;xsl:if test=&quot;string-length(@changePwdDate) &amp;gt; 0&quot;&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;Change Password Date:&lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;xsl:value-of select=&quot;@changePwdDate&quot;/&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+        &lt;/xsl:if&gt;&#10;
+        &lt;xsl:if test=&quot;string-length(@passwordHistorySize) &amp;gt; 0&quot;&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;Password History Size:&lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;xsl:value-of select=&quot;@passwordHistorySize&quot;/&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+        &lt;/xsl:if&gt;&#10;
+        &lt;xsl:if test=&quot;string-length(@failedLoginCount) &amp;gt; 0&quot;&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;Number of Failed Login Attempts:&lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;xsl:value-of select=&quot;@failedLoginCount&quot;/&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+        &lt;/xsl:if&gt;&#10;
+      &lt;/table&gt;&#10;
+&#10;
+      &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+        &lt;xsl:with-param name=&quot;label&quot;&gt;Attributes&lt;/xsl:with-param&gt;&#10;
+        &lt;xsl:with-param name=&quot;node&quot; select=&quot;attributes/attribute&quot;/&gt;&#10;
+      &lt;/xsl:call-template&gt;&#10;
+&#10;
+      &lt;!--&lt;xsl:if test=&quot;string-length(derivedAttributes/derivedAttribute) &amp;gt; 0&quot;&gt;--&gt;&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(derivedAttributes/derivedAttribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Derived Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;derivedAttributes/derivedAttribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;h5&gt;THIS USER HASN'T DERIVED ATTRIBUTES&lt;/h5&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;!--&lt;/xsl:if&gt;--&gt;&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(virtualAttributes/virtualAttribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Virtual Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;virtualAttributes/virtualAttribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;h5&gt;THIS USER HASN'T VIRTUAL ATTRIBUTES&lt;/h5&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(memberships/membership) &amp;gt; 0&quot;&gt;&#10;
+          &lt;h4&gt;Memberships&lt;/h4&gt;&#10;
+          &lt;xsl:for-each select=&quot;memberships/membership&quot;&gt;&#10;
+            &lt;h5&gt;Group: &lt;xsl:value-of select=&quot;@groupName&quot;/&gt;(&lt;xsl:value-of select=&quot;@groupId&quot;/&gt;)&lt;/h5&gt;&#10;
+            &lt;blockquote&gt;&#10;
+              &lt;xsl:choose&gt;&#10;
+                &lt;xsl:when test=&quot;string-length(attributes/attribute) &amp;gt; 0&quot;&gt;&#10;
+                  &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+                    &lt;xsl:with-param name=&quot;label&quot;&gt;Attributes&lt;/xsl:with-param&gt;&#10;
+                    &lt;xsl:with-param name=&quot;node&quot; select=&quot;attributes/attribute&quot;/&gt;&#10;
+                  &lt;/xsl:call-template&gt;&#10;
+                &lt;/xsl:when&gt;&#10;
+                &lt;xsl:otherwise&gt;&#10;
+                  &lt;h5&gt;THIS GROUP HASN'T ATTRIBUTES&lt;/h5&gt;&#10;
+                &lt;/xsl:otherwise&gt;&#10;
+              &lt;/xsl:choose&gt;&#10;
+              &lt;xsl:choose&gt;&#10;
+                &lt;xsl:when test=&quot;string-length(derivedAttributes/derivedAttribute) &amp;gt; 0&quot;&gt;&#10;
+                  &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+                    &lt;xsl:with-param name=&quot;label&quot;&gt;Derived Attributes&lt;/xsl:with-param&gt;&#10;
+                    &lt;xsl:with-param name=&quot;node&quot; select=&quot;derivedAttributes/derivedAttribute&quot;/&gt;&#10;
+                  &lt;/xsl:call-template&gt;&#10;
+                &lt;/xsl:when&gt;&#10;
+                &lt;xsl:otherwise&gt;&#10;
+                  &lt;h5&gt;THIS GROUP HASN'T DERIVED ATTRIBUTES&lt;/h5&gt;&#10;
+                &lt;/xsl:otherwise&gt;&#10;
+              &lt;/xsl:choose&gt;&#10;
+              &lt;xsl:choose&gt;&#10;
+                &lt;xsl:when test=&quot;string-length(virtualAttributes/virtualAttribute) &amp;gt; 0&quot;&gt;&#10;
+                  &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+                    &lt;xsl:with-param name=&quot;label&quot;&gt;Virtual Attributes&lt;/xsl:with-param&gt;&#10;
+                    &lt;xsl:with-param name=&quot;node&quot; select=&quot;virtualAttributes/virtualAttribute&quot;/&gt;&#10;
+                  &lt;/xsl:call-template&gt;&#10;
+                &lt;/xsl:when&gt;&#10;
+                &lt;xsl:otherwise&gt;&#10;
+                  &lt;h5&gt;THIS GROUP HASN'T VIRTUAL ATTRIBUTES&lt;/h5&gt;&#10;
+                &lt;/xsl:otherwise&gt;&#10;
+              &lt;/xsl:choose&gt;&#10;
+              &lt;xsl:call-template name=&quot;groupResources&quot;&gt;&#10;
+                &lt;xsl:with-param name=&quot;node&quot; select=&quot;resources/resource&quot;/&gt;&#10;
+              &lt;/xsl:call-template&gt;&#10;
+            &lt;/blockquote&gt;&#10;
+          &lt;/xsl:for-each&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;h5&gt;THIS USER ISN'T ASSIGNED TO A GROUP&lt;/h5&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;xsl:if test=&quot;string-length(resources) &amp;gt; 0&quot;&gt;&#10;
+        &lt;xsl:call-template name=&quot;resources&quot;&gt;&#10;
+          &lt;xsl:with-param name=&quot;node&quot; select=&quot;resources/resource&quot;/&gt;&#10;
+        &lt;/xsl:call-template&gt;&#10;
+      &lt;/xsl:if&gt;&#10;
+      &lt;hr/&gt;&#10;
+    &lt;/xsl:for-each&gt;&#10;
+       &#10;
+  &lt;/xsl:template&gt;&#10;
+&#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.GroupReportlet']&quot;&gt;&#10;
+    &lt;h2&gt;Reportlet: &lt;xsl:value-of select=&quot;@name&quot;/&gt;&lt;/h2&gt;&#10;
+    &lt;xsl:for-each select=&quot;group&quot;&gt;&#10;
+      &lt;h3&gt;Group &lt;xsl:value-of select=&quot;@name&quot;/&gt;&lt;/h3&gt;&#10;
+      &#10;
+      &lt;table style=&quot;border: 1px solid black;&quot;&gt;&#10;
+        &lt;tr&gt;&#10;
+          &lt;td&gt;Id:&lt;/td&gt;&#10;
+          &lt;td&gt;&#10;
+            &lt;xsl:value-of select=&quot;@id&quot;/&gt;&#10;
+          &lt;/td&gt;&#10;
+        &lt;/tr&gt;&#10;
+        &lt;xsl:if test=&quot;@groupOwner != 'null'&quot;&gt; &lt;!--!= null test=&quot;not(USER/FIRSTNAME)&quot; --&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;Group Owner:&lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;xsl:value-of select=&quot;@groupOwner&quot;/&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+        &lt;/xsl:if&gt;&#10;
+        &lt;xsl:if test=&quot;@userOwner != 'null'&quot;&gt;&#10;
+          &lt;tr&gt;&#10;
+            &lt;td&gt;User Owner:&lt;/td&gt;&#10;
+            &lt;td&gt;&#10;
+              &lt;xsl:value-of select=&quot;@userOwner&quot;/&gt;&#10;
+            &lt;/td&gt;&#10;
+          &lt;/tr&gt;&#10;
+        &lt;/xsl:if&gt;&#10;
+        &#10;
+      &lt;/table&gt;&#10;
+&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(attributes/attribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;attributes/attribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;h5&gt;THIS GROUP HASN'T ANY ATTRIBUTE&lt;/h5&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(derivedAttributes/derivedAttribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Derived Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;derivedAttributes/derivedAttribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;h5&gt;THIS GROUP HASN'T ANY DERIVED ATTRIBUTE&lt;/h5&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;!--&lt;/xsl:if&gt;--&gt;&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(virtualAttributes/virtualAttribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Virtual Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;virtualAttributes/virtualAttribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;h5&gt;THIS GROUP HASN'T ANY VIRTUAL ATTRIBUTE&lt;/h5&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;users/user&quot;&gt;&#10;
+          &lt;h4&gt;Users&lt;/h4&gt;&#10;
+          &lt;xsl:for-each select=&quot;users/user&quot;&gt;&#10;
+            &lt;h5&gt;User: &lt;xsl:value-of select=&quot;@userUsername&quot;/&gt; (Id: &lt;xsl:value-of select=&quot;@userId&quot;/&gt;)&lt;/h5&gt;&#10;
+          &lt;/xsl:for-each&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;h5&gt;THIS GROUP HASN'T ANY USER ASSIGNED TO&lt;/h5&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &#10;
+      &lt;xsl:call-template name=&quot;groupResources&quot;&gt;&#10;
+        &lt;xsl:with-param name=&quot;node&quot; select=&quot;resources/resource&quot;/&gt;&#10;
+      &lt;/xsl:call-template&gt;&#10;
+      &lt;hr/&gt;&#10;
+      &#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template name=&quot;attributes&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;label&quot;/&gt;&#10;
+    &lt;xsl:param name=&quot;node&quot;/&gt;&#10;
+&#10;
+    &lt;h4&gt;&#10;
+      &lt;xsl:value-of select=&quot;$label&quot;/&gt;&#10;
+    &lt;/h4&gt;&#10;
+    &#10;
+    &lt;table&gt;&#10;
+      &lt;thead&gt;&#10;
+        &lt;tr&gt;&#10;
+          &lt;th&gt;Schema name&lt;/th&gt;&#10;
+          &lt;th&gt;Value(s)&lt;/th&gt;&#10;
+        &lt;/tr&gt;&#10;
+      &lt;/thead&gt;&#10;
+      &lt;tbody&gt;&#10;
+        &lt;xsl:for-each select=&quot;$node&quot;&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(value/text()) &amp;gt; 0&quot;&gt;&#10;
+            &lt;tr&gt;&#10;
+              &lt;td&gt;&#10;
+                &lt;xsl:value-of select=&quot;@name&quot;/&gt;&#10;
+              &lt;/td&gt;&#10;
+              &lt;td&gt;&#10;
+                &lt;ul&gt;&#10;
+                  &lt;xsl:for-each select=&quot;value&quot;&gt;&#10;
+                    &lt;li&gt;&#10;
+                      &lt;xsl:value-of select=&quot;text()&quot;/&gt;&#10;
+                    &lt;/li&gt;&#10;
+                  &lt;/xsl:for-each&gt;&#10;
+                &lt;/ul&gt;&#10;
+              &lt;/td&gt;&#10;
+            &lt;/tr&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+        &lt;/xsl:for-each&gt;&#10;
+      &lt;/tbody&gt;&#10;
+    &lt;/table&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+&#10;
+  &lt;xsl:template name=&quot;resources&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;node&quot;/&gt;&#10;
+    &#10;
+    &lt;h4&gt;Resources&lt;/h4&gt;&#10;
+    &lt;ul&gt;&#10;
+      &lt;xsl:for-each select=&quot;$node&quot;&gt;&#10;
+        &lt;li&gt;&#10;
+          &lt;xsl:value-of select=&quot;@name&quot;/&gt;&#10;
+        &lt;/li&gt;&#10;
+      &lt;/xsl:for-each&gt;&#10;
+    &lt;/ul&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template name=&quot;groupResources&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;node&quot;/&gt;&#10;
+    &#10;
+    &lt;h4&gt;Group Resources&lt;/h4&gt;&#10;
+    &lt;ul&gt;&#10;
+      &lt;xsl:for-each select=&quot;$node&quot;&gt;&#10;
+        &lt;li&gt;&#10;
+          &lt;xsl:value-of select=&quot;@name&quot;/&gt;&#10;
+        &lt;/li&gt;&#10;
+      &lt;/xsl:for-each&gt;&#10;
+    &lt;/ul&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+&lt;/xsl:stylesheet&gt;&#10;"
+                  csvTemplate="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;
+&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&#10;
+                version=&quot;1.0&quot;&gt;&#10;
+ &#10;
+  &lt;xsl:param name=&quot;status&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;message&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;start&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;end&quot;/&gt;&#10;
+    &#10;
+  &lt;xsl:template match=&quot;/&quot;&gt;&#10;
+    &lt;xsl:apply-templates/&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+&#10;
+  &lt;xsl:variable name=&quot;delimiter&quot; select=&quot;';'&quot;/&gt;&#10;
+   &#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.StaticReportlet']&quot;&gt;&#10;
+    &lt;xsl:call-template name=&quot;header&quot;&gt;&#10;
+      &lt;xsl:with-param name=&quot;node&quot; select=&quot;configurations/staticAttributes&quot;/&gt;&#10;
+    &lt;/xsl:call-template&gt;&#10;
+    &#10;
+    &lt;xsl:call-template name=&quot;staticAttributes&quot;&gt;&#10;
+      &lt;xsl:with-param name=&quot;header&quot; select=&quot;configurations/staticAttributes&quot;/&gt;&#10;
+    &lt;/xsl:call-template&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template name=&quot;header&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;node&quot;/&gt;  &#10;
+    &lt;xsl:for-each select=&quot;$node/*&quot;&gt;&#10;
+      &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+      &lt;xsl:value-of select=&quot;text()&quot;/&gt;&#10;
+      &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt; &#10;
+      &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+        &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+      &lt;/xsl:if&gt;&#10;
+    &lt;/xsl:for-each&gt;&#10;
+    &lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+    &#10;
+  &lt;xsl:template name=&quot;staticAttributes&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;header&quot;/&gt;&#10;
+    &#10;
+    &lt;xsl:variable name=&quot;attrs&quot; select=&quot;.&quot;/&gt;&#10;
+    &lt;xsl:for-each select=&quot;$header/*&quot;&gt;&#10;
+      &lt;xsl:variable name=&quot;nameAttr&quot; select=&quot;text()&quot;/&gt; &#10;
+      &lt;xsl:if test=&quot;string-length($attrs/*[name(.)=$nameAttr]/text()) &amp;gt; 0 &#10;
+                      and count($attrs/*[name(.)=$nameAttr]/*/node()) = 0&quot;&gt;&#10;
+        &lt;xsl:variable name=&quot;value&quot; select=&quot;$attrs/*[name(.)=$nameAttr]/text()&quot;/&gt;&#10;
+        &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+        &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+      &lt;/xsl:if&gt;&#10;
+      &#10;
+      &lt;xsl:if test=&quot;string-length($attrs/*[name(.)=$nameAttr]/*/text()) &amp;gt; 0 &#10;
+                      and count($attrs/*[name(.)=$nameAttr]/*/node()) &amp;gt; 0&quot;&gt;&#10;
+        &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;xsl:for-each select=&quot;$attrs/*[name(.)=$nameAttr]/*&quot;&gt;&#10;
+          &lt;xsl:variable name=&quot;value&quot; select=&quot;text()&quot;/&gt;&#10;
+          &lt;xsl:text&gt;&lt;/xsl:text&gt;&#10;
+          &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+          &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+            &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+        &lt;/xsl:for-each&gt;&#10;
+        &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+      &lt;/xsl:if&gt;&#10;
+      &#10;
+      &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+        &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+      &lt;/xsl:if&gt;&#10;
+    &#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.UserReportlet']&quot;&gt;&#10;
+    &#10;
+    &lt;xsl:call-template name=&quot;header&quot;&gt;&#10;
+      &lt;xsl:with-param name=&quot;node&quot; select=&quot;configurations/userAttributes&quot;/&gt;&#10;
+    &lt;/xsl:call-template&gt;&#10;
+    &lt;xsl:for-each select=&quot;user&quot;&gt;&#10;
+      &lt;xsl:call-template name=&quot;userAttributes&quot;&gt;&#10;
+        &lt;xsl:with-param name=&quot;header&quot; select=&quot;../configurations/userAttributes&quot;/&gt;&#10;
+      &lt;/xsl:call-template&gt;&#10;
+      &lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;&#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+    &#10;
+  &lt;xsl:template name=&quot;userAttributes&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;header&quot;/&gt;&#10;
+  &#10;
+    &lt;xsl:variable name=&quot;attrs&quot; select=&quot;.&quot;/&gt;&#10;
+    &lt;xsl:for-each select=&quot;$header/*&quot;&gt;&#10;
+      &lt;xsl:variable name=&quot;nameAttr&quot; select=&quot;text()&quot;/&gt;&#10;
+      &lt;xsl:choose&gt;      &#10;
+        &lt;xsl:when test=&quot;count($attrs/@*[name()=$nameAttr]) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:variable name=&quot;userAttr&quot; select=&quot;$attrs/@*[name()=$nameAttr]&quot;/&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+          &lt;xsl:value-of select=&quot;$userAttr/.&quot;/&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:when test=&quot;string-length($attrs/*/*[@name=$nameAttr]/value/text()) &amp;gt; 0 &#10;
+                        and count($attrs/*/*[@name=$nameAttr]/node()) = 0&quot;&gt;&#10;
+          &lt;xsl:variable name=&quot;value&quot; select=&quot;$attrs/*/*[@name=$nameAttr]/value/text()&quot;/&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+          &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:when test=&quot;string-length($attrs/*/*[@name=$nameAttr]/value/text()) &amp;gt; 0 &#10;
+                        and count($attrs/*/*[@name=$nameAttr]/node()) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+          &lt;xsl:for-each select=&quot;$attrs/*/*[@name=$nameAttr]/*&quot;&gt;&#10;
+            &lt;xsl:variable name=&quot;value&quot; select=&quot;$attrs/*/*[@name=$nameAttr]/value/text()&quot;/&gt;&#10;
+            &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+            &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+              &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+            &lt;/xsl:if&gt;&#10;
+          &lt;/xsl:for-each&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:when test=&quot;name($attrs/*[name(.)=$nameAttr]/*[name(.)='membership']) &#10;
+                        and count($attrs/*[name(.)=$nameAttr]/node()) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;       &#10;
+          &lt;xsl:variable name=&quot;value&quot; select=&quot;@groupName&quot;/&gt;&#10;
+          &lt;xsl:for-each select=&quot;$attrs/*/membership&quot;&gt;&#10;
+            &lt;xsl:variable name=&quot;value&quot; select=&quot;@groupName&quot;/&gt;&#10;
+            &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+            &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+              &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+            &lt;/xsl:if&gt;&#10;
+          &lt;/xsl:for-each&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:when test=&quot;name($attrs/*[name(.)=$nameAttr]/*[name(.)='resource']) &#10;
+                        and count($attrs/*[name(.)=$nameAttr]/node()) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+          &lt;xsl:variable name=&quot;value&quot; select=&quot;@name&quot;/&gt;&#10;
+          &lt;xsl:for-each select=&quot;$attrs/*/resource&quot;&gt;&#10;
+            &lt;xsl:variable name=&quot;value&quot; select=&quot;@name&quot;/&gt;&#10;
+            &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+            &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+              &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+            &lt;/xsl:if&gt;&#10;
+          &lt;/xsl:for-each&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;xsl:text&gt;&quot;&quot;&lt;/xsl:text&gt; &#10;
+        &lt;/xsl:otherwise&gt;  &#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+        &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+      &lt;/xsl:if&gt;  &#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.GroupReportlet']&quot;&gt;&#10;
+    &#10;
+    &lt;xsl:call-template name=&quot;header&quot;&gt;&#10;
+      &lt;xsl:with-param name=&quot;node&quot; select=&quot;configurations/groupAttributes&quot;/&gt;&#10;
+    &lt;/xsl:call-template&gt;&#10;
+    &lt;xsl:for-each select=&quot;group&quot;&gt;&#10;
+      &lt;xsl:call-template name=&quot;groupAttributes&quot;&gt;&#10;
+        &lt;xsl:with-param name=&quot;header&quot; select=&quot;../configurations/groupAttributes&quot;/&gt;&#10;
+        &lt;xsl:with-param name=&quot;attrs&quot; select=&quot;.&quot;/&gt;&#10;
+      &lt;/xsl:call-template&gt;&#10;
+      &lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;&#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+    &#10;
+  &lt;xsl:template name=&quot;groupAttributes&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;header&quot;/&gt;&#10;
+    &lt;xsl:param name=&quot;attrs&quot;/&gt;&#10;
+    &#10;
+    &lt;xsl:for-each select=&quot;$header/*&quot;&gt;&#10;
+      &lt;xsl:variable name=&quot;nameAttr&quot; select=&quot;text()&quot;/&gt;&#10;
+      &#10;
+      &lt;xsl:choose&gt; &#10;
+        &lt;xsl:when test=&quot;string-length($attrs/@*[name()=$nameAttr]) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:variable name=&quot;groupAttr&quot; select=&quot;$attrs/@*[name()=$nameAttr]&quot;/&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+          &lt;xsl:value-of select=&quot;$groupAttr/.&quot;/&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:when test=&quot;name($attrs/*[name(.)=$nameAttr]/*[name(.)='resource']) &#10;
+                        and count($attrs/*[name(.)=$nameAttr]/node()) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;       &#10;
+          &lt;xsl:for-each select=&quot;$attrs/*/resource&quot;&gt;&#10;
+            &lt;xsl:variable name=&quot;value&quot; select=&quot;@name&quot;/&gt;&#10;
+            &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+            &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+              &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+            &lt;/xsl:if&gt;&#10;
+          &lt;/xsl:for-each&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:when test=&quot;name($attrs/*[name(.)=$nameAttr]/*[name(.)='user']) &#10;
+                        and count($attrs/*[name(.)=$nameAttr]/node()) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;       &#10;
+          &lt;xsl:for-each select=&quot;$attrs/*/user&quot;&gt;&#10;
+            &lt;xsl:variable name=&quot;value&quot; select=&quot;@userUsername&quot;/&gt;&#10;
+            &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+            &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+              &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+            &lt;/xsl:if&gt;&#10;
+          &lt;/xsl:for-each&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+          &lt;xsl:if test=&quot;string-length($attrs/*/*[@name=$nameAttr]/value/text()) &amp;gt; 0&quot;&gt; &#10;
+            &lt;xsl:variable name=&quot;value&quot; select=&quot;$attrs/*/*[@name=$nameAttr]/value/text()&quot;/&gt;&#10;
+            &lt;xsl:value-of select=&quot;$value&quot;/&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+          &lt;xsl:text&gt;&quot;&lt;/xsl:text&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;xsl:if test=&quot;position() != last()&quot;&gt;&#10;
+        &lt;xsl:value-of select=&quot;$delimiter&quot;/&gt;&#10;
+      &lt;/xsl:if&gt;&#10;
+    &#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+&lt;/xsl:stylesheet&gt;&#10;"
+                  foTemplate="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;
+&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&#10;
+                xmlns:fo=&quot;http://www.w3.org/1999/XSL/Format&quot;&#10;
+                version=&quot;1.0&quot;&gt;&#10;
+&#10;
+  &lt;xsl:param name=&quot;status&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;message&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;start&quot;/&gt;&#10;
+  &lt;xsl:param name=&quot;end&quot;/&gt;&#10;
+  &#10;
+  &lt;xsl:template match=&quot;/&quot;&gt;&#10;
+    &lt;fo:root xmlns:fo=&quot;http://www.w3.org/1999/XSL/Format&quot; font-family=&quot;Helvetica&quot; font-size=&quot;10pt&quot;&gt;&#10;
+      &#10;
+      &lt;!-- defines the layout master --&gt;&#10;
+      &lt;fo:layout-master-set&gt;&#10;
+        &lt;fo:simple-page-master master-name=&quot;first&quot; page-height=&quot;29.7cm&quot; page-width=&quot;21cm&quot; &#10;
+                               margin-top=&quot;1cm&quot; margin-bottom=&quot;2cm&quot; margin-left=&quot;2.5cm&quot; margin-right=&quot;2.5cm&quot;&gt;&#10;
+          &lt;fo:region-body margin-top=&quot;1cm&quot;/&gt;&#10;
+          &lt;fo:region-before extent=&quot;1cm&quot;/&gt;&#10;
+          &lt;fo:region-after extent=&quot;1.5cm&quot;/&gt;&#10;
+        &lt;/fo:simple-page-master&gt;&#10;
+      &lt;/fo:layout-master-set&gt;&#10;
+&#10;
+      &lt;!-- starts actual layout --&gt;&#10;
+      &lt;fo:page-sequence master-reference=&quot;first&quot;&gt;&#10;
+        &#10;
+        &lt;fo:flow flow-name=&quot;xsl-region-body&quot;&gt;&#10;
+          &lt;fo:block font-size=&quot;24pt&quot; font-weight=&quot;bold&quot; text-align=&quot;center&quot; space-after=&quot;1cm&quot;&gt;&#10;
+            Apache Syncope Report - &lt;xsl:value-of select=&quot;report/@name&quot;/&gt;&#10;
+          &lt;/fo:block&gt;&#10;
+&#10;
+          &lt;fo:table table-layout=&quot;fixed&quot; border-width=&quot;0.5mm&quot; border-style=&quot;solid&quot; width=&quot;100%&quot; space-after=&quot;1cm&quot;&gt;&#10;
+            &lt;fo:table-column column-width=&quot;proportional-column-width(1)&quot;/&gt;&#10;
+            &lt;fo:table-column column-width=&quot;proportional-column-width(1)&quot;/&gt;&#10;
+            &lt;fo:table-body&gt;&#10;
+              &lt;fo:table-row&gt;&#10;
+                &lt;fo:table-cell&gt;&#10;
+                  &lt;fo:block font-size=&quot;18pt&quot; font-weight=&quot;bold&quot;&gt;Report Name:&lt;/fo:block&gt;&#10;
+                &lt;/fo:table-cell&gt;&#10;
+                &lt;fo:table-cell&gt;&#10;
+                  &lt;fo:block font-size=&quot;18pt&quot; font-weight=&quot;bold&quot;&gt;&#10;
+                    &lt;xsl:value-of select=&quot;report/@name&quot;/&gt;&#10;
+                  &lt;/fo:block&gt;&#10;
+                &lt;/fo:table-cell&gt;&#10;
+              &lt;/fo:table-row&gt;&#10;
+              &lt;fo:table-row&gt;&#10;
+                &lt;fo:table-cell&gt;&#10;
+                  &lt;fo:block font-size=&quot;18pt&quot; font-weight=&quot;bold&quot;&gt;Start Date:&lt;/fo:block&gt;&#10;
+                &lt;/fo:table-cell&gt;&#10;
+                &lt;fo:table-cell&gt;&#10;
+                  &lt;fo:block font-size=&quot;18pt&quot; font-weight=&quot;bold&quot;&gt;&#10;
+                    &lt;xsl:value-of select=&quot;$start&quot;/&gt;&#10;
+                  &lt;/fo:block&gt;&#10;
+                &lt;/fo:table-cell&gt;&#10;
+              &lt;/fo:table-row&gt;&#10;
+              &lt;fo:table-row&gt;&#10;
+                &lt;fo:table-cell&gt;&#10;
+                  &lt;fo:block font-size=&quot;18pt&quot; font-weight=&quot;bold&quot;&gt;End Date:&lt;/fo:block&gt;&#10;
+                &lt;/fo:table-cell&gt;&#10;
+                &lt;fo:table-cell&gt;&#10;
+                  &lt;fo:block font-size=&quot;18pt&quot; font-weight=&quot;bold&quot;&gt;&#10;
+                    &lt;xsl:value-of select=&quot;$end&quot;/&gt;&#10;
+                  &lt;/fo:block&gt;&#10;
+                &lt;/fo:table-cell&gt;&#10;
+              &lt;/fo:table-row&gt;&#10;
+            &lt;/fo:table-body&gt;&#10;
+          &lt;/fo:table&gt;&#10;
+&#10;
+          &lt;xsl:apply-templates/&gt;&#10;
+        &lt;/fo:flow&gt;&#10;
+      &lt;/fo:page-sequence&gt;&#10;
+    &lt;/fo:root&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+&#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.StaticReportlet']&quot;&gt;&#10;
+&#10;
+    &lt;fo:block font-size=&quot;14pt&quot; font-weight=&quot;bold&quot; space-after=&quot;0.5cm&quot;&gt;Reportlet: &#10;
+      &lt;xsl:value-of select=&quot;@name&quot;/&gt;&#10;
+    &lt;/fo:block&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(string/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;fo:block font-size=&quot;11pt&quot;&gt;String value: &#10;
+        &lt;xsl:value-of select=&quot;string/text()&quot;/&gt;&#10;
+      &lt;/fo:block&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(long/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;fo:block font-size=&quot;11pt&quot;&gt;Long value: &#10;
+        &lt;xsl:value-of select=&quot;long/text()&quot;/&gt;&#10;
+      &lt;/fo:block&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(double/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;fo:block font-size=&quot;11pt&quot;&gt;Double value: &#10;
+        &lt;xsl:value-of select=&quot;double/text()&quot;/&gt;&#10;
+      &lt;/fo:block&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(date/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;fo:block font-size=&quot;11pt&quot;&gt;Date value: &#10;
+        &lt;xsl:value-of select=&quot;date/text()&quot;/&gt;&#10;
+      &lt;/fo:block&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(enum/text()) &amp;gt; 0&quot;&gt;&#10;
+      &lt;fo:block font-size=&quot;11pt&quot;&gt;Enum value: &#10;
+        &lt;xsl:value-of select=&quot;enum/text()&quot;/&gt;&#10;
+      &lt;/fo:block&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+&#10;
+    &lt;xsl:if test=&quot;string-length(list) &amp;gt; 0&quot;&gt;&#10;
+      &lt;fo:block font-size=&quot;11pt&quot;&gt;List values:&lt;/fo:block&gt;&#10;
+            &#10;
+      &lt;fo:list-block provisional-label-separation=&quot;4mm&quot; provisional-distance-between-starts=&quot;2mm&quot;&gt;&#10;
+        &lt;xsl:for-each select=&quot;list/string&quot;&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(string/text()) &amp;gt; 0&quot;&gt;&#10;
+            &lt;fo:list-item&gt;&#10;
+              &lt;fo:list-item-label end-indent=&quot;label-end()&quot;&gt;&#10;
+                &lt;fo:block&gt;&#x2022;&lt;/fo:block&gt;&#10;
+              &lt;/fo:list-item-label&gt;&#10;
+              &lt;fo:list-item-body start-indent=&quot;body-start()&quot;&gt;&#10;
+                &lt;fo:block&gt;&#10;
+                  &lt;xsl:value-of select=&quot;text()&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:list-item-body&gt;&#10;
+            &lt;/fo:list-item&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+        &lt;/xsl:for-each&gt;&#10;
+      &lt;/fo:list-block&gt;&#10;
+    &lt;/xsl:if&gt;&#10;
+        &#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.UserReportlet']&quot;&gt;&#10;
+   &#10;
+    &lt;fo:block font-size=&quot;16pt&quot; font-weight=&quot;bold&quot; space-after=&quot;0.5cm&quot; space-before=&quot;5mm&quot;&gt;Reportlet: &lt;xsl:value-of select=&quot;@name&quot;/&gt;&lt;/fo:block&gt;&#10;
+        &#10;
+    &lt;xsl:for-each select=&quot;user&quot;&gt;&#10;
+      &lt;fo:block font-size=&quot;14pt&quot; font-weight=&quot;bold&quot; space-before=&quot;15mm&quot; space-after=&quot;5mm&quot; background-color=&quot;(#8888ff)&quot;&gt;User &lt;xsl:value-of select=&quot;@username&quot;/&gt;&lt;/fo:block&gt;&#10;
+      &lt;fo:table table-layout=&quot;fixed&quot; space-after=&quot;7mm&quot;&gt;&#10;
+        &lt;fo:table-column/&gt;&#10;
+        &lt;fo:table-column/&gt;&#10;
+        &lt;fo:table-body&gt;&#10;
+          &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+            &lt;fo:table-cell&gt;&#10;
+              &lt;fo:block&gt;Status:&lt;/fo:block&gt;&#10;
+            &lt;/fo:table-cell&gt;&#10;
+            &lt;fo:table-cell&gt;&#10;
+              &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                &lt;xsl:value-of select=&quot;@status&quot;/&gt;&#10;
+              &lt;/fo:block&gt;&#10;
+            &lt;/fo:table-cell&gt;&#10;
+          &lt;/fo:table-row&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(@creationDate) &amp;gt; 0&quot;&gt;&#10;
+            &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block&gt;Creation Date:&lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                  &lt;xsl:value-of select=&quot;@creationDate&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+            &lt;/fo:table-row&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(@lastLoginDate) &amp;gt; 0&quot;&gt;&#10;
+            &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block&gt;Last Login Date:&lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                  &lt;xsl:value-of select=&quot;@lastLoginDate&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+            &lt;/fo:table-row&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(@changePwdDate) &amp;gt; 0&quot;&gt;&#10;
+            &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block&gt;Change Password Date:&lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                  &lt;xsl:value-of select=&quot;@changePwdDate&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+            &lt;/fo:table-row&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(@passwordHistorySize) &amp;gt; 0&quot;&gt;&#10;
+            &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block&gt;Password History Size:&lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                  &lt;xsl:value-of select=&quot;@passwordHistorySize&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+            &lt;/fo:table-row&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(@failedLoginCount) &amp;gt; 0&quot;&gt;&#10;
+            &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block&gt;Number of Failed Login Attempts:&lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                  &lt;xsl:value-of select=&quot;@failedLoginCount&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+            &lt;/fo:table-row&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+        &lt;/fo:table-body&gt;&#10;
+      &lt;/fo:table&gt;&#10;
+      &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+        &lt;xsl:with-param name=&quot;label&quot;&gt;Attributes&lt;/xsl:with-param&gt;&#10;
+        &lt;xsl:with-param name=&quot;node&quot; select=&quot;attributes/attribute&quot;/&gt;&#10;
+      &lt;/xsl:call-template&gt;&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(derivedAttributes/derivedAttribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Derived Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;derivedAttributes/derivedAttribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;fo:block color=&quot;red&quot; font-size=&quot;9pt&quot; space-after=&quot;3mm&quot;&gt;THIS USER HASN'T ANY DERIVED ATTRIBUTE&lt;/fo:block&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(virtualAttributes/virtualAttribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Virtual Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;virtualAttributes/virtualAttribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;fo:block color=&quot;red&quot; font-size=&quot;9pt&quot; space-after=&quot;3mm&quot;&gt;THIS USER HASN'T ANY VIRTUAL ATTRIBUTE&lt;/fo:block&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(memberships/membership) &amp;gt; 0&quot;&gt;&#10;
+          &lt;fo:block font-size=&quot;11pt&quot; font-weight=&quot;bold&quot;&gt;Memberships&lt;/fo:block&gt;&#10;
+          &lt;xsl:for-each select=&quot;memberships/membership&quot;&gt;&#10;
+            &lt;fo:block font-size=&quot;10pt&quot; font-weight=&quot;bold&quot; space-before=&quot;2mm&quot;&gt;Group: &lt;xsl:value-of select=&quot;@groupName&quot;/&gt;(&lt;xsl:value-of select=&quot;@groupId&quot;/&gt;)&lt;/fo:block&gt;&#10;
+            &lt;fo:block start-indent=&quot;1cm&quot; space-before=&quot;3mm&quot; space-after=&quot;0.5cm&quot;&gt;&#10;
+              &lt;xsl:choose&gt;&#10;
+                &lt;xsl:when test=&quot;string-length(attributes/attribute) &amp;gt; 0&quot;&gt;&#10;
+                  &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+                    &lt;xsl:with-param name=&quot;label&quot;&gt;Attributes&lt;/xsl:with-param&gt;&#10;
+                    &lt;xsl:with-param name=&quot;node&quot; select=&quot;attributes/attribute&quot;/&gt;&#10;
+                  &lt;/xsl:call-template&gt;&#10;
+                &lt;/xsl:when&gt;&#10;
+                &lt;xsl:otherwise&gt;&#10;
+                  &lt;fo:block color=&quot;red&quot; font-size=&quot;8pt&quot; space-after=&quot;2mm&quot;&gt;THIS GROUP HASN'T ANY ATTRIBUTE&lt;/fo:block&gt;&#10;
+                &lt;/xsl:otherwise&gt;&#10;
+              &lt;/xsl:choose&gt;&#10;
+              &lt;xsl:choose&gt;&#10;
+                &lt;xsl:when test=&quot;string-length(derivedAttributes/derivedAttribute) &amp;gt; 0&quot;&gt;&#10;
+                  &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+                    &lt;xsl:with-param name=&quot;label&quot;&gt;Derived Attributes&lt;/xsl:with-param&gt;&#10;
+                    &lt;xsl:with-param name=&quot;node&quot; select=&quot;derivedAttributes/derivedAttribute&quot;/&gt;&#10;
+                  &lt;/xsl:call-template&gt;&#10;
+                &lt;/xsl:when&gt;&#10;
+                &lt;xsl:otherwise&gt;&#10;
+                  &lt;fo:block color=&quot;red&quot; font-size=&quot;8pt&quot; space-after=&quot;2mm&quot;&gt;THIS GROUP HASN'T ANY DERIVED ATTRIBUTE&lt;/fo:block&gt;&#10;
+                &lt;/xsl:otherwise&gt;&#10;
+              &lt;/xsl:choose&gt;&#10;
+              &lt;xsl:choose&gt;&#10;
+                &lt;xsl:when test=&quot;string-length(virtualAttributes/virtualAttribute) &amp;gt; 0&quot;&gt;&#10;
+                  &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+                    &lt;xsl:with-param name=&quot;label&quot;&gt;Virtual Attributes&lt;/xsl:with-param&gt;&#10;
+                    &lt;xsl:with-param name=&quot;node&quot; select=&quot;virtualAttributes/virtualAttribute&quot;/&gt;&#10;
+                  &lt;/xsl:call-template&gt;&#10;
+                &lt;/xsl:when&gt;&#10;
+                &lt;xsl:otherwise&gt;&#10;
+                  &lt;fo:block color=&quot;red&quot; font-size=&quot;8pt&quot; space-after=&quot;2mm&quot;&gt;THIS GROUP HASN'T ANY VIRTUAL ATTRIBUTE&lt;/fo:block&gt;&#10;
+                &lt;/xsl:otherwise&gt;&#10;
+              &lt;/xsl:choose&gt;&#10;
+              &lt;!-- 'groupResources&quot; is defined in groupReportlet2fo.xsl --&gt;&#10;
+              &lt;xsl:call-template name=&quot;groupResources&quot;&gt;&#10;
+                &lt;xsl:with-param name=&quot;node&quot; select=&quot;resources/resource&quot;/&gt;&#10;
+              &lt;/xsl:call-template&gt;&#10;
+            &lt;/fo:block&gt;&#10;
+          &lt;/xsl:for-each&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;fo:block color=&quot;red&quot; font-size=&quot;9pt&quot; space-after=&quot;3mm&quot;&gt;THIS USER HASN'T BEEN ASSIGNED TO ANY GROUP&lt;/fo:block&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;xsl:call-template name=&quot;resources&quot;&gt;&#10;
+        &lt;xsl:with-param name=&quot;node&quot; select=&quot;resources/resource&quot;/&gt;&#10;
+      &lt;/xsl:call-template&gt;&#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template match=&quot;reportlet[@class='org.apache.syncope.core.provisioning.java.job.report.GroupReportlet']&quot;&gt;&#10;
+   &#10;
+    &lt;fo:block font-size=&quot;16pt&quot; font-weight=&quot;bold&quot; space-after=&quot;0.5cm&quot; space-before=&quot;5mm&quot;&gt;Reportlet: &lt;xsl:value-of select=&quot;@name&quot;/&gt;&lt;/fo:block&gt;&#10;
+        &#10;
+    &lt;xsl:for-each select=&quot;group&quot;&gt;&#10;
+      &lt;fo:block font-size=&quot;14pt&quot; font-weight=&quot;bold&quot; space-before=&quot;15mm&quot; space-after=&quot;5mm&quot; background-color=&quot;(#8888ff)&quot;&gt;Group &lt;xsl:value-of select=&quot;@name&quot;/&gt;&lt;/fo:block&gt;&#10;
+      &lt;fo:table table-layout=&quot;fixed&quot; space-after=&quot;7mm&quot;&gt;&#10;
+        &lt;fo:table-column/&gt;&#10;
+        &lt;fo:table-column/&gt;&#10;
+        &lt;fo:table-body&gt;&#10;
+          &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+            &lt;fo:table-cell&gt;&#10;
+              &lt;fo:block&gt;Id:&lt;/fo:block&gt;&#10;
+            &lt;/fo:table-cell&gt;&#10;
+            &lt;fo:table-cell&gt;&#10;
+              &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                &lt;xsl:value-of select=&quot;@id&quot;/&gt;&#10;
+              &lt;/fo:block&gt;&#10;
+            &lt;/fo:table-cell&gt;&#10;
+          &lt;/fo:table-row&gt;&#10;
+          &lt;xsl:if test=&quot;@groupOwner != 'null'&quot;&gt;&#10;
+            &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block&gt;Group Owner:&lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                  &lt;xsl:value-of select=&quot;@groupOwner&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+            &lt;/fo:table-row&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+          &lt;xsl:if test=&quot;@userOwner != 'null'&quot;&gt;&#10;
+            &lt;fo:table-row background-color=&quot;(#ccccff)&quot;&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block&gt;Last Login Date:&lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                  &lt;xsl:value-of select=&quot;@userOwner&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+            &lt;/fo:table-row&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+        &lt;/fo:table-body&gt;&#10;
+      &lt;/fo:table&gt;&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(attributes/attribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;attributes/attribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;fo:block color=&quot;red&quot; font-size=&quot;9pt&quot; space-after=&quot;3mm&quot;&gt;THIS GROUP HASN'T ANY ATTRIBUTE&lt;/fo:block&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(derivedAttributes/derivedAttribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Derived Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;derivedAttributes/derivedAttribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;fo:block color=&quot;red&quot; font-size=&quot;9pt&quot; space-after=&quot;3mm&quot;&gt;THIS GROUP HASN'T ANY DERIVED ATTRIBUTE&lt;/fo:block&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;string-length(virtualAttributes/virtualAttribute) &amp;gt; 0&quot;&gt;&#10;
+          &lt;xsl:call-template name=&quot;attributes&quot;&gt;&#10;
+            &lt;xsl:with-param name=&quot;label&quot;&gt;Virtual Attributes&lt;/xsl:with-param&gt;&#10;
+            &lt;xsl:with-param name=&quot;node&quot; select=&quot;virtualAttributes/virtualAttribute&quot;/&gt;&#10;
+          &lt;/xsl:call-template&gt;&#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;fo:block color=&quot;red&quot; font-size=&quot;9pt&quot; space-after=&quot;3mm&quot;&gt;THIS GROUP HASN'T ANY VIRTUAL ATTRIBUTE&lt;/fo:block&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &#10;
+      &lt;xsl:choose&gt;&#10;
+        &lt;xsl:when test=&quot;users/user&quot;&gt;&#10;
+          &lt;fo:block font-size=&quot;11pt&quot; font-weight=&quot;bold&quot;&gt;Users&lt;/fo:block&gt;&#10;
+          &lt;xsl:for-each select=&quot;users/user&quot;&gt;&#10;
+            &lt;fo:block background-color=&quot;(#ccccff)&quot; font-size=&quot;9pt&quot; font-weight=&quot;bold&quot; space-before=&quot;4mm&quot;&gt;User: &lt;xsl:value-of select=&quot;@userUsername&quot;/&gt; (Id: &lt;xsl:value-of select=&quot;@userId&quot;/&gt;)&lt;/fo:block&gt;&#10;
+                 &#10;
+          &lt;/xsl:for-each&gt; &#10;
+        &lt;/xsl:when&gt;&#10;
+        &lt;xsl:otherwise&gt;&#10;
+          &lt;fo:block color=&quot;red&quot; font-size=&quot;9pt&quot; space-after=&quot;3mm&quot;&gt;THIS GROUP HASN'T ANY USER ASSIGNED TO&lt;/fo:block&gt;&#10;
+        &lt;/xsl:otherwise&gt;&#10;
+      &lt;/xsl:choose&gt;&#10;
+      &lt;xsl:call-template name=&quot;groupResources&quot;&gt;&#10;
+        &lt;xsl:with-param name=&quot;node&quot; select=&quot;resources/resource&quot;/&gt;&#10;
+      &lt;/xsl:call-template&gt;&#10;
+    &lt;/xsl:for-each&gt;&#10;
+&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template name=&quot;attributes&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;label&quot;/&gt;&#10;
+    &lt;xsl:param name=&quot;node&quot;/&gt;&#10;
+    &lt;fo:block font-size=&quot;11pt&quot; font-weight=&quot;bold&quot; space-after=&quot;2mm&quot;&gt;&#10;
+      &lt;xsl:value-of select=&quot;$label&quot;/&gt;&#10;
+    &lt;/fo:block&gt;&#10;
+    &lt;fo:table table-layout=&quot;fixed&quot; space-after=&quot;7mm&quot;&gt;&#10;
+      &lt;fo:table-column/&gt;&#10;
+      &lt;fo:table-column/&gt;&#10;
+      &lt;fo:table-header&gt;&#10;
+        &lt;fo:table-row height=&quot;7mm&quot; background-color=&quot;(#ccccba)&quot;&gt;&#10;
+          &lt;fo:table-cell&gt;&#10;
+            &lt;fo:block font-weight=&quot;bold&quot;&gt;Schema name&lt;/fo:block&gt;&#10;
+          &lt;/fo:table-cell&gt;&#10;
+          &lt;fo:table-cell&gt;&#10;
+            &lt;fo:block font-weight=&quot;bold&quot;&gt;Value(s)&lt;/fo:block&gt;&#10;
+          &lt;/fo:table-cell&gt;&#10;
+        &lt;/fo:table-row&gt;&#10;
+      &lt;/fo:table-header&gt;&#10;
+      &lt;fo:table-body&gt;&#10;
+        &lt;xsl:for-each select=&quot;$node&quot;&gt;&#10;
+          &lt;xsl:if test=&quot;string-length(value/text()) &amp;gt; 0&quot;&gt;&#10;
+            &lt;fo:table-row height=&quot;4mm&quot; background-color=&quot;(#ccccff)&quot;&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;fo:block&gt;&#10;
+                  &lt;xsl:value-of select=&quot;@name&quot;/&gt;&#10;
+                &lt;/fo:block&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+              &lt;fo:table-cell&gt;&#10;
+                &lt;xsl:for-each select=&quot;value&quot;&gt;&#10;
+                  &lt;fo:block&gt;&lt;/fo:block&gt;&#10;
+                  &lt;fo:block font-style=&quot;italic&quot;&gt;&#10;
+                    &lt;xsl:value-of select=&quot;text()&quot;/&gt;&#10;
+                  &lt;/fo:block&gt;&#10;
+                &lt;/xsl:for-each&gt;&#10;
+              &lt;/fo:table-cell&gt;&#10;
+            &lt;/fo:table-row&gt;&#10;
+          &lt;/xsl:if&gt;&#10;
+          &lt;fo:table-row&gt;&#10;
+            &lt;fo:table-cell&gt;&#10;
+              &lt;fo:block&gt;&lt;/fo:block&gt;&#10;
+            &lt;/fo:table-cell&gt;&#10;
+            &lt;fo:table-cell&gt;&#10;
+              &lt;fo:block&gt;&lt;/fo:block&gt;&#10;
+            &lt;/fo:table-cell&gt;&#10;
+          &lt;/fo:table-row&gt;&#10;
+        &lt;/xsl:for-each&gt;&#10;
+      &lt;/fo:table-body&gt;&#10;
+    &lt;/fo:table&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+  &#10;
+  &lt;xsl:template name=&quot;resources&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;node&quot;/&gt;&#10;
+    &lt;fo:block font-size=&quot;11pt&quot; font-weight=&quot;bold&quot; space-after=&quot;3mm&quot;&gt;Resources&lt;/fo:block&gt;&#10;
+    &lt;xsl:for-each select=&quot;$node&quot;&gt;&#10;
+      &lt;fo:block&gt;&lt;/fo:block&gt; &lt;!--            &lt;fo:block&gt;&#x2022;&lt;/fo:block&gt;--&gt;&#10;
+      &lt;fo:block background-color=&quot;(#ccccff)&quot;&gt;&#10;
+        &lt;xsl:value-of select=&quot;@name&quot;/&gt;&#10;
+      &lt;/fo:block&gt;&#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+&#10;
+  &lt;xsl:template name=&quot;groupResources&quot;&gt;&#10;
+    &lt;xsl:param name=&quot;node&quot;/&gt;&#10;
+    &lt;fo:block font-size=&quot;11pt&quot; font-weight=&quot;bold&quot; space-after=&quot;3mm&quot; space-before=&quot;5mm&quot;&gt;Group Resources&lt;/fo:block&gt;&#10;
+    &lt;xsl:for-each select=&quot;$node&quot;&gt;&#10;
+      &lt;fo:block&gt;&lt;/fo:block&gt; &lt;!--            &lt;fo:block&gt;&#x2022;&lt;/fo:block&gt;--&gt;&#10;
+      &lt;fo:block background-color=&quot;(#ccccff)&quot;&gt;&#10;
+        &lt;xsl:value-of select=&quot;@name&quot;/&gt;&#10;
+      &lt;/fo:block&gt;&#10;
+    &lt;/xsl:for-each&gt;&#10;
+  &lt;/xsl:template&gt;&#10;
+&#10;
+&lt;/xsl:stylesheet&gt;&#10;"/>
+  
+  <Report id="0062ea9c-924d-4ecf-9961-4492a8cc6d1b" name="test" active="1" template_id="sample"/>
+  <Implementation id="UserReportletConf" type="REPORTLET" engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.report.UserReportletConf","name":"testUserReportlet","matchingCond":null,"plainAttrs":["fullname","gender"],"derAttrs":["cn"],"virAttrs":["virtualdata"],"features":["key","username","status","creationDate","lastLoginDate","changePwdDate","passwordHistorySize","failedLoginCount","memberships","resources"]}'/>
+  <ReportReportlet report_id="0062ea9c-924d-4ecf-9961-4492a8cc6d1b" implementation_id="UserReportletConf"/>
+  <ReportExec report_id="0062ea9c-924d-4ecf-9961-4492a8cc6d1b" id="c13f39c5-0d35-4bff-ba79-3cd5de940369"
+              status="SUCCESS" startDate="2012-02-26 15:40:04" endDate="2012-02-26 15:41:04"/>
+
+  <Report id="c3520ad9-179f-49e7-b315-d684d216dd97" name="reconciliation" active="1" template_id="empty"/>
+  <Implementation id="ReconciliationReportletConf" type="REPORTLET" engine="JAVA"
+                  body='{"@class":"org.apache.syncope.common.lib.report.ReconciliationReportletConf","name":"dashboardReconciliationReportlet","userMatchingCond":null,"groupMatchingCond":null,"anyObjectMatchingCond":null,"features":["key","username","groupName"]}'/>
+  <ReportReportlet report_id="c3520ad9-179f-49e7-b315-d684d216dd97" implementation_id="ReconciliationReportletConf"/>
+  
+  <SyncopeLogger logName="syncope.audit.[LOGIC]:[SyncopeLogic]:[]:[isSelfRegAllowed]:[SUCCESS]" logLevel="DEBUG" logType="AUDIT"/>
+  
+  <SecurityQuestion id="887028ea-66fc-41e7-b397-620d7ea6dfbb" content="What's your mother's maiden name?"/>
+</dataset>
diff --git a/core/persistence-jpa-pgjsonb/src/test/resources/persistenceTest.xml b/core/persistence-jpa-pgjsonb/src/test/resources/persistenceTest.xml
new file mode 100644
index 0000000..1e84aea
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/test/resources/persistenceTest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                           http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context
+                           http://www.springframework.org/schema/context/spring-context.xsd">
+
+  <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
+    <property name="locations">
+      <list>
+        <value>file:${conf.directory}/persistence.properties</value>
+        <value>file:${conf.directory}/domains/*.properties</value>
+        <value>classpath:security.properties</value>
+      </list>
+    </property>
+    <property name="ignoreResourceNotFound" value="true"/>
+    <property name="ignoreUnresolvablePlaceholders" value="true"/>
+  </bean>
+  
+  <bean class="org.apache.syncope.core.spring.ApplicationContextProvider"/>
+
+  <bean id="adminUser" class="java.lang.String">
+    <constructor-arg value="${adminUser}"/>
+  </bean>
+  <bean id="anonymousUser" class="java.lang.String">
+    <constructor-arg value="${anonymousUser}"/>
+  </bean>
+  
+  <context:component-scan base-package="org.apache.syncope.core.spring.security"/>
+
+  <bean class="org.apache.syncope.core.spring.security.DefaultPasswordGenerator"/>
+
+  <import resource="persistenceContext.xml"/>
+
+</beans>
diff --git a/core/persistence-jpa-pgjsonb/src/test/resources/simplelogger.properties b/core/persistence-jpa-pgjsonb/src/test/resources/simplelogger.properties
new file mode 100644
index 0000000..929ded2
--- /dev/null
+++ b/core/persistence-jpa-pgjsonb/src/test/resources/simplelogger.properties
@@ -0,0 +1,22 @@
+# 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.
+
+# See http://www.slf4j.org/api/org/slf4j/impl/SimpleLogger.html
+# Possible values: "trace", "debug", "info", "warn", or "error"
+org.slf4j.simpleLogger.defaultLogLevel=debug
+org.slf4j.simpleLogger.log.org.springframework.jdbc.core.JdbcTemplate=error
+
diff --git a/core/pom.xml b/core/pom.xml
index 0c430b4..57d8941 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -79,6 +79,7 @@ under the License.
   <modules>
     <module>persistence-api</module>
     <module>persistence-jpa</module>
+    <module>persistence-jpa-pgjsonb</module>
     <module>spring</module>
     <module>provisioning-api</module>
     <module>provisioning-java</module>