[jbpm-commits] JBoss JBPM SVN: r6397 - in jbpm4/trunk/modules: examples/src/test/java/org/jbpm/examples/concurrency and 9 other directories.
do-not-reply at jboss.org
do-not-reply at jboss.org
Wed Jun 9 13:46:56 EDT 2010
Author: swiderski.maciej
Date: 2010-06-09 13:46:55 -0400 (Wed, 09 Jun 2010)
New Revision: 6397
Added:
jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/concurrency/foreach/
jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/concurrency/foreach/ForEachTest.java
jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/concurrency/foreach/
jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/concurrency/foreach/process.jpdl.xml
jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForEachActivity.java
jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForEachBinding.java
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/activity/foreach/
jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/activity/foreach/ForEachTest.java
Modified:
jbpm4/trunk/modules/api/src/main/resources/jpdl-4.4.xsd
jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForkActivity.java
jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinActivity.java
jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinBinding.java
jbpm4/trunk/modules/jpdl/src/main/resources/jbpm.jpdl.bindings.xml
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmFunctionMapper.java
jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java
Log:
JBPM-2414: for each activity
Modified: jbpm4/trunk/modules/api/src/main/resources/jpdl-4.4.xsd
===================================================================
--- jbpm4/trunk/modules/api/src/main/resources/jpdl-4.4.xsd 2010-06-09 17:35:57 UTC (rev 6396)
+++ jbpm4/trunk/modules/api/src/main/resources/jpdl-4.4.xsd 2010-06-09 17:46:55 UTC (rev 6397)
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
- targetNamespace="http://jbpm.org/4.4/jpdl"
- xmlns:tns="http://jbpm.org/4.4/jpdl"
+ targetNamespace="http://jbpm.org/jpdl/4.4"
+ xmlns:tns="http://jbpm.org/jpdl/4.4"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
@@ -219,6 +219,23 @@
</element>
<!-- ~~~ FORK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
+ <element name="foreach">
+ <annotation><documentation>Spawns concurrent paths of execution
+ over each element of a collection.
+ </documentation></annotation>
+ <complexType>
+ <sequence>
+ <element name="description" minOccurs="0" type="string" />
+ <element ref="tns:on" minOccurs="0" maxOccurs="unbounded"/>
+ <element ref="tns:transition" minOccurs="0" maxOccurs="unbounded" />
+ </sequence>
+ <attributeGroup ref="tns:activityAttributes" />
+ <attribute name="var" type="string" default="var"/>
+ <attribute name="in" type="string" use="required"/>
+ </complexType>
+ </element>
+
+ <!-- ~~~ FORK ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<element name="fork">
<annotation><documentation>Spawns multiple concurrent paths of
execution.
@@ -245,7 +262,7 @@
<element ref="tns:transition" minOccurs="0" maxOccurs="unbounded" />
</sequence>
<attributeGroup ref="tns:activityAttributes" />
- <attribute name="multiplicity" type="int" />
+ <attribute name="multiplicity" type="string" />
<attribute name="lockmode" default="upgrade">
<simpleType>
<restriction base="string">
Added: jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/concurrency/foreach/ForEachTest.java
===================================================================
--- jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/concurrency/foreach/ForEachTest.java (rev 0)
+++ jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/concurrency/foreach/ForEachTest.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -0,0 +1,166 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, !
or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.examples.concurrency.foreach;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+import org.jbpm.api.ProcessInstance;
+import org.jbpm.api.task.Task;
+import org.jbpm.test.JbpmTestCase;
+
+/**
+ * @author Tom Baeyens
+ */
+public class ForEachTest extends JbpmTestCase {
+
+ String deploymentId;
+ String deptSales;
+ String deptHR;
+ String deptFinance;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // create identities
+ deptSales = identityService.createGroup("sales-dept");
+ deptHR = identityService.createGroup("hr-dept");
+ deptFinance = identityService.createGroup("finance-dept");
+
+ identityService.createUser("johndoe", "John", "Doe");
+ identityService.createMembership("johndoe", deptSales, "SalesManager");
+
+ identityService.createUser("joesmoe", "Joe", "Smoe");
+ identityService.createMembership("joesmoe", deptHR, "HRMana!
ger");
+
+ identityService.createUser("janedoe", "Jane", "D!
oe");
+
identityService.createMembership("janedoe", deptFinance, "FinanceManager");
+
+ deploymentId = repositoryService.createDeployment().addResourceFromClasspath("org/jbpm/examples/concurrency/foreach/process.jpdl.xml").deploy();
+ }
+
+ protected void tearDown() throws Exception {
+ repositoryService.deleteDeploymentCascade(deploymentId);
+
+ // delete identities
+ identityService.deleteGroup(deptSales);
+ identityService.deleteGroup(deptHR);
+ identityService.deleteGroup(deptFinance);
+ identityService.deleteUser("johndoe");
+ identityService.deleteUser("joesmoe");
+ identityService.deleteUser("janedoe");
+
+ super.tearDown();
+ }
+
+ public void testForEachCompleteAll() {
+
+ HashMap<String, Object> variables = new HashMap<String, Object>();
+ variables.put("listOfDepartments", new String[] { "sales-dept", "hr-dept", "finance-dept" });
+ variables.put("joinAt", 3);
+
+ ProcessInstance processInstance = executionService.startProc!
essInstanceByKey("ForEachFork", variables);
+ String processInstanceId = processInstance.getId();
+
+ // there should be 3 forked executions - same as number of departments
+ assertEquals(3, processInstance.getExecutions().size());
+
+ List<Task> taskListSales = taskService.findGroupTasks("johndoe");
+ assertEquals("Expected a single task in johndoe's task list", 1, taskListSales.size());
+
+ List<Task> taskListHR = taskService.findGroupTasks("joesmoe");
+ assertEquals("Expected a single task in joesmoe's task list", 1, taskListHR.size());
+
+ List<Task> taskListFinance = taskService.findGroupTasks("janedoe");
+ assertEquals("Expected a single task in janedoe's task list", 1, taskListFinance.size());
+
+ // a member of sales department takes the task
+ taskService.takeTask(taskListSales.get(0).getId(), "johndoe");
+
+ taskListSales = taskService.findPersonalTasks("johndoe");
+ assertEquals("Expected a single task being created", 1, tas!
kListSales.size());
+ // complete collect data from sales d!
epartmen
t
+ taskService.completeTask(taskListSales.get(0).getId());
+
+ // next a member of HR department takes the task
+ taskService.takeTask(taskListHR.get(0).getId(), "joesmoe");
+
+ taskListHR = taskService.findPersonalTasks("joesmoe");
+ assertEquals("Expected a single task being created", 1, taskListHR.size());
+ // complete collect data from HR department
+ taskService.completeTask(taskListHR.get(0).getId());
+
+ // finally a member of Finance department takes the task
+ taskService.takeTask(taskListFinance.get(0).getId(), "janedoe");
+
+ taskListFinance = taskService.findPersonalTasks("janedoe");
+ assertEquals("Expected a single task being created", 1, taskListFinance.size());
+ // complete collect data from HR department
+ taskService.completeTask(taskListFinance.get(0).getId());
+
+ Date endTime = historyService.createHistoryProcessInstanceQuery().processInstanceId(processInstance.getId()).uniqueResult().getEndTime();
+
+ !
assertNotNull(endTime);
+ }
+
+ public void testForEachCompleteAfterTwoJoined() {
+
+ HashMap<String, Object> variables = new HashMap<String, Object>();
+ variables.put("listOfDepartments", new String[] { "sales-dept", "hr-dept", "finance-dept" });
+ variables.put("joinAt", 2);
+
+ ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForEachFork", variables);
+
+ // there should be 3 forked executions - same as number of departments
+ assertEquals(3, processInstance.getExecutions().size());
+
+ List<Task> taskListSales = taskService.findGroupTasks("johndoe");
+ assertEquals("Expected a single task in johndoe's task list", 1, taskListSales.size());
+
+ List<Task> taskListHR = taskService.findGroupTasks("joesmoe");
+ assertEquals("Expected a single task in joesmoe's task list", 1, taskListHR.size());
+
+ List<Task> taskListFinance = taskService.findGroupTasks("janedoe");
+ assertEquals("Expected a single task in j!
anedoe's task list", 1, taskListFinance.size());
+
+ // a m!
ember of
sales department takes the task
+ taskService.takeTask(taskListSales.get(0).getId(), "johndoe");
+
+ taskListSales = taskService.findPersonalTasks("johndoe");
+ assertEquals("Expected a single task being created", 1, taskListSales.size());
+ // complete collect data from sales department
+ taskService.completeTask(taskListSales.get(0).getId());
+
+ // next a member of HR department takes the task
+ taskService.takeTask(taskListHR.get(0).getId(), "joesmoe");
+
+ taskListSales = taskService.findPersonalTasks("joesmoe");
+ assertEquals("Expected a single task being created", 1, taskListSales.size());
+ // complete collect data from HR department
+ taskService.completeTask(taskListSales.get(0).getId());
+
+ Date endTime = historyService.createHistoryProcessInstanceQuery().processInstanceId(processInstance.getId()).uniqueResult().getEndTime();
+
+ assertNotNull(endTime);
+ }
+}
Added: jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/concurrency/foreach/process.jpdl.xml
===================================================================
--- jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/concurrency/foreach/process.jpdl.xml (rev 0)
+++ jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/concurrency/foreach/process.jpdl.xml 2010-06-09 17:46:55 UTC (rev 6397)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<process name="ForEachFork" xmlns="http://jbpm.org/4.3/jpdl">
+ <start g="28,61,48,48" name="start1">
+ <transition to="foreach1"/>
+ </start>
+ <foreach var="department" in="#{listOfDepartments}" g="111,60,48,48" name="foreach1">
+ <transition to="Collect data"/>
+ </foreach>
+ <task candidate-groups="#{department}" g="201,58,92,52" name="Collect data">
+ <transition to="join1"/>
+ </task>
+ <join g="343,59,48,48" multiplicity="#{joinAt}" name="join1">
+ <transition to="end1"/>
+ </join>
+ <end g="433,60,48,48" name="end1"/>
+</process>
\ No newline at end of file
Added: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForEachActivity.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForEachActivity.java (rev 0)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForEachActivity.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -0,0 +1,151 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, !
or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.jpdl.internal.activity;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.jbpm.api.Execution;
+import org.jbpm.api.JbpmException;
+import org.jbpm.api.activity.ActivityExecution;
+import org.jbpm.pvm.internal.el.Expression;
+import org.jbpm.pvm.internal.env.Context;
+import org.jbpm.pvm.internal.env.EnvironmentImpl;
+import org.jbpm.pvm.internal.env.ExecutionContext;
+import org.jbpm.pvm.internal.model.ActivityImpl;
+import org.jbpm.pvm.internal.model.Condition;
+import org.jbpm.pvm.internal.model.ExecutionImpl;
+import org.jbpm.pvm.internal.model.TransitionImpl;
+
+/**
+ * @author Maciej Swiderski
+ * @author Alejandro Guizar
+ */
+public class ForEachActivity extends JpdlActivity {
+
+ private String variable;
+ private Expression collection;
+
+ private static final long serialVersionUID = 1L;
+
+ public void execute(ActivityExecu!
tion execution) throws Exception {
+ execute((ExecutionImpl!
) execut
ion);
+ }
+
+ public void execute(ExecutionImpl execution) {
+ // resolve collection values
+ Collection<?> collection = evaluateCollection(execution);
+ ActivityImpl activity = execution.getActivity();
+
+ // get concurrent root
+ ExecutionImpl concurrentRoot;
+ if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {
+ concurrentRoot = execution;
+ execution.setState(Execution.STATE_INACTIVE_CONCURRENT_ROOT);
+ execution.setActivity(null);
+ }
+ else if (Execution.STATE_ACTIVE_CONCURRENT.equals(execution.getState())) {
+ concurrentRoot = execution.getParent();
+ execution.end();
+ }
+ else {
+ // TODO is any other state possible?
+ concurrentRoot = execution;
+ }
+
+ // evaluate transition condition and create concurrent executions
+ TransitionImpl transition = activity.getDefaultOutgoingTransition();
+ List<ExecutionImpl> concurrentExecutions = new ArrayList<ExecutionImpl>();
+ int in!
dex = 1;
+
+ //execution context needs to be temporarily replaced to give access to child execution variables
+ ExecutionContext originalExecutionContext = null;
+ ExecutionContext concurrentExecutionContext = null;
+ EnvironmentImpl environment = EnvironmentImpl.getCurrent();
+ if (environment!=null) {
+ originalExecutionContext = (ExecutionContext) environment.removeContext(Context.CONTEXTNAME_EXECUTION);
+ }
+
+ for (Object value : collection) {
+ ExecutionImpl concurrentExecution = concurrentRoot.createExecution(Integer
+ .toString(index++));
+ concurrentExecution.setActivity(activity);
+ concurrentExecution.setState(Execution.STATE_ACTIVE_CONCURRENT);
+ concurrentExecution.createVariable(variable, value);
+
+ // replace in the current environment execution context for expression evaluation purpose
+ concurrentExecutionContext = new ExecutionContext(concurrentExecution);
+ environment.setContext!
(concurrentExecutionContext);
+
+ Condition condition = t!
ransitio
n.getCondition();
+ if (condition == null || condition.evaluate(concurrentExecution)) {
+ concurrentExecutions.add(concurrentExecution);
+ }
+ else {
+ concurrentExecution.end();
+ }
+ }
+ // after all concurrent execution were processed reset original execution context
+ environment.setContext(originalExecutionContext);
+
+ // if no concurrent executions should be launched
+ if (concurrentExecutions.isEmpty()) {
+ // throw exceptions to be consistent with decision activity
+ throw new JbpmException("no outgoing transition condition evaluated to true for " + activity);
+ }
+ else {
+ for (ExecutionImpl concurrentExecution : concurrentExecutions) {
+ concurrentExecution.take(transition);
+ if (concurrentRoot.isEnded()) break;
+ }
+ }
+ }
+
+ private Collection<?> evaluateCollection(ExecutionImpl execution) {
+ Object value = collection.evaluate(execution);
+ if (value instanceo!
f Collection<?>) {
+ // return collection verbatim
+ return (Collection<?>) value;
+ }
+ else if (value instanceof Object[]) {
+ // wrap array in list
+ return Arrays.asList((Object[]) value);
+ }
+ else if (value instanceof String) {
+ // split string around commas or spaces
+ String csv = (String) value;
+ return Arrays.asList(csv.split("[,\\s]+"));
+ }
+ throw new JbpmException("not a collection: " + value);
+ }
+
+ public void setVariable(String variable) {
+ this.variable = variable;
+ }
+
+ public void setCollection(Expression collection) {
+ this.collection = collection;
+ }
+
+}
Added: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForEachBinding.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForEachBinding.java (rev 0)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForEachBinding.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -0,0 +1,108 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, !
or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.jpdl.internal.activity;
+
+import java.util.List;
+
+import org.jbpm.jpdl.internal.xml.JpdlParser;
+import org.jbpm.pvm.internal.el.Expression;
+import org.jbpm.pvm.internal.model.ActivityImpl;
+import org.jbpm.pvm.internal.model.ExpressionCondition;
+import org.jbpm.pvm.internal.model.TransitionImpl;
+import org.jbpm.pvm.internal.util.XmlUtil;
+import org.jbpm.pvm.internal.wire.usercode.UserCodeCondition;
+import org.jbpm.pvm.internal.wire.usercode.UserCodeReference;
+import org.jbpm.pvm.internal.xml.Parse;
+import org.w3c.dom.Element;
+
+/**
+ * @author Alejandro Guizar
+ */
+public class ForEachBinding extends JpdlBinding {
+
+ private static final String VARIABLE = "var";
+ private static final String COLLECTION = "in";
+
+ public ForEachBinding() {
+ super("foreach");
+ }
+
+ @Override
+ public Object parseJpdl(Element element, Parse parse, JpdlParser parser) {
+ ForEachActivity activity = new !
ForEachActivity();
+
+ if (element.hasAttribute(VARIABLE)) !
{
+
activity.setVariable(element.getAttribute(VARIABLE));
+ }
+ else {
+ parse.addProblem(VARIABLE + " attribute missing", element);
+ }
+
+ if (element.hasAttribute(COLLECTION)) {
+ Expression collection = Expression
+ .create(element.getAttribute(COLLECTION), Expression.LANGUAGE_UEL_VALUE);
+ activity.setCollection(collection);
+ }
+ else {
+ parse.addProblem(COLLECTION + " attribute missing", element);
+ }
+
+ // process transition elements
+ List<Element> transitionElements = XmlUtil.elements(element, "transition");
+
+ if (transitionElements.size() != 1) {
+ parse.addProblem("foreach activity can/must have one outgoing transition, found "+ transitionElements.size() + " transitions ", element);
+ } else {
+
+ ActivityImpl activityFromStack = parse.contextStackFind(ActivityImpl.class);
+ TransitionImpl transition = activityFromStack.getDefaultOutgoingTransition();
+
+ // get first tr!
ansition
+ Element transitionElement = transitionElements.get(0);
+
+ Element conditionElement = XmlUtil.element(transitionElement, "condition");
+ if (conditionElement != null) {
+
+ if (conditionElement.hasAttribute("expr")) {
+ ExpressionCondition expressionCondition = new ExpressionCondition();
+ expressionCondition.setExpression(conditionElement.getAttribute("expr"));
+ expressionCondition.setLanguage(XmlUtil.attribute(conditionElement, "lang"));
+ transition.setCondition(expressionCondition);
+
+ } else {
+ Element conditionHandlerElement = XmlUtil.element(conditionElement, "handler");
+ if (conditionHandlerElement != null) {
+ UserCodeCondition userCodeCondition = new UserCodeCondition();
+
+ UserCodeReference conditionReference = parser.parseUserCodeReference(conditionHandlerElement, parse);
+ userCodeCondition.setConditionReference(conditionRe!
ference);
+
+ transition.setCondition(userCodeCon!
dition);
+ }
+ }
+ }
+ }
+
+ return activity;
+ }
+
+}
Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForkActivity.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForkActivity.java 2010-06-09 17:35:57 UTC (rev 6396)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/ForkActivity.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -25,6 +25,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import org.jbpm.api.Execution;
import org.jbpm.api.activity.ActivityExecution;
@@ -51,9 +52,8 @@
// evaluate the conditions and find the transitions that should be forked
List<Transition> forkingTransitions = new ArrayList<Transition>();
- List<TransitionImpl> outgoingTransitions = (List) activity.getOutgoingTransitions();
- for (TransitionImpl transition: outgoingTransitions) {
- Condition condition = transition.getCondition();
+ for (Transition transition: activity.getOutgoingTransitions()) {
+ Condition condition = ((TransitionImpl) transition).getCondition();
if ( (condition==null)
|| (condition.evaluate(execution))
) {
@@ -72,7 +72,7 @@
// if there are more transitions
} else {
- ExecutionImpl concurrentRoot = null;
+ ExecutionImpl concurrentRoot;
if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {
concurrentRoot = execution;
execution.setState(Execution.STATE_INACTIVE_CONCURRENT_ROOT);
@@ -80,20 +80,22 @@
} else if (Execution.STATE_ACTIVE_CONCURRENT.equals(execution.getState())) {
concurrentRoot = execution.getParent();
execution.end();
+ } else {
+ // TODO is any other state possible?
+ concurrentRoot = execution;
}
- Map<Transition, ExecutionImpl> childExecutionsMap = new HashMap<Transition, ExecutionImpl>();
+ Map<Transition, ExecutionImpl> concurrentExecutions = new HashMap<Transition, ExecutionImpl>();
for (Transition transition : forkingTransitions) {
- // launch a concurrent path of execution
- String childExecutionName = transition.getName();
- ExecutionImpl concurrentExecution = concurrentRoot.createExecution(childExecutionName);
+ ExecutionImpl concurrentExecution = concurrentRoot.createExecution(transition.getName());
concurrentExecution.setActivity(activity);
concurrentExecution.setState(Execution.STATE_ACTIVE_CONCURRENT);
- childExecutionsMap.put(transition, concurrentExecution);
+ concurrentExecutions.put(transition, concurrentExecution);
}
+
- for (Transition transition : childExecutionsMap.keySet()) {
- childExecutionsMap.get(transition).take(transition);
+ for (Entry<Transition, ExecutionImpl> entry : concurrentExecutions.entrySet()) {
+ entry.getValue().take(entry.getKey());
if (concurrentRoot.isEnded()) {
break;
Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinActivity.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinActivity.java 2010-06-09 17:35:57 UTC (rev 6396)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinActivity.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -22,6 +22,7 @@
package org.jbpm.jpdl.internal.activity;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import org.hibernate.LockMode;
@@ -33,9 +34,9 @@
import org.jbpm.api.model.Transition;
import org.jbpm.pvm.internal.el.Expression;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
+import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.ExecutionImpl;
-
/**
* @author Tom Baeyens
*/
@@ -43,26 +44,16 @@
private static final long serialVersionUID = 1L;
- int multiplicity = -1;
- LockMode lockMode = LockMode.UPGRADE;
- Expression multiplicityExpression;
+ private LockMode lockMode = LockMode.UPGRADE;
+ private Expression multiplicity;
public void execute(ActivityExecution execution) {
execute((ExecutionImpl)execution);
}
public void execute(ExecutionImpl execution) {
- Activity activity = execution.getActivity();
+ ActivityImpl activity = execution.getActivity();
- // evaluate multiplicity expression
- if (multiplicityExpression != null) {
- try {
- multiplicity = Integer.valueOf(multiplicityExpression.evaluate(execution).toString());
- } catch (Exception e) {
- throw new JbpmException("Problem while evaluating multiplicity attribute: " + e.getMessage());
- }
- }
-
// if this is a single, non concurrent root
if (Execution.STATE_ACTIVE_ROOT.equals(execution.getState())) {
// just pass through
@@ -84,23 +75,22 @@
ExecutionImpl concurrentRoot = execution.getParent();
List<ExecutionImpl> joinedExecutions = getJoinedExecutions(concurrentRoot, activity);
- if (isComplete(joinedExecutions, activity)) {
- endJoinedExecutions(joinedExecutions);
-
- if (multiplicity != -1) {
- // remove forked but not joined executions only when multiplicity attribute was used
- List<ExecutionImpl> forkedExecutionsToRemove = new ArrayList<ExecutionImpl>();
+ if (isComplete(execution, joinedExecutions)) {
+ endExecutions(joinedExecutions);
+ // if multiplicity was used
+ if (multiplicity != null) {
+ // collect concurrent executions still active
+ List<ExecutionImpl> danglingExecutions = new ArrayList<ExecutionImpl>();
for (ExecutionImpl concurrentExecution : concurrentRoot.getExecutions()) {
- //collect all executions from the parent that are forked
- if ( (Execution.STATE_ACTIVE_CONCURRENT.equals(concurrentExecution.getState()))) {
- forkedExecutionsToRemove.add(concurrentExecution);
+ if (Execution.STATE_ACTIVE_CONCURRENT.equals(concurrentExecution.getState())) {
+ danglingExecutions.add(concurrentExecution);
}
}
- // end all of found forked (but not joined) executions
- endJoinedExecutions(forkedExecutionsToRemove);
+ // end dangling executions
+ endExecutions(danglingExecutions);
}
ExecutionImpl outgoingExecution = null;
- if (concurrentRoot.getExecutions().size()==0) {
+ if (concurrentRoot.getExecutions().isEmpty()) {
outgoingExecution = concurrentRoot;
outgoingExecution.setState(Execution.STATE_ACTIVE_ROOT);
} else {
@@ -120,19 +110,22 @@
throw new JbpmException("invalid execution state");
}
}
-
- protected boolean isComplete(List<ExecutionImpl> joinedExecutions, Activity activity) {
- int nbrOfExecutionsToJoin = multiplicity;
- if (multiplicity==-1) {
- nbrOfExecutionsToJoin = activity.getIncomingTransitions().size();
+
+ protected boolean isComplete(ExecutionImpl execution, List<ExecutionImpl> joinedExecutions) {
+ int executionsToJoin;
+ if (multiplicity != null) {
+ executionsToJoin = evaluateMultiplicity(execution);
}
- return joinedExecutions.size()==nbrOfExecutionsToJoin;
+ else {
+ executionsToJoin = execution.getActivity().getIncomingTransitions().size();
+ }
+ return joinedExecutions.size() == executionsToJoin;
}
protected List<ExecutionImpl> getJoinedExecutions(ExecutionImpl concurrentRoot, Activity activity) {
List<ExecutionImpl> joinedExecutions = new ArrayList<ExecutionImpl>();
- List concurrentExecutions = (List)concurrentRoot.getExecutions();
- for (ExecutionImpl concurrentExecution: (List<ExecutionImpl>)concurrentExecutions) {
+ Collection<ExecutionImpl> concurrentExecutions = concurrentRoot.getExecutions();
+ for (ExecutionImpl concurrentExecution: concurrentExecutions) {
if ( (Execution.STATE_INACTIVE_JOIN.equals(concurrentExecution.getState()))
&& (concurrentExecution.getActivity()==activity)
) {
@@ -142,16 +135,30 @@
return joinedExecutions;
}
- protected void endJoinedExecutions(List<ExecutionImpl> joinedExecutions) {
- for (ExecutionImpl joinedExecution: joinedExecutions) {
- joinedExecution.end();
+ protected void endExecutions(List<ExecutionImpl> executions) {
+ for (ExecutionImpl execution: executions) {
+ execution.end();
}
}
+ private int evaluateMultiplicity(ExecutionImpl execution) {
+ if (multiplicity != null) {
+ Object value = multiplicity.evaluate(execution);
+ if (value instanceof Number) {
+ Number number = (Number) value;
+ return number.intValue();
+ }
+ if (value instanceof String) {
+ return Integer.parseInt((String) value);
+ }
+ }
+ return -1;
+ }
+
public void setLockMode(LockMode lockMode) {
this.lockMode = lockMode;
}
- public void setMultiplicityExpression(Expression multiplicityExpression) {
- this.multiplicityExpression = multiplicityExpression;
+ public void setMultiplicity(Expression multiplicity) {
+ this.multiplicity = multiplicity;
}
}
Modified: jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinBinding.java
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinBinding.java 2010-06-09 17:35:57 UTC (rev 6396)
+++ jbpm4/trunk/modules/jpdl/src/main/java/org/jbpm/jpdl/internal/activity/JoinBinding.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -45,16 +45,16 @@
JoinActivity joinActivity = new JoinActivity();
if (element.hasAttribute(MULTIPLICITY)) {
- String multiplicictyText = element.getAttribute(MULTIPLICITY);
- Expression expression = Expression.create(multiplicictyText, Expression.LANGUAGE_UEL_VALUE);
- joinActivity.setMultiplicityExpression(expression);
+ String multiplicityText = element.getAttribute(MULTIPLICITY);
+ Expression expression = Expression.create(multiplicityText, Expression.LANGUAGE_UEL_VALUE);
+ joinActivity.setMultiplicity(expression);
}
if (element.hasAttribute(LOCKMODE)) {
String lockModeText = element.getAttribute(LOCKMODE);
LockMode lockMode = LockMode.parse(lockModeText.toUpperCase());
if (lockMode==null) {
- parse.addProblem(LOCKMODE + " " + lockModeText + " is not a valid lock mode", element);
+ parse.addProblem(lockModeText + " is not a valid lock mode", element);
} else {
joinActivity.setLockMode(lockMode);
}
Modified: jbpm4/trunk/modules/jpdl/src/main/resources/jbpm.jpdl.bindings.xml
===================================================================
--- jbpm4/trunk/modules/jpdl/src/main/resources/jbpm.jpdl.bindings.xml 2010-06-09 17:35:57 UTC (rev 6396)
+++ jbpm4/trunk/modules/jpdl/src/main/resources/jbpm.jpdl.bindings.xml 2010-06-09 17:46:55 UTC (rev 6397)
@@ -6,6 +6,7 @@
<activity binding="org.jbpm.jpdl.internal.activity.EndBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.EndCancelBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.EndErrorBinding" />
+ <activity binding="org.jbpm.jpdl.internal.activity.ForEachBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.ForkBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.JoinBinding" />
<activity binding="org.jbpm.jpdl.internal.activity.HqlBinding" />
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java 2010-06-09 17:35:57 UTC (rev 6396)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -109,14 +109,15 @@
public abstract Object evaluateInScope(ScopeInstanceImpl scopeInstance);
protected ELContext getElContext(ScopeInstanceImpl scopeInstance) {
- ELContext elContext = (ELContext) (scopeInstance!=null ? scopeInstance.getElContext() : null);
- if (elContext==null) {
- JbpmElFactory contextFactory = JbpmElFactory.getJbpmElFactory();
- elContext = contextFactory.createElContext(scopeInstance);
- if (scopeInstance!=null) {
- scopeInstance.setElContext(elContext);
- }
+ if (scopeInstance == null) {
+ return JbpmElFactory.getJbpmElFactory().createElContext();
}
+
+ ELContext elContext = (ELContext) scopeInstance.getElContext();
+ if (elContext == null) {
+ elContext = JbpmElFactory.getJbpmElFactory().createElContext(scopeInstance);
+ scopeInstance.setElContext(elContext);
+ }
return elContext;
}
}
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmFunctionMapper.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmFunctionMapper.java 2010-06-09 17:35:57 UTC (rev 6396)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmFunctionMapper.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -38,7 +38,7 @@
}
public Method resolveFunction(String prefix, String localName) {
- for (Method method: functionClass.getDeclaredMethods()) {
+ for (Method method: functionClass.getMethods()) {
if (method.getName().equals(localName)) {
return method;
}
Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java 2010-06-09 17:35:57 UTC (rev 6396)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/model/ScopeInstanceImpl.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -248,7 +248,7 @@
}
if (hasVariables) {
for (Map.Entry<String, Variable> entry: variables.entrySet()) {
- String name = (String) entry.getKey();
+ String name = entry.getKey();
Variable variable = entry.getValue();
Object value = variable.getValue(this);
values.put(name, value);
Added: jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/activity/foreach/ForEachTest.java
===================================================================
--- jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/activity/foreach/ForEachTest.java (rev 0)
+++ jbpm4/trunk/modules/test-db/src/test/java/org/jbpm/test/activity/foreach/ForEachTest.java 2010-06-09 17:46:55 UTC (rev 6397)
@@ -0,0 +1,415 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, !
or see the FSF site: http://www.fsf.org.
+ */
+package org.jbpm.test.activity.foreach;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Map;
+
+import org.jbpm.api.Execution;
+import org.jbpm.api.JbpmException;
+import org.jbpm.api.ProcessInstance;
+import org.jbpm.api.history.HistoryProcessInstance;
+import org.jbpm.api.task.Task;
+import org.jbpm.test.JbpmTestCase;
+
+/**
+ * @author Maciej Swiderski
+ */
+public class ForEachTest extends JbpmTestCase {
+
+ public void testForEachLiteral() {
+ deployJpdlXmlString(""
+ + "<process name='ForEachLiteral' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' var='assign' in='alex, mike'>"
+ + " <transition name='left' to='task1' g='-44,-18'/>"
+ + " </foreach>"
+!
+ " <task name='task1' g='90,177,73,44' assignee='#{as!
sign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state name='Big car' > "
+ + " <transition name='to join2' to='join2' g='-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44' multiplicity='2'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForEachLiteral");
+
+ Task taskAlex = taskService.createTaskQuery().assignee("alex").uniqueResult();
+ assertEquals("task1", taskAlex.getActivityName());
+ taskService.completeTask(taskAlex.getId());
+
+ Task taskMike = taskService.createTaskQuery().assignee("mike").uniqueResult();
+ assertEquals("task1", taskMike.getActivityName());
+ taskService.completeTask(taskMike.getId());
+
+ processInstance = executionService.f!
indProcessInstanceById(processInstance.getId());
+ assertEquals(2, processInstance.getExecutions().size());
+
+ for (Execution exec : processInstance.getExecutions()) {
+ assertEquals(Execution.STATE_ACTIVE_CONCURRENT, exec.getState());
+ executionService.signalExecutionById(exec.getId());
+ }
+
+ HistoryProcessInstance history = historyService.createHistoryProcessInstanceQuery()
+ .processInstanceId(processInstance.getId())
+ .uniqueResult();
+ assertEquals(ProcessInstance.STATE_ENDED, history.getState());
+ assertEquals("end1", history.getEndActivityName());
+ }
+
+ public void testForEachList() {
+ deployJpdlXmlString(""
+ + "<process name='ForEachList' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' var='assign' in='#{actors}'>"
+ !
+ " <transition name='left' to='task1' g='-44,-18'/>"!
+
+ " </foreach>"
+ + " <task name='task1' g='90,177,73,44' assignee='#{assign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state name='Big car' > "
+ + " <transition name='to join2' to='join2' g='-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44' multiplicity='#{actors.size()}'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ Map<String, ?> variables = Collections.singletonMap("actors", Arrays.asList("alex", "mike"));
+ ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForEachList", variables);
+
+ Task taskAlex = taskService.createTaskQuery().assignee("alex").uniqueResult();
+ assertEquals("task1", taskAlex.getActivityName());
+ taskService.completeTask(taskAlex.getId());
+
+ Task taskMike = !
taskService.createTaskQuery().assignee("mike").uniqueResult();
+ assertEquals("task1", taskMike.getActivityName());
+ taskService.completeTask(taskMike.getId());
+
+ processInstance = executionService.findProcessInstanceById(processInstance.getId());
+ assertEquals(2, processInstance.getExecutions().size());
+
+ for (Execution exec : processInstance.getExecutions()) {
+ assertEquals(Execution.STATE_ACTIVE_CONCURRENT, exec.getState());
+ executionService.signalExecutionById(exec.getId());
+ }
+
+ HistoryProcessInstance history = historyService.createHistoryProcessInstanceQuery()
+ .processInstanceId(processInstance.getId())
+ .uniqueResult();
+ assertEquals(ProcessInstance.STATE_ENDED, history.getState());
+ assertEquals("end1", history.getEndActivityName());
+ }
+
+ public void testForEachArray() {
+ deployJpdlXmlString(""
+ + "<process name='ForEachArray' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,!
17,32,29' name='start1'>"
+ + " <transition g='-43,-!
18' name
='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' var='assign' in='#{actors}'>"
+ + " <transition name='left' to='task1' g='-44,-18'/>"
+ + " </foreach>"
+ + " <task name='task1' g='90,177,73,44' assignee='#{assign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state name='Big car' > "
+ + " <transition name='to join2' to='join2' g='-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44' multiplicity='#{length(actors)}'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ Map<String, ?> variables = Collections.singletonMap("actors", new String[] { "alex", "mike" });
+ ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForEachArray", variables);!
+
+ Task taskAlex = taskService.createTaskQuery().assignee("alex").uniqueResult();
+ assertEquals("task1", taskAlex.getActivityName());
+ taskService.completeTask(taskAlex.getId());
+
+ Task taskMike = taskService.createTaskQuery().assignee("mike").uniqueResult();
+ assertEquals("task1", taskMike.getActivityName());
+ taskService.completeTask(taskMike.getId());
+
+ processInstance = executionService.findProcessInstanceById(processInstance.getId());
+ assertEquals(2, processInstance.getExecutions().size());
+
+ for (Execution exec : processInstance.getExecutions()) {
+ assertEquals(Execution.STATE_ACTIVE_CONCURRENT, exec.getState());
+ executionService.signalExecutionById(exec.getId());
+ }
+
+ HistoryProcessInstance history = historyService.createHistoryProcessInstanceQuery()
+ .processInstanceId(processInstance.getId())
+ .uniqueResult();
+ assertEquals(ProcessInstance.STATE_ENDED, history.getState());
+ assertEqu!
als("end1", history.getEndActivityName());
+ }
+
+ public vo!
id testF
orEachInvalid() {
+ deployJpdlXmlString(""
+ + "<process name='ForEachInvalid' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' var='assign' in='#{actors}'>"
+ + " <transition name='left' to='task1' g='-44,-18'/>"
+ + " </foreach>"
+ + " <task name='task1' g='90,177,73,44' assignee='#{assign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state name='Big car' > "
+ + " <transition name='to join2' to='join2' g='-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ Map<String, ?> vari!
ables = Collections.singletonMap("actors", new Date());
+ try {
+ executionService.startProcessInstanceByKey("ForEachInvalid", variables);
+ fail("It should fail, since for-each list of items is a Date object");
+ }
+ catch (JbpmException e) {
+ // expected result
+ }
+ }
+
+ public void testForEachMissingVar() {
+ try {
+ deployJpdlXmlString(""
+ + "<process name='ForEachMissingVar' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' in='#{actors}' >"
+ + " <transition name='left' to='task1' g='-44,-18'/>"
+ + " </foreach>"
+ + " <task name='task1' g='90,177,73,44' assignee='#{assign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state !
name='Big car' > "
+ + " <transition name='to join2' !
to='join
2' g='-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ fail("expected foreach with missing variable to fail");
+ }
+ catch (JbpmException e) {
+ // expected result
+ }
+ }
+
+ public void testForEachJoinMultiplicity() {
+ deployJpdlXmlString(""
+ + "<process name='ForEachJoinMultiplicity' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' var='assign' in='#{actors}'>"
+ + " <transition name='left' to='task1' g='-44,-18'/>"
+ + " </foreach>"
+ + " <task name='task1' g='90,177,73,44' assignee='#{assign}'>"
+ + " !
<transition name='to state' to='join2' g='-43,-18'/>"
+ + " </task>"
+ + " <join name='join2' g='192,511,57,44' multiplicity='#{actors.size() - 1}'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ Map<String, ?> variables = Collections.singletonMap("actors", Arrays.asList("alex", "mike"));
+ ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForEachJoinMultiplicity", variables);
+
+ Task taskAlex = taskService.createTaskQuery().assignee("alex").uniqueResult();
+ assertEquals("task1", taskAlex.getActivityName());
+ taskService.completeTask(taskAlex.getId());
+
+ Task taskMike = taskService.createTaskQuery().assignee("mike").uniqueResult();
+ assertNull(taskMike);
+
+ HistoryProcessInstance history = historyService.createHistoryProcessInstanceQuery()
+ .processInstanceId(processInstance!
.getId())
+ .uniqueResult();
+ assertEquals(ProcessIns!
tance.ST
ATE_ENDED, history.getState());
+ assertEquals("end1", history.getEndActivityName());
+ }
+
+ public void testForEachLiteralWithTransitionExpr() {
+ deployJpdlXmlString(""
+ + "<process name='ForEachCondition' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' var='assign' in='alex, mike, peter'>"
+ + " <transition name='left' to='task1' g='-44,-18'>"
+ + " <condition expr='#{assign=="alex" or assign=="mike"}' /> "
+ + " </transition>"
+ + " </foreach>"
+ + " <task name='task1' g='90,177,73,44' assignee='#{assign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state name='Big car' > "
+ + " <transition name='to join2' to='join2' g='!
-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44' multiplicity='2'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ ProcessInstance processInstance = executionService.startProcessInstanceByKey("ForEachCondition");
+
+ Task taskAlex = taskService.createTaskQuery().assignee("alex").uniqueResult();
+ assertEquals("task1", taskAlex.getActivityName());
+ taskService.completeTask(taskAlex.getId());
+
+ Task taskMike = taskService.createTaskQuery().assignee("mike").uniqueResult();
+ assertEquals("task1", taskMike.getActivityName());
+ taskService.completeTask(taskMike.getId());
+
+ processInstance = executionService.findProcessInstanceById(processInstance.getId());
+ assertEquals(2, processInstance.getExecutions().size());
+
+ for (Execution exec : processInstance.getExecutions()) {
+ assert!
Equals(Execution.STATE_ACTIVE_CONCURRENT, exec.getState());
+ !
exe
cutionService.signalExecutionById(exec.getId());
+ }
+
+ HistoryProcessInstance history = historyService.createHistoryProcessInstanceQuery()
+ .processInstanceId(processInstance.getId())
+ .uniqueResult();
+ assertEquals(ProcessInstance.STATE_ENDED, history.getState());
+ assertEquals("end1", history.getEndActivityName());
+ }
+
+ public void testForEachTooManyTransitions() {
+ try {
+ deployJpdlXmlString(""
+ + "<process name='ForEachTooManyTransitions' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' in='#{actors}' var='assign'>"
+ + " <transition name='left' to='task1' g='-44,-18'/>"
+ + " <transition name='right' to='task1' g='-44,-18'/>"
+ + " </foreach>"
+ + " <task name='task1' g='90,177,7!
3,44' assignee='#{assign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state name='Big car' > "
+ + " <transition name='to join2' to='join2' g='-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ fail("expected foreach with too many transitions");
+ }
+ catch (JbpmException e) {
+ // expected result
+ }
+ }
+
+ public void testForEachNoTransitions() {
+ try {
+ deployJpdlXmlString(""
+ + "<process name='ForEachNoTransition' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,!
95,49,50' name='foreach1' in='#{actors}' var='assign' >"
+ !
+ "
</foreach>"
+ + " <task name='task1' g='90,177,73,44' assignee='#{assign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state name='Big car' > "
+ + " <transition name='to join2' to='join2' g='-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ fail("expected foreach with too many transitions");
+ }
+ catch (JbpmException e) {
+ // expected result
+ }
+ }
+
+ public void testForEachConditionTransitionsEvaluatedToFalse() {
+ try {
+ deployJpdlXmlString(""
+ + "<process name='ForEachConditionFalse' xmlns='http://jbpm.org/jpdl/4.4'>"
+ + " <start g='179,17,32,29' name='start1'>"
+ + " <transition g='-43,-18' name='to !
foreach1' to='foreach1'/>"
+ + " </start>"
+ + " <foreach g='185,95,49,50' name='foreach1' in='#{actors}' var='assign' >"
+ + " <transition name='left' to='task1' g='-44,-18'>"
+ + " <condition expr='#{assign=="peter"}' /> "
+ + " </transition>"
+ + " </foreach>"
+ + " <task name='task1' g='90,177,73,44' assignee='#{assign}'>"
+ + " <transition name='to state' to='Big car' g='-43,-18'/>"
+ + " </task>"
+ + " <state name='Big car' > "
+ + " <transition name='to join2' to='join2' g='-43,-18'/>"
+ + " </state> "
+ + " <join name='join2' g='192,511,57,44'>"
+ + " <transition name='to end1' to='end1' g='-42,-18'/>"
+ + " </join>"
+ + " <end g='193,606,38,33' name='end1'/>"
+ + "</process>");
+
+ Map<String, ?> variables = Collections.singletonMap("actors", Arrays.asList("alex", "mike"));
+ !
ProcessInstance processInstance = executionService.startProces!
sInstanc
eByKey("ForEachConditionFalse", variables);
+
+ fail("expected foreach all conditions evaluated to false");
+ }
+ catch (JbpmException e) {
+ // expected result
+ }
+ }
+}
More information about the jbpm-commits
mailing list