提交 e025065a 编写于 作者: J jbarrez

ACT-27: implementation otf the BPMN 2.0 call activity (subprocess only)

上级 09f4628f
/* 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.test.bpmn.callactivity;
import java.util.List;
import org.activiti.ProcessInstance;
import org.activiti.ProcessService;
import org.activiti.Task;
import org.activiti.TaskQuery;
import org.activiti.test.LogInitializer;
import org.activiti.test.ProcessDeclared;
import org.activiti.test.ProcessDeployer;
import org.junit.Rule;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @author Joram Barrez
*/
public class CallActivityTest {
@Rule
public LogInitializer logSetup = new LogInitializer();
@Rule
public ProcessDeployer deployer = new ProcessDeployer();
@Test
@ProcessDeclared(resources = {"CallActivity.testCallSimpleSubProcess.bpmn20.xml", "simpleSubProcess.bpmn20.xml"})
public void testCallSimpleSubProcess() {
ProcessInstance processInstance = deployer.getProcessService().startProcessInstanceByKey("callSimpleSubProcess");
// one task in the subprocess should be active after starting the process instance
TaskQuery taskQuery = deployer.getTaskService().createTaskQuery();
Task taskBeforeSubProcess = taskQuery.singleResult();
assertEquals("Task before subprocess", taskBeforeSubProcess.getName());
// Completing the task continues the process which leads to calling the subprocess
deployer.getTaskService().complete(taskBeforeSubProcess.getId());
Task taskInSubProcess = taskQuery.singleResult();
assertEquals("Task in subprocess", taskInSubProcess.getName());
// Completing the task in the subprocess, finishes the subprocess
deployer.getTaskService().complete(taskInSubProcess.getId());
Task taskAfterSubProcess = taskQuery.singleResult();
assertEquals("Task after subprocess", taskAfterSubProcess.getName());
// Completing this task end the process instance
deployer.getTaskService().complete(taskAfterSubProcess.getId());
deployer.assertProcessEnded(processInstance.getId());
}
/**
* Test case for a possible tricky case: reaching the end event
* of the subprocess leads to an end event in the super process instance.
*/
@Test
@ProcessDeclared(resources = {"CallActivity.testSubProcessEndsSuperProcess.bpmn20.xml", "simpleSubProcess.bpmn20.xml"})
public void testSubProcessEndsSuperProcess() {
ProcessService processService = deployer.getProcessService();
ProcessInstance processInstance = processService.startProcessInstanceByKey("subProcessEndsSuperProcess");
// one task in the subprocess should be active after starting the process instance
TaskQuery taskQuery = deployer.getTaskService().createTaskQuery();
Task taskBeforeSubProcess = taskQuery.singleResult();
assertEquals("Task in subprocess", taskBeforeSubProcess.getName());
// Completing this task ends the subprocess which leads to the end of the whole process instance
deployer.getTaskService().complete(taskBeforeSubProcess.getId());
deployer.assertProcessEnded(processInstance.getId());
assertEquals(0, processService.createProcessInstanceQuery().list().size());
}
@Test
@ProcessDeclared(resources = {"CallActivity.testCallParallelSubProcess.bpmn20.xml", "simpleParallelSubProcess.bpmn20.xml"})
public void testCallParallelSubProcess() {
ProcessInstance processInstance = deployer.getProcessService().startProcessInstanceByKey("callParallelSubProcess");
// The two tasks in the parallel subprocess should be active
TaskQuery taskQuery = deployer.getTaskService()
.createTaskQuery()
.orderAsc(TaskQuery.PROPERTY_NAME);
List<Task> tasks = taskQuery.list();
assertEquals(2, tasks.size());
Task taskA = tasks.get(0);
Task taskB = tasks.get(1);
assertEquals("Task A", taskA.getName());
assertEquals("Task B", taskB.getName());
// Completing the first task should not end the subprocess
deployer.getTaskService().complete(taskA.getId());
assertEquals(1, taskQuery.list().size());
assertEquals(2, deployer.getProcessService().createProcessInstanceQuery().list().size());
// Completing the second task should end the subprocess and end the whole process instance
deployer.getTaskService().complete(taskB.getId());
assertEquals(0, deployer.getProcessService().createProcessInstanceQuery().list().size());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.activiti.org/bpmn2.0">
<process id="callParallelSubProcess">
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="callSubProcess" />
<callActivity id="callSubProcess" calledElement="simpleParallelSubProcess" />
<sequenceFlow id="flow3" sourceRef="callSubProcess" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.activiti.org/bpmn2.0">
<process id="callSimpleSubProcess">
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="taskBeforeSubProcess" />
<userTask id="taskBeforeSubProcess" name="Task before subprocess" />
<sequenceFlow id="flow2" sourceRef="taskBeforeSubProcess" targetRef="callSubProcess" />
<callActivity id="callSubProcess" calledElement="simpleSubProcess" />
<sequenceFlow id="flow3" sourceRef="callSubProcess" targetRef="taskAfterSubProcess" />
<userTask id="taskAfterSubProcess" name="Task after subprocess" />
<sequenceFlow id="flow4" sourceRef="taskAfterSubProcess" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.activiti.org/bpmn2.0">
<process id="subProcessEndsSuperProcess">
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="callSubProcess" />
<callActivity id="callSubProcess" calledElement="simpleSubProcess" />
<sequenceFlow id="flow3" sourceRef="callSubProcess" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.activiti.org/bpmn2.0">
<process id="simpleParallelSubProcess">
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="fork" />
<parallelGateway id="fork" />
<sequenceFlow id="flow2" sourceRef="fork" targetRef="taskA" />
<sequenceFlow id="flow3" sourceRef="fork" targetRef="taskB" />
<userTask id="taskA" name="Task A" />
<sequenceFlow id="flow4" sourceRef="taskA" targetRef="subProcessEnd1" />
<endEvent id="subProcessEnd1" />
<userTask id="taskB" name="Task B" />
<sequenceFlow id="flow5" sourceRef="taskB" targetRef="subProcessEnd2" />
<endEvent id="subProcessEnd2" />
</process>
</definitions>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.activiti.org/bpmn2.0">
<process id="simpleSubProcess">
<startEvent id="theStart" />
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="task" />
<userTask id="task" name="Task in subprocess" />
<sequenceFlow id="flow2" sourceRef="task" targetRef="theEnd" />
<endEvent id="theEnd" />
</process>
</definitions>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="propertyTest"
<definitions id="definition"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
......
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="propertyTest"
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
......
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="propertyTest"
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
......
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="propertyTest"
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
......
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="propertyTest"
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
......
<?xml version="1.0" encoding="UTF-8"?>
<definitions id="propertyTest"
<definitions id="definitions"
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:activiti="http://activiti.org/bpmn-extensions"
......
......@@ -60,7 +60,11 @@ public class BpmnDeployer implements Deployer {
ByteArrayImpl resource = resources.get(resourceName);
byte[] bytes = resource.getBytes();
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
BpmnParse bpmnParse = new BpmnParser(expressionManager, scriptingEngines, businessCalendarManager).createParse().processDefinitionClass(ProcessDefinitionDbImpl.class).sourceInputStream(inputStream).execute();
BpmnParse bpmnParse = new BpmnParser(expressionManager, scriptingEngines, businessCalendarManager)
.createParse()
.processDefinitionClass(ProcessDefinitionDbImpl.class)
.sourceInputStream(inputStream)
.execute();
for (ProcessDefinitionImpl processDefinition : bpmnParse.getProcessDefinitions()) {
processDefinition.setDeployment(deployment);
......
/* 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.impl.bpmn;
import org.activiti.impl.definition.ProcessDefinitionImpl;
import org.activiti.impl.interceptor.CommandContext;
import org.activiti.impl.persistence.PersistenceSession;
import org.activiti.pvm.ActivityExecution;
import org.activiti.pvm.ObjectProcessInstance;
/**
* 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 CallActivityBehaviour extends BpmnActivity {
protected String processDefinitonKey;
public CallActivityBehaviour(String processDefinitionKey) {
this.processDefinitonKey = processDefinitionKey;
}
public void execute(ActivityExecution execution) throws Exception {
PersistenceSession persistenceSession = CommandContext.getCurrentCommandContext().getPersistenceSession();
ProcessDefinitionImpl processDefinition = persistenceSession.findLatestProcessDefinitionByKey(processDefinitonKey);
ObjectProcessInstance processInstance = execution.createSubProcessInstance(processDefinition);
processInstance.start();
}
public void event(ActivityExecution execution, Object event) throws Exception {
leave(execution);
}
}
......@@ -43,7 +43,8 @@ public class NoneEndEventActivity extends BpmnActivity {
// Special case for BPMN 2.0: when the parent is a process instance,
// but is not more active and has no children anymore
// The process instance cannot continue anymore:
// Then the process instance cannot continue anymore:
//
// eg. start -> fork -> task1 -> end1
// -> task2 -> end2
if (parent != null
......
......@@ -26,6 +26,7 @@ import org.activiti.ActivitiException;
import org.activiti.ProcessDefinition;
import org.activiti.impl.bpmn.BoundaryTimerEventActivity;
import org.activiti.impl.bpmn.BpmnInterface;
import org.activiti.impl.bpmn.CallActivityBehaviour;
import org.activiti.impl.bpmn.ExclusiveGatewayActivity;
import org.activiti.impl.bpmn.ManualTaskActivity;
import org.activiti.impl.bpmn.NoneEndEventActivity;
......@@ -50,6 +51,7 @@ import org.activiti.impl.el.ExpressionManager;
import org.activiti.impl.el.UelMethodExpressionCondition;
import org.activiti.impl.el.UelValueExpressionCondition;
import org.activiti.impl.job.TimerExecuteNestedActivityJobHandler;
import org.activiti.impl.persistence.PersistenceSession;
import org.activiti.impl.scripting.ScriptingEngines;
import org.activiti.impl.task.TaskDefinition;
import org.activiti.impl.timer.TimerDeclarationImpl;
......@@ -95,7 +97,7 @@ public class BpmnParse extends Parse {
* that this map doesn't need to be re-initialized for each new process
* definition.
*/
private final Map<String, Element> itemDefinitions = new HashMap<String, Element>();
protected Map<String, Element> itemDefinitions = new HashMap<String, Element>();
/**
* Map containing the the {@link BpmnInterface}s defined in the XML file. The
......@@ -104,7 +106,7 @@ public class BpmnParse extends Parse {
* Interfaces are defined outside the process definition(s), which means that
* this map doesn't need to be re-initialized for each new process definition.
*/
private final Map<String, BpmnInterface> bpmnInterfaces = new HashMap<String, BpmnInterface>();
protected Map<String, BpmnInterface> bpmnInterfaces = new HashMap<String, BpmnInterface>();
/**
* Map containing the {@link Operation}s defined in the XML file. The key is
......@@ -113,21 +115,22 @@ public class BpmnParse extends Parse {
* Operations are defined outside the process definition(s), which means that
* this map doesn't need to be re-initialized for each new process definition.
*/
private final Map<String, Operation> operations = new HashMap<String, Operation>();
protected Map<String, Operation> operations = new HashMap<String, Operation>();
private final ExpressionManager expressionManager;
protected ExpressionManager expressionManager;
private final ScriptingEngines scriptingEngines;
private final BusinessCalendarManager businessCalendarManager;
protected ScriptingEngines scriptingEngines;
protected BusinessCalendarManager businessCalendarManager;
/**
* Constructor to be called by the {@link BpmnParser}.
*
* Note the package modifier here: only the {@link BpmnParser} is allowed to
* create instances.
*/
BpmnParse(Parser parser, ExpressionManager expressionManager, ScriptingEngines scriptingEngines, BusinessCalendarManager businessCalendarManager) {
BpmnParse(Parser parser, ExpressionManager expressionManager, ScriptingEngines scriptingEngines,
BusinessCalendarManager businessCalendarManager) {
super(parser);
this.expressionManager = expressionManager;
this.scriptingEngines = scriptingEngines;
......@@ -347,6 +350,8 @@ public class BpmnParse extends Parse {
parseReceiveTask(activityElement, scopeElement);
} else if (activityElement.getTagName().equals("subProcess")) {
parseSubProcess(activityElement, scopeElement);
} else if (activityElement.getTagName().equals("callActivity")) {
parseCallActivity(activityElement, scopeElement);
}
}
}
......@@ -752,7 +757,7 @@ public class BpmnParse extends Parse {
* Parses a subprocess (formely known as an embedded subprocess): a subprocess
* defined withing another process definition.
*
* @param subProcessElement The XML element corresponding wit the subprocess definition
* @param subProcessElement The XML element corresponding with the subprocess definition
* @param scopeElement The current scope on which the subprocess is defined.
*/
public void parseSubProcess(Element subProcessElement, ScopeElementImpl scopeElement) {
......@@ -761,6 +766,22 @@ public class BpmnParse extends Parse {
activity.setActivityBehavior(new SubProcessActivity());
parseScope(subProcessElement, activity);
}
/**
* Parses a call activity (currenly only supporting calling subprocesses).
*
* @param callActivityElement The XML element defining the call activity
* @param scopeElement The current scope on which the call activity is defined.
*/
public void parseCallActivity(Element callActivityElement, ScopeElementImpl scopeElement) {
ActivityImpl activity = parseAndCreateActivityOnScopeElement(callActivityElement, scopeElement);
String calledElement = callActivityElement.attribute("calledElement");
if (calledElement == null) {
throw new ActivitiException("Missing attribute 'calledElement' on callActivity (line " +
+ callActivityElement.getLine() + ")");
}
activity.setActivityBehavior(new CallActivityBehaviour(calledElement));
}
/**
* Parses the properties of an element (if any) that can contain properties
......
......@@ -14,6 +14,7 @@ package org.activiti.impl.bpmn.parser;
import org.activiti.impl.calendar.BusinessCalendarManager;
import org.activiti.impl.el.ExpressionManager;
import org.activiti.impl.persistence.PersistenceSession;
import org.activiti.impl.scripting.ScriptingEngines;
import org.activiti.impl.xml.Parser;
......@@ -52,13 +53,14 @@ public class BpmnParser extends Parser {
*/
public static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
private final ExpressionManager expressionManager;
protected ExpressionManager expressionManager;
private final ScriptingEngines scriptingEngines;
protected ScriptingEngines scriptingEngines;
private final BusinessCalendarManager businessCalendarManager;
public BpmnParser(ExpressionManager expressionManager, ScriptingEngines scriptingEngines, BusinessCalendarManager businessCalendarManager) {
protected BusinessCalendarManager businessCalendarManager;
public BpmnParser(ExpressionManager expressionManager, ScriptingEngines scriptingEngines,
BusinessCalendarManager businessCalendarManager) {
this.expressionManager = expressionManager;
this.scriptingEngines = scriptingEngines;
this.businessCalendarManager = businessCalendarManager;
......
......@@ -72,7 +72,15 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
* @see #setParent(ExecutionImpl)
*/
protected String parentId;
/**
* persisted reference to the super execution of this execution
*
* @See {@link #getSuperExecution()}
* @see #setSuperExecution(ExecutionImpl)
*/
protected String superExecutionId;
protected boolean isNew = false;
protected boolean isExecutionsInitialized = false;
......@@ -113,7 +121,7 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
// process definition ///////////////////////////////////////////////////////
@Override
public void ensureProcessDefinitionInitialized() {
protected void ensureProcessDefinitionInitialized() {
if ((processDefinition == null) && (processDefinitionId != null)) {
setProcessDefinition(CommandContext.getCurrentCommandContext().getPersistenceSession().findProcessDefinitionById(processDefinitionId));
}
......@@ -128,7 +136,7 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
// process instance /////////////////////////////////////////////////////////
@Override
public void ensureProcessInstanceInitialized() {
protected void ensureProcessInstanceInitialized() {
if ((processInstance == null) && (processInstanceId != null)) {
processInstance = CommandContext.getCurrentCommandContext().getPersistenceSession().findExecution(processInstanceId);
}
......@@ -150,7 +158,7 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
// activity /////////////////////////////////////////////////////////////////
@Override
public void ensureActivityInitialized() {
protected void ensureActivityInitialized() {
if ((activity == null) && (activityId != null)) {
activity = getProcessDefinition().findActivity(activityId);
}
......@@ -169,7 +177,7 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
// executions ///////////////////////////////////////////////////////////////
@Override
public void ensureExecutionsInitialized() {
protected void ensureExecutionsInitialized() {
// If the execution is new, then the child execution objects are already
// fetched
if (!isExecutionsInitialized) {
......@@ -181,7 +189,7 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
// parent ///////////////////////////////////////////////////////////////////
@Override
public void ensureParentInitialized() {
protected void ensureParentInitialized() {
if (parent == null && parentId != null) {
parent = CommandContext.getCurrentCommandContext().getPersistenceSession().findExecution(parentId);
}
......@@ -198,6 +206,33 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
}
}
// super- and subprocess executions /////////////////////////////////////////
@Override
protected void ensureSuperExecutionInitialized() {
if (superExecution == null && superExecutionId != null) {
superExecution = CommandContext.getCurrentCommandContext().getPersistenceSession().findExecution(superExecutionId);
}
}
@Override
public void setSuperExecution(ExecutionImpl superExecution) {
super.setSuperExecution(superExecution);
if (superExecution != null) {
this.superExecutionId = superExecution.getId();
} else {
this.superExecutionId = null;
}
}
@Override
protected void ensureSubProcessInstanceInitialized() {
if (subProcessInstance != null) {
subProcessInstance = CommandContext.getCurrentCommandContext().getPersistenceSession().findSubProcessInstance(this.getId());
}
}
// customized persistence behaviour /////////////////////////////////////////
@Override
......@@ -242,7 +277,7 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
persistentState.put("isConcurrent", this.isConcurrent);
persistentState.put("isScope", this.isScope);
persistentState.put("parentId", parentId);
persistentState.put("transition", this.transition);
persistentState.put("superExecution", this.superExecutionId);
return persistentState;
}
......@@ -282,4 +317,7 @@ public class DbExecutionImpl extends ExecutionImpl implements PersistentObject {
public String getProcessDefinitionId() {
return processDefinitionId;
}
public void setProcessDefinitionId(String processDefinitionId) {
this.processDefinitionId = processDefinitionId;
}
}
......@@ -21,6 +21,8 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.activiti.ActivitiException;
import org.activiti.ProcessDefinition;
import org.activiti.ProcessInstance;
import org.activiti.impl.definition.ActivityImpl;
import org.activiti.impl.definition.ProcessDefinitionImpl;
import org.activiti.impl.definition.TransitionImpl;
......@@ -63,6 +65,12 @@ public class ExecutionImpl implements
/** nested executions representing scopes or concurrent paths */
protected List<ExecutionImpl> executions = new ArrayList<ExecutionImpl>();
/** super execution, not-null if this execution is part of a subprocess */
protected ExecutionImpl superExecution;
/** reference to a subprocessinstance, not-null if currently subprocess is started from this execution */
protected ExecutionImpl subProcessInstance;
/** indicates if this execution represents an active path of execution.
* Executions are made inactive in the following situations:
* <ul>
......@@ -152,6 +160,35 @@ public class ExecutionImpl implements
return executions;
}
public ExecutionImpl getSuperExecution() {
ensureSuperExecutionInitialized();
return superExecution;
}
public void setSuperExecution(ExecutionImpl superExecution) {
this.superExecution = superExecution;
if (superExecution != null) {
superExecution.setSubProcessInstance(null);
}
}
// Meant to be overridden by persistent subclasseses
protected void ensureSuperExecutionInitialized() {
}
public ExecutionImpl getSubProcessInstance() {
ensureSubProcessInstanceInitialized();
return subProcessInstance;
}
public void setSubProcessInstance(ExecutionImpl subProcessInstance) {
this.subProcessInstance = subProcessInstance;
}
// Meant to be overridden by persistent subclasses
protected void ensureSubProcessInstanceInitialized() {
}
/** creates a new execution. properties processDefinition, processInstance and activity will be initialized. */
public ExecutionImpl createExecution() {
// create the new child execution
......@@ -170,6 +207,19 @@ public class ExecutionImpl implements
return createdExecution;
}
public ObjectProcessInstance createSubProcessInstance(ProcessDefinition processDefinition) {
ExecutionImpl subProcessInstance = newExecution();
// manage bidirectional super-subprocess relation
subProcessInstance.setSuperExecution(this);
this.setSubProcessInstance(subProcessInstance);
// Initialize the new execution
subProcessInstance.setProcessDefinition((ProcessDefinitionImpl) processDefinition);
return subProcessInstance;
}
/** removes an execution. if there are nested executions, those will be ended recursively.
* if there is a parent, this method removes the bidirectional relation
* between parent and this execution. */
......@@ -186,10 +236,16 @@ public class ExecutionImpl implements
// if there is a parent
ensureParentInitialized();
if (parent!=null) {
// then remove the bidirectional relation
// remove the bidirectional relation
parent.removeExecution(this);
} else { // this is a process instance
} else { // this execution is a process instance
ensureSuperExecutionInitialized();
if (superExecution != null) {
ExecutionImpl superExecutionCopy = superExecution; // local copy, since we need to set it to null and still call event() on it
superExecution.setSubProcessInstance(null);
setSuperExecution(null);
superExecutionCopy.event("continue process");
}
isEnded = true;
fireEvent(EndProcessInstanceEvent.INSTANCE);
}
......
......@@ -103,7 +103,9 @@ public class IbatisPersistenceSession implements PersistenceSession {
public void delete(PersistentObject persistentObject) {
deleted.add(persistentObject);
inserted.remove(persistentObject);
loaded.remove(persistentObject);
// The persistentObject doesnt need to be removed from the loaded objects,
// since there can be updates pending that remove foreign keys which would make the delete
// fail if they aren't set to null first
}
public void flush() {
......@@ -174,6 +176,14 @@ public class IbatisPersistenceSession implements PersistenceSession {
execution.end(); // TODO replace with real delete instead of end(), since this will create history traces
}
public DbExecutionImpl findSubProcessInstance(String superExecutionId) {
DbExecutionImpl subProcessInstance = (DbExecutionImpl) sqlSession.selectOne("selectSubProcessInstanceBySuperExecutionId");
if (subProcessInstance != null) {
subProcessInstance = (DbExecutionImpl) loaded.add(subProcessInstance);
}
return subProcessInstance;
}
public long findProcessInstanceCountByDynamicCriteria(Map<String, Object> params) {
return (Long) sqlSession.selectOne(statement("selectProcessInstanceCountByDynamicCriteria"), params);
}
......
......@@ -79,6 +79,7 @@ public interface PersistenceSession extends Session {
List<DbExecutionImpl> findRootExecutionsByProcessDefintion(String processDefinitionId);
List<ExecutionImpl> findChildExecutions(String parentExecutionid);
void deleteExecution(String executionId);
DbExecutionImpl findSubProcessInstance(String superExecutionId);
List<ProcessInstance> findProcessInstancesByDynamicCriteria(Map<String, Object> params);
long findProcessInstanceCountByDynamicCriteria(Map<String, Object> params);
......
......@@ -14,6 +14,9 @@ package org.activiti.pvm;
import java.util.List;
import org.activiti.ProcessDefinition;
import org.activiti.ProcessInstance;
/**
* @author Tom Baeyens
......@@ -34,6 +37,7 @@ public interface ActivityExecution {
void setVariable(String variableName, Object value);
ActivityExecution createExecution();
ObjectProcessInstance createSubProcessInstance(ProcessDefinition processDefinition);
ActivityExecution getParent();
List<? extends ActivityExecution> getExecutions();
void end();
......
......@@ -33,6 +33,7 @@ create table ACT_EXECUTION (
PROC_INST_ID_ varchar(255),
PARENT_ID_ varchar(255),
PROC_DEF_ID_ varchar(255),
SUPER_EXEC_ varchar(255),
ACTIVITY_ID_ varchar(255),
IS_ACTIVE_ bit,
IS_CONCURRENT_ bit,
......@@ -147,6 +148,11 @@ alter table ACT_EXECUTION
add constraint FK_EXE_PARENT
foreign key (PARENT_ID_)
references ACT_EXECUTION;
alter table ACT_EXECUTION
add constraint FK_EXE_SUPER
foreign key (SUPER_EXEC_)
references ACT_EXECUTION;
alter table ACT_ID_MEMBERSHIP
add constraint FK_MEMB_GROUP
......
......@@ -33,6 +33,7 @@ create table ACT_EXECUTION (
PROC_INST_ID_ varchar(255),
PARENT_ID_ varchar(255),
PROC_DEF_ID_ varchar(255),
SUPER_EXEC_ varchar(255),
ACTIVITY_ID_ varchar(255),
IS_ACTIVE_ TINYINT,
IS_CONCURRENT_ TINYINT,
......@@ -149,7 +150,12 @@ alter table ACT_EXECUTION
add constraint FK_EXE_PARENT
foreign key (PARENT_ID_)
references ACT_EXECUTION (ID_);
alter table ACT_EXECUTION
add constraint FK_EXE_SUPER
foreign key (SUPER_EXEC_)
references ACT_EXECUTION;
alter table ACT_ID_MEMBERSHIP
add constraint FK_MEMB_GROUP
foreign key (GROUP_ID_)
......
......@@ -15,6 +15,7 @@
<result property="isConcurrent" column="IS_CONCURRENT_" jdbcType="BOOLEAN" />
<result property="isScope" column="IS_SCOPE_" jdbcType="BOOLEAN" />
<result property="parentId" column="PARENT_ID_" jdbcType="VARCHAR" />
<result property="superExecutionId" column="SUPER_EXEC_" jdbcType="VARCHAR" />
</resultMap>
<!-- SELECT -->
......@@ -57,10 +58,16 @@
</where>
</sql>
<select id="selectSubProcessInstanceBySuperExecutionId" parameterType="string" resultMap="executionResultMap">
select *
from ACT_EXECUTION
where SUPER_EXEC_ = #{superExecutionId}
</select>
<!-- INSERT -->
<insert id="insertExecution" parameterType="org.activiti.impl.db.execution.DbExecutionImpl">
insert into ACT_EXECUTION (ID_, PROC_INST_ID_, PROC_DEF_ID_, ACTIVITY_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, PARENT_ID_)
insert into ACT_EXECUTION (ID_, PROC_INST_ID_, PROC_DEF_ID_, ACTIVITY_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, PARENT_ID_, SUPER_EXEC_)
values (
#{id ,jdbcType=VARCHAR},
#{processInstanceId, jdbcType=VARCHAR},
......@@ -69,7 +76,8 @@
#{isActive ,jdbcType=BOOLEAN},
#{isConcurrent ,jdbcType=BOOLEAN},
#{isScope ,jdbcType=BOOLEAN},
#{parentId, jdbcType=VARCHAR}
#{parentId, jdbcType=VARCHAR},
#{superExecutionId, jdbcType=VARCHAR}
)
</insert>
......@@ -82,7 +90,8 @@
IS_ACTIVE_ = #{isActive, jdbcType=VARCHAR},
IS_CONCURRENT_ = #{isConcurrent, jdbcType=VARCHAR},
IS_SCOPE_ = #{isScope, jdbcType=VARCHAR},
PARENT_ID_ = #{parentId, jdbcType=VARCHAR}
PARENT_ID_ = #{parentId, jdbcType=VARCHAR},
SUPER_EXEC_ = #{superExecutionId, jdbcType=VARCHAR}
where ID_ = #{id}
</update>
......
cd ../../
mvn -Ddatabase=%1 clean install
mvn -Ddatabase=%1 -Pcheck clean install
cd qa/ci
\ No newline at end of file
#!/bin/sh
mvn -Ddatabase=$1 clean install
mvn -Ddatabase=$1 -Pcheck clean install
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册