/* 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.activiti.engine.impl.bpmn.behavior; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.activiti.bpmn.model.MapExceptionEntry; import org.activiti.engine.ActivitiException; import org.activiti.engine.ProcessEngineConfiguration; import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.Expression; import org.activiti.engine.impl.bpmn.data.AbstractDataAssociation; import org.activiti.engine.impl.bpmn.helper.ErrorPropagation; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.persistence.deploy.DeploymentManager; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.pvm.PvmProcessInstance; import org.activiti.engine.impl.pvm.delegate.ActivityExecution; import org.activiti.engine.impl.pvm.delegate.SubProcessActivityBehavior; /** * Implementation of the BPMN 2.0 call activity * (limited currently to calling a subprocess and not (yet) a global task). * * @author Joram Barrez */ public class CallActivityBehavior extends AbstractBpmnActivityBehavior implements SubProcessActivityBehavior { protected String processDefinitonKey; private List<AbstractDataAssociation> dataInputAssociations = new ArrayList<AbstractDataAssociation>(); private List<AbstractDataAssociation> dataOutputAssociations = new ArrayList<AbstractDataAssociation>(); private Expression processDefinitionExpression; protected List<MapExceptionEntry> mapExceptions; protected boolean inheritVariables; public CallActivityBehavior(String processDefinitionKey, List<MapExceptionEntry> mapExceptions) { this.processDefinitonKey = processDefinitionKey; this.mapExceptions = mapExceptions; } public CallActivityBehavior(Expression processDefinitionExpression, List<MapExceptionEntry> mapExceptions) { super(); this.processDefinitionExpression = processDefinitionExpression; this.mapExceptions = mapExceptions; } public void addDataInputAssociation(AbstractDataAssociation dataInputAssociation) { this.dataInputAssociations.add(dataInputAssociation); } public void addDataOutputAssociation(AbstractDataAssociation dataOutputAssociation) { this.dataOutputAssociations.add(dataOutputAssociation); } public void setInheritVariables(boolean inheritVariables) { this.inheritVariables = inheritVariables; } public void execute(ActivityExecution execution) throws Exception { String processDefinitonKey = this.processDefinitonKey; if (processDefinitionExpression != null) { processDefinitonKey = (String) processDefinitionExpression.getValue(execution); } DeploymentManager deploymentManager = Context.getProcessEngineConfiguration().getDeploymentManager(); ProcessDefinitionEntity processDefinition = null; if (execution.getTenantId() == null || ProcessEngineConfiguration.NO_TENANT_ID.equals(execution.getTenantId())) { processDefinition = deploymentManager.findDeployedLatestProcessDefinitionByKey(processDefinitonKey); } else { processDefinition = deploymentManager.findDeployedLatestProcessDefinitionByKeyAndTenantId(processDefinitonKey, execution.getTenantId()); } // Do not start a process instance if the process definition is suspended if (deploymentManager.isProcessDefinitionSuspended(processDefinition.getId())) { throw new ActivitiException("Cannot start process instance. Process definition " + processDefinition.getName() + " (id = " + processDefinition.getId() + ") is suspended"); } PvmProcessInstance subProcessInstance = execution.createSubProcessInstance(processDefinition); if (inheritVariables) { Map<String, Object> variables = execution.getVariables(); for (Map.Entry<String, Object> entry : variables.entrySet()) { subProcessInstance.setVariable(entry.getKey(), entry.getValue()); } } // copy process variables for (AbstractDataAssociation dataInputAssociation : dataInputAssociations) { Object value = null; if (dataInputAssociation.getSourceExpression()!=null) { value = dataInputAssociation.getSourceExpression().getValue(execution); } else { value = execution.getVariable(dataInputAssociation.getSource()); } subProcessInstance.setVariable(dataInputAssociation.getTarget(), value); } try { subProcessInstance.start(); } catch (Exception e) { if (!ErrorPropagation.mapException(e, execution, mapExceptions, true)) throw e; } } public void setProcessDefinitonKey(String processDefinitonKey) { this.processDefinitonKey = processDefinitonKey; } public String getProcessDefinitonKey() { return processDefinitonKey; } public void completing(DelegateExecution execution, DelegateExecution subProcessInstance) throws Exception { // only data. no control flow available on this execution. // copy process variables for (AbstractDataAssociation dataOutputAssociation : dataOutputAssociations) { Object value = null; if (dataOutputAssociation.getSourceExpression()!=null) { value = dataOutputAssociation.getSourceExpression().getValue(subProcessInstance); } else { value = subProcessInstance.getVariable(dataOutputAssociation.getSource()); } execution.setVariable(dataOutputAssociation.getTarget(), value); } } public void completed(ActivityExecution execution) throws Exception { // only control flow. no sub process instance data available leave(execution); } }