http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java new file mode 100644 index 0000000..d91b948 --- /dev/null +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java @@ -0,0 +1,811 @@ +/* + * 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.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.persistence.Entity; +import javax.persistence.Query; +import javax.persistence.TemporalType; +import javax.validation.ValidationException; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.common.lib.types.AnyTypeKind; +import org.apache.syncope.common.lib.types.AttrSchemaType; +import org.apache.syncope.core.misc.RealmUtils; +import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; +import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO; +import org.apache.syncope.core.persistence.api.dao.GroupDAO; +import org.apache.syncope.core.persistence.api.dao.RealmDAO; +import org.apache.syncope.core.persistence.api.dao.AnySearchDAO; +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.MembershipCond; +import org.apache.syncope.core.persistence.api.dao.search.OrderByClause; +import org.apache.syncope.core.persistence.api.dao.search.ResourceCond; +import org.apache.syncope.core.persistence.api.dao.search.RoleCond; +import org.apache.syncope.core.persistence.api.dao.search.SearchCond; +import org.apache.syncope.core.persistence.api.dao.search.AnyCond; +import org.apache.syncope.core.persistence.api.dao.search.RelationshipCond; +import org.apache.syncope.core.persistence.api.entity.Any; +import org.apache.syncope.core.persistence.api.entity.AnyUtils; +import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; +import org.apache.syncope.core.persistence.api.entity.PlainAttrValue; +import org.apache.syncope.core.persistence.api.entity.PlainSchema; +import org.apache.syncope.core.persistence.api.entity.Realm; +import org.apache.syncope.core.persistence.jpa.entity.JPAPlainSchema; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import org.springframework.util.ReflectionUtils; + +@Repository +public class JPAAnySearchDAO extends AbstractDAO<Any<?, ?, ?>, Long> implements AnySearchDAO { + + protected static final Logger LOG = LoggerFactory.getLogger(AnySearchDAO.class); + + private static final String EMPTY_ATTR_QUERY = "SELECT any_id FROM user_search_attr WHERE 1=2"; + + @Autowired + private RealmDAO realmDAO; + + @Autowired + private AnyObjectDAO anyObjectDAO; + + @Autowired + private UserDAO userDAO; + + @Autowired + private GroupDAO groupDAO; + + @Autowired + private PlainSchemaDAO schemaDAO; + + @Autowired + private AnyUtilsFactory anyUtilsFactory; + + private String getAdminRealmsFilter(final Set<String> adminRealms, final SearchSupport svs) { + Set<Long> realmKeys = new HashSet<>(); + for (String realmPath : RealmUtils.normalize(adminRealms)) { + Realm realm = realmDAO.find(realmPath); + if (realm == null) { + LOG.warn("Ignoring invalid realm {}", realmPath); + } else { + CollectionUtils.collect(realmDAO.findDescendants(realm), new Transformer<Realm, Long>() { + + @Override + public Long transform(final Realm descendant) { + return descendant.getKey(); + } + }, realmKeys); + } + } + + StringBuilder adminRealmFilter = new StringBuilder(). + append("SELECT any_id FROM ").append(svs.field().name). + append(" WHERE realm_id IN (SELECT id AS realm_id FROM Realm"); + + boolean firstRealm = true; + for (Long realmKey : realmKeys) { + if (firstRealm) { + adminRealmFilter.append(" WHERE"); + firstRealm = false; + } else { + adminRealmFilter.append(" OR"); + } + adminRealmFilter.append(" id = ").append(realmKey); + } + + adminRealmFilter.append(')'); + + return adminRealmFilter.toString(); + } + + @Override + public int count(final Set<String> adminRealms, final SearchCond searchCondition, final AnyTypeKind typeKind) { + List<Object> parameters = Collections.synchronizedList(new ArrayList<>()); + + // 1. get the query string from the search condition + SearchSupport svs = new SearchSupport(typeKind); + StringBuilder queryString = getQuery(searchCondition, parameters, typeKind, svs); + + // 2. take into account administrative realms + queryString.insert(0, "SELECT u.any_id FROM ("); + queryString.append(") u WHERE any_id IN ("); + queryString.append(getAdminRealmsFilter(adminRealms, svs)).append(')'); + + // 3. prepare the COUNT query + queryString.insert(0, "SELECT COUNT(any_id) FROM ("); + queryString.append(") count_any_id"); + + Query countQuery = entityManager.createNativeQuery(queryString.toString()); + fillWithParameters(countQuery, parameters); + + return ((Number) countQuery.getSingleResult()).intValue(); + } + + @Override + public <T extends Any<?, ?, ?>> List<T> search( + final Set<String> adminRealms, final SearchCond searchCondition, final AnyTypeKind typeKind) { + + return search(adminRealms, searchCondition, Collections.<OrderByClause>emptyList(), typeKind); + } + + @Override + public <T extends Any<?, ?, ?>> List<T> search( + final Set<String> adminRealms, final SearchCond searchCondition, final List<OrderByClause> orderBy, + final AnyTypeKind typeKind) { + + return search(adminRealms, searchCondition, -1, -1, orderBy, typeKind); + } + + @Override + public <T extends Any<?, ?, ?>> List<T> search( + final Set<String> adminRealms, final SearchCond searchCondition, final int page, final int itemsPerPage, + final List<OrderByClause> orderBy, final AnyTypeKind typeKind) { + + List<T> result = Collections.<T>emptyList(); + + if (adminRealms != null && !adminRealms.isEmpty()) { + LOG.debug("Search condition:\n{}", searchCondition); + + if (searchCondition != null && searchCondition.isValid()) { + try { + result = doSearch(adminRealms, searchCondition, page, itemsPerPage, orderBy, typeKind); + } catch (Exception e) { + LOG.error("While searching for {}", typeKind, e); + } + } else { + LOG.error("Invalid search condition:\n{}", searchCondition); + } + } + + return result; + } + + @Override + public <T extends Any<?, ?, ?>> boolean matches( + final T subject, final SearchCond searchCondition, final AnyTypeKind typeKind) { + + List<Object> parameters = Collections.synchronizedList(new ArrayList<>()); + + // 1. get the query string from the search condition + SearchSupport svs = new SearchSupport(typeKind); + StringBuilder queryString = getQuery(searchCondition, parameters, typeKind, svs); + + boolean matches; + if (queryString.length() == 0) { + // Could be empty: got into a group search with a single membership condition ... + matches = false; + } else { + // 2. take into account the passed user + queryString.insert(0, "SELECT u.any_id FROM ("); + queryString.append(") u WHERE any_id=?").append(setParameter(parameters, subject.getKey())); + + // 3. prepare the search query + Query query = entityManager.createNativeQuery(queryString.toString()); + + // 4. populate the search query with parameter values + fillWithParameters(query, parameters); + + // 5. executes query + matches = !query.getResultList().isEmpty(); + } + + return matches; + } + + private int setParameter(final List<Object> parameters, final Object parameter) { + int key; + synchronized (parameters) { + parameters.add(parameter); + key = parameters.size(); + } + + return key; + } + + private void fillWithParameters(final Query query, final List<Object> parameters) { + for (int i = 0; i < parameters.size(); i++) { + if (parameters.get(i) instanceof Date) { + query.setParameter(i + 1, (Date) parameters.get(i), TemporalType.TIMESTAMP); + } else if (parameters.get(i) instanceof Boolean) { + query.setParameter(i + 1, ((Boolean) parameters.get(i)) + ? 1 + : 0); + } else { + query.setParameter(i + 1, parameters.get(i)); + } + } + } + + private StringBuilder buildSelect(final OrderBySupport orderBySupport) { + final StringBuilder select = new StringBuilder("SELECT u.any_id"); + + for (OrderBySupport.Item obs : orderBySupport.items) { + select.append(',').append(obs.select); + } + select.append(" FROM "); + + return select; + } + + private StringBuilder buildWhere(final OrderBySupport orderBySupport) { + final StringBuilder where = new StringBuilder(" u"); + for (SearchSupport.SearchView searchView : orderBySupport.views) { + where.append(',').append(searchView.name).append(' ').append(searchView.alias); + } + where.append(" WHERE "); + for (SearchSupport.SearchView searchView : orderBySupport.views) { + where.append("u.any_id=").append(searchView.alias).append(".any_id AND "); + } + + for (OrderBySupport.Item obs : orderBySupport.items) { + if (StringUtils.isNotBlank(obs.where)) { + where.append(obs.where).append(" AND "); + } + } + where.append("u.any_id IN ("); + + return where; + } + + private StringBuilder buildOrderBy(final OrderBySupport orderBySupport) { + final StringBuilder orderBy = new StringBuilder(); + + for (OrderBySupport.Item obs : orderBySupport.items) { + orderBy.append(obs.orderBy).append(','); + } + if (!orderBySupport.items.isEmpty()) { + orderBy.insert(0, " ORDER BY "); + orderBy.deleteCharAt(orderBy.length() - 1); + } + + return orderBy; + } + + private OrderBySupport parseOrderBy(final AnyTypeKind type, final SearchSupport svs, + final List<OrderByClause> orderByClauses) { + + final AnyUtils attrUtils = anyUtilsFactory.getInstance(type); + + OrderBySupport orderBySupport = new OrderBySupport(); + + for (OrderByClause clause : orderByClauses) { + OrderBySupport.Item obs = new OrderBySupport.Item(); + + // Manage difference among external key attribute and internal JPA @Id + String fieldName = "key".equals(clause.getField()) ? "id" : clause.getField(); + + Field subjectField = ReflectionUtils.findField(attrUtils.anyClass(), fieldName); + if (subjectField == null) { + PlainSchema schema = schemaDAO.find(fieldName); + if (schema != null) { + if (schema.isUniqueConstraint()) { + orderBySupport.views.add(svs.uniqueAttr()); + + obs.select = new StringBuilder(). + append(svs.uniqueAttr().alias).append('.').append(svs.fieldName(schema.getType())). + append(" AS ").append(fieldName).toString(); + obs.where = new StringBuilder(). + append(svs.uniqueAttr().alias). + append(".schema_name='").append(fieldName).append("'").toString(); + obs.orderBy = fieldName + " " + clause.getDirection().name(); + } else { + orderBySupport.views.add(svs.attr()); + + obs.select = new StringBuilder(). + append(svs.attr().alias).append('.').append(svs.fieldName(schema.getType())). + append(" AS ").append(fieldName).toString(); + obs.where = new StringBuilder(). + append(svs.attr().alias). + append(".schema_name='").append(fieldName).append("'").toString(); + obs.orderBy = fieldName + " " + clause.getDirection().name(); + } + } + } else { + orderBySupport.views.add(svs.field()); + + obs.select = svs.field().alias + "." + fieldName; + obs.where = StringUtils.EMPTY; + obs.orderBy = svs.field().alias + "." + fieldName + " " + clause.getDirection().name(); + } + + if (obs.isEmpty()) { + LOG.warn("Cannot build any valid clause from {}", clause); + } else { + orderBySupport.items.add(obs); + } + } + + return orderBySupport; + } + + @SuppressWarnings("unchecked") + private <T extends Any<?, ?, ?>> List<T> doSearch(final Set<String> adminRealms, + final SearchCond nodeCond, final int page, final int itemsPerPage, final List<OrderByClause> orderBy, + final AnyTypeKind typeKind) { + + List<Object> parameters = Collections.synchronizedList(new ArrayList<>()); + + // 1. get the query string from the search condition + SearchSupport svs = new SearchSupport(typeKind); + StringBuilder queryString = getQuery(nodeCond, parameters, typeKind, svs); + + // 2. take into account administrative groups and ordering + OrderBySupport orderBySupport = parseOrderBy(typeKind, svs, orderBy); + if (queryString.charAt(0) == '(') { + queryString.insert(0, buildSelect(orderBySupport)); + queryString.append(buildWhere(orderBySupport)); + } else { + queryString.insert(0, buildSelect(orderBySupport).append('(')); + queryString.append(')').append(buildWhere(orderBySupport)); + } + queryString. + append(getAdminRealmsFilter(adminRealms, svs)).append(')'). + append(buildOrderBy(orderBySupport)); + + // 3. prepare the search query + Query query = entityManager.createNativeQuery(queryString.toString()); + + // 4. page starts from 1, while setFirtResult() starts from 0 + query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1)); + + if (itemsPerPage >= 0) { + query.setMaxResults(itemsPerPage); + } + + // 5. populate the search query with parameter values + fillWithParameters(query, parameters); + + // 6. Prepare the result (avoiding duplicates) + List<T> result = new ArrayList<>(); + + for (Object subjectKey : query.getResultList()) { + long actualKey; + if (subjectKey instanceof Object[]) { + actualKey = ((Number) ((Object[]) subjectKey)[0]).longValue(); + } else { + actualKey = ((Number) subjectKey).longValue(); + } + + T subject = typeKind == AnyTypeKind.USER + ? (T) userDAO.find(actualKey) + : typeKind == AnyTypeKind.GROUP + ? (T) groupDAO.find(actualKey) + : (T) anyObjectDAO.find(actualKey); + if (subject == null) { + LOG.error("Could not find {} with id {}, even though returned by the native query", + typeKind, actualKey); + } else { + if (!result.contains(subject)) { + result.add(subject); + } + } + } + + return result; + } + + private StringBuilder getQuery(final SearchCond nodeCond, final List<Object> parameters, + final AnyTypeKind type, final SearchSupport svs) { + + StringBuilder query = new StringBuilder(); + + switch (nodeCond.getType()) { + + case LEAF: + case NOT_LEAF: + if (nodeCond.getRelationshipCond() != null + && (AnyTypeKind.USER == type || AnyTypeKind.ANY_OBJECT == type)) { + + query.append(getQuery(nodeCond.getRelationshipCond(), + nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs)); + } + if (nodeCond.getMembershipCond() != null + && (AnyTypeKind.USER == type || AnyTypeKind.ANY_OBJECT == type)) { + + query.append(getQuery(nodeCond.getMembershipCond(), + nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs)); + } + if (nodeCond.getRoleCond() != null && AnyTypeKind.USER == type) { + query.append(getQuery(nodeCond.getRoleCond(), + nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, svs)); + } + if (nodeCond.getResourceCond() != null) { + query.append(getQuery(nodeCond.getResourceCond(), + nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, type, svs)); + } + if (nodeCond.getAttributeCond() != null) { + query.append(getQuery(nodeCond.getAttributeCond(), + nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, type, svs)); + } + if (nodeCond.getAnyCond() != null) { + query.append(getQuery(nodeCond.getAnyCond(), + nodeCond.getType() == SearchCond.Type.NOT_LEAF, parameters, type, svs)); + } + break; + + case AND: + query.append(getQuery(nodeCond.getLeftNodeCond(), parameters, type, svs)). + append(" AND any_id IN ( "). + append(getQuery(nodeCond.getRightNodeCond(), parameters, type, svs)). + append(")"); + break; + + case OR: + query.append(getQuery(nodeCond.getLeftNodeCond(), parameters, type, svs)). + append(" OR any_id IN ( "). + append(getQuery(nodeCond.getRightNodeCond(), parameters, type, svs)). + append(")"); + break; + + default: + } + + return query; + } + + private String getQuery(final RelationshipCond cond, final boolean not, final List<Object> parameters, + final SearchSupport svs) { + + StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM "). + append(svs.field().name).append(" WHERE "); + + if (not) { + query.append("any_id NOT IN ("); + } else { + query.append("any_id IN ("); + } + + query.append("SELECT DISTINCT any_id ").append("FROM "). + append(svs.relationship().name).append(" WHERE "). + append("right_anyObject_id=?").append(setParameter(parameters, cond.getAnyObjectKey())). + append(')'); + + return query.toString(); + } + + private String getQuery(final MembershipCond cond, final boolean not, final List<Object> parameters, + final SearchSupport svs) { + + StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM "). + append(svs.field().name).append(" WHERE "); + + if (not) { + query.append("any_id NOT IN ("); + } else { + query.append("any_id IN ("); + } + + query.append("SELECT DISTINCT any_id ").append("FROM "). + append(svs.membership().name).append(" WHERE "). + append("group_id=?").append(setParameter(parameters, cond.getGroupKey())). + append(')'); + + if (not) { + query.append("AND any_id NOT IN ("); + } else { + query.append("OR any_id IN ("); + } + + query.append("SELECT DISTINCT any_id ").append("FROM "). + append(svs.dyngroupmembership().name).append(" WHERE "). + append("group_id=?").append(setParameter(parameters, cond.getGroupKey())). + append(')'); + + return query.toString(); + } + + private String getQuery(final RoleCond cond, final boolean not, final List<Object> parameters, + final SearchSupport svs) { + + StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM "). + append(svs.field().name).append(" WHERE "); + + if (not) { + query.append("any_id NOT IN ("); + } else { + query.append("any_id IN ("); + } + + query.append("SELECT DISTINCT any_id ").append("FROM "). + append(svs.role().name).append(" WHERE "). + append("role_id=?").append(setParameter(parameters, cond.getRoleKey())). + append(')'); + + if (not) { + query.append("AND any_id NOT IN ("); + } else { + query.append("OR any_id IN ("); + } + + query.append("SELECT DISTINCT any_id ").append("FROM "). + append(svs.dynrolemembership().name).append(" WHERE "). + append("role_id=?").append(setParameter(parameters, cond.getRoleKey())). + append(')'); + + return query.toString(); + } + + private String getQuery(final ResourceCond cond, final boolean not, final List<Object> parameters, + final AnyTypeKind typeKind, final SearchSupport svs) { + + final StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM "). + append(svs.field().name).append(" WHERE "); + + if (not) { + query.append("any_id NOT IN ("); + } else { + query.append("any_id IN ("); + } + + query.append("SELECT DISTINCT any_id FROM "). + append(svs.resource().name). + append(" WHERE resource_name=?"). + append(setParameter(parameters, cond.getResourceName())); + + if (typeKind == AnyTypeKind.USER) { + query.append(" UNION SELECT DISTINCT any_id FROM "). + append(svs.groupResource().name). + append(" WHERE resource_name=?"). + append(setParameter(parameters, cond.getResourceName())); + } + + query.append(')'); + + return query.toString(); + } + + private void fillAttributeQuery(final StringBuilder query, final PlainAttrValue attrValue, + final PlainSchema schema, final AttributeCond cond, final boolean not, + final List<Object> parameters, final SearchSupport svs) { + + String column = (cond instanceof AnyCond) + ? cond.getSchema() + : "' AND " + svs.fieldName(schema.getType()); + + switch (cond.getType()) { + + case ISNULL: + query.append(column).append(not + ? " IS NOT NULL" + : " IS NULL"); + break; + + case ISNOTNULL: + query.append(column).append(not + ? " IS NULL" + : " IS NOT NULL"); + break; + + case LIKE: + if (schema.getType() == AttrSchemaType.String || schema.getType() == AttrSchemaType.Enum) { + query.append(column); + if (not) { + query.append(" NOT "); + } + query.append(" LIKE ?").append(setParameter(parameters, cond.getExpression())); + } else { + if (!(cond instanceof AnyCond)) { + query.append("' AND"); + } + query.append(" 1=2"); + LOG.error("LIKE is only compatible with string or enum schemas"); + } + break; + + case EQ: + query.append(column); + if (not) { + query.append("<>"); + } else { + query.append('='); + } + query.append('?').append(setParameter(parameters, attrValue.getValue())); + break; + + case GE: + query.append(column); + if (not) { + query.append('<'); + } else { + query.append(">="); + } + query.append('?').append(setParameter(parameters, attrValue.getValue())); + break; + + case GT: + query.append(column); + if (not) { + query.append("<="); + } else { + query.append('>'); + } + query.append('?').append(setParameter(parameters, attrValue.getValue())); + break; + + case LE: + query.append(column); + if (not) { + query.append('>'); + } else { + query.append("<="); + } + query.append('?').append(setParameter(parameters, attrValue.getValue())); + break; + + case LT: + query.append(column); + if (not) { + query.append(">="); + } else { + query.append('<'); + } + query.append('?').append(setParameter(parameters, attrValue.getValue())); + break; + + default: + } + } + + private String getQuery(final AttributeCond cond, final boolean not, final List<Object> parameters, + final AnyTypeKind typeKind, final SearchSupport svs) { + + AnyUtils attrUtils = anyUtilsFactory.getInstance(typeKind); + + PlainSchema schema = schemaDAO.find(cond.getSchema()); + if (schema == null) { + LOG.warn("Ignoring invalid schema '{}'", cond.getSchema()); + return EMPTY_ATTR_QUERY; + } + + PlainAttrValue attrValue = attrUtils.newPlainAttrValue(); + try { + if (cond.getType() != AttributeCond.Type.LIKE && cond.getType() != AttributeCond.Type.ISNULL + && cond.getType() != AttributeCond.Type.ISNOTNULL) { + + schema.getValidator().validate(cond.getExpression(), attrValue); + } + } catch (ValidationException e) { + LOG.error("Could not validate expression '" + cond.getExpression() + "'", e); + return EMPTY_ATTR_QUERY; + } + + StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM "); + if (cond.getType() == AttributeCond.Type.ISNOTNULL) { + query.append(svs.field().name). + append(" WHERE any_id NOT IN (SELECT any_id FROM "). + append(svs.nullAttr().name). + append(" WHERE schema_name='").append(schema.getKey()).append("')"); + } else { + if (cond.getType() == AttributeCond.Type.ISNULL) { + query.append(svs.nullAttr().name). + append(" WHERE schema_name='").append(schema.getKey()).append("'"); + } else { + if (schema.isUniqueConstraint()) { + query.append(svs.uniqueAttr().name); + } else { + query.append(svs.attr().name); + } + query.append(" WHERE schema_name='").append(schema.getKey()); + + fillAttributeQuery(query, attrValue, schema, cond, not, parameters, svs); + } + } + + return query.toString(); + } + + @SuppressWarnings("rawtypes") + private String getQuery(final AnyCond cond, final boolean not, final List<Object> parameters, + final AnyTypeKind typeKind, final SearchSupport svs) { + + AnyUtils attrUtils = anyUtilsFactory.getInstance(typeKind); + + // Keeps track of difference between entity's getKey() and JPA @Id fields + if ("key".equals(cond.getSchema())) { + cond.setSchema("id"); + } + + Field subjectField = ReflectionUtils.findField(attrUtils.anyClass(), cond.getSchema()); + if (subjectField == null) { + LOG.warn("Ignoring invalid schema '{}'", cond.getSchema()); + return EMPTY_ATTR_QUERY; + } + + PlainSchema schema = new JPAPlainSchema(); + schema.setKey(subjectField.getName()); + for (AttrSchemaType attrSchemaType : AttrSchemaType.values()) { + if (subjectField.getType().isAssignableFrom(attrSchemaType.getType())) { + schema.setType(attrSchemaType); + } + } + + // Deal with subject Integer fields logically mapping to boolean values + // (JPAGroup.inheritPlainAttrs, for example) + boolean foundBooleanMin = false; + boolean foundBooleanMax = false; + if (Integer.class.equals(subjectField.getType())) { + for (Annotation annotation : subjectField.getAnnotations()) { + if (Min.class.equals(annotation.annotationType())) { + foundBooleanMin = ((Min) annotation).value() == 0; + } else if (Max.class.equals(annotation.annotationType())) { + foundBooleanMax = ((Max) annotation).value() == 1; + } + } + } + if (foundBooleanMin && foundBooleanMax) { + schema.setType(AttrSchemaType.Boolean); + } + + // Deal with subject fields representing relationships to other entities + if (subjectField.getType().getAnnotation(Entity.class) != null) { + Method relMethod = null; + try { + relMethod = ClassUtils.getPublicMethod(subjectField.getType(), "getKey", new Class[0]); + } catch (Exception e) { + LOG.error("Could not find {}#getKey", subjectField.getType(), e); + } + + if (relMethod != null) { + if (Long.class.isAssignableFrom(relMethod.getReturnType())) { + cond.setSchema(cond.getSchema() + "_id"); + schema.setType(AttrSchemaType.Long); + } + if (String.class.isAssignableFrom(relMethod.getReturnType())) { + cond.setSchema(cond.getSchema() + "_name"); + schema.setType(AttrSchemaType.String); + } + } + } + + PlainAttrValue attrValue = attrUtils.newPlainAttrValue(); + if (cond.getType() != AttributeCond.Type.LIKE + && cond.getType() != AttributeCond.Type.ISNULL + && cond.getType() != AttributeCond.Type.ISNOTNULL) { + + try { + schema.getValidator().validate(cond.getExpression(), attrValue); + } catch (ValidationException e) { + LOG.error("Could not validate expression '" + cond.getExpression() + "'", e); + return EMPTY_ATTR_QUERY; + } + } + + final StringBuilder query = new StringBuilder("SELECT DISTINCT any_id FROM "). + append(svs.field().name).append(" WHERE "); + + fillAttributeQuery(query, attrValue, schema, cond, not, parameters, svs); + + return query.toString(); + } +}
http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyTypeClassDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyTypeClassDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyTypeClassDAO.java new file mode 100644 index 0000000..4d82d31 --- /dev/null +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyTypeClassDAO.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.core.persistence.jpa.dao; + +import java.util.List; +import javax.persistence.TypedQuery; +import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO; +import org.apache.syncope.core.persistence.api.entity.AnyTypeClass; +import org.apache.syncope.core.persistence.jpa.entity.JPAAnyTypeClass; +import org.springframework.stereotype.Repository; + +@Repository +public class JPAAnyTypeClassDAO extends AbstractDAO<AnyTypeClass, String> implements AnyTypeClassDAO { + + @Override + public AnyTypeClass find(final String key) { + return entityManager.find(JPAAnyTypeClass.class, key); + } + + @Override + public List<AnyTypeClass> findAll() { + TypedQuery<AnyTypeClass> query = entityManager.createQuery( + "SELECT e FROM " + JPAAnyTypeClass.class.getSimpleName() + " e ", AnyTypeClass.class); + return query.getResultList(); + } + + @Override + public AnyTypeClass save(final AnyTypeClass anyTypeClass) { + return entityManager.merge(anyTypeClass); + } + + @Override + public void delete(final String key) { + AnyTypeClass anyTypeClass = find(key); + if (anyTypeClass == null) { + return; + } + + entityManager.remove(anyTypeClass); + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyTypeDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyTypeDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyTypeDAO.java new file mode 100644 index 0000000..bbbf859 --- /dev/null +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyTypeDAO.java @@ -0,0 +1,83 @@ +/* + * 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.common.lib.types.AnyTypeKind; +import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO; +import org.apache.syncope.core.persistence.api.entity.AnyType; +import org.apache.syncope.core.persistence.jpa.entity.JPAAnyType; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +@Repository +public class JPAAnyTypeDAO extends AbstractDAO<AnyType, String> implements AnyTypeDAO { + + @Override + public AnyType find(final String key) { + return entityManager.find(JPAAnyType.class, key); + } + + private AnyType find(final AnyTypeKind typeKind) { + AnyType anyType = find(typeKind.name()); + if (anyType == null) { + anyType = new JPAAnyType(); + anyType.setKey(typeKind.name()); + anyType.setKind(typeKind); + anyType = save(anyType); + } + return anyType; + } + + @Transactional(readOnly = false) + @Override + public AnyType findUser() { + return find(AnyTypeKind.USER); + } + + @Transactional(readOnly = false) + @Override + public AnyType findGroup() { + return find(AnyTypeKind.GROUP); + } + + @Override + public List<AnyType> findAll() { + TypedQuery<AnyType> query = entityManager.createQuery( + "SELECT e FROM " + JPAAnyType.class.getSimpleName() + " e ", AnyType.class); + return query.getResultList(); + } + + @Override + public AnyType save(final AnyType anyType) { + return entityManager.merge(anyType); + } + + @Override + public void delete(final String key) { + AnyType anyType = find(key); + if (anyType == null) { + return; + } + + entityManager.remove(anyType); + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAttrTemplateDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAttrTemplateDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAttrTemplateDAO.java deleted file mode 100644 index 2b33178..0000000 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAttrTemplateDAO.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.core.persistence.jpa.dao; - -import java.util.Collections; -import java.util.List; -import javax.persistence.Query; -import org.apache.syncope.core.persistence.api.dao.AttrTemplateDAO; -import org.apache.syncope.core.persistence.api.entity.AttrTemplate; -import org.apache.syncope.core.persistence.api.entity.Schema; -import org.apache.syncope.core.persistence.api.entity.membership.MDerAttrTemplate; -import org.apache.syncope.core.persistence.api.entity.membership.MPlainAttrTemplate; -import org.apache.syncope.core.persistence.api.entity.membership.MVirAttrTemplate; -import org.apache.syncope.core.persistence.api.entity.group.GDerAttrTemplate; -import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrTemplate; -import org.apache.syncope.core.persistence.api.entity.group.GVirAttrTemplate; -import org.apache.syncope.core.persistence.jpa.entity.AbstractAttrTemplate; -import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMDerAttrTemplate; -import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMPlainAttrTemplate; -import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMVirAttrTemplate; -import org.apache.syncope.core.persistence.jpa.entity.group.JPAGDerAttrTemplate; -import org.apache.syncope.core.persistence.jpa.entity.group.JPAGPlainAttrTemplate; -import org.apache.syncope.core.persistence.jpa.entity.group.JPAGVirAttrTemplate; -import org.springframework.stereotype.Repository; -import org.springframework.util.ReflectionUtils; - -@Repository -public class JPAAttrTemplateDAO<S extends Schema> - extends AbstractDAO<AttrTemplate<S>, Long> implements AttrTemplateDAO<S> { - - private <T extends AttrTemplate<S>> Class<? extends AbstractAttrTemplate<? extends Schema>> getJPAEntityReference( - final Class<T> reference) { - - return MPlainAttrTemplate.class.isAssignableFrom(reference) - ? JPAMPlainAttrTemplate.class - : MDerAttrTemplate.class.isAssignableFrom(reference) - ? JPAMDerAttrTemplate.class - : MVirAttrTemplate.class.isAssignableFrom(reference) - ? JPAMVirAttrTemplate.class - : GPlainAttrTemplate.class.isAssignableFrom(reference) - ? JPAGPlainAttrTemplate.class - : GDerAttrTemplate.class.isAssignableFrom(reference) - ? JPAGDerAttrTemplate.class - : GVirAttrTemplate.class.isAssignableFrom(reference) - ? JPAGVirAttrTemplate.class - : null; - } - - @Override - public <T extends AttrTemplate<S>> T find(final Long key, final Class<T> reference) { - return reference.cast(entityManager.find(getJPAEntityReference(reference), key)); - } - - @Override - @SuppressWarnings("unchecked") - public <T extends AttrTemplate<S>> List<Number> findBySchemaName( - final String schemaName, final Class<T> reference) { - - Query query = null; - try { - query = entityManager.createNativeQuery("SELECT id FROM " - + ReflectionUtils.findField(getJPAEntityReference(reference), "TABLE").get(null).toString() - + " WHERE schema_name=?1"); - query.setParameter(1, schemaName); - } catch (Exception e) { - LOG.error("Unexpected exception", e); - } - - return query == null ? Collections.<Number>emptyList() : query.getResultList(); - } - - @Override - public <T extends AttrTemplate<S>> void delete(final Long key, final Class<T> reference) { - T attrTemplate = find(key, reference); - if (attrTemplate == null) { - return; - } - - delete(attrTemplate); - } - - @Override - @SuppressWarnings("unchecked") - public <T extends AttrTemplate<S>> void delete(final T attrTemplate) { - if (attrTemplate.getOwner() != null) { - attrTemplate.getOwner().getAttrTemplates(attrTemplate.getClass()).remove(attrTemplate); - } - - entityManager.remove(attrTemplate); - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java index 48e9f5e..7045a1a 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java @@ -18,15 +18,14 @@ */ package org.apache.syncope.core.persistence.jpa.dao; -import org.apache.syncope.common.lib.types.AttributableType; import org.apache.syncope.core.persistence.api.dao.ConfDAO; import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO; import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO; -import org.apache.syncope.core.persistence.api.entity.AttributableUtilsFactory; +import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue; import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr; -import org.apache.syncope.core.persistence.api.entity.conf.CPlainSchema; import org.apache.syncope.core.persistence.api.entity.conf.Conf; import org.apache.syncope.core.persistence.jpa.entity.conf.JPACPlainAttr; +import org.apache.syncope.core.persistence.jpa.entity.conf.JPACPlainAttrValue; import org.apache.syncope.core.persistence.jpa.entity.conf.JPAConf; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -41,9 +40,6 @@ public class JPAConfDAO extends AbstractDAO<Conf, Long> implements ConfDAO { @Autowired private PlainAttrDAO attrDAO; - @Autowired - private AttributableUtilsFactory attrUtilsFactory; - @Override public Conf get() { Conf instance = entityManager.find(JPAConf.class, 1L); @@ -68,10 +64,19 @@ public class JPAConfDAO extends AbstractDAO<Conf, Long> implements ConfDAO { public CPlainAttr find(final String key, final String defaultValue) { CPlainAttr result = find(key); if (result == null) { - result = new JPACPlainAttr(); - result.setSchema(schemaDAO.find(key, CPlainSchema.class)); - - result.addValue(defaultValue, attrUtilsFactory.getInstance(AttributableType.CONFIGURATION)); + JPACPlainAttr newAttr = new JPACPlainAttr(); + newAttr.setSchema(schemaDAO.find(key)); + + JPACPlainAttrValue attrValue; + if (newAttr.getSchema().isUniqueConstraint()) { + attrValue = new JPACPlainAttrValue(); + ((PlainAttrUniqueValue) attrValue).setSchema(newAttr.getSchema()); + } else { + attrValue = new JPACPlainAttrValue(); + } + newAttr.add(defaultValue, attrValue); + + result = newAttr; } return result; @@ -85,11 +90,11 @@ public class JPAConfDAO extends AbstractDAO<Conf, Long> implements ConfDAO { if (old != null && (!attr.getSchema().isUniqueConstraint() || (!attr.getUniqueValue().getStringValue().equals(old.getUniqueValue().getStringValue())))) { - instance.removePlainAttr(old); + instance.remove(old); attrDAO.delete(old.getKey(), CPlainAttr.class); } - instance.addPlainAttr(attr); + instance.add(attr); attr.setOwner(instance); return entityManager.merge(instance); @@ -100,7 +105,7 @@ public class JPAConfDAO extends AbstractDAO<Conf, Long> implements ConfDAO { Conf instance = get(); CPlainAttr attr = instance.getPlainAttr(key); if (attr != null) { - instance.removePlainAttr(attr); + instance.remove(attr); instance = entityManager.merge(instance); } http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java index e148b04..453c363 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConnInstanceDAO.java @@ -27,7 +27,7 @@ import org.apache.syncope.core.persistence.api.dao.ConnInstanceDAO; import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; import org.apache.syncope.core.persistence.api.dao.NotFoundException; import org.apache.syncope.core.persistence.api.entity.ConnInstance; -import org.apache.syncope.core.persistence.api.entity.ExternalResource; +import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; import org.apache.syncope.core.persistence.jpa.entity.JPAConnInstance; import org.apache.syncope.core.provisioning.api.ConnectorRegistry; import org.springframework.beans.factory.annotation.Autowired; http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java index ff32fb8..2162898 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerAttrDAO.java @@ -21,51 +21,51 @@ package org.apache.syncope.core.persistence.jpa.dao; import java.util.List; import javax.persistence.TypedQuery; import org.apache.syncope.core.persistence.api.dao.DerAttrDAO; -import org.apache.syncope.core.persistence.api.entity.Attributable; +import org.apache.syncope.core.persistence.api.entity.Any; import org.apache.syncope.core.persistence.api.entity.DerAttr; -import org.apache.syncope.core.persistence.api.entity.membership.MDerAttr; +import org.apache.syncope.core.persistence.api.entity.anyobject.ADerAttr; import org.apache.syncope.core.persistence.api.entity.group.GDerAttr; import org.apache.syncope.core.persistence.api.entity.user.UDerAttr; import org.apache.syncope.core.persistence.jpa.entity.AbstractDerAttr; -import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMDerAttr; +import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAADerAttr; import org.apache.syncope.core.persistence.jpa.entity.group.JPAGDerAttr; import org.apache.syncope.core.persistence.jpa.entity.user.JPAUDerAttr; import org.springframework.stereotype.Repository; @Repository -public class JPADerAttrDAO extends AbstractDAO<DerAttr, Long> implements DerAttrDAO { +public class JPADerAttrDAO extends AbstractDAO<DerAttr<?>, Long> implements DerAttrDAO { - public <T extends DerAttr> Class<? extends AbstractDerAttr> getJPAEntityReference( + public <T extends DerAttr<?>> Class<? extends AbstractDerAttr<?>> getJPAEntityReference( final Class<T> reference) { return GDerAttr.class.isAssignableFrom(reference) ? JPAGDerAttr.class - : MDerAttr.class.isAssignableFrom(reference) - ? JPAMDerAttr.class + : ADerAttr.class.isAssignableFrom(reference) + ? JPAADerAttr.class : UDerAttr.class.isAssignableFrom(reference) ? JPAUDerAttr.class : null; } @Override - public <T extends DerAttr> T find(final Long key, final Class<T> reference) { + public <T extends DerAttr<?>> T find(final Long key, final Class<T> reference) { return reference.cast(entityManager.find(getJPAEntityReference(reference), key)); } @Override - public <T extends DerAttr> List<T> findAll(final Class<T> reference) { + public <T extends DerAttr<?>> 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 DerAttr> T save(final T derAttr) { + public <T extends DerAttr<?>> T save(final T derAttr) { return entityManager.merge(derAttr); } @Override - public <T extends DerAttr> void delete(final Long key, final Class<T> reference) { + public <T extends DerAttr<?>> void delete(final Long key, final Class<T> reference) { T derAttr = find(key, reference); if (derAttr == null) { return; @@ -76,9 +76,9 @@ public class JPADerAttrDAO extends AbstractDAO<DerAttr, Long> implements DerAttr @Override @SuppressWarnings("unchecked") - public <T extends DerAttr> void delete(final T derAttr) { + public <T extends DerAttr<?>> void delete(final T derAttr) { if (derAttr.getOwner() != null) { - ((Attributable<?, T, ?>) derAttr.getOwner()).removeDerAttr(derAttr); + ((Any<?, T, ?>) derAttr.getOwner()).remove(derAttr); } entityManager.remove(derAttr); http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerSchemaDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerSchemaDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerSchemaDAO.java index be0ec94..c3c10bf 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerSchemaDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADerSchemaDAO.java @@ -20,25 +20,16 @@ package org.apache.syncope.core.persistence.jpa.dao; import java.util.List; import javax.persistence.TypedQuery; -import org.apache.commons.collections4.Closure; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.syncope.common.lib.types.AttributableType; -import org.apache.syncope.core.persistence.api.dao.AttrTemplateDAO; +import org.apache.syncope.common.lib.types.AnyTypeKind; import org.apache.syncope.core.persistence.api.dao.DerAttrDAO; import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO; import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; -import org.apache.syncope.core.persistence.api.entity.AttributableUtils; +import org.apache.syncope.core.persistence.api.entity.AnyUtils; +import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; import org.apache.syncope.core.persistence.api.entity.DerAttr; import org.apache.syncope.core.persistence.api.entity.DerSchema; -import org.apache.syncope.core.persistence.api.entity.membership.MDerSchema; -import org.apache.syncope.core.persistence.api.entity.group.GDerSchema; -import org.apache.syncope.core.persistence.api.entity.user.UDerAttr; -import org.apache.syncope.core.persistence.api.entity.user.UDerSchema; -import org.apache.syncope.core.persistence.api.entity.user.UMappingItem; -import org.apache.syncope.core.persistence.jpa.entity.AbstractDerSchema; -import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMDerSchema; -import org.apache.syncope.core.persistence.jpa.entity.group.JPAGDerSchema; -import org.apache.syncope.core.persistence.jpa.entity.user.JPAUDerSchema; +import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory; +import org.apache.syncope.core.persistence.jpa.entity.JPADerSchema; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -49,44 +40,25 @@ public class JPADerSchemaDAO extends AbstractDAO<DerSchema, String> implements D private DerAttrDAO derAttrDAO; @Autowired - private AttrTemplateDAO<DerSchema> attrTemplateDAO; - - @Autowired private ExternalResourceDAO resourceDAO; - private <T extends DerSchema> Class<? extends AbstractDerSchema> getJPAEntityReference(final Class<T> reference) { - return GDerSchema.class.isAssignableFrom(reference) - ? JPAGDerSchema.class - : MDerSchema.class.isAssignableFrom(reference) - ? JPAMDerSchema.class - : UDerSchema.class.isAssignableFrom(reference) - ? JPAUDerSchema.class - : null; - } - @Override - public <T extends DerSchema> T find(final String key, final Class<T> reference) { - return reference.cast(entityManager.find(getJPAEntityReference(reference), key)); + public DerSchema find(final String key) { + return entityManager.find(JPADerSchema.class, key); } @Override - public <T extends DerSchema> List<T> findAll(final Class<T> reference) { - TypedQuery<T> query = entityManager.createQuery( - "SELECT e FROM " + getJPAEntityReference(reference).getSimpleName() + " e", reference); + public List<DerSchema> findAll() { + TypedQuery<DerSchema> query = entityManager.createQuery( + "SELECT e FROM " + JPADerSchema.class.getSimpleName() + " e", DerSchema.class); return query.getResultList(); } @Override - public <T extends DerAttr> List<T> findAttrs(final DerSchema schema, final Class<T> reference) { + public <T extends DerAttr<?>> List<T> findAttrs(final DerSchema schema, final Class<T> reference) { final StringBuilder queryString = new StringBuilder("SELECT e FROM "). append(((JPADerAttrDAO) derAttrDAO).getJPAEntityReference(reference).getSimpleName()). - append(" e WHERE e."); - if (UDerAttr.class.isAssignableFrom(reference)) { - queryString.append("derSchema"); - } else { - queryString.append("template.schema"); - } - queryString.append("=:schema"); + append(" e WHERE e.schema=:schema"); TypedQuery<T> query = entityManager.createQuery(queryString.toString(), reference); query.setParameter("schema", schema); @@ -95,42 +67,28 @@ public class JPADerSchemaDAO extends AbstractDAO<DerSchema, String> implements D } @Override - public <T extends DerSchema> T save(final T derSchema) { + public DerSchema save(final DerSchema derSchema) { return entityManager.merge(derSchema); } @Override - @SuppressWarnings("unchecked") - public void delete(final String key, final AttributableUtils attributableUtil) { - final DerSchema schema = find(key, attributableUtil.derSchemaClass()); + public void delete(final String key) { + final DerSchema schema = find(key); if (schema == null) { return; } - CollectionUtils.forAllDo(findAttrs(schema, attributableUtil.derAttrClass()), new Closure<DerAttr>() { + AnyUtilsFactory anyUtilsFactory = new JPAAnyUtilsFactory(); + for (AnyTypeKind anyTypeKind : AnyTypeKind.values()) { + AnyUtils anyUtils = anyUtilsFactory.getInstance(anyTypeKind); - @Override - public void execute(final DerAttr input) { - derAttrDAO.delete(input.getKey(), attributableUtil.derAttrClass()); + for (DerAttr<?> attr : findAttrs(schema, anyUtils.derAttrClass())) { + derAttrDAO.delete(attr.getKey(), anyUtils.derAttrClass()); } - }); - - if (attributableUtil.getType() != AttributableType.USER) { - CollectionUtils.forAllDo(attrTemplateDAO. - findBySchemaName(schema.getKey(), attributableUtil.derAttrTemplateClass()).iterator(), - new Closure<Number>() { - - @Override - public void execute(final Number input) { - attrTemplateDAO.delete(input.longValue(), attributableUtil.derAttrTemplateClass()); - } - - }); + resourceDAO.deleteMapping(key, anyUtils.derIntMappingType()); } - resourceDAO.deleteMapping(key, attributableUtil.derIntMappingType(), UMappingItem.class); - entityManager.remove(schema); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/081d9a04/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java index 70f00f7..b13a8bd 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAExternalResourceDAO.java @@ -25,6 +25,7 @@ import javax.persistence.TypedQuery; import org.apache.syncope.common.lib.types.IntMappingType; import org.apache.syncope.common.lib.types.PolicyType; import org.apache.syncope.common.lib.types.TaskType; +import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO; import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO; import org.apache.syncope.core.persistence.api.dao.NotFoundException; import org.apache.syncope.core.persistence.api.dao.PolicyDAO; @@ -32,17 +33,17 @@ import org.apache.syncope.core.persistence.api.dao.GroupDAO; import org.apache.syncope.core.persistence.api.dao.TaskDAO; import org.apache.syncope.core.persistence.api.dao.UserDAO; import org.apache.syncope.core.persistence.api.entity.AccountPolicy; -import org.apache.syncope.core.persistence.api.entity.ExternalResource; -import org.apache.syncope.core.persistence.api.entity.Mapping; -import org.apache.syncope.core.persistence.api.entity.MappingItem; +import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; +import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; +import org.apache.syncope.core.persistence.api.entity.resource.MappingItem; import org.apache.syncope.core.persistence.api.entity.Policy; +import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject; import org.apache.syncope.core.persistence.api.entity.group.Group; -import org.apache.syncope.core.persistence.api.entity.user.UMappingItem; +import org.apache.syncope.core.persistence.api.entity.resource.Provision; import org.apache.syncope.core.persistence.api.entity.user.User; -import org.apache.syncope.core.persistence.jpa.entity.AbstractMappingItem; -import org.apache.syncope.core.persistence.jpa.entity.JPAExternalResource; -import org.apache.syncope.core.persistence.jpa.entity.group.JPAGMappingItem; -import org.apache.syncope.core.persistence.jpa.entity.user.JPAUMappingItem; +import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMappingItem; +import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource; +import org.apache.syncope.core.persistence.jpa.entity.resource.JPAMapping; import org.apache.syncope.core.provisioning.api.ConnectorRegistry; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -55,6 +56,9 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String private TaskDAO taskDAO; @Autowired + private AnyObjectDAO anyObjectDAO; + + @Autowired private UserDAO userDAO; @Autowired @@ -66,6 +70,9 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String @Autowired private ConnectorRegistry connRegistry; + @Autowired + private AnyUtilsFactory anyUtilsFactory; + @Override public ExternalResource find(final String name) { return entityManager.find(JPAExternalResource.class, name); @@ -146,33 +153,25 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String @Override @SuppressWarnings("unchecked") - public <T extends MappingItem> void deleteMapping( - final String intAttrName, final IntMappingType intMappingType, final Class<T> reference) { - + public void deleteMapping(final String intAttrName, final IntMappingType intMappingType) { if (IntMappingType.getEmbedded().contains(intMappingType)) { return; } - Class<? extends AbstractMappingItem> jpaRef = reference.equals(UMappingItem.class) - ? JPAUMappingItem.class - : JPAGMappingItem.class; - - TypedQuery<T> query = entityManager.createQuery("SELECT m FROM " + jpaRef.getSimpleName() - + " m WHERE m.intAttrName=:intAttrName AND m.intMappingType=:intMappingType", reference); + TypedQuery<MappingItem> query = entityManager.createQuery( + "SELECT m FROM " + JPAMappingItem.class.getSimpleName() + + " m WHERE m.intAttrName=:intAttrName AND m.intMappingType=:intMappingType", MappingItem.class); query.setParameter("intAttrName", intAttrName); query.setParameter("intMappingType", intMappingType); - Set<Long> itemIds = new HashSet<>(); - for (T item : query.getResultList()) { - itemIds.add(item.getKey()); + Set<Long> itemKeys = new HashSet<>(); + for (MappingItem item : query.getResultList()) { + itemKeys.add(item.getKey()); } - Class<?> mappingRef = null; - for (Long itemId : itemIds) { - T item = (T) entityManager.find(jpaRef, itemId); + for (Long itemKey : itemKeys) { + MappingItem item = entityManager.find(JPAMappingItem.class, itemKey); if (item != null) { - mappingRef = item.getMapping().getClass(); - - ((Mapping<T>) item.getMapping()).removeItem(item); + item.getMapping().remove(item); item.setMapping(null); entityManager.remove(item); @@ -180,10 +179,8 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String } // Make empty query cache for *MappingItem and related *Mapping - entityManager.getEntityManagerFactory().getCache().evict(jpaRef); - if (mappingRef != null) { - entityManager.getEntityManagerFactory().getCache().evict(mappingRef); - } + entityManager.getEntityManagerFactory().getCache().evict(JPAMappingItem.class); + entityManager.getEntityManagerFactory().getCache().evict(JPAMapping.class); } @Override @@ -197,11 +194,14 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String taskDAO.deleteAll(resource, TaskType.SYNCHRONIZATION); taskDAO.deleteAll(resource, TaskType.PUSH); + for (AnyObject anyObject : anyObjectDAO.findByResource(resource)) { + anyObject.remove(resource); + } for (User user : userDAO.findByResource(resource)) { - user.removeResource(resource); + user.remove(resource); } for (Group group : groupDAO.findByResource(resource)) { - group.removeResource(resource); + group.remove(resource); } for (AccountPolicy policy : policyDAO.findByResource(resource)) { policy.removeResource(resource); @@ -214,21 +214,13 @@ public class JPAExternalResourceDAO extends AbstractDAO<ExternalResource, String } resource.setConnector(null); - if (resource.getUmapping() != null) { - for (MappingItem item : resource.getUmapping().getItems()) { - item.setMapping(null); - } - resource.getUmapping().getItems().clear(); - resource.getUmapping().setResource(null); - resource.setUmapping(null); - } - if (resource.getGmapping() != null) { - for (MappingItem item : resource.getGmapping().getItems()) { + for (Provision provision : resource.getProvisions()) { + for (MappingItem item : provision.getMapping().getItems()) { item.setMapping(null); } - resource.getGmapping().getItems().clear(); - resource.getGmapping().setResource(null); - resource.setGmapping(null); + provision.getMapping().getItems().clear(); + provision.setMapping(null); + provision.setResource(null); } entityManager.remove(resource);
