Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update ProcessInstanceHelper.java to fix runtime bundle executing wrong start event when start process instance by message [issue #4382] #4383

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@
import org.activiti.engine.runtime.ProcessInstance;

/**


*
*/
public class ProcessInstanceHelper {

Expand Down Expand Up @@ -78,6 +77,46 @@ public FlowElement getInitialFlowElement(Process process, String processDefiniti
return initialFlowElement;
}

protected FlowElement getInitialFlowElementByMessage(Process process, ProcessDefinition processDefinition, String messageName) {
FlowElement initialFlowElement = null;
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinition.getId());
for (FlowElement flowElement : process.getFlowElements()) {
if (flowElement instanceof StartEvent) {
StartEvent startEvent = (StartEvent) flowElement;
if (CollectionUtil.isNotEmpty(startEvent.getEventDefinitions()) && startEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {

MessageEventDefinition messageEventDefinition = (MessageEventDefinition) startEvent.getEventDefinitions().get(0);
String messageRef = messageEventDefinition.getMessageRef();
if (messageRef.equals(messageName)) {
initialFlowElement = flowElement;
break;
}
}
}
}
if (initialFlowElement == null) {
for (FlowElement flowElement : process.getFlowElements()) {
if (flowElement instanceof StartEvent) {
StartEvent startEvent = (StartEvent) flowElement;
if (CollectionUtil.isNotEmpty(startEvent.getEventDefinitions()) && startEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {

MessageEventDefinition messageEventDefinition = (MessageEventDefinition) startEvent.getEventDefinitions().get(0);
String messageRef = messageEventDefinition.getMessageRef();
if (bpmnModel.containsMessageId(messageRef)) {
Message message = bpmnModel.getMessage(messageRef);
messageEventDefinition.setMessageRef(message.getName());
initialFlowElement = flowElement;
break;
}
}
}

}
}
return initialFlowElement;
}


protected ProcessInstance createAndStartProcessInstance(ProcessDefinition processDefinition,
String businessKey, String processInstanceName,
Map<String, Object> variables, Map<String, Object> transientVariables, boolean startProcessInstance) {
Expand Down Expand Up @@ -110,28 +149,7 @@ public ProcessInstance createAndStartProcessInstanceByMessage(ProcessDefinition

Process process = this.getActiveProcess(processDefinition);

FlowElement initialFlowElement = null;
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinition.getId());
for (FlowElement flowElement : process.getFlowElements()) {
if (flowElement instanceof StartEvent) {
StartEvent startEvent = (StartEvent) flowElement;
if (CollectionUtil.isNotEmpty(startEvent.getEventDefinitions()) && startEvent.getEventDefinitions().get(0) instanceof MessageEventDefinition) {

MessageEventDefinition messageEventDefinition = (MessageEventDefinition) startEvent.getEventDefinitions().get(0);
String messageRef = messageEventDefinition.getMessageRef();
if (messageRef.equals(messageName)) {
initialFlowElement = flowElement;
break;
} // FIXME: We should not need to reset eventDefinition messageRef to message name
else if (bpmnModel.containsMessageId(messageRef)) {
Message message = bpmnModel.getMessage(messageRef);
messageEventDefinition.setMessageRef(message.getName());
initialFlowElement = flowElement;
break;
}
}
}
}
FlowElement initialFlowElement = getInitialFlowElementByMessage(process, processDefinition, messageName);
if (initialFlowElement == null) {
throw new ActivitiException("No message start event found for process definition " + processDefinition.getId() + " and message name " + messageName);
}
Expand Down Expand Up @@ -177,14 +195,14 @@ public ProcessInstance createAndStartProcessInstanceWithInitialFlowElement(Proce
return processInstance;
}

private void recordStartProcessInstance(CommandContext commandContext, FlowElement initialFlowElement, ExecutionEntity processInstance){
private void recordStartProcessInstance(CommandContext commandContext, FlowElement initialFlowElement, ExecutionEntity processInstance) {
updateProcessInstanceStartDate(processInstance);
commandContext.getHistoryManager().recordProcessInstanceStart(processInstance, initialFlowElement);
}

private void createProcessVariables(ExecutionEntity processInstance,
Map<String, Object> variables, Map<String, Object> transientVariables,
Process process){
Map<String, Object> variables, Map<String, Object> transientVariables,
Process process) {
processInstance.setVariables(processDataObjects(process.getDataObjects()));
// Set the variables passed into the start command
if (variables != null) {
Expand Down Expand Up @@ -345,7 +363,7 @@ public ExecutionEntity createProcessInstanceWithInitialFlowElement(ProcessDefini
return processInstance;
}

private void setProcessInstanceName(CommandContext commandContext, ExecutionEntity processInstance, String processInstanceName){
private void setProcessInstanceName(CommandContext commandContext, ExecutionEntity processInstance, String processInstanceName) {
if (processInstanceName != null) {
processInstance.setName(processInstanceName);
commandContext.getHistoryManager()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package org.activiti.engine.impl.util;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedStatic;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mockStatic;
import static org.assertj.core.api.Assertions.assertThat;


public class ProcessInstanceHelperTest {

private ProcessInstanceHelper processInstancehelper;

private MockedStatic mockedStatic;

private BpmnXMLConverter converter;

private InputStream fin;

private XMLStreamReader reader;


@Before
public void setup() throws XMLStreamException {
converter = new BpmnXMLConverter();
mockedStatic = mockStatic(ProcessDefinitionUtil.class);
processInstancehelper = new ProcessInstanceHelper();
}

@After
public void clear() {
mockedStatic.close();
}

@Test
public void testInitialFlowByMessageForEvent1() throws XMLStreamException, IOException {
String MESSAGE_NAME = "event1";
String allMessagesExistPath = "/org/activiti/engine/test/impl/util/StartProcessInstanceByMessage.testInitialFlowElementByMessage.bpmn20.xml";
try{
fin = this.getClass().getResourceAsStream(allMessagesExistPath);
reader = XMLInputFactory.newInstance().createXMLStreamReader(fin);
BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
Process process = bpmnModel.getProcessById("Process_1");
mockedStatic.when(() -> ProcessDefinitionUtil.getBpmnModel(any())).thenReturn(bpmnModel);
FlowElement initialFlowElementByMessage = processInstancehelper.getInitialFlowElementByMessage(process, new ProcessDefinitionEntityImpl(), MESSAGE_NAME);
assertThat(initialFlowElementByMessage).isNotNull();
assertThat(initialFlowElementByMessage.getName()).isEqualTo("start1");
}catch(XMLStreamException e){
throw e;
}finally {
fin.close();
reader.close();
}
}

@Test
public void testInitialFlowByMessageForEvent2() throws XMLStreamException, IOException {
String MESSAGE_NAME = "event2";
String allMessagesExistPath = "/org/activiti/engine/test/impl/util/StartProcessInstanceByMessage.testInitialFlowElementByMessage.bpmn20.xml";
try {
fin = this.getClass().getResourceAsStream(allMessagesExistPath);
reader = XMLInputFactory.newInstance().createXMLStreamReader(fin);
BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
Process process = bpmnModel.getProcessById("Process_1");
mockedStatic.when(() -> ProcessDefinitionUtil.getBpmnModel(any())).thenReturn(bpmnModel);
FlowElement initialFlowElementByMessage = processInstancehelper.getInitialFlowElementByMessage(process, new ProcessDefinitionEntityImpl(), MESSAGE_NAME);
assertThat(initialFlowElementByMessage).isNotNull();
assertThat(initialFlowElementByMessage.getName()).isEqualTo("start2");
}catch(XMLStreamException e){
throw e;
}finally {
fin.close();
reader.close();
}
}

// When messageName passed does not match any messageRef
@Test
public void testInitialFlowByMessageForMessageNameNotPresentInMessageRefs() throws XMLStreamException, IOException {
String allMessagesExistPath = "/org/activiti/engine/test/impl/util/StartProcessInstanceByMessage.testInitialFlowElementByMessage.bpmn20.xml";
String MESSAGE_NAME = "eventinvalid";
try {
fin = this.getClass().getResourceAsStream(allMessagesExistPath);
reader = XMLInputFactory.newInstance().createXMLStreamReader(fin);
BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
Process process = bpmnModel.getProcessById("Process_1");
mockedStatic.when(() -> ProcessDefinitionUtil.getBpmnModel(any())).thenReturn(bpmnModel);
FlowElement initialFlowElementByMessage = processInstancehelper.getInitialFlowElementByMessage(process, new ProcessDefinitionEntityImpl(), MESSAGE_NAME);
assertThat(initialFlowElementByMessage).isNotNull();
assertThat(initialFlowElementByMessage.getName()).isEqualTo("start1");
}catch(XMLStreamException e){
throw e;
}finally {
fin.close();
reader.close();
}
}

@Test
public void testInitialFlowByMessageForNoMessageExists() throws XMLStreamException, IOException {
String noMessagesExistPath = "/org/activiti/engine/test/impl/util/StartProcessInstanceByMessage.testNoMessagePresent.bpmn20.xml";
String MESSAGE_NAME = "eventinvalid";
try {
fin = this.getClass().getResourceAsStream(noMessagesExistPath);
reader = XMLInputFactory.newInstance().createXMLStreamReader(fin);
BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
Process process = bpmnModel.getProcessById("Process_No_Message");
mockedStatic.when(() -> ProcessDefinitionUtil.getBpmnModel(any())).thenReturn(bpmnModel);
FlowElement initialFlowElementByMessage = processInstancehelper.getInitialFlowElementByMessage(process, new ProcessDefinitionEntityImpl(), MESSAGE_NAME);
assertThat(initialFlowElementByMessage).isNull();
}catch(XMLStreamException e){
throw e;
}finally {
fin.close();
reader.close();
}
}


@Test
public void testInitialFlowByMessageForOnlyOneMessageExist() throws XMLStreamException, IOException {
String noMessagesExistPath = "/org/activiti/engine/test/impl/util/StartProcessInstanceByMessage.testOnlyOneMessageExist.bpmn20.xml";
String MESSAGE_NAME = "eventinvalid";
try {
fin = this.getClass().getResourceAsStream(noMessagesExistPath);
reader = XMLInputFactory.newInstance().createXMLStreamReader(fin);
BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
Process process = bpmnModel.getProcessById("Process_One_Message");
mockedStatic.when(() -> ProcessDefinitionUtil.getBpmnModel(any())).thenReturn(bpmnModel);
FlowElement initialFlowElementByMessage = processInstancehelper.getInitialFlowElementByMessage(process, new ProcessDefinitionEntityImpl(), MESSAGE_NAME);
assertThat(initialFlowElementByMessage).isNotNull();
assertThat(initialFlowElementByMessage.getName()).isEqualTo("start2");
}catch(XMLStreamException e){
throw e;
}finally {
fin.close();
reader.close();
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
id="sid-38422fae-e03e-43a3-bef4-bd33b32041b2" targetNamespace="elements">

<message id="event1" name="event1"/>
<message id="event2" name="event2"/>
<process id="Process_1" isExecutable="true">

<scriptTask id="Activity_1ly55ze">
<incoming>Flow_0vkeqm9</incoming>
<outgoing>Flow_1w2ff2b</outgoing>
</scriptTask>
<scriptTask id="Activity_1wc8f9w">
<incoming>Flow_07er313</incoming>
<outgoing>Flow_0dkfij3</outgoing>
</scriptTask>
<endEvent id="Event_10pb2io">
<incoming>Flow_1w2ff2b</incoming>
<incoming>Flow_0dkfij3</incoming>
</endEvent>
<sequenceFlow id="Flow_1w2ff2b" sourceRef="Activity_1ly55ze" targetRef="Event_10pb2io"/>
<sequenceFlow id="Flow_0dkfij3" sourceRef="Activity_1wc8f9w" targetRef="Event_10pb2io"/>
<startEvent id="Event_1rvunkn" name="start1">
<outgoing>Flow_0vkeqm9</outgoing>
<messageEventDefinition id="MessageEventDefinition_07guavf" messageRef="event1">
</messageEventDefinition>
</startEvent>
<sequenceFlow id="Flow_0vkeqm9" sourceRef="Event_1rvunkn" targetRef="Activity_1ly55ze"/>

<startEvent id="Event_1h9d4hc" name="start2">
<outgoing>Flow_07er313</outgoing>
<messageEventDefinition id="MessageEventDefinition_141as5w" messageRef="event2">
</messageEventDefinition>
</startEvent>
<sequenceFlow id="Flow_07er313" sourceRef="Event_1h9d4hc" targetRef="Activity_1wc8f9w"/>
</process>
<bpmndi:BPMNDiagram id="BpmnDiagram_1">
<bpmndi:BPMNPlane id="BpmnPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="Activity_1ly55ze_di" bpmnElement="Activity_1ly55ze">
<omgdc:Bounds x="320" y="80" width="100" height="80"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1wc8f9w_di" bpmnElement="Activity_1wc8f9w">
<omgdc:Bounds x="320" y="180" width="100" height="80"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_10pb2io_di" bpmnElement="Event_10pb2io">
<omgdc:Bounds x="562" y="152" width="36" height="36"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1rvunkn_di" bpmnElement="Event_1rvunkn">
<omgdc:Bounds x="152" y="102" width="36" height="36"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds x="153" y="145" width="34" height="14"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1h9d4hc_di" bpmnElement="Event_1h9d4hc">
<omgdc:Bounds x="152" y="202" width="36" height="36"/>
<bpmndi:BPMNLabel>
<omgdc:Bounds x="153" y="245" width="34" height="14"/>
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="Flow_1w2ff2b_di" bpmnElement="Flow_1w2ff2b">
<omgdi:waypoint x="420" y="120"/>
<omgdi:waypoint x="491" y="120"/>
<omgdi:waypoint x="491" y="170"/>
<omgdi:waypoint x="562" y="170"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0dkfij3_di" bpmnElement="Flow_0dkfij3">
<omgdi:waypoint x="420" y="220"/>
<omgdi:waypoint x="491" y="220"/>
<omgdi:waypoint x="491" y="170"/>
<omgdi:waypoint x="562" y="170"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0vkeqm9_di" bpmnElement="Flow_0vkeqm9">
<omgdi:waypoint x="188" y="120"/>
<omgdi:waypoint x="320" y="120"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_07er313_di" bpmnElement="Flow_07er313">
<omgdi:waypoint x="188" y="220"/>
<omgdi:waypoint x="320" y="220"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>