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/02/12 10:14:41 UTC
[36/54] [abbrv] [partial] syncope git commit: [SYNCOPE-620] Renaming
'server' after 'core',
to provide continuity with older releases (especially for archetype)
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
new file mode 100644
index 0000000..c08e1a2
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Resource;
+import javax.persistence.NoResultException;
+import javax.persistence.TypedQuery;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.core.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.RoleDAO;
+import org.apache.syncope.core.persistence.api.dao.SubjectSearchDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.search.AttributeCond;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.core.persistence.api.dao.search.SubjectCond;
+import org.apache.syncope.core.persistence.api.entity.AttributableUtilFactory;
+import org.apache.syncope.core.persistence.api.entity.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.Subject;
+import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.membership.Membership;
+import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.core.persistence.api.entity.user.UDerAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUser;
+import org.apache.syncope.core.misc.security.AuthContextUtil;
+import org.apache.syncope.core.misc.security.UnauthorizedRoleException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+@Repository
+public class JPAUserDAO extends AbstractSubjectDAO<UPlainAttr, UDerAttr, UVirAttr> implements UserDAO {
+
+ @Autowired
+ private SubjectSearchDAO searchDAO;
+
+ @Autowired
+ private RoleDAO roleDAO;
+
+ @Resource(name = "anonymousUser")
+ private String anonymousUser;
+
+ @Autowired
+ private AttributableUtilFactory attrUtilFactory;
+
+ @Override
+ protected Subject<UPlainAttr, UDerAttr, UVirAttr> findInternal(Long key) {
+ return find(key);
+ }
+
+ @Override
+ public User find(final Long key) {
+ TypedQuery<User> query = entityManager.createQuery(
+ "SELECT e FROM " + JPAUser.class.getSimpleName() + " e WHERE e.id = :id", User.class);
+ query.setParameter("id", key);
+
+ User result = null;
+ try {
+ result = query.getSingleResult();
+ } catch (NoResultException e) {
+ LOG.debug("No user found with id {}", key, e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public User find(final String username) {
+ TypedQuery<User> query = entityManager.createQuery("SELECT e FROM " + JPAUser.class.getSimpleName()
+ + " e WHERE e.username = :username", User.class);
+ query.setParameter("username", username);
+
+ User result = null;
+ try {
+ result = query.getSingleResult();
+ } catch (NoResultException e) {
+ LOG.debug("No user found with username {}", username, e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public User findByWorkflowId(final String workflowId) {
+ TypedQuery<User> query = entityManager.createQuery("SELECT e FROM " + JPAUser.class.getSimpleName()
+ + " e WHERE e.workflowId = :workflowId", User.class);
+ query.setParameter("workflowId", workflowId);
+
+ User result = null;
+ try {
+ result = query.getSingleResult();
+ } catch (NoResultException e) {
+ LOG.debug("No user found with workflow id {}", workflowId, e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public User findByToken(final String token) {
+ TypedQuery<User> query = entityManager.createQuery("SELECT e FROM " + JPAUser.class.getSimpleName()
+ + " e WHERE e.token LIKE :token", User.class);
+ query.setParameter("token", token);
+
+ User result = null;
+ try {
+ result = query.getSingleResult();
+ } catch (NoResultException e) {
+ LOG.debug("No user found with token {}", token, e);
+ }
+
+ return result;
+ }
+
+ @Override
+ public List<User> findBySecurityQuestion(final SecurityQuestion securityQuestion) {
+ TypedQuery<User> query = entityManager.createQuery("SELECT e FROM " + JPAUser.class.getSimpleName()
+ + " e WHERE e.securityQuestion = :securityQuestion", User.class);
+ query.setParameter("securityQuestion", securityQuestion);
+
+ return query.getResultList();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<User> findByAttrValue(final String schemaName, final UPlainAttrValue attrValue) {
+ return (List<User>) findByAttrValue(
+ schemaName, attrValue, attrUtilFactory.getInstance(AttributableType.USER));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public User findByAttrUniqueValue(final String schemaName, final UPlainAttrValue attrUniqueValue) {
+ return (User) findByAttrUniqueValue(schemaName, attrUniqueValue,
+ attrUtilFactory.getInstance(AttributableType.USER));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<User> findByDerAttrValue(final String schemaName, final String value) {
+ return (List<User>) findByDerAttrValue(
+ schemaName, value, attrUtilFactory.getInstance(AttributableType.USER));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<User> findByResource(final ExternalResource resource) {
+ return (List<User>) findByResource(resource, attrUtilFactory.getInstance(AttributableType.USER));
+ }
+
+ @Override
+ public final List<User> findAll(final Set<Long> adminRoles, final int page, final int itemsPerPage) {
+ return findAll(adminRoles, page, itemsPerPage, Collections.<OrderByClause>emptyList());
+ }
+
+ private SearchCond getAllMatchingCond() {
+ SubjectCond idCond = new SubjectCond(AttributeCond.Type.ISNOTNULL);
+ idCond.setSchema("id");
+ return SearchCond.getLeafCond(idCond);
+ }
+
+ @Override
+ public List<User> findAll(final Set<Long> adminRoles,
+ final int page, final int itemsPerPage, final List<OrderByClause> orderBy) {
+
+ return searchDAO.search(
+ adminRoles, getAllMatchingCond(), page, itemsPerPage, orderBy, SubjectType.USER);
+ }
+
+ @Override
+ public final int count(final Set<Long> adminRoles) {
+ return searchDAO.count(adminRoles, getAllMatchingCond(), SubjectType.USER);
+ }
+
+ @Override
+ public User save(final User user) {
+ final User merged = entityManager.merge(user);
+ for (VirAttr virAttr : merged.getVirAttrs()) {
+ virAttr.getValues().clear();
+ virAttr.getValues().addAll(user.getVirAttr(virAttr.getSchema().getKey()).getValues());
+ }
+
+ return merged;
+ }
+
+ @Override
+ public void delete(final Long key) {
+ User user = (User) findInternal(key);
+ if (user == null) {
+ return;
+ }
+
+ delete(user);
+ }
+
+ @Override
+ public void delete(final User user) {
+ // Not calling membershipDAO.delete() here because it would try to save this user as well, thus going into
+ // ConcurrentModificationException
+ for (Membership membership : user.getMemberships()) {
+ membership.setUser(null);
+
+ roleDAO.save(membership.getRole());
+ membership.setRole(null);
+
+ entityManager.remove(membership);
+ }
+ user.getMemberships().clear();
+
+ entityManager.remove(user);
+ }
+
+ private void securityChecks(final User user) {
+ // Allows anonymous (during self-registration) and self (during self-update) to read own user,
+ // otherwise goes thorugh security checks to see if needed role entitlements are owned
+ if (!AuthContextUtil.getAuthenticatedUsername().equals(anonymousUser)
+ && !AuthContextUtil.getAuthenticatedUsername().equals(user.getUsername())) {
+
+ Set<Long> roleKeys = user.getRoleKeys();
+ Set<Long> adminRoleKeys = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+ roleKeys.removeAll(adminRoleKeys);
+ if (!roleKeys.isEmpty()) {
+ throw new UnauthorizedRoleException(roleKeys);
+ }
+ }
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public User authFetch(final Long key) {
+ if (key == null) {
+ throw new NotFoundException("Null user id");
+ }
+
+ User user = find(key);
+ if (user == null) {
+ throw new NotFoundException("User " + key);
+ }
+
+ securityChecks(user);
+
+ return user;
+ }
+
+ @Transactional(readOnly = true)
+ @Override
+ public User authFetch(final String username) {
+ if (username == null) {
+ throw new NotFoundException("Null username");
+ }
+
+ User user = find(username);
+ if (user == null) {
+ throw new NotFoundException("User " + username);
+ }
+
+ securityChecks(user);
+
+ return user;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirAttrDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirAttrDAO.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirAttrDAO.java
new file mode 100644
index 0000000..2235295
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirAttrDAO.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.List;
+import javax.persistence.TypedQuery;
+import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
+import org.apache.syncope.core.persistence.api.entity.Attributable;
+import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.membership.MVirAttr;
+import org.apache.syncope.core.persistence.api.entity.role.RVirAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractVirAttr;
+import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMVirAttr;
+import org.apache.syncope.core.persistence.jpa.entity.role.JPARVirAttr;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirAttr;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class JPAVirAttrDAO extends AbstractDAO<VirAttr, Long> implements VirAttrDAO {
+
+ public <T extends VirAttr> Class<? extends AbstractVirAttr> getJPAEntityReference(
+ final Class<T> reference) {
+
+ return RVirAttr.class.isAssignableFrom(reference)
+ ? JPARVirAttr.class
+ : MVirAttr.class.isAssignableFrom(reference)
+ ? JPAMVirAttr.class
+ : UVirAttr.class.isAssignableFrom(reference)
+ ? JPAUVirAttr.class
+ : null;
+ }
+
+ @Override
+ public <T extends VirAttr> T find(final Long key, final Class<T> reference) {
+ return reference.cast(entityManager.find(getJPAEntityReference(reference), key));
+ }
+
+ @Override
+ public <T extends VirAttr> List<T> findAll(final Class<T> reference) {
+ TypedQuery<T> query = entityManager.createQuery(
+ "SELECT e FROM " + getJPAEntityReference(reference).getSimpleName() + " e", reference);
+ return query.getResultList();
+ }
+
+ @Override
+ public <T extends VirAttr> T save(final T virAttr) {
+ return entityManager.merge(virAttr);
+ }
+
+ @Override
+ public <T extends VirAttr> void delete(final Long key, final Class<T> reference) {
+ T virAttr = find(key, reference);
+ if (virAttr == null) {
+ return;
+ }
+
+ delete(virAttr);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T extends VirAttr> void delete(final T virAttr) {
+ if (virAttr.getOwner() != null) {
+ ((Attributable<?, ?, T>) virAttr.getOwner()).removeVirAttr(virAttr);
+ }
+
+ entityManager.remove(virAttr);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
new file mode 100644
index 0000000..f7a1e55
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAVirSchemaDAO.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.persistence.TypedQuery;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.core.persistence.api.dao.AttrTemplateDAO;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.VirAttrDAO;
+import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.membership.MVirSchema;
+import org.apache.syncope.core.persistence.api.entity.role.RVirSchema;
+import org.apache.syncope.core.persistence.api.entity.user.UMappingItem;
+import org.apache.syncope.core.persistence.api.entity.user.UVirAttr;
+import org.apache.syncope.core.persistence.api.entity.user.UVirSchema;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractVirSchema;
+import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMVirSchema;
+import org.apache.syncope.core.persistence.jpa.entity.role.JPARVirSchema;
+import org.apache.syncope.core.persistence.jpa.entity.user.JPAUVirSchema;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class JPAVirSchemaDAO extends AbstractDAO<VirSchema, String> implements VirSchemaDAO {
+
+ @Autowired
+ private VirAttrDAO virAttrDAO;
+
+ @Autowired
+ private AttrTemplateDAO<VirSchema> attrTemplateDAO;
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ private <T extends VirSchema> Class<? extends AbstractVirSchema> getJPAEntityReference(final Class<T> reference) {
+ return RVirSchema.class.isAssignableFrom(reference)
+ ? JPARVirSchema.class
+ : MVirSchema.class.isAssignableFrom(reference)
+ ? JPAMVirSchema.class
+ : UVirSchema.class.isAssignableFrom(reference)
+ ? JPAUVirSchema.class
+ : null;
+ }
+
+ @Override
+ public <T extends VirSchema> T find(final String key, final Class<T> reference) {
+ return reference.cast(entityManager.find(getJPAEntityReference(reference), key));
+ }
+
+ @Override
+ public <T extends VirSchema> List<T> findAll(final Class<T> reference) {
+ TypedQuery<T> query = entityManager.createQuery(
+ "SELECT e FROM " + getJPAEntityReference(reference).getSimpleName() + " e", reference);
+ return query.getResultList();
+ }
+
+ @Override
+ public <T extends VirAttr> List<T> findAttrs(final VirSchema schema, final Class<T> reference) {
+ final StringBuilder queryString = new StringBuilder("SELECT e FROM ").
+ append(((JPAVirAttrDAO) virAttrDAO).getJPAEntityReference(reference).getSimpleName()).
+ append(" e WHERE e.");
+ if (UVirAttr.class.isAssignableFrom(reference)) {
+ queryString.append("virSchema");
+ } else {
+ queryString.append("template.schema");
+ }
+ queryString.append("=:schema");
+
+ TypedQuery<T> query = entityManager.createQuery(queryString.toString(), reference);
+ query.setParameter("schema", schema);
+
+ return query.getResultList();
+ }
+
+ @Override
+ public <T extends VirSchema> T save(final T virSchema) {
+ return entityManager.merge(virSchema);
+ }
+
+ @Override
+ public void delete(final String name, final AttributableUtil attributableUtil) {
+ final VirSchema schema = find(name, attributableUtil.virSchemaClass());
+ if (schema == null) {
+ return;
+ }
+
+ final Set<Long> attrIds = new HashSet<>();
+ for (VirAttr attr : findAttrs(schema, attributableUtil.virAttrClass())) {
+ attrIds.add(attr.getKey());
+ }
+ for (Long attrId : attrIds) {
+ virAttrDAO.delete(attrId, attributableUtil.virAttrClass());
+ }
+
+ if (attributableUtil.getType() != AttributableType.USER) {
+ for (Iterator<Number> it = attrTemplateDAO.
+ findBySchemaName(schema.getKey(), attributableUtil.virAttrTemplateClass()).iterator();
+ it.hasNext();) {
+
+ attrTemplateDAO.delete(it.next().longValue(), attributableUtil.virAttrTemplateClass());
+ }
+ }
+
+ resourceDAO.deleteMapping(name, attributableUtil.virIntMappingType(), UMappingItem.class);
+
+ entityManager.remove(schema);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
new file mode 100644
index 0000000..63f442e
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/OrderBySupport.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+class OrderBySupport {
+
+ static class Item {
+
+ protected String select;
+
+ protected String where;
+
+ protected String orderBy;
+
+ protected boolean isEmpty() {
+ return (select == null || select.isEmpty())
+ && (where == null || where.isEmpty())
+ && (orderBy == null || orderBy.isEmpty());
+ }
+ }
+
+ protected Set<SearchSupport.SearchView> views = new HashSet<>();
+
+ protected List<Item> items = new ArrayList<>();
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
new file mode 100644
index 0000000..6922b85
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/SearchSupport.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.dao;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.SubjectType;
+
+class SearchSupport {
+
+ static class SearchView {
+
+ protected String alias;
+
+ protected String name;
+
+ protected SearchView(final String alias, final String name) {
+ this.alias = alias;
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+ }
+
+ private final SubjectType type;
+
+ public SearchSupport(final SubjectType type) {
+ this.type = type;
+ }
+
+ public String fieldName(final AttrSchemaType type) {
+ String result;
+
+ switch (type) {
+ case Boolean:
+ result = "booleanvalue";
+ break;
+
+ case Date:
+ result = "datevalue";
+ break;
+
+ case Double:
+ result = "doublevalue";
+ break;
+
+ case Long:
+ result = "longvalue";
+ break;
+
+ case String:
+ case Enum:
+ result = "stringvalue";
+ break;
+
+ default:
+ result = null;
+ }
+
+ return result;
+ }
+
+ public SearchView field() {
+ String result = "";
+
+ switch (type) {
+ case USER:
+ default:
+ result = "user_search";
+ break;
+
+ case ROLE:
+ result = "role_search";
+ break;
+ }
+
+ return new SearchView("sv", result);
+ }
+
+ public SearchView attr() {
+ return new SearchView("sva", field().name + "_attr");
+ }
+
+ public SearchView membership() {
+ return new SearchView("svm", field().name + "_membership");
+ }
+
+ public SearchView nullAttr() {
+ return new SearchView("svna", field().name + "_null_attr");
+ }
+
+ public SearchView resource() {
+ return new SearchView("svr", field().name + "_resource");
+ }
+
+ public SearchView roleResource() {
+ return new SearchView("svrr", field().name + "_role_resource");
+ }
+
+ public SearchView uniqueAttr() {
+ return new SearchView("svua", field().name + "_unique_attr");
+ }
+
+ public SearchView entitlements() {
+ return new SearchView("sve", field().name + "_entitlements");
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAnnotatedEntity.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAnnotatedEntity.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAnnotatedEntity.java
new file mode 100644
index 0000000..c9bbe77
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAnnotatedEntity.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.Date;
+import javax.persistence.Column;
+import javax.persistence.EntityListeners;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import org.apache.syncope.core.persistence.api.entity.AnnotatedEntity;
+
+/**
+ * Abstract wrapper for common system information.
+ */
+@MappedSuperclass
+@EntityListeners(value = AnnotatedEntityListener.class)
+public abstract class AbstractAnnotatedEntity<KEY> extends AbstractEntity<KEY> implements AnnotatedEntity<KEY> {
+
+ private static final long serialVersionUID = -4801685541488201219L;
+
+ /**
+ * Username of the user that has created this profile.
+ * <br/>
+ * Reference to existing user cannot be used: the creator can either be <tt>admin</tt> or was deleted.
+ */
+ @Column(nullable = false)
+ private String creator;
+
+ /**
+ * Creation date.
+ */
+ @Column(nullable = false)
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date creationDate;
+
+ /**
+ * Username of the user that has performed the last modification to this profile.
+ * <br/>
+ * This field cannot be null: at creation time it needs to be initialized with the creator username.
+ * <br/>
+ * The modifier can be the user itself if the last performed change was a self-modification.
+ * <br/>
+ * Reference to existing user cannot be used: the creator can either be <tt>admin</tt> or was deleted.
+ */
+ @Column(nullable = false)
+ private String lastModifier;
+
+ /**
+ * Last change date.
+ * <br/>
+ * This field cannot be null: at creation time it needs to be initialized with <tt>creationDate</tt> field value.
+ */
+ @Column(nullable = false)
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date lastChangeDate;
+
+ @Override
+ public String getCreator() {
+ return creator;
+ }
+
+ @Override
+ public void setCreator(final String creator) {
+ this.creator = creator;
+ }
+
+ @Override
+ public Date getCreationDate() {
+ return creationDate == null ? null : new Date(creationDate.getTime());
+ }
+
+ @Override
+ public void setCreationDate(final Date creationDate) {
+ this.creationDate = creationDate == null ? null : new Date(creationDate.getTime());
+ }
+
+ @Override
+ public String getLastModifier() {
+ return lastModifier;
+ }
+
+ @Override
+ public void setLastModifier(final String lastModifier) {
+ this.lastModifier = lastModifier;
+ }
+
+ @Override
+ public Date getLastChangeDate() {
+ return lastChangeDate == null ? creationDate : lastChangeDate;
+ }
+
+ @Override
+ public void setLastChangeDate(final Date lastChangeDate) {
+ this.lastChangeDate = lastChangeDate == null ? null : new Date(lastChangeDate.getTime());
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttrTemplate.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttrTemplate.java
new file mode 100644
index 0000000..f2a32a1
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttrTemplate.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import org.apache.syncope.core.persistence.api.entity.AttrTemplate;
+import org.apache.syncope.core.persistence.api.entity.Schema;
+
+public abstract class AbstractAttrTemplate<S extends Schema> extends AbstractEntity<Long> implements AttrTemplate<S> {
+
+ private static final long serialVersionUID = 4829112252713766666L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttributable.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttributable.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttributable.java
new file mode 100644
index 0000000..d648748
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAttributable.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.syncope.core.persistence.api.entity.Attributable;
+import org.apache.syncope.core.persistence.api.entity.DerAttr;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.VirAttr;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+
+public abstract class AbstractAttributable<P extends PlainAttr, D extends DerAttr, V extends VirAttr>
+ extends AbstractAnnotatedEntity<Long> implements Attributable<P, D, V> {
+
+ private static final long serialVersionUID = -4801685541488201119L;
+
+ @Override
+ public P getPlainAttr(final String plainSchemaName) {
+ P result = null;
+ for (P plainAttr : getPlainAttrs()) {
+ if (plainAttr != null && plainAttr.getSchema() != null
+ && plainSchemaName.equals(plainAttr.getSchema().getKey())) {
+
+ result = plainAttr;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public D getDerAttr(final String derSchemaName) {
+ D result = null;
+ for (D derAttr : getDerAttrs()) {
+ if (derAttr != null && derAttr.getSchema() != null
+ && derSchemaName.equals(derAttr.getSchema().getKey())) {
+
+ result = derAttr;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public V getVirAttr(final String virSchemaName) {
+ V result = null;
+ for (V virAttr : getVirAttrs()) {
+ if (virAttr != null && virAttr.getSchema() != null
+ && virSchemaName.equals(virAttr.getSchema().getKey())) {
+
+ result = virAttr;
+ }
+ }
+
+ return result;
+ }
+
+ protected Map<PlainSchema, P> getPlainAttrMap() {
+ final Map<PlainSchema, P> map = new HashMap<>();
+
+ for (P attr : getPlainAttrs()) {
+ map.put(attr.getSchema(), attr);
+ }
+
+ return map;
+ }
+
+ protected Map<DerSchema, D> getDerAttrMap() {
+ final Map<DerSchema, D> map = new HashMap<>();
+
+ for (D attr : getDerAttrs()) {
+ map.put(attr.getSchema(), attr);
+ }
+
+ return map;
+ }
+
+ protected Map<VirSchema, V> getVirAttrMap() {
+ final Map<VirSchema, V> map = new HashMap<>();
+
+ for (V attr : getVirAttrs()) {
+ map.put(attr.getSchema(), attr);
+ }
+
+ return map;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java
new file mode 100644
index 0000000..c43e786
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttr.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.Collection;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import org.apache.syncope.core.persistence.api.entity.DerAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.misc.jexl.JexlUtil;
+
+@MappedSuperclass
+public abstract class AbstractDerAttr extends AbstractEntity<Long> implements DerAttr {
+
+ private static final long serialVersionUID = 4740924251090424771L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ protected Long id;
+
+ @Override
+ public Long getKey() {
+ return id;
+ }
+
+ /**
+ * @param attributes the set of attributes against which evaluate this derived attribute
+ * @return the value of this derived attribute
+ */
+ @Override
+ public String getValue(final Collection<? extends PlainAttr> attributes) {
+ return JexlUtil.evaluate(getSchema().getExpression(), getOwner(), attributes);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttrTemplate.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttrTemplate.java
new file mode 100644
index 0000000..3846b12
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerAttrTemplate.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+
+@MappedSuperclass
+public abstract class AbstractDerAttrTemplate<D extends DerSchema> extends AbstractAttrTemplate<D> {
+
+ private static final long serialVersionUID = 8871895736733379865L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ protected Long id;
+
+ @Override
+ public Long getKey() {
+ return id;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerSchema.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerSchema.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerSchema.java
new file mode 100644
index 0000000..195f41d
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractDerSchema.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.jpa.validation.entity.SchemaNameCheck;
+
+@MappedSuperclass
+@SchemaNameCheck
+public abstract class AbstractDerSchema extends AbstractEntity<String> implements DerSchema {
+
+ private static final long serialVersionUID = -6173643493348674060L;
+
+ @Id
+ private String name;
+
+ @Column(nullable = false)
+ private String expression;
+
+ @Override
+ public String getKey() {
+ return name;
+ }
+
+ @Override
+ public void setKey(final String key) {
+ this.name = key;
+ }
+
+ @Override
+ public String getExpression() {
+ return expression;
+ }
+
+ @Override
+ public void setExpression(final String expression) {
+ this.expression = expression;
+ }
+
+ @Override
+ public AttrSchemaType getType() {
+ return AttrSchemaType.String;
+ }
+
+ @Override
+ public String getMandatoryCondition() {
+ return Boolean.FALSE.toString().toLowerCase();
+ }
+
+ @Override
+ public boolean isMultivalue() {
+ return Boolean.TRUE;
+ }
+
+ @Override
+ public boolean isUniqueConstraint() {
+ return Boolean.FALSE;
+ }
+
+ @Override
+ public boolean isReadonly() {
+ return Boolean.FALSE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractEntity.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractEntity.java
new file mode 100644
index 0000000..dfd706d
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractEntity.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+
+public abstract class AbstractEntity<KEY> implements Entity<KEY> {
+
+ private static final long serialVersionUID = -9017214159540857901L;
+
+ /**
+ * Logger.
+ */
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractEntity.class);
+
+ protected void checkType(final Object object, final Class<?> clazz) {
+ if (object != null && !clazz.isInstance(object)) {
+ throw new ClassCastException("Expected " + clazz.getName() + ", got " + object.getClass().getName());
+ }
+ }
+
+ /**
+ * @param property the integer representing a boolean value
+ * @return the boolean value corresponding to the property param
+ */
+ public final boolean isBooleanAsInteger(final Integer property) {
+ return property != null && property == 1;
+ }
+
+ /**
+ * @param value the boolean value to be represented as integer
+ * @return the integer corresponding to the property param
+ */
+ public final Integer getBooleanAsInteger(final Boolean value) {
+ return Boolean.TRUE.equals(value)
+ ? 1
+ : 0;
+ }
+
+ /**
+ * @return fields to be excluded when computing equals() or hashcode()
+ */
+ private String[] getExcludeFields() {
+ Set<String> excludeFields = new HashSet<>();
+
+ for (PropertyDescriptor propDesc : BeanUtils.getPropertyDescriptors(getClass())) {
+ if (propDesc.getPropertyType().isInstance(Collections.emptySet())
+ || propDesc.getPropertyType().isInstance(Collections.emptyList())) {
+
+ excludeFields.add(propDesc.getName());
+ }
+ }
+
+ return excludeFields.toArray(new String[] {});
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return EqualsBuilder.reflectionEquals(this, obj, getExcludeFields());
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this, getExcludeFields());
+ }
+
+ @Override
+ public String toString() {
+ Method method = BeanUtils.findMethod(getClass(), "getKey");
+
+ StringBuilder result = new StringBuilder().append(getClass().getSimpleName()).append('[');
+ if (method != null) {
+ try {
+ result.append(method.invoke(this));
+ } catch (Exception e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.error("While serializing to string", e);
+ }
+ }
+ }
+ result.append(']');
+
+ return result.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java
new file mode 100644
index 0000000..7e52010
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractExec.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Lob;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import org.apache.syncope.core.persistence.api.entity.Exec;
+
+@MappedSuperclass
+public abstract class AbstractExec extends AbstractEntity<Long> implements Exec {
+
+ private static final long serialVersionUID = -812344822970166317L;
+
+ @Column(nullable = false)
+ protected String status;
+
+ /**
+ * Any information to be accompanied to this execution's result.
+ */
+ @Lob
+ protected String message;
+
+ /**
+ * Start instant of this execution.
+ */
+ @Temporal(TemporalType.TIMESTAMP)
+ protected Date startDate;
+
+ /**
+ * End instant of this execution.
+ */
+ @Temporal(TemporalType.TIMESTAMP)
+ protected Date endDate;
+
+ @Override
+ public String getStatus() {
+ return status;
+ }
+
+ @Override
+ public void setStatus(final String status) {
+ this.status = status;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ * Set a message for this execution, taking care of replacing every null character with newline.
+ *
+ * @param message the message to set for this execution
+ */
+ @Override
+ public void setMessage(String message) {
+ if (message != null) {
+ message = message.replace('\0', '\n');
+ }
+ this.message = message;
+ }
+
+ @Override
+ public Date getEndDate() {
+ return endDate == null
+ ? null
+ : new Date(endDate.getTime());
+ }
+
+ @Override
+
+ public void setEndDate(final Date endDate) {
+ this.endDate = endDate == null
+ ? null
+ : new Date(endDate.getTime());
+ }
+
+ @Override
+
+ public Date getStartDate() {
+ return startDate == null
+ ? null
+ : new Date(startDate.getTime());
+ }
+
+ @Override
+
+ public void setStartDate(final Date startDate) {
+ this.startDate = startDate == null
+ ? null
+ : new Date(startDate.getTime());
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractMapping.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractMapping.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractMapping.java
new file mode 100644
index 0000000..3a85859
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractMapping.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import javax.persistence.Cacheable;
+import javax.persistence.MappedSuperclass;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.core.persistence.api.entity.Mapping;
+import org.apache.syncope.core.persistence.api.entity.MappingItem;
+
+@MappedSuperclass
+@Cacheable
+public abstract class AbstractMapping<T extends MappingItem> extends AbstractEntity<Long> implements Mapping<T> {
+
+ private static final long serialVersionUID = 4316047254916259158L;
+
+ /**
+ * A JEXL expression for determining how to find the account id in external resource's space.
+ */
+ private String accountLink;
+
+ @Override
+ public String getAccountLink() {
+ return accountLink;
+ }
+
+ @Override
+ public void setAccountLink(final String accountLink) {
+ this.accountLink = accountLink;
+ }
+
+ @Override
+ public T getAccountIdItem() {
+ T accountIdItem = null;
+ for (T item : getItems()) {
+ if (item.isAccountid()) {
+ accountIdItem = item;
+ }
+ }
+ return accountIdItem;
+ }
+
+ protected boolean addAccountIdItem(final T accountIdItem) {
+ if (IntMappingType.UserVirtualSchema == accountIdItem.getIntMappingType()
+ || IntMappingType.RoleVirtualSchema == accountIdItem.getIntMappingType()
+ || IntMappingType.MembershipVirtualSchema == accountIdItem.getIntMappingType()
+ || IntMappingType.Password == accountIdItem.getIntMappingType()) {
+
+ throw new IllegalArgumentException("Virtual attributes cannot be set as accountId");
+ }
+ if (IntMappingType.Password == accountIdItem.getIntMappingType()) {
+ throw new IllegalArgumentException("Password attributes cannot be set as accountId");
+ }
+
+ accountIdItem.setExtAttrName(accountIdItem.getExtAttrName());
+ accountIdItem.setAccountid(true);
+
+ return this.addItem(accountIdItem);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractMappingItem.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractMappingItem.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractMappingItem.java
new file mode 100644
index 0000000..c183908
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractMappingItem.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import javax.persistence.Basic;
+import javax.persistence.Cacheable;
+import javax.persistence.Column;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.MappedSuperclass;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.core.persistence.api.entity.MappingItem;
+
+@MappedSuperclass
+@Cacheable
+public abstract class AbstractMappingItem extends AbstractEntity<Long> implements MappingItem {
+
+ private static final long serialVersionUID = 7383601853619332424L;
+
+ @Column(nullable = true)
+ private String intAttrName;
+
+ @Column(nullable = false)
+ @Enumerated(EnumType.STRING)
+ private IntMappingType intMappingType;
+
+ /**
+ * Target resource's field to be mapped.
+ */
+ @Column(nullable = true)
+ private String extAttrName;
+
+ /**
+ * Specify if the mapped target resource's field is nullable.
+ */
+ @Column(nullable = false)
+ private String mandatoryCondition;
+
+ /**
+ * Specify if the mapped target resource's field is the key.
+ */
+ @Column(nullable = false)
+ @Basic
+ @Min(0)
+ @Max(1)
+ private Integer accountid;
+
+ /**
+ * Specify if the mapped target resource's field is the password.
+ */
+ @Column(nullable = false)
+ @Basic
+ @Min(0)
+ @Max(1)
+ private Integer password;
+
+ /**
+ * Mapping purposes: SYNCHRONIZATION, PROPAGATION, BOTH.
+ */
+ @Column(nullable = false)
+ @Enumerated(EnumType.STRING)
+ private MappingPurpose purpose;
+
+ public AbstractMappingItem() {
+ super();
+
+ mandatoryCondition = Boolean.FALSE.toString();
+
+ accountid = getBooleanAsInteger(false);
+ password = getBooleanAsInteger(false);
+ }
+
+ @Override
+ public String getExtAttrName() {
+ return extAttrName;
+ }
+
+ @Override
+ public void setExtAttrName(final String extAttrName) {
+ this.extAttrName = extAttrName;
+ }
+
+ @Override
+ public String getMandatoryCondition() {
+ return mandatoryCondition;
+ }
+
+ @Override
+ public void setMandatoryCondition(final String mandatoryCondition) {
+ this.mandatoryCondition = mandatoryCondition;
+ }
+
+ @Override
+ public String getIntAttrName() {
+ final String name;
+
+ switch (getIntMappingType()) {
+ case UserId:
+ case RoleId:
+ case MembershipId:
+ name = "id";
+ break;
+
+ case Username:
+ name = "username";
+ break;
+
+ case Password:
+ name = "password";
+ break;
+
+ case RoleName:
+ name = "roleName";
+ break;
+
+ case RoleOwnerSchema:
+ name = "roleOwnerSchema";
+ break;
+
+ default:
+ name = intAttrName;
+ }
+
+ return name;
+ }
+
+ @Override
+ public void setIntAttrName(final String intAttrName) {
+ this.intAttrName = intAttrName;
+ }
+
+ @Override
+ public IntMappingType getIntMappingType() {
+ return intMappingType;
+ }
+
+ @Override
+ public void setIntMappingType(final IntMappingType intMappingType) {
+ this.intMappingType = intMappingType;
+ }
+
+ @Override
+ public boolean isAccountid() {
+ return isBooleanAsInteger(accountid);
+ }
+
+ @Override
+ public void setAccountid(final boolean accountid) {
+ this.accountid = getBooleanAsInteger(accountid);
+ }
+
+ @Override
+ public boolean isPassword() {
+ return isBooleanAsInteger(password);
+ }
+
+ @Override
+ public void setPassword(final boolean password) {
+ this.password = getBooleanAsInteger(password);
+ }
+
+ @Override
+ public MappingPurpose getPurpose() {
+ return purpose;
+ }
+
+ @Override
+ public void setPurpose(final MappingPurpose purpose) {
+ this.purpose = purpose;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
new file mode 100644
index 0000000..659b7f1
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttr.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.MappedSuperclass;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.jpa.validation.entity.PlainAttrCheck;
+
+@MappedSuperclass
+@PlainAttrCheck
+public abstract class AbstractPlainAttr extends AbstractEntity<Long> implements PlainAttr {
+
+ private static final long serialVersionUID = -9115431608821806124L;
+
+ protected abstract boolean addValue(PlainAttrValue attrValue);
+
+ @Override
+ public void addValue(final String value, final AttributableUtil attributableUtil)
+ throws InvalidPlainAttrValueException {
+
+ PlainAttrValue attrValue;
+ if (getSchema().isUniqueConstraint()) {
+ attrValue = attributableUtil.newPlainAttrUniqueValue();
+ ((PlainAttrUniqueValue) attrValue).setSchema(getSchema());
+ } else {
+ attrValue = attributableUtil.newPlainAttrValue();
+ }
+
+ attrValue.setAttr(this);
+ getSchema().getValidator().validate(value, attrValue);
+
+ if (getSchema().isUniqueConstraint()) {
+ setUniqueValue((PlainAttrUniqueValue) attrValue);
+ } else {
+ if (!getSchema().isMultivalue()) {
+ getValues().clear();
+ }
+ addValue(attrValue);
+ }
+ }
+
+ @Override
+ public List<String> getValuesAsStrings() {
+ List<String> result;
+ if (getUniqueValue() == null) {
+ result = new ArrayList<>(getValues().size());
+ for (PlainAttrValue attributeValue : getValues()) {
+ result.add(attributeValue.getValueAsString());
+ }
+ } else {
+ result = Collections.singletonList(getUniqueValue().getValueAsString());
+ }
+
+ return result;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrTemplate.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrTemplate.java
new file mode 100644
index 0000000..a6777a1
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrTemplate.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+
+public abstract class AbstractPlainAttrTemplate<P extends PlainSchema> extends AbstractAttrTemplate<P> {
+
+ private static final long serialVersionUID = -943169893494860655L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
new file mode 100644
index 0000000..4977dad
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.Date;
+import javax.persistence.Basic;
+import javax.persistence.Lob;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.misc.DataFormat;
+import org.apache.syncope.core.persistence.jpa.validation.entity.PlainAttrValueCheck;
+import org.apache.syncope.core.misc.security.Encryptor;
+
+@MappedSuperclass
+@PlainAttrValueCheck
+public abstract class AbstractPlainAttrValue extends AbstractEntity<Long> implements PlainAttrValue {
+
+ private static final long serialVersionUID = -9141923816611244785L;
+
+ private String stringValue;
+
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date dateValue;
+
+ @Basic
+ @Min(0)
+ @Max(1)
+ private Integer booleanValue;
+
+ private Long longValue;
+
+ private Double doubleValue;
+
+ @Lob
+ private byte[] binaryValue;
+
+ @Override
+ public Boolean getBooleanValue() {
+ return booleanValue == null
+ ? null
+ : isBooleanAsInteger(booleanValue);
+ }
+
+ @Override
+ public void setBooleanValue(final Boolean booleanValue) {
+ this.booleanValue = booleanValue == null
+ ? null
+ : getBooleanAsInteger(booleanValue);
+ }
+
+ @Override
+ public Date getDateValue() {
+ return dateValue == null
+ ? null
+ : new Date(dateValue.getTime());
+ }
+
+ @Override
+ public void setDateValue(final Date dateValue) {
+ this.dateValue = dateValue == null
+ ? null
+ : new Date(dateValue.getTime());
+ }
+
+ @Override
+ public Double getDoubleValue() {
+ return doubleValue;
+ }
+
+ @Override
+ public void setDoubleValue(final Double doubleValue) {
+ this.doubleValue = doubleValue;
+ }
+
+ @Override
+ public Long getLongValue() {
+ return longValue;
+ }
+
+ @Override
+ public void setLongValue(final Long longValue) {
+ this.longValue = longValue;
+ }
+
+ @Override
+ public String getStringValue() {
+ return stringValue;
+ }
+
+ @Override
+ public void setStringValue(final String stringValue) {
+ this.stringValue = stringValue;
+ }
+
+ @Override
+ public byte[] getBinaryValue() {
+ return binaryValue;
+ }
+
+ @Override
+ public void setBinaryValue(final byte[] binaryValue) {
+ this.binaryValue = ArrayUtils.clone(binaryValue);
+ }
+
+ @Override
+ public void parseValue(final PlainSchema schema, final String value) throws ParsingValidationException {
+ Exception exception = null;
+
+ switch (schema.getType()) {
+
+ case Boolean:
+ this.setBooleanValue(Boolean.parseBoolean(value));
+ break;
+
+ case Long:
+ try {
+ this.setLongValue(schema.getConversionPattern() == null
+ ? Long.valueOf(value)
+ : DataFormat.parseNumber(value, schema.getConversionPattern()).longValue());
+ } catch (Exception pe) {
+ exception = pe;
+ }
+ break;
+
+ case Double:
+ try {
+ this.setDoubleValue(schema.getConversionPattern() == null
+ ? Double.valueOf(value)
+ : DataFormat.parseNumber(value, schema.getConversionPattern()).doubleValue());
+ } catch (Exception pe) {
+ exception = pe;
+ }
+ break;
+
+ case Date:
+ try {
+ this.setDateValue(schema.getConversionPattern() == null
+ ? DataFormat.parseDate(value)
+ : new Date(DataFormat.parseDate(value, schema.getConversionPattern()).getTime()));
+ } catch (Exception pe) {
+ exception = pe;
+ }
+ break;
+
+ case Encrypted:
+ try {
+ this.setStringValue(Encryptor.getInstance(schema.getSecretKey()).
+ encode(value, schema.getCipherAlgorithm()));
+ } catch (Exception pe) {
+ exception = pe;
+ }
+ break;
+
+ case Binary:
+ this.setBinaryValue(Base64.decodeBase64(value));
+ break;
+
+ case String:
+ case Enum:
+ default:
+ this.setStringValue(value);
+ }
+
+ if (exception != null) {
+ throw new ParsingValidationException("While trying to parse '" + value + "' as " + schema.getKey(),
+ exception);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T getValue() {
+ return (T) (booleanValue != null
+ ? getBooleanValue()
+ : dateValue != null
+ ? getDateValue()
+ : doubleValue != null
+ ? getDoubleValue()
+ : longValue != null
+ ? getLongValue()
+ : binaryValue != null
+ ? getBinaryValue()
+ : stringValue);
+ }
+
+ @Override
+ public String getValueAsString() {
+ final AttrSchemaType type = getAttr() == null || getAttr().getSchema() == null
+ || getAttr().getSchema().getType() == null
+ ? AttrSchemaType.String
+ : getAttr().getSchema().getType();
+
+ return getValueAsString(type);
+ }
+
+ @Override
+ public String getValueAsString(final AttrSchemaType type) {
+ Exception exception = null;
+
+ String result = null;
+
+ switch (type) {
+
+ case Boolean:
+ result = getBooleanValue().toString();
+ break;
+
+ case Long:
+ result = getAttr() == null || getAttr().getSchema() == null
+ || getAttr().getSchema().getConversionPattern() == null
+ ? getLongValue().toString()
+ : DataFormat.format(getLongValue(), getAttr().getSchema().getConversionPattern());
+ break;
+
+ case Double:
+ result = getAttr() == null || getAttr().getSchema() == null
+ || getAttr().getSchema().getConversionPattern() == null
+ ? getDoubleValue().toString()
+ : DataFormat.format(getDoubleValue(), getAttr().getSchema().getConversionPattern());
+ break;
+
+ case Date:
+ result = getAttr() == null || getAttr().getSchema() == null
+ || getAttr().getSchema().getConversionPattern() == null
+ ? DataFormat.format(getDateValue())
+ : DataFormat.format(getDateValue(), false, getAttr().getSchema().
+ getConversionPattern());
+ break;
+
+ case Binary:
+ result = new String(Base64.encodeBase64String(getBinaryValue()));
+ break;
+
+ case String:
+ case Enum:
+ case Encrypted:
+ default:
+ result = getStringValue();
+ break;
+ }
+
+ if (exception != null) {
+ throw new InvalidPlainAttrValueException(
+ "While trying to format '" + getValue() + "' as " + type, exception);
+ }
+
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainSchema.java
----------------------------------------------------------------------
diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainSchema.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainSchema.java
new file mode 100644
index 0000000..cf0a3c9
--- /dev/null
+++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainSchema.java
@@ -0,0 +1,272 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.lang.reflect.Constructor;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Transient;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.CipherAlgorithm;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.Validator;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.jpa.attrvalue.validation.BasicValidator;
+import org.apache.syncope.core.persistence.jpa.validation.entity.PlainSchemaCheck;
+import org.apache.syncope.core.persistence.jpa.validation.entity.SchemaNameCheck;
+
+@MappedSuperclass
+@PlainSchemaCheck
+@SchemaNameCheck
+public abstract class AbstractPlainSchema extends AbstractEntity<String> implements PlainSchema {
+
+ private static final long serialVersionUID = -8621028596062054739L;
+
+ @Id
+ private String name;
+
+ @Column(nullable = false)
+ @Enumerated(EnumType.STRING)
+ private AttrSchemaType type;
+
+ @Column(nullable = false)
+ private String mandatoryCondition;
+
+ @Basic
+ @Min(0)
+ @Max(1)
+ private Integer multivalue;
+
+ @Basic
+ @Min(0)
+ @Max(1)
+ private Integer uniqueConstraint;
+
+ @Basic
+ @Min(0)
+ @Max(1)
+ private Integer readonly;
+
+ @Column(nullable = true)
+ private String conversionPattern;
+
+ @Column(nullable = true)
+ private String validatorClass;
+
+ @Column(nullable = true)
+ @Lob
+ private String enumerationValues;
+
+ @Column(nullable = true)
+ @Lob
+ private String enumerationKeys;
+
+ @Column(nullable = true)
+ private String secretKey;
+
+ @Column(nullable = true)
+ @Enumerated(EnumType.STRING)
+ private CipherAlgorithm cipherAlgorithm;
+
+ @Column(nullable = true)
+ private String mimeType;
+
+ @Transient
+ private Validator validator;
+
+ public AbstractPlainSchema() {
+ super();
+
+ type = AttrSchemaType.String;
+ mandatoryCondition = Boolean.FALSE.toString();
+ multivalue = getBooleanAsInteger(false);
+ uniqueConstraint = getBooleanAsInteger(false);
+ readonly = getBooleanAsInteger(false);
+ }
+
+ @Override
+ public String getKey() {
+ return name;
+ }
+
+ @Override
+ public void setKey(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public AttrSchemaType getType() {
+ return type;
+ }
+
+ @Override
+ public void setType(final AttrSchemaType type) {
+ this.type = type;
+ }
+
+ @Override
+ public String getMandatoryCondition() {
+ return mandatoryCondition;
+ }
+
+ @Override
+ public void setMandatoryCondition(final String condition) {
+ this.mandatoryCondition = condition;
+ }
+
+ @Override
+ public boolean isMultivalue() {
+ return isBooleanAsInteger(multivalue);
+ }
+
+ @Override
+ public void setMultivalue(boolean multivalue) {
+ this.multivalue = getBooleanAsInteger(multivalue);
+ }
+
+ @Override
+ public boolean isUniqueConstraint() {
+ return isBooleanAsInteger(uniqueConstraint);
+ }
+
+ @Override
+ public void setUniqueConstraint(final boolean uniquevalue) {
+ this.uniqueConstraint = getBooleanAsInteger(uniquevalue);
+ }
+
+ @Override
+ public boolean isReadonly() {
+ return isBooleanAsInteger(readonly);
+ }
+
+ @Override
+ public void setReadonly(final boolean readonly) {
+ this.readonly = getBooleanAsInteger(readonly);
+ }
+
+ @Override
+ public Validator getValidator() {
+ if (validator != null) {
+ return validator;
+ }
+
+ if (getValidatorClass() != null && getValidatorClass().length() > 0) {
+ try {
+ Constructor<?> validatorConstructor = Class.forName(getValidatorClass()).
+ getConstructor(new Class<?>[] { PlainSchema.class });
+ validator = (Validator) validatorConstructor.newInstance(this);
+ } catch (Exception e) {
+ LOG.error("Could not instantiate validator of type {}, reverting to {}",
+ getValidatorClass(), BasicValidator.class.getSimpleName(), e);
+ }
+ }
+
+ if (validator == null) {
+ validator = new BasicValidator(this);
+ }
+
+ return validator;
+ }
+
+ @Override
+ public String getValidatorClass() {
+ return validatorClass;
+ }
+
+ @Override
+ public void setValidatorClass(final String validatorClass) {
+ this.validatorClass = validatorClass;
+ }
+
+ @Override
+ public String getEnumerationValues() {
+ return enumerationValues;
+ }
+
+ @Override
+ public void setEnumerationValues(final String enumerationValues) {
+ this.enumerationValues = enumerationValues;
+ }
+
+ @Override
+ public String getEnumerationKeys() {
+ return enumerationKeys;
+ }
+
+ @Override
+ public void setEnumerationKeys(String enumerationKeys) {
+ this.enumerationKeys = enumerationKeys;
+ }
+
+ @Override
+ public String getConversionPattern() {
+ if (!getType().isConversionPatternNeeded()) {
+ LOG.debug("Conversion pattern is not needed: {}'s type is {}", this, getType());
+ }
+
+ return conversionPattern;
+ }
+
+ @Override
+ public void setConversionPattern(final String conversionPattern) {
+ if (StringUtils.isNotBlank(conversionPattern) && !getType().isConversionPatternNeeded()) {
+ LOG.warn("Conversion pattern will be ignored: this attribute type is {}", getType());
+ }
+
+ this.conversionPattern = conversionPattern;
+ }
+
+ @Override
+ public String getSecretKey() {
+ return secretKey;
+ }
+
+ @Override
+ public void setSecretKey(final String secretKey) {
+ this.secretKey = secretKey;
+ }
+
+ @Override
+ public CipherAlgorithm getCipherAlgorithm() {
+ return cipherAlgorithm;
+ }
+
+ @Override
+ public void setCipherAlgorithm(final CipherAlgorithm cipherAlgorithm) {
+ this.cipherAlgorithm = cipherAlgorithm;
+ }
+
+ @Override
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ @Override
+ public void setMimeType(final String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+}