/* * Copyright 2014 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.kie.services.impl; import org.drools.core.command.impl.ExecutableCommand; import org.drools.core.command.impl.RegistryContext; import org.drools.core.command.runtime.process.SetProcessInstanceVariablesCommand; import org.drools.core.command.runtime.process.StartProcessCommand; import org.drools.core.process.instance.WorkItemManager; import org.jbpm.process.instance.impl.ProcessInstanceImpl; import org.jbpm.services.api.DeploymentNotFoundException; import org.jbpm.services.api.DeploymentService; import org.jbpm.services.api.ProcessInstanceNotFoundException; import org.jbpm.services.api.ProcessService; import org.jbpm.services.api.RuntimeDataService; import org.jbpm.services.api.WorkItemNotFoundException; import org.jbpm.services.api.model.DeployedUnit; import org.jbpm.services.api.model.NodeInstanceDesc; import org.jbpm.services.api.model.ProcessInstanceDesc; import org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl; import org.jbpm.workflow.instance.node.CompositeNodeInstance; import org.jbpm.workflow.instance.node.EventNodeInstance; import org.kie.api.command.Command; import org.kie.api.runtime.EnvironmentName; import org.kie.api.runtime.KieSession; import org.kie.api.runtime.manager.Context; import org.kie.api.runtime.manager.RuntimeEngine; import org.kie.api.runtime.manager.RuntimeManager; import org.kie.api.runtime.process.NodeInstance; import org.kie.api.runtime.process.ProcessInstance; import org.kie.api.runtime.process.WorkItem; import org.kie.api.runtime.process.WorkflowProcessInstance; import org.kie.internal.process.CorrelationAwareProcessRuntime; import org.kie.internal.process.CorrelationKey; import org.kie.internal.runtime.manager.InternalRuntimeManager; import org.kie.internal.runtime.manager.SessionNotFoundException; import org.kie.internal.runtime.manager.context.CaseContext; import org.kie.internal.runtime.manager.context.CorrelationKeyContext; import org.kie.internal.runtime.manager.context.ProcessInstanceIdContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; public class ProcessServiceImpl implements ProcessService, VariablesAware { private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class); protected DeploymentService deploymentService; protected RuntimeDataService dataService; public void setDeploymentService(DeploymentService deploymentService) { this.deploymentService = deploymentService; } public void setDataService(RuntimeDataService dataService) { this.dataService = dataService; } @Override public Long startProcess(String deploymentId, String processId) { return startProcess(deploymentId, processId, new HashMap<String, Object>()); } @Override public Long startProcess(String deploymentId, String processId, Map<String, Object> params) { DeployedUnit deployedUnit = deploymentService.getDeployedUnit(deploymentId); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + deploymentId); } if (!deployedUnit.isActive()) { throw new DeploymentNotFoundException("Deployments " + deploymentId + " is not active"); } RuntimeManager manager = deployedUnit.getRuntimeManager(); params = process(params, ((InternalRuntimeManager) manager).getEnvironment().getClassLoader()); RuntimeEngine engine = manager.getRuntimeEngine(getContext(params)); KieSession ksession = engine.getKieSession(); ProcessInstance pi = null; try { pi = ksession.startProcess(processId, params); return pi.getId(); } finally { disposeRuntimeEngine(manager, engine); } } @Override public Long startProcess(String deploymentId, String processId, CorrelationKey correlationKey) { return startProcess(deploymentId, processId, correlationKey, new HashMap<String, Object>()); } @Override public Long startProcess(String deploymentId, String processId, CorrelationKey correlationKey, Map<String, Object> params) { DeployedUnit deployedUnit = deploymentService.getDeployedUnit(deploymentId); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + deploymentId); } if (!deployedUnit.isActive()) { throw new DeploymentNotFoundException("Deployments " + deploymentId + " is not active"); } RuntimeManager manager = deployedUnit.getRuntimeManager(); params = process(params, ((InternalRuntimeManager) manager).getEnvironment().getClassLoader()); RuntimeEngine engine = manager.getRuntimeEngine(getContext(params)); KieSession ksession = engine.getKieSession(); ProcessInstance pi = null; try { pi = ((CorrelationAwareProcessRuntime)ksession).startProcess(processId, correlationKey, params); return pi.getId(); } finally { disposeRuntimeEngine(manager, engine); } } protected Context<?> getContext(Map<String, Object> params) { if (params == null) { return ProcessInstanceIdContext.get(); } String caseId = (String) params.get(EnvironmentName.CASE_ID); if (caseId != null && !caseId.isEmpty()) { return CaseContext.get(caseId); } return ProcessInstanceIdContext.get(); } @Override public void abortProcessInstance(Long processInstanceId) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null || piDesc.getState().intValue() != 1) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); ksession.abortProcessInstance(processInstanceId); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public void abortProcessInstances(List<Long> processInstanceIds) { for (long processInstanceId : processInstanceIds) { abortProcessInstance(processInstanceId); } } @Override public void signalProcessInstance(Long processInstanceId, String signalName, Object event) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null || piDesc.getState().intValue() != 1) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); event = process(event, ((InternalRuntimeManager) manager).getEnvironment().getClassLoader()); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); ksession.signalEvent(signalName, event, processInstanceId); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public void signalProcessInstances(List<Long> processInstanceIds, String signalName, Object event) { for (Long processInstanceId : processInstanceIds) { signalProcessInstance(processInstanceId, signalName, event); } } @Override public void signalEvent(String deployment, String signalName, Object event) { DeployedUnit deployedUnit = deploymentService.getDeployedUnit(deployment); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + deployment); } RuntimeManager manager = deployedUnit.getRuntimeManager(); event = process(event, ((InternalRuntimeManager) manager).getEnvironment().getClassLoader()); manager.signalEvent(signalName, event); } @Override public ProcessInstance getProcessInstance(Long processInstanceId) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null) { return null; } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); return ksession.getProcessInstance(processInstanceId); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public ProcessInstance getProcessInstance(CorrelationKey key) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceByCorrelationKey(key); if (piDesc == null) { return null; } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(CorrelationKeyContext.get(key)); KieSession ksession = engine.getKieSession(); try { return ((CorrelationAwareProcessRuntime)ksession).getProcessInstance(key); } finally { disposeRuntimeEngine(manager, engine); } } @Override public void setProcessVariable(Long processInstanceId, String variableId, Object value) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null || piDesc.getState().intValue() != 1) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); value = process(value, ((InternalRuntimeManager) manager).getEnvironment().getClassLoader()); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); ksession.execute(new SetProcessInstanceVariablesCommand(processInstanceId, Collections.singletonMap(variableId, value))); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public void setProcessVariables(Long processInstanceId, Map<String, Object> variables) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null || piDesc.getState().intValue() != 1) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); variables = process(variables, ((InternalRuntimeManager) manager).getEnvironment().getClassLoader()); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); ksession.execute(new SetProcessInstanceVariablesCommand(processInstanceId, variables)); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public Object getProcessInstanceVariable(Long processInstanceId, String variableName) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null || piDesc.getState().intValue() != 1) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); Object variable = ksession.execute(new ExecutableCommand<Object>() { private static final long serialVersionUID = -2693525229757876896L; @Override public Object execute(org.kie.api.runtime.Context context) { KieSession ksession = ((RegistryContext) context).lookup( KieSession.class ); WorkflowProcessInstance pi = (WorkflowProcessInstance) ksession.getProcessInstance(processInstanceId, true); if (pi == null) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } Object variable = pi.getVariable(variableName); return variable; } }); return variable; } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public Map<String, Object> getProcessInstanceVariables(Long processInstanceId) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null || piDesc.getState().intValue() != 1) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); WorkflowProcessInstanceImpl pi = (WorkflowProcessInstanceImpl) ksession.getProcessInstance(processInstanceId, true); return pi.getVariables(); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public Collection<String> getAvailableSignals(Long processInstanceId) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); ProcessInstance processInstance = ksession.getProcessInstance(processInstanceId); Collection<String> activeSignals = new ArrayList<String>(); if (processInstance != null) { ((ProcessInstanceImpl) processInstance) .setProcess(ksession.getKieBase().getProcess(processInstance.getProcessId())); Collection<NodeInstance> activeNodes = ((WorkflowProcessInstance) processInstance).getNodeInstances(); activeSignals.addAll(collectActiveSignals(activeNodes)); } return activeSignals; } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public void completeWorkItem(Long id, Map<String, Object> results) { NodeInstanceDesc nodeDesc = dataService.getNodeInstanceForWorkItem(id); if (nodeDesc == null) { throw new WorkItemNotFoundException("Work item with id " + id + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(nodeDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + nodeDesc.getDeploymentId()); } Long processInstanceId = nodeDesc.getProcessInstanceId(); RuntimeManager manager = deployedUnit.getRuntimeManager(); results = process(results, ((InternalRuntimeManager) manager).getEnvironment().getClassLoader()); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); ksession.getWorkItemManager().completeWorkItem(id, results); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public void abortWorkItem(Long id) { NodeInstanceDesc nodeDesc = dataService.getNodeInstanceForWorkItem(id); if (nodeDesc == null) { throw new WorkItemNotFoundException("Work item with id " + id + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(nodeDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + nodeDesc.getDeploymentId()); } Long processInstanceId = nodeDesc.getProcessInstanceId(); RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); ksession.getWorkItemManager().abortWorkItem(id); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public WorkItem getWorkItem(Long id) { NodeInstanceDesc nodeDesc = dataService.getNodeInstanceForWorkItem(id); if (nodeDesc == null) { throw new WorkItemNotFoundException("Work item with id " + id + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(nodeDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + nodeDesc.getDeploymentId()); } Long processInstanceId = nodeDesc.getProcessInstanceId(); RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); return ((WorkItemManager)ksession.getWorkItemManager()).getWorkItem(id); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public List<WorkItem> getWorkItemByProcessInstance(Long processInstanceId) { ProcessInstanceDesc piDesc = dataService.getProcessInstanceById(processInstanceId); if (piDesc == null || piDesc.getState().intValue() != 1) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found"); } DeployedUnit deployedUnit = deploymentService.getDeployedUnit(piDesc.getDeploymentId()); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + piDesc.getDeploymentId()); } RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); List<WorkItem> workItems = new ArrayList<WorkItem>(); Collection<NodeInstanceDesc> nodes = dataService.getProcessInstanceHistoryActive(processInstanceId, null); for (NodeInstanceDesc node : nodes) { if (node.getWorkItemId() != null) { workItems.add(((WorkItemManager)ksession.getWorkItemManager()).getWorkItem(node.getWorkItemId())); } } return workItems; } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public <T> T execute(String deploymentId, Command<T> command) { Long processInstanceId = CommonUtils.getProcessInstanceId(command); logger.debug("Executing command {} with process instance id {} as contextual data", command, processInstanceId); DeployedUnit deployedUnit = deploymentService.getDeployedUnit(deploymentId); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + deploymentId); } disallowWhenNotActive(deployedUnit, command); RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get(processInstanceId)); try { KieSession ksession = engine.getKieSession(); return ksession.execute(command); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with id " + processInstanceId + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } @Override public <T> T execute(String deploymentId, Context<?> context, Command<T> command) { DeployedUnit deployedUnit = deploymentService.getDeployedUnit(deploymentId); if (deployedUnit == null) { throw new DeploymentNotFoundException("No deployments available for " + deploymentId); } disallowWhenNotActive(deployedUnit, command); RuntimeManager manager = deployedUnit.getRuntimeManager(); RuntimeEngine engine = manager.getRuntimeEngine(context); try { KieSession ksession = engine.getKieSession(); return ksession.execute(command); } catch(SessionNotFoundException e) { throw new ProcessInstanceNotFoundException("Process instance with context id " + context.getContextId() + " was not found", e); } finally { disposeRuntimeEngine(manager, engine); } } protected void disallowWhenNotActive(DeployedUnit deployedUnit, Command<?> cmd) { if (!deployedUnit.isActive() && cmd instanceof StartProcessCommand) { throw new DeploymentNotFoundException("Deployments " + deployedUnit.getDeploymentUnit().getIdentifier() + " is not active"); } } protected Collection<String> collectActiveSignals( Collection<NodeInstance> activeNodes) { Collection<String> activeNodesComposite = new ArrayList<String>(); for (NodeInstance nodeInstance : activeNodes) { if (nodeInstance instanceof EventNodeInstance) { String type = ((EventNodeInstance) nodeInstance).getEventNode().getType(); if (type != null && !type.startsWith("Message-")) { activeNodesComposite.add(type); } } if (nodeInstance instanceof CompositeNodeInstance) { Collection<NodeInstance> currentNodeInstances = ((CompositeNodeInstance) nodeInstance).getNodeInstances(); // recursively check current nodes activeNodesComposite .addAll(collectActiveSignals(currentNodeInstances)); } } return activeNodesComposite; } @Override public <T> T process(T variables, ClassLoader cl) { // do nothing here as there is no need to process variables return variables; } protected void disposeRuntimeEngine(RuntimeManager manager, RuntimeEngine engine) { manager.disposeRuntimeEngine(engine); } }