diff --git a/imixs-workflow-core/src/main/java/org/imixs/workflow/bpmn/BPMNModelHandler.java b/imixs-workflow-core/src/main/java/org/imixs/workflow/bpmn/BPMNModelHandler.java index ce8e253e4..1a45138a6 100644 --- a/imixs-workflow-core/src/main/java/org/imixs/workflow/bpmn/BPMNModelHandler.java +++ b/imixs-workflow-core/src/main/java/org/imixs/workflow/bpmn/BPMNModelHandler.java @@ -829,12 +829,12 @@ private List 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. - * + *

* 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 is already assigned to the sourceTask, the method returns without * adding the event. * @@ -866,7 +866,7 @@ private void addImixsEvent(String eventID, ItemCollection sourceTask) throws Mod try { if (model.getEvent(sourceTask.getItemValueInteger("numProcessID"), event.getItemValueInteger("numactivityid")) != null) { - logger.finest("......Imixs BPMN Event '" + eventName + "' is already assigned tosource task!"); + logger.finest("......Imixs BPMN Event '" + eventName + "' is already assigned to a source task!"); return; } } catch (ModelException me1) { @@ -889,7 +889,8 @@ private void addImixsEvent(String eventID, ItemCollection sourceTask) throws Mod targetList = new ElementResolver().findAllImixsTargetIDs(outgoingFlow, targetList); } if (targetList.size() > 1) { - // we have a multi event which need to be handled like a loop event + // MULTI target - the event has MANY outgoing targets + event.removeItem("keyFollowUp"); event.replaceItemValue("numNextProcessID", sourceTask.getItemValue("numProcessID")); @@ -1002,14 +1003,11 @@ private void addImixsEvent(String eventID, ItemCollection sourceTask) throws Mod } } else { - // normal case - the event has one outgoing target and we test the - // target element now - + // SINGLE target - the event has only ONE outgoing target // test target element.... - // SequenceFlow outgoingFlow = outFlows.get(0); String followUpEventID = null; for (SequenceFlow outgoingFlow : outFlows) { - // is this Event connected to a followUp Activity? + // is this Event connected to a followUp Event? followUpEventID = new ElementResolver().findImixsTargetEventID(outgoingFlow); if (followUpEventID != null) { break; @@ -1022,7 +1020,6 @@ private void addImixsEvent(String eventID, ItemCollection sourceTask) throws Mod ItemCollection followUpEvent = eventCache.get(followUpEventID); event.replaceItemValue("keyFollowUp", "1"); event.replaceItemValue("numNextActivityID", followUpEvent.getItemValue("numactivityid")); - } else { // test if we found a target task. ItemCollection targetTask = null; @@ -1039,9 +1036,24 @@ private void addImixsEvent(String eventID, ItemCollection sourceTask) throws Mod } } if (targetTask == null) { - // invalid model!! - no target task - throw new ModelException(ModelException.INVALID_MODEL, - "Imixs BPMN Event '" + eventName + "' has no target task element!"); + // test if the event is associated with a LinkThrowEvent + String outgoingLink =null; + List outLinkFlows = findOutgoingFlows(eventID); + for (SequenceFlow _outLink: outLinkFlows) { + if (linkThrowEventCache.containsKey(_outLink.target)) { + outgoingLink=_outLink.target; + logger.fine("...event is associated with link event: " + outgoingLink); + } + } + if (outgoingLink!=null) { + // accept this as a valid situation - e.g. linking into another model + event.removeItem("keyFollowUp"); + event.replaceItemValue("numNextProcessID", sourceTask.getItemValue("numProcessID")); + } else { + // we found no target task or link event ! + throw new ModelException(ModelException.INVALID_MODEL, + "Imixs BPMN Event '" + eventName + "' has no target task or link element!"); + } } } } diff --git a/imixs-workflow-core/src/test/java/org/imixs/workflow/bpmn/TestBPMNParserLinkEvent.java b/imixs-workflow-core/src/test/java/org/imixs/workflow/bpmn/TestBPMNParserLinkEvent.java index b43498ac3..d33f9eb03 100644 --- a/imixs-workflow-core/src/test/java/org/imixs/workflow/bpmn/TestBPMNParserLinkEvent.java +++ b/imixs-workflow-core/src/test/java/org/imixs/workflow/bpmn/TestBPMNParserLinkEvent.java @@ -225,6 +225,74 @@ public void testLinkEventFollowup() throws ParseException, ParserConfigurationEx + + /** + * This test test intermediate link events within an exit situation (e.g. model switch) + * @throws ParseException + * @throws ParserConfigurationException + * @throws SAXException + * @throws IOException + * @throws ModelException + */ + @Test + public void testLinkEventExit() throws ParseException, ParserConfigurationException, SAXException, IOException, ModelException { + + String VERSION = "1.0.0"; + + InputStream inputStream = getClass().getResourceAsStream("/bpmn/link-event_exit.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); + Assert.assertEquals("environment.profile", profile.getItemValueString("txtname")); + Assert.assertEquals("WorkflowEnvironmentEntity", profile.getItemValueString("type")); + Assert.assertEquals(VERSION, profile.getItemValueString("$ModelVersion")); + + Assert.assertTrue(model.getGroups().contains("Simple")); + + // test count of elements + Assert.assertEquals(2, model.findAllTasks().size()); + + // test task 1000 + ItemCollection task = model.getTask(1000 ); + Assert.assertNotNull(task); + Assert.assertEquals("1.0.0", task.getItemValueString("$ModelVersion")); + Assert.assertEquals("Simple", task.getItemValueString("txtworkflowgroup")); + + // test activity for task 1000 + List events = model.findAllEventsByTask(1000 ); + Assert.assertEquals(2, events.size()); + + + /* Test confirm1 Event 1000.20 with link event */ + ItemCollection activity = model.getEvent(1000, 20 ); + Assert.assertNotNull(activity); + Assert.assertEquals("1.0.0", + activity.getItemValueString("$ModelVersion")); + + // the event is still connected to the source task 1000 + Assert.assertEquals("confirm2", activity.getItemValueString("txtName")); + Assert.assertEquals("1000", activity.getItemValueString("numNextProcessID")); + + + } + + + + + @Test public void testComplexParserTest() throws ParseException, ParserConfigurationException, SAXException, IOException { diff --git a/imixs-workflow-core/src/test/resources/bpmn/link-event_exit.bpmn b/imixs-workflow-core/src/test/resources/bpmn/link-event_exit.bpmn new file mode 100644 index 000000000..fefd82c32 --- /dev/null +++ b/imixs-workflow-core/src/test/resources/bpmn/link-event_exit.bpmn @@ -0,0 +1,162 @@ + + + + + + + + + + + SequenceFlow_9 + + + SequenceFlow_8 + + + SequenceFlow_9 + SequenceFlow_13 + SequenceFlow_14 + + + + SequenceFlow_13 + SequenceFlow_6 + + + + SequenceFlow_6 + SequenceFlow_2 + SequenceFlow_8 + + + + SequenceFlow_14 + SequenceFlow_12 + + + SequenceFlow_12 + + + + SequenceFlow_2 + + + + + + + This situation can be used to switch the model version. The target task in this case did not change. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file