/* * Copyright 2013 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.executor.impl.jpa; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.NoResultException; import org.drools.core.command.impl.ExecutableCommand; import org.jbpm.shared.services.impl.JpaPersistenceContext; import org.jbpm.shared.services.impl.QueryManager; import org.kie.api.executor.ErrorInfo; import org.kie.api.executor.ExecutorService; import org.kie.api.executor.RequestInfo; import org.kie.api.executor.STATUS; import org.kie.api.runtime.CommandExecutor; import org.kie.api.runtime.Context; import org.kie.api.runtime.query.QueryContext; import org.kie.internal.executor.api.ExecutorQueryService; import org.kie.internal.runtime.manager.RuntimeManagerRegistry; /** * Default implementation of <code>ExecutorQueryService</code> that is backed with JPA * IMPORTANT: please keep all classes from package org.jbpm.shared.services.impl as FQCN * inside method body to avoid exception logged by CDI when used with in memory mode */ public class ExecutorQueryServiceImpl implements ExecutorQueryService { private CommandExecutor commandService; private List<STATUS> waitingForExecutionOnly = Arrays.asList(STATUS.QUEUED, STATUS.RETRYING); public ExecutorQueryServiceImpl(boolean active) { QueryManager.get().addNamedQueries("META-INF/Executor-orm.xml"); } public void setCommandService(CommandExecutor commandService) { this.commandService = commandService; } /** * {@inheritDoc} */ @Override public List<RequestInfo> getPendingRequests() { return getPendingRequests(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getPendingRequestById(Long id) { Map<String, Object> params = new HashMap<String, Object>(); params.put("id", id); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("PendingRequestById", params)); } /** * {@inheritDoc} */ @Override public RequestInfo getRequestById(Long id) { return commandService.execute(new org.jbpm.shared.services.impl.commands.FindObjectCommand<org.jbpm.executor.entities.RequestInfo>(id, org.jbpm.executor.entities.RequestInfo.class)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getRunningRequests() { return getRunningRequests(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getQueuedRequests() { return getQueuedRequests(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getFutureQueuedRequests() { return getFutureQueuedRequests(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getCompletedRequests() { return getCompletedRequests(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getInErrorRequests() { return getInErrorRequests(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getCancelledRequests() { return getCancelledRequests(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<ErrorInfo> getAllErrors() { return getAllErrors(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<ErrorInfo> getErrorsByRequestId(Long requestId) { Map<String, Object> params = new HashMap<String, Object>(); params.put("id", requestId); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<ErrorInfo>>("GetErrorsByRequestId", params)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getAllRequests() { return getAllRequests(new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getRequestsByStatus(List<STATUS> statuses) { return getRequestsByStatus(statuses, new QueryContext(0, 100)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getRequestByBusinessKey(String businessKey, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("businessKey", businessKey); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("GetRequestsByBusinessKey", params)); } /** * {@inheritDoc} */ @Override public List<RequestInfo> getRequestByCommand(String command, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("command", command); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("GetRequestsByCommand", params)); } /** * {@inheritDoc} */ @Override public RequestInfo getRequestForProcessing() { // need to do the lock here to avoid many executor services fetch the same element RequestInfo request = commandService.execute(new LockAndUpdateRequestInfoCommand()); return request; } public RequestInfo getRequestForProcessing(Long requestId) { // need to do the lock here to avoid many executor services fetch the same element RequestInfo request = commandService.execute(new LockAndUpdateRequestInfoByIdCommand(requestId)); return request; } private class LockAndUpdateRequestInfoCommand implements ExecutableCommand<RequestInfo> { private static final long serialVersionUID = 8670412133363766161L; @Override public RequestInfo execute(Context context) { Map<String, Object> params = new HashMap<String, Object>(); params.put("now", new Date()); params.put("firstResult", 0); params.put("maxResults", 1); params.put("owner", ExecutorService.EXECUTOR_ID); params.put("deploymentId", getDeploymentIds()); RequestInfo request = null; try { org.jbpm.shared.services.impl.JpaPersistenceContext ctx = (org.jbpm.shared.services.impl.JpaPersistenceContext) context; request = ctx.queryAndLockWithParametersInTransaction("PendingRequestsForProcessing",params, true, RequestInfo.class); if (request != null) { request.setStatus(STATUS.RUNNING); // update date on when it was started to be executed ((org.jbpm.executor.entities.RequestInfo)request).setTime(new Date()); ctx.merge(request); } } catch (NoResultException e) { } return request; } } private class LockAndUpdateRequestInfoByIdCommand implements ExecutableCommand<RequestInfo> { private static final long serialVersionUID = 8670412133363766161L; private Long requestId; LockAndUpdateRequestInfoByIdCommand(Long requestId) { this.requestId = requestId; } @Override public RequestInfo execute(Context context) { Map<String, Object> params = new HashMap<String, Object>(); params.put("requestId", requestId); params.put("deploymentId", getDeploymentIds()); RequestInfo request = null; org.jbpm.shared.services.impl.JpaPersistenceContext ctx = (org.jbpm.shared.services.impl.JpaPersistenceContext) context; List<RequestInfo> foundInstance = ctx.queryAndLockWithParametersInTransaction("PendingRequestByIdForProcessing",params, false, List.class); if (foundInstance != null && !foundInstance.isEmpty()) { request = foundInstance.get(0); if (request != null) { request.setStatus(STATUS.RUNNING); // update date on when it was started to be executed ((org.jbpm.executor.entities.RequestInfo)request).setTime(new Date()); ctx.merge(request); } } return request; } } @Override public List<RequestInfo> getQueuedRequests(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("QueuedRequests", params)); } @Override public List<RequestInfo> getCompletedRequests(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("CompletedRequests", params)); } @Override public List<RequestInfo> getInErrorRequests(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("InErrorRequests", params)); } @Override public List<RequestInfo> getCancelledRequests(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("CancelledRequests", params)); } @Override public List<ErrorInfo> getAllErrors(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<ErrorInfo>>("GetAllErrors", params)); } @Override public List<RequestInfo> getAllRequests(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("GetAllRequests", params)); } @Override public List<RequestInfo> getRunningRequests(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("RunningRequests", params)); } @Override public List<RequestInfo> getFutureQueuedRequests(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); params.put("now", new Date()); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("FutureQueuedRequests", params)); } @Override public List<RequestInfo> getRequestsByStatus(List<STATUS> statuses, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); params.put("statuses", statuses); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("GetRequestsByStatus", params)); } @Override public List<RequestInfo> getPendingRequests(QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); applyQueryContext(params, queryContext); params.put("now", new Date()); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("PendingRequests", params)); } protected void applyQueryContext(Map<String, Object> params, QueryContext queryContext) { if (queryContext != null) { params.put(JpaPersistenceContext.FIRST_RESULT, queryContext.getOffset()); params.put(JpaPersistenceContext.MAX_RESULTS, queryContext.getCount()); if (queryContext.getOrderBy() != null && !queryContext.getOrderBy().isEmpty()) { params.put(QueryManager.ORDER_BY_KEY, queryContext.getOrderBy()); if (queryContext.isAscending()) { params.put(QueryManager.ASCENDING_KEY, "true"); } else { params.put(QueryManager.DESCENDING_KEY, "true"); } } } } @Override public List<RequestInfo> getRequestsByBusinessKey(String businessKey, List<STATUS> statuses, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("businessKey", businessKey); params.put("statuses", adjust(statuses)); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("GetRequestsByBusinessKeyAndStatus", params)); } @Override public List<RequestInfo> getRequestsByCommand(String command, List<STATUS> statuses, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("command", command); params.put("statuses", adjust(statuses)); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("GetRequestsByCommandAndStatus", params)); } @Override public List<RequestInfo> getRequestsByDeployment(String deploymentId, List<STATUS> statuses, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("deploymentId", deploymentId); params.put("statuses", adjust(statuses)); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("GetRequestsByDeploymentAndStatus", params)); } @Override public List<RequestInfo> getRequestsByProcessInstance(Long processInstanceId, List<STATUS> statuses, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("processInstanceId", processInstanceId); params.put("statuses", adjust(statuses)); applyQueryContext(params, queryContext); return commandService.execute(new org.jbpm.shared.services.impl.commands.QueryNameCommand<List<RequestInfo>>("GetRequestsByProcessInstanceAndStatus", params)); } protected List<STATUS> adjust(List<STATUS> statuses) { if (statuses == null || statuses.isEmpty()) { return waitingForExecutionOnly; } return statuses; } protected List<String> getDeploymentIds() { List<String> deployed = new ArrayList<>(RuntimeManagerRegistry.get().getRegisteredIdentifiers()); if (deployed.isEmpty()) { deployed.add(""); } return deployed; } }