syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [22/32] syncope git commit: [SYNCOPE-620] JPA entities + basic tests
Date Thu, 01 Jan 2015 18:12:17 GMT
http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUDerAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUDerAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUDerAttr.java
new file mode 100644
index 0000000..868b263
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUDerAttr.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.user;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.ManyToOne;
+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.user.UDerAttr;
+import org.apache.syncope.persistence.api.entity.user.UDerSchema;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.persistence.jpa.entity.AbstractDerAttr;
+
+@Entity
+@Table(name = JPAUDerAttr.TABLE)
+public class JPAUDerAttr extends AbstractDerAttr implements UDerAttr {
+
+    private static final long serialVersionUID = 4723044452807292060L;
+
+    public static final String TABLE = "UDerAttr";
+
+    @ManyToOne
+    private JPAUser owner;
+
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAUDerSchema derSchema;
+
+    @Override
+    public User getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Attributable<?, ?, ?> owner) {
+        checkType(owner, JPAUser.class);
+        this.owner = (JPAUser) owner;
+    }
+
+    @Override
+    public UDerSchema getSchema() {
+        return derSchema;
+    }
+
+    @Override
+    public void setSchema(final DerSchema derSchema) {
+        checkType(derSchema, JPAUDerSchema.class);
+        this.derSchema = (JPAUDerSchema) derSchema;
+    }
+}

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

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUMapping.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUMapping.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUMapping.java
new file mode 100644
index 0000000..f778eeb
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUMapping.java
@@ -0,0 +1,125 @@
+/*
+ * 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.user;
+
+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.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.persistence.api.entity.user.UMapping;
+import org.apache.syncope.persistence.api.entity.user.UMappingItem;
+import org.apache.syncope.persistence.jpa.entity.AbstractMapping;
+import org.apache.syncope.persistence.jpa.entity.JPAExternalResource;
+import org.identityconnectors.framework.common.objects.OperationalAttributes;
+
+@Entity
+@Table(name = JPAUMapping.TABLE)
+public class JPAUMapping extends AbstractMapping<UMappingItem> implements UMapping {
+
+    private static final long serialVersionUID = 4285801404504561073L;
+
+    public static final String TABLE = "UMapping";
+
+    @Id
+    private Long id;
+
+    /**
+     * Resource owning this mapping.
+     */
+    @OneToOne
+    private JPAExternalResource resource;
+
+    /**
+     * Attribute mappings.
+     */
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "mapping")
+    private List<JPAUMappingItem> items;
+
+    public JPAUMapping() {
+        super();
+
+        items = new ArrayList<>();
+    }
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public ExternalResource getResource() {
+        return resource;
+    }
+
+    @Override
+    public void setResource(final ExternalResource resource) {
+        checkType(resource, JPAExternalResource.class);
+        this.resource = (JPAExternalResource) resource;
+    }
+
+    @Override
+    public void setAccountIdItem(final UMappingItem item) {
+        checkType(item, JPAUMappingItem.class);
+        this.addAccountIdItem((JPAUMappingItem) item);
+    }
+
+    @Override
+    public UMappingItem getPasswordItem() {
+        UMappingItem passwordItem = null;
+        for (MappingItem item : getItems()) {
+            if (item.isPassword()) {
+                passwordItem = (JPAUMappingItem) item;
+            }
+        }
+        return passwordItem;
+    }
+
+    @Override
+    public boolean setPasswordItem(final UMappingItem passwordItem) {
+        checkType(passwordItem, JPAUMappingItem.class);
+
+        passwordItem.setExtAttrName(OperationalAttributes.PASSWORD_NAME);
+        passwordItem.setPassword(true);
+        return this.addItem((JPAUMappingItem) passwordItem);
+    }
+
+    @Override
+    public List<? extends UMappingItem> getItems() {
+        return items;
+    }
+
+    @Override
+    public boolean addItem(final UMappingItem item) {
+        checkType(item, JPAUMappingItem.class);
+        return items.contains((JPAUMappingItem) item) || items.add((JPAUMappingItem) item);
+    }
+
+    @Override
+    public boolean removeItem(final UMappingItem item) {
+        checkType(item, JPAUMappingItem.class);
+        return items.remove((JPAUMappingItem) item);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUMappingItem.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUMappingItem.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUMappingItem.java
new file mode 100644
index 0000000..47aa4e9
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUMappingItem.java
@@ -0,0 +1,58 @@
+/*
+ * 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.user;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.Mapping;
+import org.apache.syncope.persistence.api.entity.user.UMappingItem;
+import org.apache.syncope.persistence.jpa.entity.AbstractMappingItem;
+
+@Entity
+@Table(name = JPAUMappingItem.TABLE)
+public class JPAUMappingItem extends AbstractMappingItem implements UMappingItem {
+
+    private static final long serialVersionUID = 2936446317887310833L;
+
+    public static final String TABLE = "UMappingItem";
+
+    @Id
+    private Long id;
+
+    @ManyToOne
+    private JPAUMapping mapping;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public Mapping<UMappingItem> getMapping() {
+        return mapping;
+    }
+
+    @Override
+    public void setMapping(final Mapping<?> mapping) {
+        checkType(mapping, JPAUMapping.class);
+        this.mapping = (JPAUMapping) mapping;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttr.java
new file mode 100644
index 0000000..7f32ae3
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttr.java
@@ -0,0 +1,147 @@
+/*
+ * 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.user;
+
+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.user.UPlainAttr;
+import org.apache.syncope.persistence.api.entity.user.UPlainAttrUniqueValue;
+import org.apache.syncope.persistence.api.entity.user.UPlainAttrValue;
+import org.apache.syncope.persistence.api.entity.user.UPlainSchema;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttr;
+
+@Entity
+@Table(name = JPAUPlainAttr.TABLE)
+public class JPAUPlainAttr extends AbstractPlainAttr implements UPlainAttr {
+
+    private static final long serialVersionUID = 6333601983691157406L;
+
+    public static final String TABLE = "UPlainAttr";
+
+    /**
+     * Auto-generated id for this table.
+     */
+    @Id
+    private Long id;
+
+    /**
+     * The owner of this attribute.
+     */
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAUser owner;
+
+    /**
+     * The schema of this attribute.
+     */
+    @ManyToOne(fetch = FetchType.EAGER)
+    @JoinColumn(name = "schema_name")
+    private JPAUPlainSchema schema;
+
+    /**
+     * Values of this attribute (if schema is not UNIQUE).
+     */
+    @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true, mappedBy = "attribute")
+    @Valid
+    private List<JPAUPlainAttrValue> values;
+
+    /**
+     * Value of this attribute (if schema is UNIQUE).
+     */
+    @OneToOne(cascade = CascadeType.ALL, mappedBy = "attribute")
+    @Valid
+    private JPAUPlainAttrUniqueValue uniqueValue;
+
+    /**
+     * Default constructor.
+     */
+    public JPAUPlainAttr() {
+        super();
+        values = new ArrayList<>();
+    }
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public User getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Attributable<?, ?, ?> owner) {
+        checkType(owner, JPAUser.class);
+        this.owner = (JPAUser) owner;
+    }
+
+    @Override
+    public UPlainSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        checkType(schema, JPAUPlainSchema.class);
+        this.schema = (JPAUPlainSchema) schema;
+    }
+
+    @Override
+    protected boolean addValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, JPAUPlainAttrValue.class);
+        return values.add((JPAUPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public boolean removeValue(final PlainAttrValue attrValue) {
+        checkType(attrValue, JPAUPlainAttrValue.class);
+        return values.remove((JPAUPlainAttrValue) attrValue);
+    }
+
+    @Override
+    public List<? extends UPlainAttrValue> getValues() {
+        return values;
+    }
+
+    @Override
+    public UPlainAttrUniqueValue getUniqueValue() {
+        return uniqueValue;
+    }
+
+    @Override
+    public void setUniqueValue(final PlainAttrUniqueValue uniqueValue) {
+        checkType(uniqueValue, JPAUPlainAttrUniqueValue.class);
+        this.uniqueValue = (JPAUPlainAttrUniqueValue) 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/user/JPAUPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttrUniqueValue.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttrUniqueValue.java
new file mode 100644
index 0000000..d65c569
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttrUniqueValue.java
@@ -0,0 +1,79 @@
+/*
+ * 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.user;
+
+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.user.UPlainAttr;
+import org.apache.syncope.persistence.api.entity.user.UPlainAttrUniqueValue;
+import org.apache.syncope.persistence.api.entity.user.UPlainSchema;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@Entity
+@Table(name = JPAUPlainAttrUniqueValue.TABLE)
+public class JPAUPlainAttrUniqueValue extends AbstractPlainAttrValue implements UPlainAttrUniqueValue {
+
+    private static final long serialVersionUID = -64080804563305387L;
+
+    public static final String TABLE = "UPlainAttrUniqueValue";
+
+    @Id
+    private Long id;
+
+    @OneToOne(optional = false)
+    private JPAUPlainAttr attribute;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "schema_name")
+    private JPAUPlainSchema schema;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public UPlainAttr getAttr() {
+        return attribute;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr attr) {
+        checkType(attr, JPAUPlainAttr.class);
+        this.attribute = (JPAUPlainAttr) attr;
+    }
+
+    @Override
+    public UPlainSchema getSchema() {
+        return schema;
+    }
+
+    @Override
+    public void setSchema(final PlainSchema schema) {
+        checkType(schema, JPAUPlainSchema.class);
+        this.schema = (JPAUPlainSchema) 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/user/JPAUPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttrValue.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttrValue.java
new file mode 100644
index 0000000..6f97915
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainAttrValue.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.user;
+
+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.user.UPlainAttr;
+import org.apache.syncope.persistence.api.entity.user.UPlainAttrValue;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttrValue;
+
+@Entity
+@Table(name = JPAUPlainAttrValue.TABLE)
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+public class JPAUPlainAttrValue extends AbstractPlainAttrValue implements UPlainAttrValue {
+
+    private static final long serialVersionUID = -6259576015647897446L;
+
+    public static final String TABLE = "UPlainAttrValue";
+
+    @Id
+    private Long id;
+
+    @ManyToOne
+    @NotNull
+    private JPAUPlainAttr attribute;
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    public UPlainAttr getAttr() {
+        return attribute;
+    }
+
+    @Override
+    public void setAttr(final PlainAttr attr) {
+        checkType(attr, JPAUPlainAttr.class);
+        this.attribute = (JPAUPlainAttr) 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/user/JPAUPlainSchema.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainSchema.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainSchema.java
new file mode 100644
index 0000000..1054a59
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUPlainSchema.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.user;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import org.apache.syncope.persistence.api.entity.user.UPlainSchema;
+import org.apache.syncope.persistence.jpa.entity.AbstractPlainSchema;
+
+@Entity
+@Table(name = JPAUPlainSchema.TABLE)
+@Cacheable
+public class JPAUPlainSchema extends AbstractPlainSchema implements UPlainSchema {
+
+    public static final String TABLE = "UPlainSchema";
+
+    private static final long serialVersionUID = -7272127460142463237L;
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUVirAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUVirAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUVirAttr.java
new file mode 100644
index 0000000..06770d5
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUVirAttr.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.user;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.ManyToOne;
+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.user.UVirAttr;
+import org.apache.syncope.persistence.api.entity.user.UVirSchema;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.persistence.jpa.entity.AbstractVirAttr;
+
+@Entity
+@Table(name = JPAUVirAttr.TABLE)
+public class JPAUVirAttr extends AbstractVirAttr implements UVirAttr {
+
+    private static final long serialVersionUID = 2943450934283989741L;
+
+    public static final String TABLE = "UVirAttr";
+
+    @ManyToOne
+    private JPAUser owner;
+
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAUVirSchema virSchema;
+
+    @Override
+    public User getOwner() {
+        return owner;
+    }
+
+    @Override
+    public void setOwner(final Attributable<?, ?, ?> owner) {
+        checkType(owner, JPAUser.class);
+        this.owner = (JPAUser) owner;
+    }
+
+    @Override
+    public UVirSchema getSchema() {
+        return virSchema;
+    }
+
+    @Override
+    public void setSchema(final VirSchema virSchema) {
+        checkType(virSchema, JPAUVirSchema.class);
+        this.virSchema = (JPAUVirSchema) virSchema;
+    }
+}

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

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java
new file mode 100644
index 0000000..ec28d6c
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java
@@ -0,0 +1,536 @@
+/*
+ * 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.user;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.persistence.Basic;
+import javax.persistence.Cacheable;
+import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.Lob;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+import javax.validation.Valid;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import org.apache.syncope.common.lib.types.CipherAlgorithm;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+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.SecurityQuestion;
+import org.apache.syncope.persistence.api.entity.user.UDerAttr;
+import org.apache.syncope.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.persistence.api.entity.user.UVirAttr;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.persistence.jpa.validation.entity.UserCheck;
+import org.apache.syncope.persistence.jpa.entity.AbstractSubject;
+import org.apache.syncope.persistence.jpa.entity.JPAExternalResource;
+import org.apache.syncope.persistence.jpa.entity.membership.JPAMembership;
+import org.apache.syncope.server.security.Encryptor;
+import org.apache.syncope.server.security.SecureRandomUtil;
+
+/**
+ * Syncope user bean.
+ */
+@Entity
+@Table(name = JPAUser.TABLE)
+@Cacheable
+@UserCheck
+public class JPAUser extends AbstractSubject<UPlainAttr, UDerAttr, UVirAttr> implements User {
+
+    private static final long serialVersionUID = -3905046855521446823L;
+
+    public static final String TABLE = "SyncopeUser";
+
+    @Id
+    private Long id;
+
+    @Column(nullable = true)
+    private String password;
+
+    @Transient
+    private String clearPassword;
+
+    @OneToMany(cascade = CascadeType.MERGE, mappedBy = "user")
+    @Valid
+    private List<JPAMembership> memberships;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @Valid
+    private List<JPAUPlainAttr> plainAttrs;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @Valid
+    private List<JPAUDerAttr> derAttrs;
+
+    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @Valid
+    private List<JPAUVirAttr> virAttrs;
+
+    private String workflowId;
+
+    @Column(nullable = true)
+    private String status;
+
+    @Lob
+    private String token;
+
+    @Temporal(TemporalType.TIMESTAMP)
+    private Date tokenExpireTime;
+
+    @Column(nullable = true)
+    @Enumerated(EnumType.STRING)
+    private CipherAlgorithm cipherAlgorithm;
+
+    @ElementCollection
+    @Column(name = "passwordHistoryValue")
+    @CollectionTable(name = "SyncopeUser_passwordHistory",
+            joinColumns =
+            @JoinColumn(name = "SyncopeUser_id", referencedColumnName = "id"))
+    private List<String> passwordHistory;
+
+    /**
+     * Subsequent failed logins.
+     */
+    @Column(nullable = true)
+    private Integer failedLogins;
+
+    /**
+     * Username/Login.
+     */
+    @Column(unique = true)
+    @NotNull(message = "Blank username")
+    private String username;
+
+    /**
+     * Last successful login date.
+     */
+    @Column(nullable = true)
+    @Temporal(TemporalType.TIMESTAMP)
+    private Date lastLoginDate;
+
+    /**
+     * Change password date.
+     */
+    @Column(nullable = true)
+    @Temporal(TemporalType.TIMESTAMP)
+    private Date changePwdDate;
+
+    @Basic
+    @Min(0)
+    @Max(1)
+    private Integer suspended;
+
+    /**
+     * Provisioning external resources.
+     */
+    @ManyToMany(fetch = FetchType.EAGER)
+    @JoinTable(joinColumns =
+            @JoinColumn(name = "user_id"),
+            inverseJoinColumns =
+            @JoinColumn(name = "resource_name"))
+    @Valid
+    private Set<JPAExternalResource> resources;
+
+    @ManyToOne(fetch = FetchType.EAGER, optional = true)
+    private SecurityQuestion securityQuestion;
+
+    @Column(nullable = true)
+    private String securityAnswer;
+
+    public JPAUser() {
+        super();
+
+        memberships = new ArrayList<>();
+        plainAttrs = new ArrayList<>();
+        derAttrs = new ArrayList<>();
+        virAttrs = new ArrayList<>();
+        passwordHistory = new ArrayList<>();
+        failedLogins = 0;
+        suspended = getBooleanAsInteger(Boolean.FALSE);
+        resources = new HashSet<>();
+    }
+
+    @Override
+    public Long getKey() {
+        return id;
+    }
+
+    @Override
+    protected Set<? extends ExternalResource> internalGetResources() {
+        return resources;
+    }
+
+    @Override
+    public boolean addMembership(final Membership membership) {
+        checkType(membership, JPAMembership.class);
+        return memberships.contains((JPAMembership) membership) || memberships.add((JPAMembership) membership);
+    }
+
+    @Override
+    public boolean removeMembership(final Membership membership) {
+        return memberships.remove(membership);
+    }
+
+    @Override
+    public Membership getMembership(final Long syncopeRoleId) {
+        Membership result = null;
+        Membership membership;
+        for (Iterator<? extends Membership> itor = getMemberships().iterator(); result == null && itor.hasNext();) {
+            membership = itor.next();
+            if (membership.getRole() != null && syncopeRoleId.equals(membership.getRole().getKey())) {
+                result = membership;
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public List<? extends Membership> getMemberships() {
+        return memberships;
+    }
+
+    @Override
+    public List<Role> getRoles() {
+        List<Role> result = new ArrayList<>();
+
+        for (Membership membership : memberships) {
+            if (membership.getRole() != null) {
+                result.add(membership.getRole());
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public Set<Long> getRoleIds() {
+        List<Role> roles = getRoles();
+
+        Set<Long> result = new HashSet<>(roles.size());
+        for (Role role : roles) {
+            result.add(role.getKey());
+        }
+
+        return result;
+    }
+
+    @Override
+    public Set<ExternalResource> getResources() {
+        Set<ExternalResource> result = new HashSet<>();
+        result.addAll(super.getResources());
+        for (Role role : getRoles()) {
+            result.addAll(role.getResources());
+        }
+
+        return result;
+    }
+
+    @Override
+    public Set<? extends ExternalResource> getOwnResources() {
+        return super.getResources();
+    }
+
+    @Override
+    public String getPassword() {
+        return password;
+    }
+
+    @Override
+    public String getClearPassword() {
+        return clearPassword;
+    }
+
+    @Override
+    public void removeClearPassword() {
+        clearPassword = null;
+    }
+
+    @Override
+    public void setEncodedPassword(final String password, final CipherAlgorithm cipherAlgoritm) {
+        // clear password
+        this.clearPassword = null;
+
+        this.password = password;
+        this.cipherAlgorithm = cipherAlgoritm;
+    }
+
+    @Override
+    public void setPassword(final String password, final CipherAlgorithm cipherAlgoritm) {
+        // clear password
+        this.clearPassword = password;
+
+        try {
+            this.password = Encryptor.getInstance().encode(password, cipherAlgoritm);
+            this.cipherAlgorithm = cipherAlgoritm;
+        } catch (Exception e) {
+            LOG.error("Could not encode password", e);
+            this.password = null;
+        }
+    }
+
+    @Override
+    public CipherAlgorithm getCipherAlgorithm() {
+        return cipherAlgorithm;
+    }
+
+    @Override
+    public boolean canDecodePassword() {
+        return this.cipherAlgorithm != null && this.cipherAlgorithm.isInvertible();
+    }
+
+    @Override
+    public boolean addPlainAttr(final UPlainAttr attr) {
+        checkType(attr, JPAUPlainAttr.class);
+        return plainAttrs.add((JPAUPlainAttr) attr);
+    }
+
+    @Override
+    public boolean removePlainAttr(final UPlainAttr attr) {
+        checkType(attr, JPAUPlainAttr.class);
+        return plainAttrs.remove((JPAUPlainAttr) attr);
+    }
+
+    @Override
+    public List<? extends UPlainAttr> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public boolean addDerAttr(final UDerAttr attr) {
+        checkType(attr, JPAUDerAttr.class);
+        return derAttrs.add((JPAUDerAttr) attr);
+    }
+
+    @Override
+    public boolean removeDerAttr(final UDerAttr attr) {
+        checkType(attr, JPAUDerAttr.class);
+        return derAttrs.remove((JPAUDerAttr) attr);
+    }
+
+    @Override
+    public List<? extends UDerAttr> getDerAttrs() {
+        return derAttrs;
+    }
+
+    @Override
+    public boolean addVirAttr(final UVirAttr attr) {
+        checkType(attr, JPAUVirAttr.class);
+        return virAttrs.add((JPAUVirAttr) attr);
+    }
+
+    @Override
+    public boolean removeVirAttr(final UVirAttr attr) {
+        checkType(attr, JPAUVirAttr.class);
+        return virAttrs.remove((JPAUVirAttr) attr);
+    }
+
+    @Override
+    public List<? extends UVirAttr> getVirAttrs() {
+        return virAttrs;
+    }
+
+    @Override
+    public String getWorkflowId() {
+        return workflowId;
+    }
+
+    @Override
+    public void setWorkflowId(final String workflowId) {
+        this.workflowId = workflowId;
+    }
+
+    @Override
+    public String getStatus() {
+        return status;
+    }
+
+    @Override
+    public void setStatus(final String status) {
+        this.status = status;
+    }
+
+    @Override
+    public void generateToken(final int tokenLength, final int tokenExpireTime) {
+        this.token = SecureRandomUtil.generateRandomPassword(tokenLength);
+
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.MINUTE, tokenExpireTime);
+        this.tokenExpireTime = calendar.getTime();
+    }
+
+    @Override
+    public void removeToken() {
+        this.token = null;
+        this.tokenExpireTime = null;
+    }
+
+    @Override
+    public String getToken() {
+        return token;
+    }
+
+    @Override
+    public Date getTokenExpireTime() {
+        return tokenExpireTime == null
+                ? null
+                : new Date(tokenExpireTime.getTime());
+    }
+
+    @Override
+    public boolean checkToken(final String token) {
+        return this.token == null || this.token.equals(token) && !hasTokenExpired();
+    }
+
+    @Override
+    public boolean hasTokenExpired() {
+        return tokenExpireTime == null
+                ? false
+                : tokenExpireTime.before(new Date());
+    }
+
+    @Override
+    public void setCipherAlgorithm(final CipherAlgorithm cipherAlgorithm) {
+        this.cipherAlgorithm = cipherAlgorithm;
+    }
+
+    @Override
+    public List<String> getPasswordHistory() {
+        return passwordHistory;
+    }
+
+    @Override
+    public Date getChangePwdDate() {
+        return changePwdDate == null
+                ? null
+                : new Date(changePwdDate.getTime());
+    }
+
+    @Override
+    public void setChangePwdDate(final Date changePwdDate) {
+        this.changePwdDate = changePwdDate == null
+                ? null
+                : new Date(changePwdDate.getTime());
+    }
+
+    @Override
+    public Integer getFailedLogins() {
+        return failedLogins == null ? 0 : failedLogins;
+    }
+
+    @Override
+    public void setFailedLogins(final Integer failedLogins) {
+        this.failedLogins = failedLogins;
+    }
+
+    @Override
+    public Date getLastLoginDate() {
+        return lastLoginDate == null
+                ? null
+                : new Date(lastLoginDate.getTime());
+    }
+
+    @Override
+    public void setLastLoginDate(final Date lastLoginDate) {
+        this.lastLoginDate = lastLoginDate == null
+                ? null
+                : new Date(lastLoginDate.getTime());
+    }
+
+    @Override
+    public String getUsername() {
+        return username;
+    }
+
+    @Override
+    public void setUsername(final String username) {
+        this.username = username;
+    }
+
+    @Override
+    public void setSuspended(final Boolean suspended) {
+        this.suspended = getBooleanAsInteger(suspended);
+    }
+
+    @Override
+    public Boolean isSuspended() {
+        return suspended == null ? null : isBooleanAsInteger(suspended);
+    }
+
+    @Override
+    public boolean verifyPasswordHistory(final String password, final int size) {
+        boolean res = false;
+
+        if (size > 0) {
+            try {
+                res = passwordHistory.subList(size >= passwordHistory.size()
+                        ? 0
+                        : passwordHistory.size() - size, passwordHistory.size()).contains(cipherAlgorithm == null
+                                        ? password
+                                        : Encryptor.getInstance().encode(password, cipherAlgorithm));
+            } catch (Exception e) {
+                LOG.error("Error evaluating password history", e);
+            }
+        }
+
+        return res;
+    }
+
+    @Override
+    public SecurityQuestion getSecurityQuestion() {
+        return securityQuestion;
+    }
+
+    @Override
+    public void setSecurityQuestion(final SecurityQuestion securityQuestion) {
+        this.securityQuestion = securityQuestion;
+    }
+
+    @Override
+    public String getSecurityAnswer() {
+        return securityAnswer;
+    }
+
+    @Override
+    public void setSecurityAnswer(final String securityAnswer) {
+        this.securityAnswer = securityAnswer;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/AbstractValidator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/AbstractValidator.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/AbstractValidator.java
new file mode 100644
index 0000000..6ebfb15
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/AbstractValidator.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.persistence.jpa.validation.entity;
+
+import java.lang.annotation.Annotation;
+import java.util.regex.Pattern;
+import javax.validation.ConstraintValidator;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractValidator<A extends Annotation, T> implements ConstraintValidator<A, T> {
+
+    /**
+     * Logger.
+     */
+    protected static final Logger LOG = LoggerFactory.getLogger(AbstractValidator.class);
+
+    protected static final Pattern NAME_PATTERN =
+            Pattern.compile("^[\\w \\-@.]+", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
+
+    @Override
+    public void initialize(final A annotation) {
+        // no initialization
+    }
+
+    protected final String getTemplate(final EntityViolationType type, final String message) {
+        return type.name() + ";" + message;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceCheck.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceCheck.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceCheck.java
new file mode 100644
index 0000000..f96cd8f
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceCheck.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.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 = ConnInstanceValidator.class)
+@Documented
+public @interface ConnInstanceCheck {
+
+    String message() default "{org.apache.syncope.persistence.validation.connninstance}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.java
new file mode 100644
index 0000000..ba60ae4
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.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.validation.entity;
+
+import javax.validation.ConstraintValidatorContext;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.persistence.api.entity.ConnInstance;
+import org.apache.syncope.persistence.jpa.entity.JPAConnPoolConf;
+import org.apache.syncope.server.utils.URIUtil;
+import org.apache.syncope.provisioning.api.ConnPoolConfUtil;
+
+public class ConnInstanceValidator extends AbstractValidator<ConnInstanceCheck, ConnInstance> {
+
+    @Override
+    public boolean isValid(final ConnInstance connInstance, final ConstraintValidatorContext context) {
+        boolean isValid = true;
+
+        try {
+            URIUtil.buildForConnId(connInstance.getLocation());
+        } catch (Exception e) {
+            LOG.error("While validating {}", connInstance.getLocation(), e);
+
+            context.disableDefaultConstraintViolation();
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidConnInstanceLocation, e.getMessage())).
+                    addPropertyNode("location").addConstraintViolation();
+
+            isValid = false;
+        }
+
+        if (isValid && connInstance.getPoolConf() != null) {
+            try {
+                ConnPoolConfUtil.getObjectPoolConfiguration(connInstance.getPoolConf()).validate();
+            } catch (Exception e) {
+                LOG.error("Invalid pool configuration", e);
+
+                context.disableDefaultConstraintViolation();
+                context.buildConstraintViolationWithTemplate(
+                        getTemplate(EntityViolationType.InvalidConnPoolConf, e.getMessage())).
+                        addPropertyNode("poolConf").addConstraintViolation();
+
+                isValid = false;
+            }
+        }
+
+        return isValid;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/EntityValidationListener.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/EntityValidationListener.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/EntityValidationListener.java
new file mode 100644
index 0000000..4836e87
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/EntityValidationListener.java
@@ -0,0 +1,51 @@
+/*
+ * 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.validation.entity;
+
+import java.util.Set;
+import javax.persistence.PrePersist;
+import javax.persistence.PreUpdate;
+import javax.validation.ConstraintViolation;
+import javax.validation.Validator;
+import org.apache.syncope.persistence.api.attrvalue.validation.InvalidEntityException;
+import org.apache.syncope.server.spring.ApplicationContextProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * JPA validation listener implementing bean validation.
+ */
+public class EntityValidationListener {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(EntityValidationListener.class);
+
+    @PrePersist
+    @PreUpdate
+    public void validate(final Object object) {
+        final Validator validator = ApplicationContextProvider.getApplicationContext().getBean(Validator.class);
+        Set<ConstraintViolation<Object>> violations = validator.validate(object);
+        if (!violations.isEmpty()) {
+            LOG.warn("Bean validation errors found: {}", violations);
+            throw new InvalidEntityException(object.getClass().getSimpleName(), violations);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ExternalResourceCheck.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ExternalResourceCheck.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ExternalResourceCheck.java
new file mode 100644
index 0000000..f2f3843
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ExternalResourceCheck.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.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 = ExternalResourceValidator.class)
+@Documented
+public @interface ExternalResourceCheck {
+
+    String message() default "{org.apache.syncope.persistence.validation.externalresource}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ExternalResourceValidator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ExternalResourceValidator.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ExternalResourceValidator.java
new file mode 100644
index 0000000..db4fb94
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ExternalResourceValidator.java
@@ -0,0 +1,130 @@
+/*
+ * 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.validation.entity;
+
+import javax.validation.ConstraintValidatorContext;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.Mapping;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.provisioning.api.propagation.PropagationActions;
+
+public class ExternalResourceValidator extends AbstractValidator<ExternalResourceCheck, ExternalResource> {
+
+    private boolean isValid(final MappingItem item, final ConstraintValidatorContext context) {
+        if (StringUtils.isBlank(item.getExtAttrName())) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, item + ".extAttrName is null")).
+                    addPropertyNode("extAttrName").addConstraintViolation();
+
+            return false;
+        }
+
+        if (StringUtils.isBlank(item.getIntAttrName())) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, item + ".intAttrName is null")).
+                    addPropertyNode("intAttrName").addConstraintViolation();
+
+            return false;
+        }
+
+        if (item.getPurpose() == null) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, item + ".purpose is null")).
+                    addPropertyNode("purpose").addConstraintViolation();
+
+            return false;
+        }
+
+        return true;
+    }
+
+    private boolean isValid(final Mapping<?> mapping, final ConstraintValidatorContext context) {
+        if (mapping == null) {
+            return true;
+        }
+
+        int accountIds = 0;
+        for (MappingItem item : mapping.getItems()) {
+            if (item.isAccountid()) {
+                accountIds++;
+            }
+        }
+        if (accountIds != 1) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, "One and only one accountId mapping is needed")).
+                    addPropertyNode("accountId.size").addConstraintViolation();
+            return false;
+        }
+
+        boolean isValid = true;
+
+        int passwords = 0;
+        for (MappingItem item : mapping.getItems()) {
+            isValid &= isValid(item, context);
+
+            if (item.isPassword()) {
+                passwords++;
+            }
+        }
+        if (passwords > 1) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidMapping, "One and only one password mapping is allowed")).
+                    addPropertyNode("password.size").addConstraintViolation();
+            isValid = false;
+        }
+
+        return isValid;
+    }
+
+    @Override
+    public boolean isValid(final ExternalResource resource, final ConstraintValidatorContext context) {
+        context.disableDefaultConstraintViolation();
+
+        if (!NAME_PATTERN.matcher(resource.getKey()).matches()) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidName, "Invalid Resource name")).
+                    addPropertyNode("name").addConstraintViolation();
+            return false;
+        }
+
+        if (!resource.getPropagationActionsClassNames().isEmpty()) {
+            for (String className : resource.getPropagationActionsClassNames()) {
+                Class<?> actionsClass = null;
+                boolean isAssignable = false;
+                try {
+                    actionsClass = Class.forName(className);
+                    isAssignable = PropagationActions.class.isAssignableFrom(actionsClass);
+                } catch (Exception e) {
+                    LOG.error("Invalid PropagationActions specified: {}", className, e);
+                }
+
+                if (actionsClass == null || !isAssignable) {
+                    context.buildConstraintViolationWithTemplate(
+                            getTemplate(EntityViolationType.InvalidResource, "Invalid actions class name")).
+                            addPropertyNode("actionsClassName").addConstraintViolation();
+                    return false;
+                }
+            }
+        }
+
+        return isValid(resource.getUmapping(), context) && isValid(resource.getRmapping(), context);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/NotificationCheck.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/NotificationCheck.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/NotificationCheck.java
new file mode 100644
index 0000000..cee0bde
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/NotificationCheck.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.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 = NotificationValidator.class)
+@Documented
+public @interface NotificationCheck {
+
+    String message() default "{org.apache.syncope.persistence.validation.notification}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/NotificationValidator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/NotificationValidator.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/NotificationValidator.java
new file mode 100644
index 0000000..fe815c8
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/NotificationValidator.java
@@ -0,0 +1,59 @@
+/*
+ * 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.validation.entity;
+
+import java.util.regex.Matcher;
+import javax.validation.ConstraintValidatorContext;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.persistence.api.entity.Notification;
+
+public class NotificationValidator extends AbstractValidator<NotificationCheck, Notification> {
+
+    @Override
+    public boolean isValid(final Notification value, final ConstraintValidatorContext context) {
+        context.disableDefaultConstraintViolation();
+
+        boolean isValid = true;
+
+        if (value.getEvents().isEmpty()) {
+            isValid = false;
+
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidNotification, "No events")).
+                    addPropertyNode("events").addConstraintViolation();
+        }
+
+        if (!value.getStaticRecipients().isEmpty()) {
+            for (String mail : value.getStaticRecipients()) {
+                Matcher matcher = SyncopeConstants.EMAIL_PATTERN.matcher(mail);
+                if (!matcher.matches()) {
+                    LOG.error("Invalid mail address: {}", mail);
+                    isValid = false;
+
+                    context.buildConstraintViolationWithTemplate(
+                            getTemplate(EntityViolationType.InvalidNotification, "Invalid mail address: " + mail)).
+                            addPropertyNode("staticRecipients").addConstraintViolation();
+                }
+            }
+        }
+
+        return isValid;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrCheck.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrCheck.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrCheck.java
new file mode 100644
index 0000000..4381013
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrCheck.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.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 = PlainAttrValidator.class)
+@Documented
+public @interface PlainAttrCheck {
+
+    String message() default "{org.apache.syncope.syncope.validation.attr}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValidator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValidator.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValidator.java
new file mode 100644
index 0000000..88fcbfc
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValidator.java
@@ -0,0 +1,59 @@
+/*
+ * 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.validation.entity;
+
+import javax.validation.ConstraintValidatorContext;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+
+public class PlainAttrValidator extends AbstractValidator<PlainAttrCheck, PlainAttr> {
+
+    @Override
+    public boolean isValid(final PlainAttr object, final ConstraintValidatorContext context) {
+        boolean isValid;
+
+        if (object == null) {
+            isValid = true;
+        } else {
+            if (object.getSchema().isUniqueConstraint()) {
+                isValid = object.getValues().isEmpty() && object.getUniqueValue() != null;
+            } else {
+                isValid = !object.getValues().isEmpty() && object.getUniqueValue() == null;
+
+                if (!object.getSchema().isMultivalue()) {
+                    isValid &= object.getValues().size() == 1;
+                }
+            }
+
+            if (!isValid) {
+                LOG.error("Invalid values for attribute " + object + ": " + "schema=" + object.getSchema().getKey()
+                        + ", " + "values={}", object.getValuesAsStrings());
+
+                context.disableDefaultConstraintViolation();
+
+                context.buildConstraintViolationWithTemplate(
+                        getTemplate(EntityViolationType.InvalidValueList,
+                                "Invalid values " + object.getValuesAsStrings())).
+                        addPropertyNode(object.getSchema().getKey()).addConstraintViolation();
+            }
+        }
+
+        return isValid;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValueCheck.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValueCheck.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValueCheck.java
new file mode 100644
index 0000000..17cf362
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValueCheck.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.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 = PlainAttrValueValidator.class)
+@Documented
+public @interface PlainAttrValueCheck {
+
+    String message() default "{org.apache.syncope.persistence.validation.attrvalue}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValueValidator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValueValidator.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValueValidator.java
new file mode 100644
index 0000000..f68bb66
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainAttrValueValidator.java
@@ -0,0 +1,98 @@
+/*
+ * 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.validation.entity;
+
+import javax.validation.ConstraintValidatorContext;
+import org.apache.syncope.common.lib.types.EntityViolationType;
+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.MPlainSchema;
+import org.apache.syncope.persistence.api.entity.role.RPlainSchema;
+import org.apache.syncope.persistence.api.entity.user.UPlainSchema;
+
+public class PlainAttrValueValidator extends AbstractValidator<PlainAttrValueCheck, PlainAttrValue> {
+
+    @Override
+    public boolean isValid(final PlainAttrValue object, final ConstraintValidatorContext context) {
+        boolean isValid;
+
+        if (object == null) {
+            isValid = true;
+        } else {
+            int nonNullVales = 0;
+            if (object.getBooleanValue() != null) {
+                nonNullVales++;
+            }
+            if (object.getDateValue() != null) {
+                nonNullVales++;
+            }
+            if (object.getDoubleValue() != null) {
+                nonNullVales++;
+            }
+            if (object.getLongValue() != null) {
+                nonNullVales++;
+            }
+            if (object.getBinaryValue() != null) {
+                nonNullVales++;
+            }
+            if (object.getStringValue() != null) {
+                nonNullVales++;
+            }
+            isValid = nonNullVales == 1;
+
+            if (!isValid) {
+                LOG.error("More than one non-null value for " + object);
+
+                context.disableDefaultConstraintViolation();
+                context.buildConstraintViolationWithTemplate(
+                        getTemplate(EntityViolationType.MoreThanOneNonNull, "More than one non-null value found")).
+                        addPropertyNode(object.getClass().getSimpleName().replaceAll("\\n", " ")).
+                        addConstraintViolation();
+
+            } else if (object instanceof PlainAttrUniqueValue) {
+                PlainSchema uniqueValueSchema = ((PlainAttrUniqueValue) object).getSchema();
+                PlainSchema attrSchema = object.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);
+
+                    EntityViolationType violationType = attrSchema instanceof UPlainSchema
+                            ? EntityViolationType.InvalidUPlainSchema
+                            : attrSchema instanceof RPlainSchema
+                                    ? EntityViolationType.InvalidRPlainSchema
+                                    : attrSchema instanceof MPlainSchema
+                                            ? EntityViolationType.InvalidMPlainSchema
+                                            : EntityViolationType.InvalidCPlainSchema;
+
+                    context.disableDefaultConstraintViolation();
+                    context.buildConstraintViolationWithTemplate(getTemplate(violationType,
+                            "Unique value schema is " + uniqueValueSchema
+                            + ", while owning attribute schema is " + attrSchema)).addPropertyNode("schema").
+                            addConstraintViolation();
+                }
+            }
+        }
+
+        return isValid;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/556d5186/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainSchemaCheck.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainSchemaCheck.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainSchemaCheck.java
new file mode 100644
index 0000000..fd25842
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/PlainSchemaCheck.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.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 = PlainSchemaValidator.class)
+@Documented
+public @interface PlainSchemaCheck {
+
+    String message() default "{org.apache.syncope.persistence.validation.schema}";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}


Mime
View raw message