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

[24/32] syncope git commit: [SYNCOPE-620] JPA entities + basic tests

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPasswordPolicy.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPasswordPolicy.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPasswordPolicy.java
new file mode 100644
index 0000000..1f0ee3a
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPasswordPolicy.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.persistence.jpa.entity;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+
+@Entity
+@DiscriminatorValue("PasswordPolicy")
+public class JPAPasswordPolicy extends JPAPolicy implements PasswordPolicy {
+
+    private static final long serialVersionUID = 9138550910385232849L;
+
+    public JPAPasswordPolicy() {
+        this(false);
+    }
+
+    public JPAPasswordPolicy(boolean global) {
+        super();
+
+        this.type = global
+                ? PolicyType.GLOBAL_PASSWORD
+                : PolicyType.PASSWORD;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPolicy.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPolicy.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPolicy.java
new file mode 100644
index 0000000..af0ab0a
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPolicy.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.persistence.jpa.entity;
+
+import javax.persistence.DiscriminatorColumn;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.Lob;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import org.apache.syncope.common.lib.types.PolicySpec;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.syncope.persistence.api.entity.Policy;
+import org.apache.syncope.persistence.jpa.validation.entity.PolicyCheck;
+import org.apache.syncope.server.utils.serialization.POJOHelper;
+
+@Entity
+@Table(name = JPAPolicy.TABLE)
+@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
+@DiscriminatorColumn(name = "DTYPE")
+@PolicyCheck
+public abstract class JPAPolicy extends AbstractEntity<Long> implements Policy {
+
+    private static final long serialVersionUID = -5844833125843247458L;
+
+    public static final String TABLE = "Policy";
+
+    @Id
+    private Long id;
+
+    @NotNull
+    private String description;
+
+    @NotNull
+    @Enumerated(EnumType.STRING)
+    protected PolicyType type;
+
+    @Lob
+    private String specification;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public void setDescription(final String description) {
+        this.description = description;
+    }
+
+    @Override
+    public PolicyType getType() {
+        return type;
+    }
+
+    @Override
+    public <T extends PolicySpec> T getSpecification(final Class<T> reference) {
+        return POJOHelper.deserialize(specification, reference);
+    }
+
+    @Override
+    public void setSpecification(final PolicySpec policy) {
+        this.specification = POJOHelper.serialize(policy);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java
new file mode 100644
index 0000000..1a661a9
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java
@@ -0,0 +1,42 @@
+/*
+ * 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.persistence.jpa.entity;
+
+import javax.persistence.Entity;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.syncope.persistence.api.entity.PushPolicy;
+
+@Entity
+public class JPAPushPolicy extends JPAPolicy implements PushPolicy {
+
+    private static final long serialVersionUID = -6090413855809521279L;
+
+    public JPAPushPolicy() {
+        this(false);
+    }
+
+    public JPAPushPolicy(final boolean global) {
+        super();
+
+        this.type = global
+                ? PolicyType.GLOBAL_PUSH
+                : PolicyType.PUSH;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReport.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReport.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReport.java
new file mode 100644
index 0000000..3fcdd63
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReport.java
@@ -0,0 +1,150 @@
+/*
+ * 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.persistence.jpa.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.persistence.api.entity.Report;
+import org.apache.syncope.persistence.api.entity.ReportExec;
+import org.apache.syncope.persistence.jpa.validation.entity.ReportCheck;
+
+@Entity
+@Table(name = JPAReport.TABLE)
+@ReportCheck
+public class JPAReport extends AbstractEntity<Long> implements Report {
+
+    private static final long serialVersionUID = -587652654964285834L;
+
+    public static final String TABLE = "Report";
+
+    @Id
+    private Long id;
+
+    @Column(unique = true, nullable = false)
+    private String name;
+
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "report")
+    private List<JPAReportletConfInstance> reportletConfs;
+
+    private String cronExpression;
+
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "report")
+    private List<JPAReportExec> executions;
+
+    public JPAReport() {
+        super();
+
+        reportletConfs = new ArrayList<>();
+        executions = new ArrayList<>();
+    }
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    @Override
+    public boolean addExec(final ReportExec exec) {
+        checkType(exec, JPAReportExec.class);
+        return exec != null && !executions.contains((JPAReportExec) exec) && executions.add((JPAReportExec) exec);
+    }
+
+    @Override
+    public boolean removeExec(final ReportExec exec) {
+        checkType(exec, JPAReportExec.class);
+        return exec != null && executions.remove((JPAReportExec) exec);
+    }
+
+    @Override
+    public List<? extends ReportExec> getExecs() {
+        return executions;
+    }
+
+    @Override
+    public boolean addReportletConf(final ReportletConf reportletConf) {
+        if (reportletConf == null) {
+            return false;
+        }
+
+        JPAReportletConfInstance instance = new JPAReportletConfInstance();
+        instance.setReport(this);
+        instance.setInstance(reportletConf);
+
+        return reportletConfs.add(instance);
+    }
+
+    @Override
+    public boolean removeReportletConf(final ReportletConf reportletConf) {
+        if (reportletConf == null) {
+            return false;
+        }
+
+        checkType(reportletConf, JPAReportletConfInstance.class);
+
+        JPAReportletConfInstance found = null;
+        for (JPAReportletConfInstance instance : reportletConfs) {
+            if (reportletConf.equals(instance.getInstance())) {
+                found = instance;
+            }
+        }
+
+        return found == null
+                ? false
+                : reportletConfs.remove(found);
+    }
+
+    @Override
+    public List<ReportletConf> getReportletConfs() {
+        List<ReportletConf> result = new ArrayList<>(reportletConfs.size());
+
+        for (JPAReportletConfInstance instance : reportletConfs) {
+            result.add(instance.getInstance());
+        }
+
+        return result;
+    }
+
+    @Override
+    public String getCronExpression() {
+        return cronExpression;
+    }
+
+    @Override
+    public void setCronExpression(final String cronExpression) {
+        this.cronExpression = cronExpression;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReportExec.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReportExec.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReportExec.java
new file mode 100644
index 0000000..9f9be18
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReportExec.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.persistence.jpa.entity;
+
+import javax.persistence.Basic;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.types.ReportExecStatus;
+import org.apache.syncope.persistence.api.entity.Report;
+import org.apache.syncope.persistence.api.entity.ReportExec;
+
+@Entity
+@Table(name = JPAReportExec.TABLE)
+public class JPAReportExec extends AbstractExec implements ReportExec {
+
+    private static final long serialVersionUID = -6178274296037547769L;
+
+    public static final String TABLE = "ReportExec";
+
+    @Id
+    private Long id;
+
+    /**
+     * The referred report.
+     */
+    @ManyToOne(optional = false)
+    private JPAReport report;
+
+    /**
+     * Report execution result, stored as an XML stream.
+     */
+    @Lob
+    @Basic(fetch = FetchType.LAZY)
+    private Byte[] execResult;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public Report getReport() {
+        return report;
+    }
+
+    @Override
+    public void setReport(final Report report) {
+        checkType(report, JPAReport.class);
+        this.report = (JPAReport) report;
+    }
+
+    @Override
+    public byte[] getExecResult() {
+        return execResult == null ? null : ArrayUtils.toPrimitive(execResult);
+    }
+
+    @Override
+    public void setExecResult(final byte[] execResult) {
+        this.execResult = execResult == null ? null : ArrayUtils.toObject(execResult);
+    }
+
+    @Override
+    public void setStatus(final ReportExecStatus status) {
+        super.setStatus(status.name());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReportletConfInstance.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReportletConfInstance.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReportletConfInstance.java
new file mode 100644
index 0000000..dbe3cf2
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAReportletConfInstance.java
@@ -0,0 +1,77 @@
+/*
+ * 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.persistence.jpa.entity;
+
+import org.apache.syncope.persistence.api.entity.ReportletConfInstance;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.persistence.api.entity.Report;
+import org.apache.syncope.server.utils.serialization.POJOHelper;
+
+@Entity
+@Table(name = JPAReportletConfInstance.TABLE)
+public class JPAReportletConfInstance extends AbstractEntity<Long> implements ReportletConfInstance {
+
+    private static final long serialVersionUID = -2436055132955674610L;
+
+    public static final String TABLE = "ReportletConfInstance";
+
+    @Id
+    private Long id;
+
+    @Lob
+    private String serializedInstance;
+
+    @ManyToOne
+    private JPAReport report;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public Report getReport() {
+        return report;
+    }
+
+    @Override
+    public void setReport(final Report report) {
+        checkType(report, JPAReport.class);
+        this.report = (JPAReport) report;
+    }
+
+    @Override
+    public ReportletConf getInstance() {
+        return serializedInstance == null
+                ? null
+                : POJOHelper.deserialize(serializedInstance, ReportletConf.class);
+    }
+
+    @Override
+    public void setInstance(final ReportletConf instance) {
+        this.serializedInstance = instance == null
+                ? null
+                : POJOHelper.serialize(instance);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java
new file mode 100644
index 0000000..bfe76bc
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java
@@ -0,0 +1,56 @@
+/*
+ * 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.persistence.jpa.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.user.SecurityQuestion;
+
+@Entity
+@Table(name = JPASecurityQuestion.TABLE)
+public class JPASecurityQuestion extends AbstractEntity<Long> implements SecurityQuestion {
+
+    private static final long serialVersionUID = -7646140284033489392L;
+
+    public static final String TABLE = "SecurityQuestion";
+
+    @Id
+    private Long id;
+
+    @Column(unique = true)
+    private String content;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public String getContent() {
+        return content;
+    }
+
+    @Override
+    public void setContent(final String content) {
+        this.content = content;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASyncPolicy.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASyncPolicy.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASyncPolicy.java
new file mode 100644
index 0000000..d78425b
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASyncPolicy.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.persistence.jpa.entity;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.syncope.persistence.api.entity.SyncPolicy;
+
+@Entity
+@DiscriminatorValue("SyncPolicy")
+public class JPASyncPolicy extends JPAPolicy implements SyncPolicy {
+
+    private static final long serialVersionUID = -6090413855809521279L;
+
+    public JPASyncPolicy() {
+        this(false);
+    }
+
+    public JPASyncPolicy(final boolean global) {
+        super();
+
+        this.type = global
+                ? PolicyType.GLOBAL_SYNC
+                : PolicyType.SYNC;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java
new file mode 100644
index 0000000..74c7d66
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java
@@ -0,0 +1,150 @@
+/*
+ * 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.persistence.jpa.entity.conf;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.validation.Valid;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttrUniqueValue;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttrValue;
+import org.apache.syncope.persistence.api.entity.conf.CPlainSchema;
+import org.apache.syncope.persistence.api.entity.conf.Conf;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttr;
+
+/**
+ * Configuration attribute.
+ */
+@Entity
+@Table(name = JPACPlainAttr.TABLE)
+public class JPACPlainAttr extends AbstractPlainAttr implements CPlainAttr {
+
+    private static final long serialVersionUID = 6333601983691157406L;
+
+    public static final String TABLE = "CPlainAttr";
+
+    /**
+     * Auto-generated id for this table.
+     */
+    @Id
+    private Long id;
+
+    /**
+     * The owner of this attribute.
+     */
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAConf owner;
+
+    /**
+     * The schema of this attribute.
+     */
+    @ManyToOne(fetch = FetchType.EAGER)
+    @JoinColumn(name = "schema_name")
+    private JPACPlainSchema schema;
+
+    /**
+     * Values of this attribute (if schema is not UNIQUE).
+     */
+    @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true, mappedBy = "attribute")
+    @Valid
+    private List<JPACPlainAttrValue> values;
+
+    /**
+     * Value of this attribute (if schema is UNIQUE).
+     */
+    @OneToOne(cascade = CascadeType.ALL, mappedBy = "attribute")
+    @Valid
+    private JPACPlainAttrUniqueValue uniqueValue;
+
+    /**
+     * Default constructor.
+     */
+    public JPACPlainAttr() {
+        super();
+        values = new ArrayList<>();
+    }
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public Conf getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Attributable<?, ?, ?> owner) {
+        checkType(owner, JPAConf.class);
+        this.owner = (JPAConf) owner;
+    }
+
+    @Override
+    public CPlainSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        checkType(schema, JPACPlainSchema.class);
+        this.schema = (JPACPlainSchema) schema;
+    }
+
+    @Override
+    protected boolean addValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, JPACPlainAttrValue.class);
+        return values.add((JPACPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public boolean removeValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, JPACPlainAttrValue.class);
+        return values.remove((JPACPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public List<? extends CPlainAttrValue> getValues() {
+        return values;
+    }
+
+    @Override
+    public CPlainAttrUniqueValue getUniqueValue() {
+        return uniqueValue;
+    }
+
+    @Override
+    public void setUniqueValue(final PlainAttrUniqueValue uniqueValue) {
+        checkType(owner, JPACPlainAttrUniqueValue.class);
+        this.uniqueValue = (JPACPlainAttrUniqueValue) uniqueValue;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
new file mode 100644
index 0000000..13e8e04
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.persistence.jpa.entity.conf;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttrUniqueValue;
+import org.apache.syncope.persistence.api.entity.conf.CPlainSchema;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@Entity
+@Table(name = JPACPlainAttrUniqueValue.TABLE)
+public class JPACPlainAttrUniqueValue extends AbstractPlainAttrValue implements CPlainAttrUniqueValue {
+
+    private static final long serialVersionUID = -64080804563305387L;
+
+    public static final String TABLE = "CPlainAttrUniqueValue";
+
+    @Id
+    private Long id;
+
+    @OneToOne(optional = false)
+    private JPACPlainAttr attribute;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "schema_name")
+    private JPACPlainSchema schema;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public CPlainAttr getAttr() {
+        return attribute;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr attr) {
+        checkType(attr, JPACPlainAttr.class);
+        this.attribute = (JPACPlainAttr) attr;
+    }
+
+    @Override
+    public CPlainSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        checkType(schema, JPACPlainSchema.class);
+        this.schema = (JPACPlainSchema) schema;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java
new file mode 100644
index 0000000..70e30f3
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java
@@ -0,0 +1,64 @@
+/*
+ * 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.persistence.jpa.entity.conf;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttrValue;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@Entity
+@Table(name = JPACPlainAttrValue.TABLE)
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+public class JPACPlainAttrValue extends AbstractPlainAttrValue implements CPlainAttrValue {
+
+    private static final long serialVersionUID = -6259576015647897446L;
+
+    public static final String TABLE = "CPlainAttrValue";
+
+    @Id
+    private Long id;
+
+    @ManyToOne
+    @NotNull
+    private JPACPlainAttr attribute;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public CPlainAttr getAttr() {
+        return attribute;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr attr) {
+        checkType(attr, JPACPlainAttr.class);
+        this.attribute = (JPACPlainAttr) attr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainSchema.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainSchema.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainSchema.java
new file mode 100644
index 0000000..e0c4ec8
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainSchema.java
@@ -0,0 +1,36 @@
+/*
+ * 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.persistence.jpa.entity.conf;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.conf.CPlainSchema;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainSchema;
+
+@Entity
+@Table(name = JPACPlainSchema.TABLE)
+@Cacheable
+public class JPACPlainSchema extends AbstractPlainSchema implements CPlainSchema {
+
+    private static final long serialVersionUID = 3363019039331594433L;
+
+    public static final String TABLE = "CPlainSchema";
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java
new file mode 100644
index 0000000..3bfa884
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java
@@ -0,0 +1,116 @@
+/*
+ * 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.persistence.jpa.entity.conf;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.persistence.Cacheable;
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.validation.Valid;
+import org.apache.syncope.persistence.api.entity.DerAttr;
+import org.apache.syncope.persistence.api.entity.VirAttr;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.persistence.api.entity.conf.Conf;
+import org.apache.syncope.persistence.jpa.entity.AbstractAttributable;
+
+@Entity
+@Table(name = JPAConf.TABLE)
+@Cacheable
+public class JPAConf extends AbstractAttributable<CPlainAttr, DerAttr, VirAttr> implements Conf {
+
+    private static final long serialVersionUID = -5281258853142421875L;
+
+    public static final String TABLE = "SyncopeConf";
+
+    @Id
+    private Long id;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @Valid
+    private List<JPACPlainAttr> plainAttrs;
+
+    public JPAConf() {
+        super();
+
+        plainAttrs = new ArrayList<>();
+    }
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public void setKey(final Long key) {
+        this.id = key;
+    }
+
+    @Override
+    public boolean addPlainAttr(final CPlainAttr attr) {
+        checkType(attr, JPACPlainAttr.class);
+        return plainAttrs.add((JPACPlainAttr) attr);
+    }
+
+    @Override
+    public boolean removePlainAttr(final CPlainAttr attr) {
+        checkType(attr, JPACPlainAttr.class);
+        return plainAttrs.remove((JPACPlainAttr) attr);
+    }
+
+    @Override
+    public List<? extends CPlainAttr> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public boolean addDerAttr(final DerAttr attr) {
+        return false;
+    }
+
+    @Override
+    public boolean removeDerAttr(final DerAttr derAttr) {
+        return false;
+    }
+
+    @Override
+    public List<? extends DerAttr> getDerAttrs() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean addVirAttr(final VirAttr attr) {
+        return false;
+    }
+
+    @Override
+    public boolean removeVirAttr(final VirAttr virAttr) {
+        return false;
+    }
+
+    @Override
+    public List<? extends VirAttr> getVirAttrs() {
+        return Collections.emptyList();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttr.java
new file mode 100644
index 0000000..c154e90
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttr.java
@@ -0,0 +1,82 @@
+/*
+ * 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.persistence.jpa.entity.membership;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.DerSchema;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttr;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MDerSchema;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.jpa.entity.AbstractDerAttr;
+
+@Entity
+@Table(name = JPAMDerAttr.TABLE)
+public class JPAMDerAttr extends AbstractDerAttr implements MDerAttr {
+
+    private static final long serialVersionUID = -443509121923448129L;
+
+    public static final String TABLE = "MDerAttr";
+
+    @ManyToOne
+    private JPAMembership owner;
+
+    @Column(nullable = false)
+    @OneToOne(cascade = CascadeType.MERGE)
+    private JPAMDerAttrTemplate template;
+
+    @Override
+    public Membership getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Attributable<?, ?, ?> owner) {
+        checkType(owner, JPAMembership.class);
+        this.owner = (JPAMembership) owner;
+    }
+
+    @Override
+    public MDerAttrTemplate getTemplate() {
+        return template;
+    }
+
+    @Override
+    public void setTemplate(final MDerAttrTemplate template) {
+        checkType(template, JPAMDerAttrTemplate.class);
+        this.template = (JPAMDerAttrTemplate) template;
+    }
+
+    @Override
+    public MDerSchema getSchema() {
+        return template == null ? null : template.getSchema();
+    }
+
+    @Override
+    public void setSchema(final DerSchema schema) {
+        LOG.warn("This is role attribute, set template to select schema");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java
new file mode 100644
index 0000000..7ec7fcf
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.persistence.jpa.entity.membership;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MDerSchema;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.jpa.entity.AbstractAttrTemplate;
+import org.apache.syncope.persistence.jpa.entity.role.JPARole;
+
+@Entity
+@Table(name = JPAMDerAttrTemplate.TABLE)
+public class JPAMDerAttrTemplate extends AbstractAttrTemplate<MDerSchema> implements MDerAttrTemplate {
+
+    private static final long serialVersionUID = -3424574558427502145L;
+
+    public static final String TABLE = "MDerAttrTemplate";
+
+    @ManyToOne
+    private JPARole owner;
+
+    @ManyToOne
+    @JoinColumn(name = "schema_name")
+    private JPAMDerSchema schema;
+
+    @Override
+    public MDerSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final MDerSchema schema) {
+        checkType(schema, JPAMDerSchema.class);
+        this.schema = (JPAMDerSchema) schema;
+    }
+
+    @Override
+    public Role getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Role owner) {
+        checkType(owner, JPARole.class);
+        this.owner = (JPARole) owner;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerSchema.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerSchema.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerSchema.java
new file mode 100644
index 0000000..d3e2e03
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerSchema.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.persistence.jpa.entity.membership;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.membership.MDerSchema;
+import org.apache.syncope.persistence.jpa.entity.AbstractDerSchema;
+
+@Entity
+@Table(name = JPAMDerSchema.TABLE)
+public class JPAMDerSchema extends AbstractDerSchema implements MDerSchema {
+
+    private static final long serialVersionUID = -4694082505732174583L;
+
+    public static final String TABLE = "MDerSchema";
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttr.java
new file mode 100644
index 0000000..38f2b24
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttr.java
@@ -0,0 +1,141 @@
+/*
+ * 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.persistence.jpa.entity.membership;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.validation.Valid;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttr;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrUniqueValue;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrValue;
+import org.apache.syncope.persistence.api.entity.membership.MPlainSchema;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttr;
+
+@Entity
+@Table(name = JPAMPlainAttr.TABLE)
+public class JPAMPlainAttr extends AbstractPlainAttr implements MPlainAttr {
+
+    private static final long serialVersionUID = 3755864809152866489L;
+
+    public static final String TABLE = "MPlainAttr";
+
+    @Id
+    private Long id;
+
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAMembership owner;
+
+    @Column(nullable = false)
+    @OneToOne(cascade = CascadeType.MERGE)
+    private JPAMPlainAttrTemplate template;
+
+    @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true, mappedBy = "attribute")
+    @Valid
+    private List<JPAMPlainAttrValue> values;
+
+    @OneToOne(cascade = CascadeType.ALL, mappedBy = "attribute")
+    @Valid
+    private JPAMPlainAttrUniqueValue uniqueValue;
+
+    public JPAMPlainAttr() {
+        super();
+        values = new ArrayList<>();
+    }
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public Membership getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Attributable<?, ?, ?> owner) {
+        checkType(owner, JPAMembership.class);
+        this.owner = (JPAMembership) owner;
+    }
+
+    @Override
+    public MPlainAttrTemplate getTemplate() {
+        return template;
+    }
+
+    @Override
+    public void setTemplate(final MPlainAttrTemplate template) {
+        checkType(template, JPAMPlainAttrTemplate.class);
+        this.template = (JPAMPlainAttrTemplate) template;
+    }
+
+    @Override
+    public MPlainSchema getSchema() {
+        return template == null ? null : template.getSchema();
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        LOG.warn("This is role attribute, set template to select schema");
+    }
+
+    @Override
+    protected boolean addValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, JPAMPlainAttrValue.class);
+        return values.add((JPAMPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public boolean removeValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, JPAMPlainAttrValue.class);
+        return values.remove((JPAMPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public List<? extends MPlainAttrValue> getValues() {
+        return values;
+    }
+
+    @Override
+    public MPlainAttrUniqueValue getUniqueValue() {
+        return uniqueValue;
+    }
+
+    @Override
+    public void setUniqueValue(final PlainAttrUniqueValue uniqueValue) {
+        checkType(owner, JPAMPlainAttrUniqueValue.class);
+        this.uniqueValue = (JPAMPlainAttrUniqueValue) uniqueValue;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java
new file mode 100644
index 0000000..fb8e728
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java
@@ -0,0 +1,68 @@
+/*
+ * 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.persistence.jpa.entity.membership;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MPlainSchema;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.jpa.entity.AbstractAttrTemplate;
+import org.apache.syncope.persistence.jpa.entity.role.JPARole;
+
+@Entity
+@Table(name = JPAMPlainAttrTemplate.TABLE)
+public class JPAMPlainAttrTemplate extends AbstractAttrTemplate<MPlainSchema> implements MPlainAttrTemplate {
+
+    private static final long serialVersionUID = -3424574558427502145L;
+
+    public static final String TABLE = "MPlainAttrTemplate";
+
+    @ManyToOne
+    private JPARole owner;
+
+    @ManyToOne
+    @JoinColumn(name = "schema_name")
+    private JPAMPlainSchema schema;
+
+    @Override
+    public MPlainSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final MPlainSchema schema) {
+        checkType(schema, JPAMPlainSchema.class);
+        this.schema = (JPAMPlainSchema) schema;
+    }
+
+    @Override
+    public JPARole getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Role owner) {
+        checkType(owner, JPARole.class);
+        this.owner = (JPARole) owner;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrUniqueValue.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrUniqueValue.java
new file mode 100644
index 0000000..344ebc2
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrUniqueValue.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.persistence.jpa.entity.membership;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttr;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrUniqueValue;
+import org.apache.syncope.persistence.api.entity.membership.MPlainSchema;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@Entity
+@Table(name = JPAMPlainAttrUniqueValue.TABLE)
+public class JPAMPlainAttrUniqueValue extends AbstractPlainAttrValue implements MPlainAttrUniqueValue {
+
+    private static final long serialVersionUID = 3985867531873453718L;
+
+    public static final String TABLE = "MPlainAttrUniqueValue";
+
+    @Id
+    private Long id;
+
+    @OneToOne(optional = false)
+    private JPAMPlainAttr attribute;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "schema_name")
+    private JPAMPlainSchema schema;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public MPlainAttr getAttr() {
+        return attribute;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr attr) {
+        checkType(attr, JPAMPlainAttr.class);
+        this.attribute = (JPAMPlainAttr) attr;
+    }
+
+    @Override
+    public MPlainSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        checkType(schema, JPAMPlainSchema.class);
+        this.schema = (JPAMPlainSchema) schema;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrValue.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrValue.java
new file mode 100644
index 0000000..520e244
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrValue.java
@@ -0,0 +1,64 @@
+/*
+ * 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.persistence.jpa.entity.membership;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttr;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrValue;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@Entity
+@Table(name = JPAMPlainAttrValue.TABLE)
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+public class JPAMPlainAttrValue extends AbstractPlainAttrValue implements MPlainAttrValue {
+
+    private static final long serialVersionUID = -7188881172631198385L;
+
+    public static final String TABLE = "MPlainAttrValue";
+
+    @Id
+    private Long id;
+
+    @ManyToOne
+    @NotNull
+    private JPAMPlainAttr attribute;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public MPlainAttr getAttr() {
+        return attribute;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr attr) {
+        checkType(attr, JPAMPlainAttr.class);
+        this.attribute = (JPAMPlainAttr) attr;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainSchema.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainSchema.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainSchema.java
new file mode 100644
index 0000000..e4ba2a9
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainSchema.java
@@ -0,0 +1,36 @@
+/*
+ * 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.persistence.jpa.entity.membership;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.membership.MPlainSchema;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainSchema;
+
+@Entity
+@Table(name = JPAMPlainSchema.TABLE)
+@Cacheable
+public class JPAMPlainSchema extends AbstractPlainSchema implements MPlainSchema {
+
+    private static final long serialVersionUID = -8053736450044590651L;
+
+    public static final String TABLE = "MPlainSchema";
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttr.java
new file mode 100644
index 0000000..4cfe207
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttr.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.persistence.jpa.entity.membership;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.VirSchema;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttr;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MVirSchema;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.jpa.entity.AbstractVirAttr;
+
+@Entity
+@Table(name = JPAMVirAttr.TABLE)
+public class JPAMVirAttr extends AbstractVirAttr implements MVirAttr {
+
+    private static final long serialVersionUID = 7774760571251641332L;
+
+    public static final String TABLE = "MVirAttr";
+
+    @ManyToOne
+    private JPAMembership owner;
+
+    @Column(nullable = false)
+    @OneToOne(cascade = CascadeType.MERGE)
+    private JPAMVirAttrTemplate template;
+
+    @Override
+    public Membership getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Attributable<?, ?, ?> owner) {
+        checkType(owner, JPAMembership.class);
+        this.owner = (JPAMembership) owner;
+    }
+
+    @Override
+    public MVirAttrTemplate getTemplate() {
+        return template;
+    }
+
+    @Override
+    public void setTemplate(final MVirAttrTemplate template) {
+        checkType(template, JPAMVirAttrTemplate.class);
+        this.template = (JPAMVirAttrTemplate) template;
+    }
+
+    @Override
+    public MVirSchema getSchema() {
+        return template == null ? null : template.getSchema();
+    }
+
+    @Override
+    public void setSchema(final VirSchema schema) {
+        LOG.warn("This is role attribute, set template to select schema");
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java
new file mode 100644
index 0000000..7bd60db
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.persistence.jpa.entity.membership;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MVirSchema;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.jpa.entity.AbstractAttrTemplate;
+import org.apache.syncope.persistence.jpa.entity.role.JPARole;
+
+@Entity
+@Table(name = JPAMVirAttrTemplate.TABLE)
+public class JPAMVirAttrTemplate extends AbstractAttrTemplate<MVirSchema> implements MVirAttrTemplate {
+
+    private static final long serialVersionUID = -3424574558427502145L;
+
+    public static final String TABLE = "MVirAttrTemplate";
+
+    @ManyToOne
+    private JPARole owner;
+
+    @ManyToOne
+    @JoinColumn(name = "schema_name")
+    private JPAMVirSchema schema;
+
+    @Override
+    public MVirSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final MVirSchema schema) {
+        checkType(schema, JPAMVirSchema.class);
+        this.schema = (JPAMVirSchema) schema;
+    }
+
+    @Override
+    public Role getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Role role) {
+        checkType(role, JPARole.class);
+        this.owner = (JPARole) role;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirSchema.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirSchema.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirSchema.java
new file mode 100644
index 0000000..78b0358
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirSchema.java
@@ -0,0 +1,36 @@
+/*
+ * 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.persistence.jpa.entity.membership;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.membership.MVirSchema;
+import org.apache.syncope.persistence.jpa.entity.AbstractVirSchema;
+
+@Entity
+@Table(name = JPAMVirSchema.TABLE)
+@Cacheable
+public class JPAMVirSchema extends AbstractVirSchema implements MVirSchema {
+
+    private static final long serialVersionUID = 6255905733563668766L;
+
+    public static final String TABLE = "MVirSchema";
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMembership.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMembership.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMembership.java
new file mode 100644
index 0000000..5f7cef3
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMembership.java
@@ -0,0 +1,195 @@
+/*
+ * 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.persistence.jpa.entity.membership;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import javax.validation.Valid;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttr;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttr;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttr;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.persistence.jpa.entity.AbstractAttributable;
+import org.apache.syncope.persistence.jpa.entity.role.JPARole;
+import org.apache.syncope.persistence.jpa.entity.user.JPAUser;
+
+@Entity
+@Table(name = JPAMembership.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "user_id", "role_id" }))
+public class JPAMembership extends AbstractAttributable<MPlainAttr, MDerAttr, MVirAttr> implements Membership {
+
+    private static final long serialVersionUID = 5030106264797289469L;
+
+    public static final String TABLE = "Membership";
+
+    @Id
+    private Long id;
+
+    @ManyToOne
+    private JPAUser user;
+
+    @ManyToOne
+    private JPARole role;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @Valid
+    private List<JPAMPlainAttr> plainAttrs;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @Valid
+    private List<JPAMDerAttr> derAttrs;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @Valid
+    private List<JPAMVirAttr> virAttrs;
+
+    public JPAMembership() {
+        super();
+
+        plainAttrs = new ArrayList<>();
+        derAttrs = new ArrayList<>();
+        virAttrs = new ArrayList<>();
+    }
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public Role getRole() {
+        return role;
+    }
+
+    @Override
+    public void setRole(final Role role) {
+        checkType(role, JPARole.class);
+        this.role = (JPARole) role;
+    }
+
+    @Override
+    public User getUser() {
+        return user;
+    }
+
+    @Override
+    public void setUser(final User user) {
+        checkType(user, JPAUser.class);
+        this.user = (JPAUser) user;
+    }
+
+    @Override
+    public boolean addPlainAttr(final MPlainAttr attr) {
+        checkType(attr, JPAMPlainAttr.class);
+        return plainAttrs.add((JPAMPlainAttr) attr);
+    }
+
+    @Override
+    public boolean removePlainAttr(final MPlainAttr attr) {
+        checkType(attr, JPAMPlainAttr.class);
+        return plainAttrs.remove((JPAMPlainAttr) attr);
+    }
+
+    @Override
+    public List<? extends MPlainAttr> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public boolean addDerAttr(final MDerAttr derAttr) {
+        checkType(derAttr, JPAMDerAttr.class);
+
+        if (getRole() != null && derAttr.getSchema() != null) {
+            MDerAttrTemplate found = null;
+            for (MDerAttrTemplate template : getRole().findInheritedTemplates(MDerAttrTemplate.class)) {
+                if (derAttr.getSchema().equals(template.getSchema())) {
+                    found = template;
+                }
+            }
+            if (found != null) {
+                derAttr.setTemplate(found);
+                return derAttrs.add((JPAMDerAttr) derAttr);
+            }
+        }
+
+        LOG.warn("Attribute not added because either role was not yet set, "
+                + "schema was not specified or no template for that schema is available");
+        return false;
+    }
+
+    @Override
+    public boolean removeDerAttr(final MDerAttr derAttr) {
+        checkType(derAttr, JPAMDerAttr.class);
+        return derAttrs.remove((JPAMDerAttr) derAttr);
+    }
+
+    @Override
+    public List<? extends MDerAttr> getDerAttrs() {
+        return derAttrs;
+    }
+
+    @Override
+    public boolean addVirAttr(final MVirAttr virAttr) {
+        checkType(virAttr, JPAMVirAttr.class);
+
+        if (getRole() != null && virAttr.getSchema() != null) {
+            MVirAttrTemplate found = null;
+            for (MVirAttrTemplate template : getRole().findInheritedTemplates(MVirAttrTemplate.class)) {
+                if (virAttr.getSchema().equals(template.getSchema())) {
+                    found = template;
+                }
+            }
+            if (found != null) {
+                virAttr.setTemplate(found);
+                return virAttrs.add((JPAMVirAttr) virAttr);
+            }
+        }
+
+        LOG.warn("Attribute not added because either "
+                + "schema was not specified or no template for that schema is available");
+        return false;
+    }
+
+    @Override
+    public boolean removeVirAttr(final MVirAttr virAttr) {
+        checkType(virAttr, JPAMVirAttr.class);
+        return virAttrs.remove((JPAMVirAttr) virAttr);
+    }
+
+    @Override
+    public List<? extends MVirAttr> getVirAttrs() {
+        return virAttrs;
+    }
+
+    @Override
+    public String toString() {
+        return "Membership[" + "id=" + id + ", " + user + ", " + role + ']';
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttr.java
new file mode 100644
index 0000000..a4dbd7a
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttr.java
@@ -0,0 +1,82 @@
+/*
+ * 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.persistence.jpa.entity.role;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.DerSchema;
+import org.apache.syncope.persistence.api.entity.role.RDerAttr;
+import org.apache.syncope.persistence.api.entity.role.RDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RDerSchema;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.jpa.entity.AbstractDerAttr;
+
+@Entity
+@Table(name = JPARDerAttr.TABLE)
+public class JPARDerAttr extends AbstractDerAttr implements RDerAttr {
+
+    private static final long serialVersionUID = 8007080005675899946L;
+
+    public static final String TABLE = "RDerAttr";
+
+    @ManyToOne
+    private JPARole owner;
+
+    @Column(nullable = false)
+    @OneToOne(cascade = CascadeType.MERGE)
+    private JPARDerAttrTemplate template;
+
+    @Override
+    public Role getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Attributable<?, ?, ?> owner) {
+        checkType(owner, JPARole.class);
+        this.owner = (JPARole) owner;
+    }
+
+    @Override
+    public RDerAttrTemplate getTemplate() {
+        return template;
+    }
+
+    @Override
+    public void setTemplate(final RDerAttrTemplate template) {
+        checkType(template, JPARDerAttrTemplate.class);
+        this.template = (JPARDerAttrTemplate) template;
+    }
+
+    @Override
+    public RDerSchema getSchema() {
+        return template == null ? null : template.getSchema();
+    }
+
+    @Override
+    public void setSchema(final DerSchema schema) {
+        LOG.warn("This is role attribute, set template to select schema");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java
new file mode 100644
index 0000000..ba565a7
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java
@@ -0,0 +1,66 @@
+/*
+ * 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.persistence.jpa.entity.role;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.role.RDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RDerSchema;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.jpa.entity.AbstractAttrTemplate;
+
+@Entity
+@Table(name = JPARDerAttrTemplate.TABLE)
+public class JPARDerAttrTemplate extends AbstractAttrTemplate<RDerSchema> implements RDerAttrTemplate {
+
+    private static final long serialVersionUID = -3424574558427502145L;
+
+    public static final String TABLE = "RDerAttrTemplate";
+
+    @ManyToOne
+    private JPARole owner;
+
+    @ManyToOne
+    @JoinColumn(name = "schema_name")
+    private JPARDerSchema schema;
+
+    @Override
+    public RDerSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final RDerSchema schema) {
+        checkType(schema, JPARDerSchema.class);
+        this.schema = (JPARDerSchema) schema;
+    }
+
+    @Override
+    public Role getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Role owner) {
+        checkType(owner, JPARole.class);
+        this.owner = (JPARole) owner;
+    }
+}