/* * Copyright 2013 uaiHebert Solucoes em Informatica * * Licensed 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 com.uaihebert.uaicriteria.base.element; import com.uaihebert.uaicriteria.wrapper.JoinWrapper; import javax.persistence.criteria.AbstractQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.JoinType; import javax.persistence.criteria.Order; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import javax.persistence.criteria.Selection; import javax.persistence.criteria.Subquery; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class BaseCriteria<T> { public static final int DEFAULT_OR_PREDICATE_INDEX = 0; private final Class<T> entityClass; private final Root<T> root; private final Subquery<T> subquery; private final CriteriaQuery<T> criteriaQuery; private final CriteriaBuilder criteriaBuilder; private final Map<String, String> createdHintMap = new HashMap<String, String>(); private final Map<String, JoinWrapper> createdJoinWrapperMap = new HashMap<String, JoinWrapper>(); private final List<Order> orderByList = new ArrayList<Order>(); private final List<Predicate> createdPredicateList = new ArrayList<Predicate>(); private final List<Expression> multiselectSelectList = new ArrayList<Expression>(); private final List<Expression> groupByList = new ArrayList<Expression>(); private final Map<Integer, List<Predicate>> orPredicateMap = new HashMap<Integer, List<Predicate>>(); private final Map<Integer, List<Predicate>> andSeparatedByOrPredicateMap = new HashMap<Integer, List<Predicate>>(); public BaseCriteria(final Root<T> root, final CriteriaQuery<T> criteriaQuery, final CriteriaBuilder criteriaBuilder, final Class<T> entityClass) { this.root = root; this.subquery = null; this.criteriaQuery = criteriaQuery; this.criteriaBuilder = criteriaBuilder; this.entityClass = entityClass; } public BaseCriteria(final Root<T> root, final Subquery<T> subquery, final CriteriaBuilder criteriaBuilder, final Class<T> entityClass) { this.root = root; this.subquery = subquery; this.criteriaQuery = null; this.criteriaBuilder = criteriaBuilder; this.entityClass = entityClass; } public AbstractQuery<T> getCriteriaQuery() { if (subquery != null) { return subquery; } return criteriaQuery; } public Map<String, String> getCreatedHintMap() { final Map<String, String> result = new HashMap<String, String>(createdHintMap); createdHintMap.clear(); return result; } public CriteriaBuilder getCriteriaBuilder() { return criteriaBuilder; } public Subquery<T> getSubquery() { return subquery; } public Class<T> getEntityClass() { return entityClass; } public void addAndPredicate(final Predicate predicate) { createdPredicateList.add(predicate); } public void setUpCriteria() { addWhereConditions(); addOrderByConditions(); addGroupByValues(); } private void addOrderByConditions() { if (orderByList.isEmpty()) { return; } final List<Order> ordinationList = new ArrayList<Order>(orderByList); final CriteriaQuery<T> convertedCriteriaQuery = getConvertedCriteriaQuery(); convertedCriteriaQuery.orderBy(ordinationList); orderByList.clear(); } public CriteriaQuery<T> getConvertedCriteriaQuery() { final AbstractQuery<T> abstractQuery = getCriteriaQuery(); return (CriteriaQuery) abstractQuery; } private void addWhereConditions() { final List<Predicate> conditionList = extractAllConditions(); if (conditionList.isEmpty()) { return; } final Predicate[] predicateArraySize = new Predicate[conditionList.size()]; final Predicate[] predicateArray = conditionList.toArray(predicateArraySize); getCriteriaQuery().where(predicateArray); } private List<Predicate> extractAllConditions() { final List<Predicate> conditionList = new ArrayList<Predicate>(); addWhereConditions(conditionList); addOrConditions(conditionList); addAndSeparatedByConditions(conditionList); return conditionList; } private void addAndSeparatedByConditions(final List<Predicate> conditionList) { if (andSeparatedByOrPredicateMap.isEmpty()) { return; } final List<Predicate> orPredicateList = convertCriteriaToAndOrPredicateList(); final Predicate or = createOrPredicateFromList(orPredicateList); orPredicateList.clear(); orPredicateList.add(or); conditionList.addAll(orPredicateList); } private Predicate createOrPredicateFromList(final List<Predicate> orPredicateList) { final Predicate[] predicateArraySize = new Predicate[orPredicateList.size()]; final Predicate[] predicateArray = orPredicateList.toArray(predicateArraySize); return criteriaBuilder.or(predicateArray); } private List<Predicate> convertCriteriaToAndOrPredicateList() { final List<Predicate> orPredicateList = new ArrayList<Predicate>(); for (final List<Predicate> predicateList : andSeparatedByOrPredicateMap.values()) { final Predicate and = createAndCondition(predicateList); final Predicate orPredicate = criteriaBuilder.or(and); orPredicateList.add(orPredicate); } return orPredicateList; } private Predicate createAndCondition(final List<Predicate> predicateList) { final Predicate[] predicateArraySize = new Predicate[predicateList.size()]; final Predicate[] predicateArray = predicateList.toArray(predicateArraySize); return criteriaBuilder.and(predicateArray); } private void addOrConditions(final List<Predicate> conditionList) { if (orPredicateMap.isEmpty()) { return; } final List<Predicate> orPredicateList = new ArrayList<Predicate>(); for (final List<Predicate> predicateList : orPredicateMap.values()) { final Predicate orPredicate = createOrPredicateFromList(predicateList); orPredicateList.add(orPredicate); } conditionList.addAll(orPredicateList); } private void addWhereConditions(final List<Predicate> conditionList) { conditionList.addAll(createdPredicateList); } public JoinWrapper addJoin(final String joinName, final JoinType joinType, final boolean isFetch) { final JoinWrapper join = new JoinWrapper(root); join.createJoinInRoot(joinName, joinType, isFetch); createdJoinWrapperMap.put(joinName, join); return join; } public JoinWrapper addJoinFromJoin(final String joinName, final JoinWrapper joinWrapper) { createdJoinWrapperMap.put(joinName, joinWrapper); return joinWrapper; } public JoinWrapper getJoin(final String joinName) { final JoinWrapper join = createdJoinWrapperMap.get(joinName); if (join == null) { throw new IllegalArgumentException("The requested Join: " + joinName + " was not found. " + "\n Did you create the join by invoking any of the join methods?"); } return join; } public Path getPath(final String requiredPath) { return root.get(requiredPath); } public void addHint(final String key, final String value) { createdHintMap.put(key, value); } public void addOrPredicate(final int index, final Predicate predicate) { final List<Predicate> predicateList = getOrPredicateList(index); predicateList.add(predicate); } private List<Predicate> getOrPredicateList(final int index) { List<Predicate> predicateList = orPredicateMap.get(index); if (predicateList == null) { predicateList = new ArrayList<Predicate>(); orPredicateMap.put(index, predicateList); } return predicateList; } private List<Predicate> getAndSeparatedByOrPredicateList(final int index) { List<Predicate> predicateList = andSeparatedByOrPredicateMap.get(index); if (predicateList == null) { predicateList = new ArrayList<Predicate>(); andSeparatedByOrPredicateMap.put(index, predicateList); } return predicateList; } public void addAndSeparatedByOr(final int index, final Predicate predicate) { final List<Predicate> predicateList = getAndSeparatedByOrPredicateList(index); predicateList.add(predicate); } public boolean hasJoin(final String currentJoin) { return createdJoinWrapperMap.containsKey(currentJoin); } public void addOrdination(final Order currentOrdination) { orderByList.add(currentOrdination); } public void setDistinctTrue() { getCriteriaQuery().distinct(true); } private CriteriaQuery<Long> getCountCriteriaQuery() { return (CriteriaQuery<Long>) criteriaQuery; } public void setCountSelect() { if (getCriteriaQuery().isDistinct()) { useCountDistinctInsteadOfQueryDistinct(); return; } getCountCriteriaQuery().select(criteriaBuilder.count(root)); } public void setMultiSelectSelect() { addMultiSelectMultiSelectValues(); } private void addGroupByValues() { if (groupByList.isEmpty()) { return; } final Expression[] multiselectGroupByArray = new Expression[groupByList.size()]; groupByList.toArray(multiselectGroupByArray); getCriteriaQuery().groupBy(multiselectGroupByArray); } private void addMultiSelectMultiSelectValues() { if (multiselectSelectList.isEmpty()) { throw new IllegalStateException("You want to extract a multiselect query, but you have not added any attribute or method to the query"); } final Selection[] multiselectSelectArray = new Selection[multiselectSelectList.size()]; multiselectSelectList.toArray(multiselectSelectArray); getConvertedCriteriaQuery().multiselect(multiselectSelectArray); } private void useCountDistinctInsteadOfQueryDistinct() { getCriteriaQuery().distinct(false); getCountCriteriaQuery().select(criteriaBuilder.countDistinct(root)); } public void addMultiSelectOperationExpression(final Expression multiselectPredicate) { multiselectSelectList.add(multiselectPredicate); } public void addMultiSelectPathException(final Expression multiselectPredicate) { multiselectSelectList.add(multiselectPredicate); } public void groupBy(final Path attributeToGroup) { groupByList.add(attributeToGroup); } }