/*
* Copyright 2016 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.casemgmt.impl;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static org.kie.internal.query.QueryParameterIdentifiers.FILTER;
import static org.jbpm.kie.services.impl.CommonUtils.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.jbpm.casemgmt.api.CaseNotFoundException;
import org.jbpm.casemgmt.api.CaseRuntimeDataService;
import org.jbpm.casemgmt.api.auth.AuthorizationManager;
import org.jbpm.casemgmt.api.generator.CaseIdGenerator;
import org.jbpm.casemgmt.api.model.AdHocFragment;
import org.jbpm.casemgmt.api.model.CaseDefinition;
import org.jbpm.casemgmt.api.model.CaseFileItem;
import org.jbpm.casemgmt.api.model.CaseMilestone;
import org.jbpm.casemgmt.api.model.CaseRole;
import org.jbpm.casemgmt.api.model.CaseStage;
import org.jbpm.casemgmt.api.model.CaseStatus;
import org.jbpm.casemgmt.api.model.instance.CaseInstance;
import org.jbpm.casemgmt.api.model.instance.CaseMilestoneInstance;
import org.jbpm.casemgmt.api.model.instance.CaseStageInstance;
import org.jbpm.casemgmt.api.model.instance.StageStatus;
import org.jbpm.casemgmt.impl.model.AdHocFragmentImpl;
import org.jbpm.casemgmt.impl.model.CaseDefinitionComparator;
import org.jbpm.casemgmt.impl.model.CaseDefinitionImpl;
import org.jbpm.casemgmt.impl.model.CaseMilestoneImpl;
import org.jbpm.casemgmt.impl.model.CaseRoleImpl;
import org.jbpm.casemgmt.impl.model.CaseStageImpl;
import org.jbpm.casemgmt.impl.model.ProcessDefinitionComparator;
import org.jbpm.casemgmt.impl.model.instance.CaseMilestoneInstanceImpl;
import org.jbpm.casemgmt.impl.model.instance.CaseStageInstanceImpl;
import org.jbpm.kie.services.impl.model.NodeInstanceDesc;
import org.jbpm.kie.services.impl.model.ProcessAssetDesc;
import org.jbpm.kie.services.impl.security.DeploymentRolesManager;
import org.jbpm.runtime.manager.impl.AbstractRuntimeManager;
import org.jbpm.services.api.DeploymentEvent;
import org.jbpm.services.api.DeploymentEventListener;
import org.jbpm.services.api.RuntimeDataService;
import org.jbpm.services.api.model.DeployedAsset;
import org.jbpm.services.api.model.ProcessDefinition;
import org.jbpm.services.api.model.ProcessInstanceDesc;
import org.jbpm.shared.services.impl.QueryManager;
import org.jbpm.shared.services.impl.TransactionalCommandService;
import org.jbpm.shared.services.impl.commands.QueryNameCommand;
import org.jbpm.workflow.core.WorkflowProcess;
import org.jbpm.workflow.core.node.BoundaryEventNode;
import org.jbpm.workflow.core.node.DynamicNode;
import org.jbpm.workflow.core.node.MilestoneNode;
import org.jbpm.workflow.core.node.StartNode;
import org.kie.api.KieBase;
import org.kie.api.definition.process.Node;
import org.kie.api.definition.process.NodeContainer;
import org.kie.api.definition.process.Process;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.api.task.model.Status;
import org.kie.api.task.model.TaskSummary;
import org.kie.internal.KieInternalServices;
import org.kie.internal.identity.IdentityProvider;
import org.kie.internal.process.CorrelationKey;
import org.kie.internal.process.CorrelationKeyFactory;
import org.kie.api.runtime.query.QueryContext;
public class CaseRuntimeDataServiceImpl implements CaseRuntimeDataService, DeploymentEventListener {
protected Set<CaseDefinitionImpl> availableCases = new HashSet<CaseDefinitionImpl>();
protected Set<ProcessDefinition> availableProcesses = new HashSet<ProcessDefinition>();
private CorrelationKeyFactory correlationKeyFactory = KieInternalServices.Factory.get().newCorrelationKeyFactory();
private CaseIdGenerator caseIdGenerator;
private RuntimeDataService runtimeDataService;
private TransactionalCommandService commandService;
private IdentityProvider identityProvider;
private DeploymentRolesManager deploymentRolesManager = new DeploymentRolesManager();
// default statuses set to active only
private List<CaseStatus> statuses = Arrays.asList(CaseStatus.OPEN);
private static final List<Status> allActiveStatus = Arrays.asList(
Status.Created,
Status.Ready,
Status.Reserved,
Status.InProgress,
Status.Suspended
);
public CaseRuntimeDataServiceImpl() {
QueryManager.get().addNamedQueries("META-INF/CaseMgmtorm.xml");
}
public CaseIdGenerator getCaseIdGenerator() {
return caseIdGenerator;
}
public void setCaseIdGenerator(CaseIdGenerator caseIdGenerator) {
this.caseIdGenerator = caseIdGenerator;
}
public void setRuntimeDataService(RuntimeDataService runtimeDataService) {
this.runtimeDataService = runtimeDataService;
}
public void setCommandService(TransactionalCommandService commandService) {
this.commandService = commandService;
}
public void setIdentityProvider(IdentityProvider identityProvider) {
this.identityProvider = identityProvider;
}
public void setDeploymentRolesManager(DeploymentRolesManager deploymentRolesManager) {
this.deploymentRolesManager = deploymentRolesManager;
}
/*
* Deploy and undeploy handling
*/
@Override
public void onDeploy(DeploymentEvent event) {
AbstractRuntimeManager runtimeManager = (AbstractRuntimeManager) event.getDeployedUnit().getRuntimeManager();
KieBase kieBase = runtimeManager.getEnvironment().getKieBase();
Collection<Process> processes = kieBase.getProcesses();
Map<String, DeployedAsset> mapProcessById = event.getDeployedUnit().getDeployedAssets()
.stream()
.collect(toMap(DeployedAsset::getId, asset -> asset));
for( Process process : processes ) {
if( ((WorkflowProcess)process).isDynamic()) {
String caseIdPrefix = collectCaseIdPrefix(process);
Collection<CaseMilestone> caseMilestones = collectMilestoness(process);
Collection<CaseStage> caseStages = collectCaseStages(event.getDeploymentId(), process.getId(), ((WorkflowProcess)process));
Collection<CaseRole> caseRoles = collectCaseRoles(process);
Collection<AdHocFragment> adHocFragments = collectAdHocFragments((WorkflowProcess)process);
CaseDefinitionImpl caseDef = new CaseDefinitionImpl((ProcessAssetDesc) mapProcessById.get(process.getId()), caseIdPrefix, caseStages, caseMilestones, caseRoles, adHocFragments);
availableCases.add(caseDef);
caseIdGenerator.register(caseIdPrefix);
}
}
// collect role information
Collection<DeployedAsset> assets = event.getDeployedUnit().getDeployedAssets();
List<String> roles = null;
for( DeployedAsset asset : assets ) {
if( asset instanceof ProcessAssetDesc ) {
// if it's not dynamic it's considered as not case definition
if (!((ProcessAssetDesc) asset).isDynamic()) {
availableProcesses.add((ProcessAssetDesc) asset);
}
if (roles == null) {
roles = ((ProcessAssetDesc) asset).getRoles();
}
}
}
if (roles == null) {
roles = Collections.emptyList();
}
deploymentRolesManager.addRolesForDeployment(event.getDeploymentId(), roles);
}
@Override
public void onUnDeploy(DeploymentEvent event) {
Collection<CaseDefinitionImpl> undeployed = availableCases.stream()
.filter(caseDef -> caseDef.getDeploymentId().equals(event.getDeploymentId()))
.collect(toList());
availableCases.removeAll(undeployed);
Collection<ProcessDefinition> undeployedProcesses = availableProcesses.stream()
.filter(process -> process.getDeploymentId().equals(event.getDeploymentId()))
.collect(toList());
availableProcesses.removeAll(undeployedProcesses);
undeployed.forEach(caseDef -> caseIdGenerator.unregister(caseDef.getIdentifierPrefix()));
deploymentRolesManager.removeRolesForDeployment(event.getDeploymentId());
}
@Override
public void onActivate(DeploymentEvent event) {
// no op - all is done on RuntimeDataService level as CaseDefinition depends on ProcessDefinition
}
@Override
public void onDeactivate(DeploymentEvent event) {
// no op - all is done on RuntimeDataService level as CaseDefinition depends on ProcessDefinition
}
/*
* CaseDefinition operations
*/
@Override
public CaseDefinition getCase(String deploymentId, String caseDefinitionId) {
return availableCases.stream()
.filter(caseDef -> caseDef.getDeploymentId().equals(deploymentId)
&& caseDef.getId().equals(caseDefinitionId))
.findFirst()
.orElse(null);
}
@Override
public Collection<CaseDefinition> getCases(QueryContext queryContext) {
Collection<CaseDefinition> cases = availableCases.stream()
.filter(caseDef -> caseDef.isActive())
.sorted(new CaseDefinitionComparator(queryContext.getOrderBy(), queryContext.isAscending()))
.skip(queryContext.getOffset())
.limit(queryContext.getCount())
.collect(toList());
return cases;
}
@Override
public Collection<CaseDefinition> getCases(String filter, QueryContext queryContext) {
String pattern = "(?i)^.*"+filter+".*$";
Collection<CaseDefinition> cases = availableCases.stream()
.filter(caseDef -> caseDef.isActive()
&& (caseDef.getId().matches(pattern) || caseDef.getName().matches(pattern)))
.sorted(new CaseDefinitionComparator(queryContext.getOrderBy(), queryContext.isAscending()))
.skip(queryContext.getOffset())
.limit(queryContext.getCount())
.collect(toList());
return cases;
}
@Override
public Collection<CaseDefinition> getCasesByDeployment(String deploymentId, QueryContext queryContext) {
Collection<CaseDefinition> cases = availableCases.stream()
.filter(caseDef -> caseDef.isActive() && caseDef.getDeploymentId().equals(deploymentId))
.sorted(new CaseDefinitionComparator(queryContext.getOrderBy(), queryContext.isAscending()))
.skip(queryContext.getOffset())
.limit(queryContext.getCount())
.collect(toList());
return cases;
}
/*
* Process definitions related
*/
@Override
public Collection<ProcessDefinition> getProcessDefinitions(QueryContext queryContext) {
Collection<ProcessDefinition> cases = availableProcesses.stream()
.filter(caseDef -> caseDef.isActive())
.sorted(new ProcessDefinitionComparator(queryContext.getOrderBy(), queryContext.isAscending()))
.skip(queryContext.getOffset())
.limit(queryContext.getCount())
.collect(toList());
return cases;
}
@Override
public Collection<ProcessDefinition> getProcessDefinitions(String filter, QueryContext queryContext) {
String pattern = "(?i)^.*"+filter+".*$";
Collection<ProcessDefinition> cases = availableProcesses.stream()
.filter(caseDef -> caseDef.isActive()
&& (caseDef.getId().matches(pattern) || caseDef.getName().matches(pattern)))
.sorted(new ProcessDefinitionComparator(queryContext.getOrderBy(), queryContext.isAscending()))
.skip(queryContext.getOffset())
.limit(queryContext.getCount())
.collect(toList());
return cases;
}
@Override
public Collection<ProcessDefinition> getProcessDefinitionsByDeployment(String deploymentId, QueryContext queryContext) {
Collection<ProcessDefinition> cases = availableProcesses.stream()
.filter(caseDef -> caseDef.isActive() && caseDef.getDeploymentId().equals(deploymentId))
.sorted(new ProcessDefinitionComparator(queryContext.getOrderBy(), queryContext.isAscending()))
.skip(queryContext.getOffset())
.limit(queryContext.getCount())
.collect(toList());
return cases;
}
/*
* Case instance and its process instances operations
*/
@Override
public Collection<ProcessInstanceDesc> getProcessInstancesForCase(String caseId, QueryContext queryContext) {
CorrelationKey correlationKey = correlationKeyFactory.newCorrelationKey(caseId);
return runtimeDataService.getProcessInstancesByCorrelationKey(correlationKey, queryContext);
}
@Override
public Collection<ProcessInstanceDesc> getProcessInstancesForCase(String caseId, List<Integer> processStates, QueryContext queryContext) {
CorrelationKey correlationKey = correlationKeyFactory.newCorrelationKey(caseId);
return runtimeDataService.getProcessInstancesByCorrelationKeyAndStatus(correlationKey, processStates, queryContext);
}
@Override
public Collection<CaseMilestoneInstance> getCaseInstanceMilestones(String caseId, boolean achievedOnly, QueryContext queryContext) {
ProcessInstanceDesc pi = runtimeDataService.getProcessInstanceByCorrelationKey(correlationKeyFactory.newCorrelationKey(caseId));
if (pi == null || !pi.getState().equals(ProcessInstance.STATE_ACTIVE)) {
throw new CaseNotFoundException("No case instance found with id " + caseId + " or it's not active anymore");
}
CorrelationKey correlationKey = correlationKeyFactory.newCorrelationKey(caseId);
Collection<org.jbpm.services.api.model.NodeInstanceDesc> nodes = runtimeDataService.getNodeInstancesByCorrelationKeyNodeType(correlationKey,
Arrays.asList(ProcessInstance.STATE_ACTIVE),
Arrays.asList("MilestoneNode"),
queryContext);
Collection<Long> completedNodes = nodes.stream().filter(n -> ((NodeInstanceDesc)n).getType() == 1).map(n -> n.getId()).collect(toList());
Predicate<org.jbpm.services.api.model.NodeInstanceDesc> filterNodes = null;
if (achievedOnly) {
filterNodes = n -> ((NodeInstanceDesc)n).getType() == 1;
} else {
filterNodes = n -> ((NodeInstanceDesc)n).getType() == 0;
}
List<String> foundMilestones = new ArrayList<>();
List<CaseMilestoneInstance> milestones = nodes.stream()
.filter(filterNodes)
.map(n -> {
foundMilestones.add(n.getName());
return new CaseMilestoneInstanceImpl(String.valueOf(n.getId()), n.getName(), completedNodes.contains(n.getId()), n.getDataTimeStamp());
})
.collect(toList());
if (!achievedOnly) {
// add other milestones that are present in the definition
CaseDefinition caseDef = getCase(pi.getDeploymentId(), pi.getProcessId());
caseDef.getCaseMilestones().stream()
.filter(cm -> !foundMilestones.contains(cm.getName()))
.map(cm -> new CaseMilestoneInstanceImpl(cm.getId(), cm.getName(), false, null))
.forEach(cmi -> milestones.add(cmi));
}
return applyPagination(milestones, queryContext);
}
@Override
public Collection<CaseStageInstance> getCaseInstanceStages(String caseId, boolean activeOnly, QueryContext queryContext) {
ProcessInstanceDesc pi = runtimeDataService.getProcessInstanceByCorrelationKey(correlationKeyFactory.newCorrelationKey(caseId));
if (pi == null || !pi.getState().equals(ProcessInstance.STATE_ACTIVE)) {
throw new CaseNotFoundException("No case instance found with id " + caseId + " or it's not active anymore");
}
CaseDefinition caseDef = getCase(pi.getDeploymentId(), pi.getProcessId());
List<CaseStageInstance> stages = internalGetCaseStages(caseDef, caseId, activeOnly, queryContext);
return applyPagination(stages, queryContext);
}
/*
* Case instance queries
*/
@Override
public Collection<org.jbpm.services.api.model.NodeInstanceDesc> getActiveNodesForCase(String caseId, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId + "%");
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<org.jbpm.services.api.model.NodeInstanceDesc> nodeInstances = commandService.execute(new QueryNameCommand<List<org.jbpm.services.api.model.NodeInstanceDesc>>("getActiveNodesForCase", params));
return nodeInstances;
}
@Override
public Collection<org.jbpm.services.api.model.NodeInstanceDesc> getCompletedNodesForCase(String caseId, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId + "%");
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<org.jbpm.services.api.model.NodeInstanceDesc> nodeInstances = commandService.execute(new QueryNameCommand<List<org.jbpm.services.api.model.NodeInstanceDesc>>("getCompletedNodesForCase", params));
return nodeInstances;
}
@Override
public Collection<CaseInstance> getCaseInstances(QueryContext queryContext) {
return getCaseInstances(statuses, queryContext);
}
@Override
public Collection<CaseInstance> getCaseInstances(List<CaseStatus> statuses, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("statuses", resolveCaseStatuses(statuses));
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstances", params));
return processInstances;
}
@Override
public Collection<CaseInstance> getCaseInstancesByDeployment(String deploymentId, List<CaseStatus> statuses, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("deploymentId", deploymentId);
params.put("statuses", resolveCaseStatuses(statuses));
params.put("entities", collectUserAuthInfo());
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstancesByDeployment", params));
return processInstances;
}
@Override
public Collection<CaseInstance> getCaseInstancesByDefinition(String definitionId, List<CaseStatus> statuses, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("definitionId", definitionId);
params.put("statuses", resolveCaseStatuses(statuses));
params.put("entities", collectUserAuthInfo());
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstancesByDefinition", params));
return processInstances;
}
@Override
public Collection<CaseInstance> getCaseInstancesOwnedBy(String owner, List<CaseStatus> statuses, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("owner", owner);
params.put("statuses", resolveCaseStatuses(statuses));
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstancesOwnedBy", params));
return processInstances;
}
@Override
public Collection<CaseInstance> getCaseInstancesByRole(String roleName, List<CaseStatus> statuses, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("roleName", roleName);
params.put("entities", collectUserAuthInfo());
params.put("statuses", resolveCaseStatuses(statuses));
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstancesByRole", params));
return processInstances;
}
@Override
public Collection<CaseInstance> getCaseInstancesAnyRole(List<CaseStatus> statuses, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("entities", collectUserAuthInfo());
params.put("statuses", resolveCaseStatuses(statuses));
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstancesAnyRole", params));
return processInstances;
}
@Override
public Collection<CaseInstance> getCaseInstancesByDateItem(String dataItemName, List<CaseStatus> statuses, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("itemName", dataItemName);
params.put("entities", collectUserAuthInfo());
params.put("statuses", resolveCaseStatuses(statuses));
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstancesByVariableName", params));
return processInstances;
}
@Override
public Collection<CaseInstance> getCaseInstancesByDateItemAndValue(String dataItemName, String dataItemValue, List<CaseStatus> statuses, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("itemName", dataItemName);
params.put("itemValue", dataItemValue);
params.put("entities", collectUserAuthInfo());
params.put("statuses", resolveCaseStatuses(statuses));
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstancesByVariableNameAndValue", params));
return processInstances;
}
@Override
public CaseInstance getCaseInstanceById(String caseId) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("correlationKey", caseId);
params.put("maxResults", 1);
List<CaseInstance> processInstances = commandService.execute(new QueryNameCommand<List<CaseInstance>>("getCaseInstanceById", params));
if (!processInstances.isEmpty()) {
return processInstances.get(0);
}
throw new CaseNotFoundException("Case " + caseId + " was not found");
}
@Override
public Collection<AdHocFragment> getAdHocFragmentsForCase(String caseId) {
ProcessInstanceDesc pi = runtimeDataService.getProcessInstanceByCorrelationKey(correlationKeyFactory.newCorrelationKey(caseId));
if (pi == null || !pi.getState().equals(ProcessInstance.STATE_ACTIVE)) {
throw new CaseNotFoundException("No case instance found with id " + caseId + " or it's not active anymore");
}
CaseDefinition caseDef = getCase(pi.getDeploymentId(), pi.getProcessId());
List<AdHocFragment> adHocFragments = new ArrayList<>();
adHocFragments.addAll(caseDef.getAdHocFragments());
Collection<CaseStageInstance> activeStages = internalGetCaseStages(caseDef, caseId, true, new QueryContext(0, 100));
activeStages.forEach(stage -> adHocFragments.addAll(stage.getAdHocFragments()));
return adHocFragments;
}
/*
* Task related queries
*/
@Override
public List<TaskSummary> getCaseTasksAssignedAsPotentialOwner(String caseId, String userId, List<Status> status, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId + "%");
params.put("userId", userId);
params.put("status", adoptList(status, allActiveStatus));
params.put("groupIds", getAuthenticatedUserRoles(identityProvider));
applyQueryContext(params, queryContext);
List<TaskSummary> tasks = commandService.execute(new QueryNameCommand<List<TaskSummary>>("getCaseTasksAsPotentialOwner", params));
return tasks;
}
@Override
public List<TaskSummary> getCaseTasksAssignedAsBusinessAdmin(String caseId, String userId, List<Status> status, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId + "%");
params.put("userId", userId);
params.put("status", adoptList(status, allActiveStatus));
params.put("groupIds", getAuthenticatedUserRoles(identityProvider));
applyQueryContext(params, queryContext);
List<TaskSummary> tasks = commandService.execute(new QueryNameCommand<List<TaskSummary>>("getCaseTasksAsBusinessAdmin", params));
return tasks;
}
@Override
public List<TaskSummary> getCaseTasksAssignedAsStakeholder(String caseId, String userId, List<Status> status, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId + "%");
params.put("userId", userId);
params.put("status", adoptList(status, allActiveStatus));
params.put("groupIds", getAuthenticatedUserRoles(identityProvider));
applyQueryContext(params, queryContext);
List<TaskSummary> tasks = commandService.execute(new QueryNameCommand<List<TaskSummary>>("getCaseTasksAsStakeholder", params));
return tasks;
}
/*
* Helper methods to parse process and extract case related information
*/
public List<CaseStageInstance> internalGetCaseStages(CaseDefinition caseDef, String caseId, boolean activeOnly, QueryContext queryContext) {
CorrelationKey correlationKey = correlationKeyFactory.newCorrelationKey(caseId);
Collection<org.jbpm.services.api.model.NodeInstanceDesc> nodes = runtimeDataService.getNodeInstancesByCorrelationKeyNodeType(correlationKey,
Arrays.asList(ProcessInstance.STATE_ACTIVE),
Arrays.asList("DynamicNode"),
queryContext);
Collection<Long> completedNodes = nodes.stream().filter(n -> ((NodeInstanceDesc)n).getType() == 1).map(n -> n.getId()).collect(toList());
Map<String, CaseStage> stagesByName = caseDef.getCaseStages().stream()
.collect(toMap(CaseStage::getId, c -> c));
Predicate<org.jbpm.services.api.model.NodeInstanceDesc> filterNodes = null;
if (activeOnly) {
filterNodes = n -> ((NodeInstanceDesc)n).getType() == 0 && !completedNodes.contains(((NodeInstanceDesc)n).getId());
} else {
filterNodes = n -> ((NodeInstanceDesc)n).getType() == 0;
}
List<String> triggeredStages = new ArrayList<>();
List<CaseStageInstance> stages = new ArrayList<>();
nodes.stream()
.filter(filterNodes)
.map(n -> {
StageStatus status = StageStatus.Active;
if (completedNodes.contains(((NodeInstanceDesc)n).getId())) {
status = StageStatus.Completed;
}
Collection<org.jbpm.services.api.model.NodeInstanceDesc> activeNodes = getActiveNodesForCaseAndStage(caseId, n.getNodeId(), new QueryContext(0, 100));
return new CaseStageInstanceImpl(n.getNodeId(), n.getName(), stagesByName.get(n.getNodeId()).getAdHocFragments(), activeNodes, status);
})
.forEach(csi -> {
stages.add(csi);
triggeredStages.add(csi.getName());
});
if (!activeOnly) {
// add other stages that are present in the definition
caseDef.getCaseStages().stream()
.filter(cs -> !triggeredStages.contains(cs.getName()))
.map(cs -> new CaseStageInstanceImpl(cs.getId(), cs.getName(), cs.getAdHocFragments(), Collections.emptyList(), StageStatus.Available))
.forEach(csi -> stages.add(csi));
}
return stages;
}
protected Collection<org.jbpm.services.api.model.NodeInstanceDesc> getActiveNodesForCaseAndStage(String caseId, String stageId, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId + "%");
params.put("nodeContainerId", stageId);
applyQueryContext(params, queryContext);
applyDeploymentFilter(params);
List<org.jbpm.services.api.model.NodeInstanceDesc> nodeInstances = commandService.execute(new QueryNameCommand<List<org.jbpm.services.api.model.NodeInstanceDesc>>("getActiveNodesForCaseAndStage", params));
return nodeInstances;
}
private Collection<CaseRole> collectCaseRoles(Process process) {
String roles = (String) process.getMetaData().get("customCaseRoles");
if (roles == null) {
return Collections.emptyList();
}
List<CaseRole> result = new ArrayList<CaseRole>();
String[] roleStrings = roles.split(",");
for (String roleString: roleStrings) {
String[] elements = roleString.split(":");
CaseRoleImpl role = new CaseRoleImpl(elements[0]);
result.add(role);
if (elements.length > 1) {
role.setCardinality(Integer.parseInt(elements[1]));
}
}
return result;
}
private String collectCaseIdPrefix(Process process) {
String caseIdPrefix = (String) process.getMetaData().get("customCaseIdPrefix");
if (caseIdPrefix == null) {
return CaseDefinition.DEFAULT_PREFIX;
}
return caseIdPrefix;
}
private Collection<CaseMilestone> collectMilestoness(Process process) {
Collection<CaseMilestone> result = new ArrayList<CaseMilestone>();
getMilestones((WorkflowProcess) process, result);
return result;
}
private void getMilestones(NodeContainer container, Collection<CaseMilestone> result) {
for (Node node: container.getNodes()) {
if (node instanceof MilestoneNode) {
result.add(new CaseMilestoneImpl((String) node.getMetaData().get("UniqueId"), node.getName(), ((MilestoneNode) node).getConstraint(), false));
}
if (node instanceof NodeContainer) {
getMilestones((NodeContainer) node, result);
}
}
}
private Collection<CaseStage> collectCaseStages(String deploymentId, String processId, NodeContainer process) {
Collection<CaseStage> result = new ArrayList<CaseStage>();
for (Node node : process.getNodes()) {
if (node instanceof DynamicNode) {
DynamicNode dynamicNode = (DynamicNode) node;
Collection<AdHocFragment> adHocFragments = collectAdHocFragments(dynamicNode);
result.add(new CaseStageImpl((String) ((DynamicNode) node).getMetaData("UniqueId"),
node.getName(),
adHocFragments));
}
}
return result;
}
private Collection<AdHocFragment> collectAdHocFragments(NodeContainer process) {
List<AdHocFragment> result = new ArrayList<AdHocFragment>();
checkAdHoc(process, result);
return result;
}
private void checkAdHoc(NodeContainer nodeContainer, List<AdHocFragment> result) {
for (Node node : nodeContainer.getNodes()) {
if (node instanceof StartNode || node instanceof BoundaryEventNode) {
continue;
}
if (node.getIncomingConnections().isEmpty()) {
result.add(new AdHocFragmentImpl(node.getName(), node.getClass().getSimpleName()));
}
}
}
protected void applyQueryContext(Map<String, Object> params, QueryContext queryContext) {
if (queryContext != null) {
params.put("firstResult", queryContext.getOffset());
params.put("maxResults", 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");
}
}
}
}
protected void applyDeploymentFilter(Map<String, Object> params) {
if (deploymentRolesManager != null) {
List<String> deploymentIdForUser = deploymentRolesManager.getDeploymentsForUser(identityProvider);
if (deploymentIdForUser != null && !deploymentIdForUser.isEmpty()) {
params.put(FILTER, " log.externalId in (:deployments) ");
params.put("deployments", deploymentIdForUser);
}
}
}
protected List<?> adoptList(List<?> source, List<?> values) {
if (source == null || source.isEmpty()) {
List<Object> data = new ArrayList<Object>();
for (Object value : values) {
data.add(value);
}
return data;
}
return source;
}
protected List<String> collectUserAuthInfo() {
List<String> entities = new ArrayList<>();
entities.add(identityProvider.getName());
entities.addAll(getAuthenticatedUserRoles(identityProvider));
// add special public role to allow to find cases that do not use case roles
entities.add(AuthorizationManager.PUBLIC_GROUP);
return entities;
}
protected <T> Collection<T> applyPagination(List<T> input, QueryContext queryContext) {
if (queryContext != null) {
int start = queryContext.getOffset();
int end = start + queryContext.getCount();
if (input.size() < start) {
// no elements in given range
return new ArrayList<T>();
} else if (input.size() >= end) {
return Collections.unmodifiableCollection(new ArrayList<T>(input.subList(start, end)));
} else if (input.size() < end) {
return Collections.unmodifiableCollection(new ArrayList<T>(input.subList(start, input.size())));
}
}
return Collections.unmodifiableCollection(input);
}
protected List<Integer> resolveCaseStatuses(List<CaseStatus> caseStatusesList) {
return caseStatusesList != null ? caseStatusesList.stream().map(event -> event.getId()).collect(Collectors.toList()) : null;
}
@Override
public Collection<CaseFileItem> getCaseInstanceDataItems(String caseId, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId);
params.put("entities", collectUserAuthInfo());
applyQueryContext(params, queryContext);
List<CaseFileItem> caseFileItems = commandService.execute(new QueryNameCommand<List<CaseFileItem>>("getCaseInstanceDataItems", params));
return caseFileItems;
}
@Override
public Collection<CaseFileItem> getCaseInstanceDataItemsByName(String caseId, List<String> names, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId);
params.put("itemNames", names);
params.put("entities", collectUserAuthInfo());
applyQueryContext(params, queryContext);
List<CaseFileItem> caseFileItems = commandService.execute(new QueryNameCommand<List<CaseFileItem>>("getCaseInstanceDataItemsByName", params));
return caseFileItems;
}
@Override
public Collection<CaseFileItem> getCaseInstanceDataItemsByType(String caseId, List<String> types, QueryContext queryContext) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("caseId", caseId);
params.put("itemTypes", types);
params.put("entities", collectUserAuthInfo());
applyQueryContext(params, queryContext);
List<CaseFileItem> caseFileItems = commandService.execute(new QueryNameCommand<List<CaseFileItem>>("getCaseInstanceDataItemsByType", params));
return caseFileItems;
}
}