Skip to content

Commit

Permalink
implementation
Browse files Browse the repository at this point in the history
issue #299
  • Loading branch information
rsoika committed Sep 10, 2017
1 parent 2fe0195 commit 6101d9e
Show file tree
Hide file tree
Showing 4 changed files with 356 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ public class BPMNModelHandler extends DefaultHandler {
boolean bLinkCatchEvent = false;
boolean bItemValue = false;
boolean bdocumentation = false;
boolean bSequenceFlow = false;

boolean bconditionExpression = false;

ItemCollection currentEntity = null;
String currentItemName = null;
String currentItemType = null;
String currentWorkflowGroup = null;
String currentMessageName = null;
String currentAnnotationName = null;
String currentLinkName = null;

String bpmnID = null;
StringBuilder characterStream = null;

Expand All @@ -72,7 +77,10 @@ public class BPMNModelHandler extends DefaultHandler {
Map<String, String> messageCache = null;
Map<String, String> annotationCache = null;

Map<String, String> conditionCache = null;

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

ItemCollection definition = null;

Expand All @@ -86,10 +94,13 @@ public BPMNModelHandler() {
eventCache = new HashMap<String, ItemCollection>();
messageCache = new HashMap<String, String>();
annotationCache = new HashMap<String, String>();
conditionCache = new HashMap<String, String>();

linkThrowEventCache = new HashMap<String, String>();
linkCatchEventCache = new HashMap<String, String>();

conditionalGatewayCache = new ArrayList<String>();

startEvents = new ArrayList<String>();

sequenceCache = new HashMap<String, SequenceFlow>();
Expand Down Expand Up @@ -201,6 +212,7 @@ public void startElement(String uri, String localName, String qName, Attributes
// bpmn2:sequenceFlow - cache all sequenceFlows...
if (qName.equalsIgnoreCase("bpmn2:sequenceFlow")) {
bpmnID = attributes.getValue("id");
bSequenceFlow = true;
String source = attributes.getValue("sourceRef");
String target = attributes.getValue("targetRef");
sequenceCache.put(bpmnID, new SequenceFlow(source, target));
Expand Down Expand Up @@ -245,6 +257,18 @@ public void startElement(String uri, String localName, String qName, Attributes
currentMessageName = attributes.getValue("name");
}

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

// test for conditional Expression...
if (qName.equalsIgnoreCase("bpmn2:conditionExpression")) {
bconditionExpression = true;
characterStream = new StringBuilder();
}

if (qName.equalsIgnoreCase("bpmn2:textAnnotation")) {
bAnnotation = true;
currentAnnotationName = attributes.getValue("id");
Expand Down Expand Up @@ -346,13 +370,21 @@ public void endElement(String uri, String localName, String qName) throws SAXExc
linkCatchEventCache.put(currentLinkName, bpmnID);
}

// test conditional sequence flow...
if (bSequenceFlow && bconditionExpression && qName.equalsIgnoreCase("bpmn2:conditionExpression")) {
String svalue = characterStream.toString();
logger.fine("conditional SequenceFlow:" + bpmnID + "=" + svalue);
bconditionExpression = false;
conditionCache.put(bpmnID, svalue);
}

}

// @SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void characters(char ch[], int start, int length) throws SAXException {

if (bdocumentation) {
if (bdocumentation || bconditionExpression) {
characterStream = characterStream.append(new String(ch, start, length));
}

Expand All @@ -367,19 +399,19 @@ public void characters(char ch[], int start, int length) throws SAXException {

/**
* This method builds the model from the information parsed by the handler.
* First all task elements were adds as unique process entities into the
* model. In the second step the method adds the Activity elements to the
* assigned Task. We look also for activities with no incoming SequenceFlow.
* First all task elements were adds as unique process entities into the model.
* In the second step the method adds the Activity elements to the assigned
* Task. We look also for activities with no incoming SequenceFlow.
*
* The builder verifies the ProcessIDs for each task element to guaranty
* that the numProcessID is unique
* The builder verifies the ProcessIDs for each task element to guaranty that
* the numProcessID is unique
*
* The build connects pairs of Catch and Throw LinkEvents with a virtual
* SequenceFlow to support the same behavior as if those elements where
* connected directly in the model.
*
* The method tests the model for bpmn2:message elements and replace links
* in Activity elements attribute 'rtfMailBody'
* The method tests the model for bpmn2:message elements and replace links in
* Activity elements attribute 'rtfMailBody'
*
* @throws ModelException
*/
Expand Down Expand Up @@ -487,13 +519,13 @@ private String getAnnotationForElement(String elementID) {
}

/**
* This method returns all SourceTask Elements connected to a given eventID.
* The method takes care about loop events and follow up events. Later ones
* are handled by the method addImixsEvent(). For that reason, the result of
* this method can be also an empty list.
* This method returns all SourceTask Elements connected to a given eventID. The
* method takes care about loop events and follow up events. Later ones are
* handled by the method addImixsEvent(). For that reason, the result of this
* method can be also an empty list.
*
* An event can be a shared event so it is possible that more than one
* source tasks are found
* An event can be a shared event so it is possible that more than one source
* tasks are found
*
* @param eventID
* @throws ModelException
Expand Down Expand Up @@ -578,16 +610,16 @@ private List<ItemCollection> findSourceTasks(String eventID) throws ModelExcepti
}

/**
* This method computes the target for an event and adds the event to a
* source task. The method call recursive if the target is a followUp Event.
* This method computes the target for an event and adds the event to a source
* task. The method call recursive if the target is a followUp Event.
*
* If a event has no target the method throws an exception
*
* If a event has more than one targets (task or event elements) then the
* event is handled as a loop event.
* If a event has more than one targets (task or event elements) then the event
* is handled as a loop event.
*
* If a event is already assigned to the sourceTask, the method returns
* without adding the event.
* If a event is already assigned to the sourceTask, the method returns without
* adding the event.
*
* @param sourceTask
* @param event
Expand Down Expand Up @@ -644,6 +676,36 @@ 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...
List<SequenceFlow> outgoingList = this.findOutgoingFlows(eventID);
if (outgoingList != null && outgoingList.size() > 0) {
Map<Integer,String> conditions=new HashMap<Integer,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(targetTask.getItemValueInteger("numProcessid"), sExpression);
}
}

}

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

}

// here we need to check if one of the targets is an event - this
// need to be handled in a recursive call
for (String elementID : targetList) {
Expand Down Expand Up @@ -673,9 +735,7 @@ private void addImixsEvent(String eventID, ItemCollection sourceTask) throws Mod
if (followUpEventID != null) {
// recursive call!
addImixsEvent(followUpEventID, sourceTask);

ItemCollection followUpEvent = eventCache.get(followUpEventID);

event.replaceItemValue("keyFollowUp", "1");
event.replaceItemValue("numNextActivityID", followUpEvent.getItemValue("numactivityid"));

Expand Down Expand Up @@ -709,9 +769,8 @@ private void addImixsEvent(String eventID, ItemCollection sourceTask) throws Mod
}

/**
* This helper method verifies if the activity of the event is still unique
* for the task element. If not the method computes a new one and updates
* the event
* This helper method verifies if the activity of the event is still unique for
* the task element. If not the method computes a new one and updates the event
*
* @param event
* @param task
Expand Down Expand Up @@ -788,8 +847,7 @@ private List<SequenceFlow> findOutgoingFlows(String elementID) {
}

/**
* This method returns all incoming Associations flows for a given element
* ID
* This method returns all incoming Associations flows for a given element ID
*
* @param elementID
* @return
Expand All @@ -808,8 +866,7 @@ private List<SequenceFlow> findIncomingAssociations(String elementID) {
}

/**
* This method returns all outgoing Associations flows for a given element
* ID
* This method returns all outgoing Associations flows for a given element ID
*
* @param elementID
* @return
Expand All @@ -826,6 +883,30 @@ private List<SequenceFlow> findOutgoingAssociations(String elementID) {
return result;
}

/**
* This method returns an optional condition for a given sequenceFlow object.
* The method iterates the conditionCache to lookup the condition
*
* @param flow
* @return the condition if available or null
*/
private String findConditionBySquenceFlow(SequenceFlow flow) {
if (conditionCache == null) {
return null;
}
// first we need do figure out the squenceFlowID for the flow object
String sequenceID = null;
for (Map.Entry<String, SequenceFlow> entry : sequenceCache.entrySet()) {
String key = entry.getKey();
SequenceFlow value = entry.getValue();
if (value == flow) {
sequenceID = key;
break;
}
}
return conditionCache.get(sequenceID);
}

/**
* This method parses an event for the text fragment
* <bpmn2:message>...</bpmn2:message> and replaces the tag with the
Expand Down Expand Up @@ -877,9 +958,8 @@ public SequenceFlow(String source, String target) {
}

/**
* This helper class provides methods to resolve the connected Imixs
* elements to a flow element. The constructor is used to initialize a
* loopDetection cache
* This helper class provides methods to resolve the connected Imixs elements to
* a flow element. The constructor is used to initialize a loopDetection cache
*
* @author rsoika
*
Expand All @@ -893,9 +973,9 @@ public ElementResolver() {
}

/**
* This method searches a Imixs Task Element connected to the given
* SequenceFlow element. If the Sequence Flow is not connected to a
* Imixs Task element the method returns null.
* This method searches a Imixs Task Element connected to the given SequenceFlow
* element. If the Sequence Flow is not connected to a Imixs Task element the
* method returns null.
*
*
* @return the Imixs Task element or null if no Task Element was found.
Expand Down Expand Up @@ -943,12 +1023,11 @@ public List<ItemCollection> findAllImixsSourceTasks(SequenceFlow flow, List<Item

/**
* This method searches a Imixs Event Element connected to the given
* SequenceFlow element. If the Sequence Flow is not connected to a
* Imixs Event element the method returns null.
* SequenceFlow element. If the Sequence Flow is not connected to a Imixs Event
* element the method returns null.
*
*
* @return the Imixs event element or null if no event Element was
* found.
* @return the Imixs event element or null if no event Element was found.
* @return
*/
public ItemCollection findImixsSourceEvent(SequenceFlow flow) {
Expand Down Expand Up @@ -992,8 +1071,8 @@ public ItemCollection findImixsSourceEvent(SequenceFlow flow) {

/**
* This method searches a Imixs Task Element targeted from the given
* SequenceFlow element. If the Sequence Flow is not connected to a
* Imixs Task element the method returns null.
* SequenceFlow element. If the Sequence Flow is not connected to a Imixs Task
* element the method returns null.
*
* If the target is a Event (FollowUp Event) the method returns null.
*
Expand Down Expand Up @@ -1038,12 +1117,12 @@ public ItemCollection findImixsTargetTask(SequenceFlow flow) {
}

/**
* This method searches the id for a Imixs follow-Up activity. This is
* the case if the target is another Imixs Event element. The method
* returns the id of the followup event
* This method searches the id for a Imixs follow-Up activity. This is the case
* if the target is another Imixs Event element. The method returns the id of
* the followup event
*
* @return the ID of the Imixs Event element or null if no Event Element
* was found.
* @return the ID of the Imixs Event element or null if no Event Element was
* found.
* @return
*/
public String findImixsTargetEventID(SequenceFlow flow) {
Expand Down Expand Up @@ -1082,12 +1161,12 @@ public String findImixsTargetEventID(SequenceFlow flow) {
}

/**
* This method searches for all target events or task for a outgoing
* sequence flow. The method returns a List of possible target elemetns.
* This method searches for all target events or task for a outgoing sequence
* flow. The method returns a List of possible target elemetns.
*
*
* @return the ID of the Imixs Event element or null if no Event Element
* was found.
* @return the ID of the Imixs Event element or null if no Event Element was
* found.
* @return
*/
public List<String> findAllImixsTargetIDs(SequenceFlow flow, List<String> targetList) {
Expand Down Expand Up @@ -1133,12 +1212,12 @@ public List<String> findAllImixsTargetIDs(SequenceFlow flow, List<String> target
}

/**
* This method searches for all target tasks for a outgoing sequence
* flow. The method returns a List of possible imixs task elements.
* This method searches for all target tasks for a outgoing sequence flow. The
* method returns a List of possible imixs task elements.
*
*
* @return the ID of the Imixs Event element or null if no Event Element
* was found.
* @return the ID of the Imixs Event element or null if no Event Element was
* found.
* @return
*/
public List<String> findAllImixsTargetTaskIDs(SequenceFlow flow, List<String> targetList) {
Expand Down
Loading

0 comments on commit 6101d9e

Please sign in to comment.