Skip to content

Commit

Permalink
implementation
Browse files Browse the repository at this point in the history
issue #302
  • Loading branch information
rsoika committed Sep 14, 2017
1 parent 571b3aa commit d80592f
Show file tree
Hide file tree
Showing 9 changed files with 1,150 additions and 82 deletions.
374 changes: 313 additions & 61 deletions imixs-workflow-core/src/main/java/org/imixs/workflow/WorkflowKernel.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class BPMNModelHandler extends DefaultHandler {

List<String> startEvents = null;
List<String> conditionalGatewayCache = null;
List<String> parallelGatewayCache = null;

ItemCollection definition = null;

Expand All @@ -100,6 +101,7 @@ public BPMNModelHandler() {
linkCatchEventCache = new HashMap<String, String>();

conditionalGatewayCache = new ArrayList<String>();
parallelGatewayCache = new ArrayList<String>();

startEvents = new ArrayList<String>();

Expand Down Expand Up @@ -257,12 +259,19 @@ public void startElement(String uri, String localName, String qName, Attributes
currentMessageName = attributes.getValue("name");
}

// parallel gateway
if (qName.equalsIgnoreCase("bpmn2:exclusiveGateway") || qName.equalsIgnoreCase("bpmn2:inclusiveGateway")
|| qName.equalsIgnoreCase("bpmn2:eventBasedGateway")) {
// Put conditona Gateway ID into th gateway cache...
// Put conditional Gateway ID into the gateway cache...
conditionalGatewayCache.add(attributes.getValue("id"));
}

// conditional gateway
if (qName.equalsIgnoreCase("bpmn2:parallelGateway")) {
// Put parallel Gateway ID into the gateway cache...
parallelGatewayCache.add(attributes.getValue("id"));
}

// test for conditional Expression...
if (qName.equalsIgnoreCase("bpmn2:conditionExpression")) {
bconditionExpression = true;
Expand Down Expand Up @@ -676,42 +685,109 @@ private void addImixsEvent(String eventID, ItemCollection sourceTask) throws Mod
event.removeItem("keyFollowUp");
event.replaceItemValue("numNextProcessID", sourceTask.getItemValue("numProcessID"));

// test if this is a conditional event - search for gateway...
// test if this is a conditional event - search for conditional gateway...
List<SequenceFlow> outgoingList = this.findOutgoingFlows(eventID);
if (outgoingList != null && outgoingList.size() > 0) {
Map<String,String> conditions=new HashMap<String,String>();
Map<String, String> conditions = new HashMap<String, String>();
for (SequenceFlow flow : outgoingList) {
if (conditionalGatewayCache.contains(flow.target)) {

String conditionalGatewayID = flow.target;
// get all outgoing flows from this gateway
List<SequenceFlow> conditionalFlows = this.findOutgoingFlows(conditionalGatewayID);
for (SequenceFlow condFlow : conditionalFlows) {
ItemCollection targetTask = new ElementResolver().findImixsTargetTask(condFlow);
// build the condition
if (targetTask != null) {
String sExpression = findConditionBySquenceFlow(condFlow);
logger.fine("add condition: " +targetTask.getItemValueInteger("numProcessid") + "="+ sExpression);
conditions.put("task="+targetTask.getItemValueInteger("numProcessid"), sExpression);
String sExpression = findConditionBySquenceFlow(condFlow);
if (sExpression!=null && !sExpression.trim().isEmpty()) {
logger.fine("add condition: " + targetTask.getItemValueInteger("numProcessid") + "="
+ sExpression);
conditions.put("task=" + targetTask.getItemValueInteger("numProcessid"), sExpression);
}
} else {
// test for an event....
String targetEventID = new ElementResolver().findImixsTargetEventID(condFlow);
ItemCollection targetEvent = eventCache.get(targetEventID);
if (targetEvent != null) {
String sExpression = findConditionBySquenceFlow(condFlow);
if (sExpression!=null && !sExpression.trim().isEmpty()) {
logger.fine("add condition: " + targetEvent.getItemValueInteger("numActivityid")
+ "=" + sExpression);
conditions.put("event=" + targetEvent.getItemValueInteger("numActivityid"),
sExpression);
}
}

}
}

}

}
// add the attribute 'keyExclusiveConditions' if available...
if (!conditions.isEmpty()) {
event.replaceItemValue("keyExclusiveConditions", conditions);
}

}

// test if this is a split event - search for parallel gateway...
outgoingList = this.findOutgoingFlows(eventID);
if (outgoingList != null && outgoingList.size() > 0) {
Map<String, String> conditions = new HashMap<String, String>();
for (SequenceFlow flow : outgoingList) {
if (parallelGatewayCache.contains(flow.target)) {

boolean foundConditionForMasterVersion=false;
String parallelGatewayID = flow.target;
// get all outgoing flows from this gateway
List<SequenceFlow> parallelFlows = this.findOutgoingFlows(parallelGatewayID);
for (SequenceFlow parallelFlow : parallelFlows) {
ItemCollection targetTask = new ElementResolver().findImixsTargetTask(parallelFlow);
// build the condition
if (targetTask != null) {
String sExpression = findConditionBySquenceFlow(parallelFlow);
if (sExpression!=null && !sExpression.trim().isEmpty()) {
logger.fine("add condition: " + targetTask.getItemValueInteger("numProcessid") + "="
+ sExpression);
conditions.put("task=" + targetTask.getItemValueInteger("numProcessid"), sExpression);

if (foundConditionForMasterVersion) {
logger.warning("ParallelGateway does not uniquely define an outcome for the Master Version! Multiple condition defined!");
}
foundConditionForMasterVersion=true;
}
} else {
// test for an event....
String targetEventID=new ElementResolver().findImixsTargetEventID(condFlow);
ItemCollection targetEvent=eventCache.get(targetEventID);
String targetEventID = new ElementResolver().findImixsTargetEventID(parallelFlow);
ItemCollection targetEvent = eventCache.get(targetEventID);
if (targetEvent != null) {
String sExpression = findConditionBySquenceFlow(condFlow);
logger.fine("add condition: " +targetEvent.getItemValueInteger("numActivityid") + "="+ sExpression);
conditions.put("event="+targetEvent.getItemValueInteger("numActivityid"), sExpression);
}

String sExpression = findConditionBySquenceFlow(parallelFlow);
if (sExpression!=null && !sExpression.trim().isEmpty()) {
logger.fine("add condition: " + targetEvent.getItemValueInteger("numActivityid")
+ "=" + sExpression);
conditions.put("event=" + targetEvent.getItemValueInteger("numActivityid"),
sExpression);
if (foundConditionForMasterVersion) {
logger.warning("ParallelGateway does not uniquely define an outcome for the Master Version! Multiple condition defined!");
}
foundConditionForMasterVersion=true;
}
}

}
}
if (!foundConditionForMasterVersion) {
logger.warning("ParallelGateway dose not uniquely define an outcome for the Master Version! Master condition is missing");
}

}

}
// add the attribute 'keyConditions' if available...
// add the attribute 'keySplitConditions' if available...
if (!conditions.isEmpty()) {
event.replaceItemValue("keyConditions", conditions);
event.replaceItemValue("keySplitConditions", conditions);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.IOException;
import java.security.Principal;
import java.text.ParseException;
import java.util.List;
import java.util.logging.Logger;

import javax.ejb.SessionContext;
Expand Down Expand Up @@ -229,5 +230,114 @@ public void testConditionalEventModel2() {
}

}





/**
* Test model split_event1.bpmn.
*
* Here we have two conditions: both to a task.
*
* @throws IOException
* @throws SAXException
* @throws ParserConfigurationException
* @throws ParseException
* @throws ModelException
*/
@Test
@Category(org.imixs.workflow.WorkflowKernel.class)
public void testSplitEventModel1() {
try {
// provide a mock modelManger class
when(workflowContext.getModelManager()).thenReturn(new MokModelManager("/bpmn/split_event1.bpmn"));

// test Condition 1
ItemCollection itemCollection = new ItemCollection();
itemCollection.replaceItemValue("txtTitel", "Hello");
itemCollection.replaceItemValue("$processid", 1000);
itemCollection.replaceItemValue("$activityid", 10);
itemCollection.replaceItemValue("$modelversion", MokModel.DEFAULT_MODEL_VERSION);


itemCollection = kernel.process(itemCollection);
Assert.assertEquals("Hello", itemCollection.getItemValueString("txttitel"));
Assert.assertEquals(1100, itemCollection.getProcessID());
Assert.assertEquals(10, itemCollection.getItemValueInteger("$lastEvent"));

// test new version...
List<ItemCollection> versions = kernel.getSplitWorkitems();
Assert.assertNotNull(versions);
Assert.assertTrue(versions.size()==1);
ItemCollection version=versions.get(0);

Assert.assertEquals("Hello", version.getItemValueString("txttitel"));
Assert.assertEquals(1200, version.getProcessID());

} catch (Exception e) {
Assert.fail();
e.printStackTrace();

}

}



/**
* Test model split_event1.bpmn.
*
* Here we have two conditions: both to a task.
*
* @throws IOException
* @throws SAXException
* @throws ParserConfigurationException
* @throws ParseException
* @throws ModelException
*/
@Test
@Category(org.imixs.workflow.WorkflowKernel.class)
public void testSplitEventModel2() {
try {
// provide a mock modelManger class
when(workflowContext.getModelManager()).thenReturn(new MokModelManager("/bpmn/split_event2.bpmn"));

// test Condition 1
ItemCollection itemCollection = new ItemCollection();
itemCollection.replaceItemValue("txtTitel", "Hello");
itemCollection.replaceItemValue("$processid", 1000);
itemCollection.replaceItemValue("$activityid", 10);
itemCollection.replaceItemValue("$modelversion", MokModel.DEFAULT_MODEL_VERSION);


itemCollection = kernel.process(itemCollection);
Assert.assertEquals("Hello", itemCollection.getItemValueString("txttitel"));
Assert.assertEquals(1100, itemCollection.getProcessID());
Assert.assertEquals(10, itemCollection.getItemValueInteger("$lastEvent"));

// test new version...
List<ItemCollection> versions = kernel.getSplitWorkitems();
Assert.assertNotNull(versions);
Assert.assertTrue(versions.size()==1);
ItemCollection version=versions.get(0);

Assert.assertEquals("Hello", version.getItemValueString("txttitel"));
Assert.assertEquals(1200, version.getProcessID());
// $lastEvent should be 20
Assert.assertEquals(20, version.getItemValueInteger("$lastEvent"));


// Master $unqiueid must not match the version $uniqueid
Assert.assertFalse(itemCollection.getUniqueID().equals(version.getUniqueID()));

} catch (Exception e) {
Assert.fail();
e.printStackTrace();

}

}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.imixs.workflow.bpmn;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;

import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.exceptions.ModelException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.xml.sax.SAXException;

import junit.framework.Assert;

/**
* Test class test the Imixs BPMNParser.
*
* Special case: Conditional-Events
*
* @see issue #299
* @author rsoika
*/
public class TestBPMNParserSplitEvents {

@Before
public void setup() {

}

@After
public void teardown() {

}

@SuppressWarnings("unchecked")
@Test
public void testSimple()
throws ParseException, ParserConfigurationException, SAXException, IOException, ModelException {

InputStream inputStream = getClass().getResourceAsStream("/bpmn/split_event1.bpmn");

BPMNModel model = null;
try {
model = BPMNParser.parseModel(inputStream, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
Assert.fail();
} catch (ModelException e) {
e.printStackTrace();
Assert.fail();
}
Assert.assertNotNull(model);

// Test Environment
ItemCollection profile = model.getDefinition();
Assert.assertNotNull(profile);

// test count of elements
Assert.assertEquals(3, model.findAllTasks().size());

// test task 1000
ItemCollection task = model.getTask(1000);
Assert.assertNotNull(task);

// test events for task 1000
List<ItemCollection> events = model.findAllEventsByTask(1000);
Assert.assertNotNull(events);
Assert.assertEquals(1, events.size());

// test activity 1000.10 submit
ItemCollection activity = model.getEvent(1000, 10);
Assert.assertNotNull(activity);
Assert.assertEquals("split event", activity.getItemValueString("txtname"));

Assert.assertEquals(1000, activity.getItemValueInteger("numNextProcessID"));

// Now we need to evaluate if the Event is marked as an conditional Event with
// the condition list copied from the gateway.
Assert.assertTrue(activity.hasItem("keySplitConditions"));
Map<String,String> conditions=(Map<String,String>) activity.getItemValue("keySplitConditions").get(0);
Assert.assertNotNull(conditions);
Assert.assertEquals("true", conditions.get("task=1100"));
}




}
Loading

0 comments on commit d80592f

Please sign in to comment.