All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jbpm.services.task.persistence.TaskSummaryQueryCriteriaUtil Maven / Gradle / Ivy

/*
 * Copyright 2017 Red Hat, Inc. and/or its affiliates.
 *
 * 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 org.jbpm.services.task.persistence;

import static org.kie.internal.query.QueryParameterIdentifiers.ACTUAL_OWNER_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.ARCHIVED;
import static org.kie.internal.query.QueryParameterIdentifiers.BUSINESS_ADMIN_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.CREATED_BY_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.CREATED_ON_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.DEPLOYMENT_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.EXCLUDED_OWNER_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.EXPIRATION_TIME_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.POTENTIAL_OWNER_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.PROCESS_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.PROCESS_INSTANCE_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.PROCESS_SESSION_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.SKIPPABLE;
import static org.kie.internal.query.QueryParameterIdentifiers.STAKEHOLDER_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.SUB_TASKS_STRATEGY;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_ACTIVATION_TIME_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_DESCRIPTION_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_FORM_NAME_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_NAME_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_PARENT_ID_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_PRIORITY_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_STATUS_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_SUBJECT_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TASK_USER_ROLES_LIMIT_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.TYPE_LIST;
import static org.kie.internal.query.QueryParameterIdentifiers.WORK_ITEM_ID_LIST;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.persistence.Tuple;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Selection;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.CollectionAttribute;
import javax.persistence.metamodel.ListAttribute;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SetAttribute;
import javax.persistence.metamodel.SingularAttribute;

import org.jbpm.query.jpa.data.QueryCriteria;
import org.jbpm.query.jpa.data.QueryParameterIdentifiersUtil;
import org.jbpm.query.jpa.data.QueryWhere;
import org.jbpm.query.jpa.data.QueryWhere.QueryCriteriaType;
import org.jbpm.query.jpa.service.QueryModificationService;
import org.jbpm.services.task.impl.model.I18NTextImpl;
import org.jbpm.services.task.impl.model.I18NTextImpl_;
import org.jbpm.services.task.impl.model.OrganizationalEntityImpl;
import org.jbpm.services.task.impl.model.OrganizationalEntityImpl_;
import org.jbpm.services.task.impl.model.PeopleAssignmentsImpl;
import org.jbpm.services.task.impl.model.PeopleAssignmentsImpl_;
import org.jbpm.services.task.impl.model.TaskDataImpl;
import org.jbpm.services.task.impl.model.TaskDataImpl_;
import org.jbpm.services.task.impl.model.TaskImpl;
import org.jbpm.services.task.impl.model.TaskImpl_;
import org.jbpm.services.task.impl.model.UserImpl;
import org.jbpm.services.task.impl.model.UserImpl_;
import org.jbpm.services.task.query.TaskSummaryImpl;
import org.kie.api.task.UserGroupCallback;
import org.kie.api.task.model.Status;
import org.kie.api.task.model.TaskSummary;
import org.kie.internal.query.QueryParameterIdentifiers;
import org.kie.internal.task.api.TaskPersistenceContext;
import org.kie.internal.task.api.model.SubTasksStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TaskSummaryQueryCriteriaUtil extends AbstractTaskQueryCriteriaUtil {

    public final static Logger logger = LoggerFactory.getLogger(TaskSummaryQueryCriteriaUtil.class);

    // Query Field Info -----------------------------------------------------------------------------------------------------------

    public final static Map> criteriaAttributes
        = new ConcurrentHashMap>();

    private ServiceLoader queryModificationServiceLoader = ServiceLoader.load(QueryModificationService.class);

    @Override
    protected synchronized boolean initializeCriteriaAttributes() {
        if( TaskImpl_.id == null ) {
            // EMF/persistence has not been initialized:
            // When a persistence unit (EntityManagerFactory) is initialized,
            // the fields of classes annotated with @StaticMetamodel are filled using reflection
            return false;
        }
        // do not do initialization twice (slow performance, otherwise it doesn't matter)
        if( ! criteriaAttributes.isEmpty() ) {
            return true;
        }

        // TaskImpl
        addCriteria(criteriaAttributes, TASK_ACTIVATION_TIME_LIST,  TaskImpl.class, TaskDataImpl_.activationTime);
        addCriteria(criteriaAttributes, ARCHIVED,                   TaskImpl_.archived);
        addCriteria(criteriaAttributes, CREATED_ON_LIST,            TaskImpl.class, TaskDataImpl_.createdOn);
        addCriteria(criteriaAttributes, DEPLOYMENT_ID_LIST,         TaskImpl.class, TaskDataImpl_.deploymentId);
        addCriteria(criteriaAttributes, EXPIRATION_TIME_LIST,       TaskImpl.class, TaskDataImpl_.expirationTime);
        addCriteria(criteriaAttributes, TASK_FORM_NAME_LIST,        TaskImpl_.formName);
        addCriteria(criteriaAttributes, PROCESS_ID_LIST,            TaskImpl.class, TaskDataImpl_.processId);
        addCriteria(criteriaAttributes, PROCESS_INSTANCE_ID_LIST,   TaskImpl.class, TaskDataImpl_.processInstanceId);
        addCriteria(criteriaAttributes, PROCESS_SESSION_ID_LIST,    TaskImpl.class, TaskDataImpl_.processSessionId);
        addCriteria(criteriaAttributes, SKIPPABLE,                  TaskImpl.class, TaskDataImpl_.skipable);
        addCriteria(criteriaAttributes, TASK_STATUS_LIST,           TaskImpl.class, TaskDataImpl_.status);
        addCriteria(criteriaAttributes, SUB_TASKS_STRATEGY,         TaskImpl_.subTaskStrategy);
        addCriteria(criteriaAttributes, TASK_ID_LIST,               TaskImpl_.id);
        addCriteria(criteriaAttributes, TASK_PARENT_ID_LIST,        TaskImpl.class, TaskDataImpl_.parentId);
        addCriteria(criteriaAttributes, TYPE_LIST,                  TaskImpl_.taskType);
        addCriteria(criteriaAttributes, WORK_ITEM_ID_LIST,          TaskImpl.class, TaskDataImpl_.workItemId);
        addCriteria(criteriaAttributes, TASK_PRIORITY_LIST,         TaskImpl.class, TaskImpl_.priority);

        addCriteria(criteriaAttributes, TASK_DESCRIPTION_LIST,      TaskImpl_.descriptions);
        addCriteria(criteriaAttributes, TASK_NAME_LIST,             TaskImpl_.names);
        addCriteria(criteriaAttributes, TASK_SUBJECT_LIST,          TaskImpl_.subjects);

        addCriteria(criteriaAttributes, ACTUAL_OWNER_ID_LIST,       TaskImpl.class, TaskDataImpl_.actualOwner);
        addCriteria(criteriaAttributes, CREATED_BY_LIST,            TaskImpl.class, TaskDataImpl_.createdBy); // initiator

        addCriteria(criteriaAttributes, BUSINESS_ADMIN_ID_LIST,     TaskImpl.class, PeopleAssignmentsImpl_.businessAdministrators);
        addCriteria(criteriaAttributes, POTENTIAL_OWNER_ID_LIST,    TaskImpl.class, PeopleAssignmentsImpl_.potentialOwners);
        addCriteria(criteriaAttributes, STAKEHOLDER_ID_LIST,        TaskImpl.class, PeopleAssignmentsImpl_.taskStakeholders);
        addCriteria(criteriaAttributes, EXCLUDED_OWNER_ID_LIST,     TaskImpl.class, PeopleAssignmentsImpl_.excludedOwners);


        return true;
    }

    private static final Set taskUserRoleLimitingListIds = new HashSet();
    static {
        taskUserRoleLimitingListIds.add(ACTUAL_OWNER_ID_LIST);
        taskUserRoleLimitingListIds.add(CREATED_BY_LIST);
        taskUserRoleLimitingListIds.add(BUSINESS_ADMIN_ID_LIST);
        taskUserRoleLimitingListIds.add(POTENTIAL_OWNER_ID_LIST);
        taskUserRoleLimitingListIds.add(STAKEHOLDER_ID_LIST);
    }

    public TaskSummaryQueryCriteriaUtil(TaskPersistenceContext persistenceContext) {
        super(persistenceContext);
        initialize(criteriaAttributes);
    }

    public TaskSummaryQueryCriteriaUtil() {
        initialize(criteriaAttributes);
    }

    // Implementation specific methods --------------------------------------------------------------------------------------------

    public List doCriteriaQuery(String userId, UserGroupCallback userGroupCallback, QueryWhere queryWhere) {

        // 1. create builder and query instances
        CriteriaBuilder builder = getCriteriaBuilder();
        CriteriaQuery criteriaQuery = builder.createTupleQuery();

        // 2. query base
        Root taskRoot = criteriaQuery.from(TaskImpl.class);
        criteriaQuery = criteriaQuery.multiselect(
                taskRoot.get(TaskImpl_.id),                                                         // 0
                taskRoot.get(TaskImpl_.name),                                                       // 1
                taskRoot.get(TaskImpl_.subject),                                                    // 2
                taskRoot.get(TaskImpl_.description),                                                // 3

                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.status),                         // 4
                taskRoot.get(TaskImpl_.priority),                                                   // 5
                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.skipable),                       // 6

                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.actualOwner).get(UserImpl_.id),  // 7
                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.createdBy).get(UserImpl_.id),    // 8

                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.createdOn),                      // 9
                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.activationTime),                 // 10
                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.expirationTime),                 // 11

                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.processId),                      // 12
                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.processSessionId),               // 13
                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.processInstanceId),              // 14
                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.deploymentId),                   // 15

                taskRoot.get(TaskImpl_.subTaskStrategy),                                            // 16
                taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.parentId)                        // 17
                );
        taskRoot.join(TaskImpl_.taskData); // added for convienence sake, since other logic expects to find this join

        addUserGroupsViaCallBackToQueryWhere(userGroupCallback, queryWhere.getCriteria());

        // 3. check to see if there's already a user(/security)-limitation in the search
        checkExistingCriteriaForUserBasedLimit(queryWhere, userId, userGroupCallback);
        for( QueryModificationService queryModificationService : queryModificationServiceLoader ) {
            queryModificationService.optimizeCriteria(queryWhere);
        }

        // 4. process query criteria
        fillCriteriaQuery(criteriaQuery, queryWhere, builder, TaskImpl.class);

        // 5. retrieve result (after also applying meta-criteria)
        useDistinctWhenLefOuterJoinsPresent(criteriaQuery);
        List result = createQueryAndCallApplyMetaCriteriaAndGetResult(queryWhere, criteriaQuery, builder);

        List taskSummaryList = new ArrayList(result.size());
        for( Tuple tupleRow : result ) {
            int i = 0;
            //@formatter:off
            TaskSummaryImpl taskSummaryImpl = new TaskSummaryImpl(
               // id
               tupleRow.get(i++, Long.class),
               // name, subject, description
               tupleRow.get(i++, String.class), tupleRow.get(i++, String.class), tupleRow.get(i++, String.class),
               // status, prio, skippable
               tupleRow.get(i++, Status.class), tupleRow.get(i++, Integer.class), tupleRow.get(i++, Boolean.class),
               // actual owner, created by
               tupleRow.get(i++, String.class), tupleRow.get(i++, String.class),
               // created on, activation time, expiration time
               tupleRow.get(i++, Date.class), tupleRow.get(i++, Date.class), tupleRow.get(i++, Date.class),
               // process id, process session id, process inst id, deployment id
               tupleRow.get(i++, String.class), tupleRow.get(i++, Long.class), tupleRow.get(i++, Long.class), tupleRow.get(i++, String.class),
               tupleRow.get(i++, SubTasksStrategy.class),
               tupleRow.get(i++, Long.class) );
            //@formatter:on
            taskSummaryList.add(taskSummaryImpl);

        }
        return taskSummaryList;
    }

    /**
     * @param userGroupCallback
     * @param criteriaList
     */
    private void addUserGroupsViaCallBackToQueryWhere(UserGroupCallback userGroupCallback, List criteriaList) {
        if (criteriaList.isEmpty()) {
            return;
        }

        for (QueryCriteria criteria : criteriaList) {
            if (criteria.isGroupCriteria()) {
                addUserGroupsViaCallBackToQueryWhere(userGroupCallback, criteria.getCriteria());
            } else {
                String critieraListId = criteria.getListId();
                if (critieraListId.equals(POTENTIAL_OWNER_ID_LIST) || critieraListId.equals(ACTUAL_OWNER_ID_LIST)
                        || critieraListId.equals(STAKEHOLDER_ID_LIST) || critieraListId.equals(BUSINESS_ADMIN_ID_LIST)) {

                    List allNewGroupIds = new ArrayList<>();
                    for (Object userObj : criteria.getValues()) {
                        if (userObj instanceof String) {
                            List groupIds = userGroupCallback.getGroupsForUser(userObj.toString());
                            if (groupIds != null && !groupIds.isEmpty()) {
                                allNewGroupIds.addAll(groupIds);
                            }
                        }
                    }

                    if (!allNewGroupIds.isEmpty()) {
                        criteria.getValues().addAll(allNewGroupIds);
                    }
                }
            }
        }
    }

    /**
     * This method checks whether or not the query *already* contains a limiting criteria (in short, a criteria that limits results
     * of the query) that refers to the user or (the user's groups).  If there is no user/group limiting criteria, then a
     * {@link QueryCriteria} with the user and group ids is added to the {@link QueryWhere} instance
     * 

* If this method returns true, then there is no need to add additional criteria to the query to limit the query results * to tasks that the user may see -- there is already query present in the query that takes care of this. * * @param queryWhere The {@link QueryWhere} instance containing the query criteria * @param userId The string user id of the user calling the query * @param userGroupCallback A {@link UserGroupCallback} instance in order to retrieve the groups of the given user */ private void checkExistingCriteriaForUserBasedLimit(QueryWhere queryWhere, String userId, UserGroupCallback userGroupCallback) { List groupIds = userGroupCallback.getGroupsForUser(userId); Set userAndGroupIds = new HashSet(); if( groupIds != null ) { userAndGroupIds.addAll(groupIds); } userAndGroupIds.add(userId); if( ! criteriaListForcesUserLimitation(userAndGroupIds, queryWhere.getCriteria()) ) { addUserRolesLimitCriteria(queryWhere, userId, groupIds); } } /** * This method calls itself recursively to determine whether or not the given {@link List}<{@link QueryCriteria}> contains a * user/group limiting criteria. * * @param userAndGroupIds A set containing the user id and all group ids * @param criteriaList The {@link List} of {@link QueryCriteria} to search * @return Whether or not the {@link QueryCriteria} list contains a user/group limiting criteria */ private static boolean criteriaListForcesUserLimitation(Set userAndGroupIds, List criteriaList) { boolean userLimitiationIntersection = false; if( criteriaList.isEmpty() ) { return false; } for( QueryCriteria criteria : criteriaList ) { if( criteria.isUnion() && criteriaList.size() > 1) { return false; } if( criteria.isGroupCriteria() ) { if( criteriaListForcesUserLimitation(userAndGroupIds, criteria.getCriteria()) ) { return true; } continue; } // intersection criteria if( taskUserRoleLimitingListIds.contains(criteria.getListId()) ) { for( Object param : criteria.getParameters() ) { if( userAndGroupIds.contains(param) ) { return true; } } } } return userLimitiationIntersection; } /** * Adds an (intersecting) {@link QueryCriteria} that limits the results to results that the user is allowed to see * * @param queryWhere The {@link QueryWhere} instance that defines the query criteria * @param userId The user id * @param groupIds The user's group ids */ private void addUserRolesLimitCriteria( QueryWhere queryWhere, String userId, List groupIds ) { List newBaseCriteriaList = new ArrayList(2); // user role limiting criteria QueryCriteria userRolesLimitingCriteria = new QueryCriteria( QueryParameterIdentifiers.TASK_USER_ROLES_LIMIT_LIST, false, QueryCriteriaType.NORMAL, 2); userRolesLimitingCriteria.setFirst(true); userRolesLimitingCriteria.getValues().add(userId); userRolesLimitingCriteria.getValues().add(groupIds); newBaseCriteriaList.add(userRolesLimitingCriteria); // original criteria list in a new group if( ! queryWhere.getCriteria().isEmpty() ) { QueryCriteria originalBaseCriteriaGroup = new QueryCriteria(false); originalBaseCriteriaGroup.setCriteria(queryWhere.getCriteria()); newBaseCriteriaList.add(originalBaseCriteriaGroup); } queryWhere.setCriteria(newBaseCriteriaList); } /* * (non-Javadoc) * @see org.jbpm.query.jpa.impl.QueryCriteriaUtil#getEntityField(javax.persistence.criteria.CriteriaQuery, java.lang.Class, java.lang.String) */ @Override protected Expression getEntityField(CriteriaQuery query, String listId, Attribute attr) { if( attr == null ) { return null; } Root taskRoot = null; Join taskDataJoin = null; Join peopAssignJoin = null; for( Root root : query.getRoots() ) { if( TaskImpl.class.equals(root.getJavaType()) ) { taskRoot = (Root) root; for( Join join : taskRoot.getJoins() ) { if( TaskDataImpl.class.equals(join.getJavaType()) ) { taskDataJoin = (Join) join; } else if( PeopleAssignmentsImpl.class.equals(join.getJavaType()) ) { peopAssignJoin = (Join) join; } } } } assert taskRoot != null : "Unable to find TaskImpl Root in query!"; if( taskDataJoin == null ) { taskDataJoin = taskRoot.join(TaskImpl_.taskData); } assert taskDataJoin != null : "Unable to find TaskDataImpl Join in query!"; return taskImplSpecificGetEntityField(query, taskRoot, taskDataJoin, peopAssignJoin, listId, attr); } @SuppressWarnings("unchecked") public static Expression taskImplSpecificGetEntityField(CriteriaQuery query, Root taskRoot, Join taskDataJoin, Join peopleAssignJoin, String listId, Attribute attr) { Expression entityField = null; if( attr != null ) { if( listId.equals(TASK_DESCRIPTION_LIST) || listId.equals(TASK_NAME_LIST) || listId.equals(TASK_SUBJECT_LIST) ) { // we can *not* query on @LOB annotated fields (and it would be inefficient for a query api to do this?) // so we query on the (max 255 char length) string equivalent fields entityField = getJoinedEntityField(taskRoot, (Attribute) attr, I18NTextImpl_.shortText); } else if( listId.equals(ACTUAL_OWNER_ID_LIST) || listId.equals(CREATED_BY_LIST) ) { if( taskDataJoin == null ) { taskDataJoin = taskRoot.join(TaskImpl_.taskData); } // task -> taskData -> (actualOwn/createdBy) UserImpl -> id entityField = getJoinedEntityField(taskDataJoin, (Attribute) attr, UserImpl_.id); } else if( listId.equals(BUSINESS_ADMIN_ID_LIST) || listId.equals(POTENTIAL_OWNER_ID_LIST) || listId.equals(STAKEHOLDER_ID_LIST) || listId.equals(EXCLUDED_OWNER_ID_LIST) ) { if( peopleAssignJoin == null ) { peopleAssignJoin = taskRoot.join(TaskImpl_.peopleAssignments); } // task -> peopleAssignments -> (bus admin/pot owner/stake holder/excl user) OrganizationalEntityImpl -> id entityField = getJoinedEntityField(peopleAssignJoin, (Attribute) attr, OrganizationalEntityImpl_.id); } else { if( taskDataJoin == null ) { taskDataJoin = taskRoot.join(TaskImpl_.taskData); } Class attrType = attr.getDeclaringType().getJavaType(); From [] taskRoots = { taskRoot, taskDataJoin }; for( From from : taskRoots ) { if( from.getJavaType().equals(attrType) ) { if( attr != null ) { if( attr instanceof SingularAttribute ) { entityField = from.get((SingularAttribute) attr); } else if( attr instanceof PluralAttribute ) { entityField = from.get((PluralAttribute) attr); } else { throw new IllegalStateException("Unexpected attribute type when processing criteria with list id " + listId + ": " + attr.getClass().getName() ); } break; } } } } } return entityField; } /** * This retrieves the correct field ({@link Expression}) that should be used when building the {@link Predicate}. *

* This field is necessary because of the amount of joins and the complexity in the human-task schema. * * @param grandparentJoin This is the parent join, * for example the join between TaskDataImpl -> PeopleAssignments * @param parentJoinAttr This is the {@link Attribute} with the information over the join (from the parent) that we need to create, * for example the {@link SingularAttribute}<{@link PeopleAssignmentsImpl}, {@link OrganizationalEntityImpl}> {@link Attribute}. * @param fieldAttr This is the {@link Attribute} with the actual attribute that we create an {@link Expression} to build a {@link Predicate} for, * for example the {@link OrganizationalEntityImpl_#id} field. * @return an {@link Expression} that can be used in a predicate with the values/parameters from a {@link QueryCriteria} instance */ @SuppressWarnings("unchecked") public static Expression getJoinedEntityField(From grandparentJoin, Attribute parentJoinAttr, SingularAttribute fieldAttr) { // task -> * -> origJoin -> (fieldParentAttr field in) tojoinType -> fieldAttr Class toAttrJoinType; if( parentJoinAttr instanceof SingularAttribute ) { toAttrJoinType = parentJoinAttr.getJavaType(); } else if( parentJoinAttr instanceof PluralAttribute ) { toAttrJoinType = ((PluralAttribute) parentJoinAttr).getElementType().getJavaType(); } else { String joinName = parentJoinAttr.getDeclaringType().getJavaType().getSimpleName() + "." + parentJoinAttr.getName(); throw new IllegalStateException("Unknown attribute type encountered when trying to join " + joinName ); } Join fieldParentJoin = null; for( Join join : grandparentJoin.getJoins() ) { if( join.getJavaType().equals(toAttrJoinType) ) { if( join.getAttribute().equals(parentJoinAttr) ) { fieldParentJoin = (Join) join; if( ! JoinType.INNER.equals(fieldParentJoin.getJoinType()) ) { // This a criteria set by the user (as opposed to the user-limiting criteria) -- it MUST be followed // This means that the join is not optional (LEFT) but mandatory (INNER) fieldParentJoin = null; } break; } } } if( fieldParentJoin == null ) { if( parentJoinAttr instanceof SingularAttribute) { fieldParentJoin = grandparentJoin.join((SingularAttribute) parentJoinAttr); } else if( parentJoinAttr instanceof CollectionAttribute) { fieldParentJoin = grandparentJoin.join((CollectionAttribute) parentJoinAttr); } else if( parentJoinAttr instanceof ListAttribute) { fieldParentJoin = grandparentJoin.join((ListAttribute) parentJoinAttr); } else if( parentJoinAttr instanceof SetAttribute) { fieldParentJoin = grandparentJoin.join((SetAttribute) parentJoinAttr); } else { throw new IllegalStateException("Unknown attribute type encountered when trying to join" + parentJoinAttr.getName() ); } } return fieldParentJoin.get(fieldAttr); } @Override protected Predicate implSpecificCreatePredicateFromSingleCriteria( CriteriaQuery query, CriteriaBuilder builder, Class queryType, QueryCriteria criteria, QueryWhere queryWhere) { Predicate predicate = null; String listId = criteria.getListId(); if( TASK_USER_ROLES_LIMIT_LIST.equals(listId) ) { predicate = createTaskUserRolesLimitPredicate(criteria, query, builder); } else { for( QueryModificationService queryModService : queryModificationServiceLoader ) { if( queryModService.accepts(listId) ) { return queryModService.createPredicate(criteria, query, builder); } } throw new IllegalStateException("List id " + QueryParameterIdentifiersUtil.getQueryParameterIdNameMap().get(Integer.parseInt(criteria.getListId())) + " is not supported for queries on " + TaskImpl.class.getSimpleName() + "."); } return predicate; } @SuppressWarnings("unchecked") private static Predicate createTaskUserRolesLimitPredicate(QueryCriteria criteria, CriteriaQuery criteriaQuery, CriteriaBuilder builder) { String userId = (String) criteria.getValues().get(0); List groupIds = (List) criteria.getValues().get(1); Root taskRoot = getRoot(criteriaQuery, TaskImpl.class); assert taskRoot != null : "TaskImpl Root instance could not be found in query!"; boolean groupIdsPresent = (groupIds.size() > 0); int numPredicates = groupIdsPresent ? 5 : 2; // joins that apply to the user id's Predicate [] userGroupLimitingPredicates = new Predicate[numPredicates]; userGroupLimitingPredicates[0] = builder.equal(taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.actualOwner).get(UserImpl_.id), userId); userGroupLimitingPredicates[1] = builder.equal(taskRoot.get(TaskImpl_.taskData).get(TaskDataImpl_.createdBy).get(UserImpl_.id), userId); Join taskDataJoin = null; Join peopleAssignJoin = null; if( taskRoot != null ) { for( Join join : taskRoot.getJoins() ) { if( join.getJavaType().equals(PeopleAssignmentsImpl.class) ) { peopleAssignJoin = (Join) join; } else if( join.getJavaType().equals(TaskDataImpl.class) ) { taskDataJoin = (Join) join; } } } assert taskDataJoin != null : "TaskImpl -> TaskDataImpl join could not be found in query!"; // joins that apply to the group id's if( groupIdsPresent ) { if( peopleAssignJoin == null ) { peopleAssignJoin = taskRoot.join(TaskImpl_.peopleAssignments); } ListJoin [] groupJoins = getPeopleAssignmentsJoins(peopleAssignJoin); for( int i = 0; i < groupJoins.length; ++i ) { userGroupLimitingPredicates[i+2] = builder.or( builder.equal( groupJoins[i].get(OrganizationalEntityImpl_.id), userId ), groupJoins[i].get(OrganizationalEntityImpl_.id).in(groupIds) ); } } return builder.or(userGroupLimitingPredicates); } private static ListJoin [] getPeopleAssignmentsJoins( Join peopleAssignJoin) { ListJoin [] joins = new ListJoin[3]; for( Join join : peopleAssignJoin.getJoins() ) { String joinFieldName = join.getAttribute().getName(); if( PeopleAssignmentsImpl_.businessAdministrators.getName().equals(joinFieldName) ) { joins[0] = (ListJoin) join; } else if( PeopleAssignmentsImpl_.potentialOwners.getName().equals(joinFieldName) ) { joins[1] = (ListJoin) join; } else if( PeopleAssignmentsImpl_.taskStakeholders.getName().equals(joinFieldName) ) { joins[2] = (ListJoin) join; } } if( joins[0] == null ) { joins[0] = peopleAssignJoin.join(PeopleAssignmentsImpl_.businessAdministrators, JoinType.LEFT); } if( joins[1] == null ) { joins[1] = peopleAssignJoin.join(PeopleAssignmentsImpl_.potentialOwners, JoinType.LEFT); } if( joins[2] == null ) { joins[2] = peopleAssignJoin.join(PeopleAssignmentsImpl_.taskStakeholders, JoinType.LEFT); } assert joins[0] != null : "Could not find business administrators join!"; assert joins[1] != null : "Could not find potential owners join!"; assert joins[2] != null : "Could not find task stakeholders join!"; return joins; } private void useDistinctWhenLefOuterJoinsPresent(CriteriaQuery criteriaQuery) { boolean useDistinct = false; Root taskRoot = null; ROOTS_FOR: for( Root root : criteriaQuery.getRoots() ) { if( TaskImpl.class.equals(root.getJavaType()) ) { taskRoot = (Root) root; for( Join taskJoin : taskRoot.getJoins() ) { if( PeopleAssignmentsImpl.class.equals(taskJoin.getJavaType()) ) { Join peopleAssignJoin = (Join) taskJoin; if( JoinType.LEFT.equals(peopleAssignJoin.getJoinType()) ) { useDistinct = true; break ROOTS_FOR; } for( Join peopleAssignJoinJoin : peopleAssignJoin.getJoins() ) { if( JoinType.LEFT.equals(peopleAssignJoinJoin.getJoinType()) ) { useDistinct = true; break ROOTS_FOR; } } } } } } if( useDistinct ) { criteriaQuery.distinct(true); } } @Override protected Expression getOrderByExpression(CriteriaQuery query, Class queryType, String orderByListId) { List> selections = query.getSelection().getCompoundSelectionItems(); Selection orderBySelection = null; if( orderByListId.equals(QueryParameterIdentifiers.TASK_ID_LIST) ) { orderBySelection = selections.get(0); } else if( orderByListId.equals(QueryParameterIdentifiers.TASK_NAME_LIST) ) { orderBySelection = selections.get(1); } else if( orderByListId.equals(QueryParameterIdentifiers.TASK_STATUS_LIST) ) { orderBySelection = selections.get(4); } else if( orderByListId.equals(QueryParameterIdentifiers.CREATED_BY_LIST) ) { orderBySelection = selections.get(8); } else if( orderByListId.equals(QueryParameterIdentifiers.CREATED_ON_LIST) ) { orderBySelection = selections.get(9); } else if( orderByListId.equals(QueryParameterIdentifiers.PROCESS_INSTANCE_ID_LIST) ) { orderBySelection = selections.get(14); } return (Expression) orderBySelection; } public static Predicate taskSpecificCreatePredicateFromSingleCriteria( CriteriaQuery query, CriteriaBuilder builder, QueryCriteria criteria, QueryWhere queryWhere) { Predicate predicate = null; String listId = criteria.getListId(); if( TASK_USER_ROLES_LIMIT_LIST.equals(listId) ) { predicate = createTaskUserRolesLimitPredicate(criteria, query, builder); } else { throw new IllegalStateException("List id " + QueryParameterIdentifiersUtil.getQueryParameterIdNameMap().get(Integer.parseInt(criteria.getListId())) + " is not supported for queries on " + TaskImpl.class.getSimpleName() + "."); } return predicate; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy