Skip to content

Commit ebca71f

Browse files
mramendiemmurphy1
andauthored
Event listener development (#161) (#3915)
* Event listener development * Corrections for transactions for event listener development * SME review change * SME review change 2 * Update doc-content/jbpm-docs/src/main/asciidoc/CoreEngine/event-listeners-timing-con.adoc Co-authored-by: emmurphy1 <[email protected]> * Update doc-content/jbpm-docs/src/main/asciidoc/CoreEngine/event-listeners-development-con.adoc Co-authored-by: emmurphy1 <[email protected]> * Update doc-content/jbpm-docs/src/main/asciidoc/CoreEngine/event-listeners-development-con.adoc Co-authored-by: emmurphy1 <[email protected]> * Peer review change Co-authored-by: emmurphy1 <[email protected]> Co-authored-by: emmurphy1 <[email protected]>
1 parent a7a71a1 commit ebca71f

File tree

7 files changed

+269
-63
lines changed

7 files changed

+269
-63
lines changed

assemblies/assembly-process-engine.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ include::{jbpm-dir}/CoreEngine/deployment-versions-con.adoc[leveloffset=+3]
4444
include::{jbpm-dir}/CoreEngine/deployment-synchronization-con.adoc[leveloffset=+3]
4545

4646
include::{jbpm-dir}/CoreEngine/threads-process-con.adoc[leveloffset=+2]
47+
4748
include::{jbpm-dir}/CoreEngine/event-listeners-con.adoc[leveloffset=+2]
49+
include::{jbpm-dir}/CoreEngine/event-listeners-interfaces-ref.adoc[leveloffset=+3]
50+
include::{jbpm-dir}/CoreEngine/event-listeners-timing-con.adoc[leveloffset=+3]
51+
include::{jbpm-dir}/CoreEngine/event-listeners-development-con.adoc[leveloffset=+3]
52+
include::{jbpm-dir}/CoreEngine/event-listeners-registration-con.adoc[leveloffset=+3]
4853
include::{jbpm-dir}/CoreEngine/runtime-logger-listener-con.adoc[leveloffset=+3]
4954

5055
include::{jbpm-dir}/CoreEngine/process-engine-configuration-ref.adoc[leveloffset=+2]

doc-content/jbpm-docs/src/main/asciidoc/CoreEngine-chapter.adoc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ include::CoreEngine/deployment-synchronization-con.adoc[leveloffset=+2]
3636

3737
include::CoreEngine/threads-process-con.adoc[leveloffset=+1]
3838
include::CoreEngine/event-listeners-con.adoc[leveloffset=+1]
39+
include::CoreEngine/event-listeners-interfaces-ref.adoc[leveloffset=+2]
40+
include::CoreEngine/event-listeners-timing-con.adoc[leveloffset=+2]
41+
include::CoreEngine/event-listeners-development-con.adoc[leveloffset=+2]
42+
include::CoreEngine/event-listeners-registration-con.adoc[leveloffset=+2]
3943
include::CoreEngine/runtime-logger-listener-con.adoc[leveloffset=+2]
4044

4145
include::CoreEngine/process-engine-configuration-ref.adoc[leveloffset=+1]
42-
Lines changed: 3 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,6 @@
11
[id='event-listeners-con_{context}']
2-
= Event Listeners in the {PROCESS_ENGINE}
2+
= Event listeners in the {PROCESS_ENGINE}
33

4-
You can develop a class that implements the `ProcessEventListener` interface. This class can listen to process-related events, such as starting or completing a process or entering and leaving a node.
4+
Every time that a process or task changes to a different point in its lifecycle, the {PROCESS_ENGINE} generates an event. You can develop a class that receives and processes such events. This class is called an _event listener_.
55

6-
The {PROCESS_ENGINE} passes an event object to this class. The object provides access to related information, like the process instance and node instance linked to the event.
7-
8-
The following list shows the different methods of the `ProcessEventListener` interface:
9-
10-
.Methods of the `ProcessEventListener` interface
11-
[source,java]
12-
----
13-
public interface ProcessEventListener {
14-
15-
void beforeProcessStarted( ProcessStartedEvent event );
16-
void afterProcessStarted( ProcessStartedEvent event );
17-
void beforeProcessCompleted( ProcessCompletedEvent event );
18-
void afterProcessCompleted( ProcessCompletedEvent event );
19-
void beforeNodeTriggered( ProcessNodeTriggeredEvent event );
20-
void afterNodeTriggered( ProcessNodeTriggeredEvent event );
21-
void beforeNodeLeft( ProcessNodeLeftEvent event );
22-
void afterNodeLeft( ProcessNodeLeftEvent event );
23-
void beforeVariableChanged(ProcessVariableChangedEvent event);
24-
void afterVariableChanged(ProcessVariableChangedEvent event);
25-
26-
}
27-
----
28-
29-
The `before` and `after` event calls typically act like a stack. If event A directly causes event B, the following sequence of calls happens:
30-
31-
* Before A
32-
* Before B
33-
* After B
34-
* After A
35-
36-
For example, if leaving node X triggers node Y, all event calls related to triggering node Y occur between the `beforeNodeLeft` and `afterNodeLeft` calls for node X.
37-
38-
In the same way, if starting a process directly causes some nodes to start, all `nodeTriggered` and `nodeLeft` event calls occur between the `beforeProcessStarted` and `afterProcessStarted` calls.
39-
40-
This approach reflects cause and effect relationships between events. However, the timing and order of `after` event calls are not always intuitive. For example, an `afterProcessStarted` call can happen after the `afterNodeLeft` calls for some nodes in the process.
41-
42-
In general, to be notified when a particular event occurs, use the `before` call for the event. Use an `after` call only if you want to make sure that all processing related to this event has ended, for example, when you want to be notified when all steps associated with starting a particular process instance have been completed.
43-
44-
Depending on the type of node, some nodes might only generate `nodeLeft` calls and others might only generate `nodeTriggered` calls. For example, catch intermediate event nodes do not generate `nodeTriggered` calls, because they are not triggered by another process node. Similarly, throw intermediate event nodes do not generate `nodeLeft` calls, as these nodes do not have an outgoing connection to another node.
45-
46-
The `KieSession` class implements the `RuleRuntimeEventManager` interface that provides methods for registering, removing, and listing event listeners, as shown in the following list.
47-
48-
.Methods of the `RuleRuntimeEventManager` interface
49-
[source,java,subs="attributes+"]
50-
----
51-
void addEventListener(AgendaEventListener listener);
52-
void addEventListener(RuleRuntimeEventListener listener);
53-
void removeEventListener(AgendaEventListener listener);
54-
void removeEventListener(RuleRuntimeEventListener listener);
55-
Collection<AgendaEventListener> getAgendaEventListeners();
56-
Collection<RuleRuntimeEventListener> getRuleRintimeEventListeners();
57-
----
58-
59-
However, in a typical case, do not use these methods.
60-
61-
If you are using the `RuntimeManager` interface, you can use the `RuntimeEnvironment` class to register event listeners.
62-
63-
If you are using the Services API, you can add fully qualified class names of event listeners to the `META-INF/services/org.jbpm.services.task.deadlines.NotificationListener` file in your project. The Services API also registers some default listeners, including `org.jbpm.services.task.deadlines.notifications.impl.email.EmailNotificationListener`, which can send email notifications for events.
64-
65-
To exclude a default listener, you can add the fully qualified name of the listener to the `org.kie.jbpm.notification_listeners.exclude` JVM system property.
6+
The {PROCESS_ENGINE} passes an event object to this class. The object provides access to related information. For example, if the event is related to a process node, the object provides access to the process instance and the node instance.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[id='event-listeners-development-con_{context}']
2+
= Practices for development of event listeners
3+
4+
The {PROCESS_ENGINE} calls event listeners during processing of events or tasks. The calls happen within {PROCESS_ENGINE} transactions and block execution. Therefore, the event listener can affect the logic and performance of the {PROCESS_ENGINE}.
5+
6+
To ensure minimal disruption, observe the following practices:
7+
8+
* Any action must be as short as possible.
9+
* A listener class must not have a state. The {PROCESS_ENGINE} can destroy and re-create a listener class at any time.
10+
* If the listener modifies any resource that exists outside the scope of the listener method, ensure that the resource is enlisted in the current transaction. The transaction might be rolled back. In this case, if the modified resource is not a part of the transaction, the state of the resource becomes inconsistent.
11+
+
12+
Database-related resources provided by {EAP} are always enlisted in the current transaction. In other cases, check the JTA information for the runtime environment that you are using.
13+
+
14+
* Do not use logic that relies on the order of execution of different event listeners.
15+
* Do not include interaction with different entities outside the {PROCESS_ENGINE} within a listener. For example, do not include REST calls for notification of events. Instead, use process nodes to complete such calls. An excepting is output of logging information; however, a logging listener must be as simple as possible.
16+
* You can use a listener to modify the state of the process or task that is involved in the event, for example, to change its variables.
17+
* You can use a listener to interact with the {PROCESS_ENGINE}, for example, to send signals or to interact with process instances that are not involved in the event.
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
[id='event-listeners-interfaces-ref_{context}']
2+
= Interfaces for event listeners
3+
4+
You can use the following interfaces to develop event listeners for the {PROCESS_ENGINE}.
5+
6+
== Interfaces for process event listeners
7+
8+
You can develop a class that implements the `ProcessEventListener` interface. This class can listen to process-related events, such as starting or completing a process or entering and leaving a node.
9+
10+
The following source code shows the different methods of the `ProcessEventListener` interface:
11+
12+
.The `ProcessEventListener` interface
13+
[source,java]
14+
----
15+
public interface ProcessEventListener
16+
extends
17+
EventListener {
18+
19+
/**
20+
* This listener method is invoked right before a process instance is being started.
21+
* @param event
22+
*/
23+
void beforeProcessStarted(ProcessStartedEvent event);
24+
25+
/**
26+
* This listener method is invoked right after a process instance has been started.
27+
* @param event
28+
*/
29+
void afterProcessStarted(ProcessStartedEvent event);
30+
31+
/**
32+
* This listener method is invoked right before a process instance is being completed (or aborted).
33+
* @param event
34+
*/
35+
void beforeProcessCompleted(ProcessCompletedEvent event);
36+
37+
/**
38+
* This listener method is invoked right after a process instance has been completed (or aborted).
39+
* @param event
40+
*/
41+
void afterProcessCompleted(ProcessCompletedEvent event);
42+
43+
/**
44+
* This listener method is invoked right before a node in a process instance is being triggered
45+
* (which is when the node is being entered, for example when an incoming connection triggers it).
46+
* @param event
47+
*/
48+
void beforeNodeTriggered(ProcessNodeTriggeredEvent event);
49+
50+
/**
51+
* This listener method is invoked right after a node in a process instance has been triggered
52+
* (which is when the node was entered, for example when an incoming connection triggered it).
53+
* @param event
54+
*/
55+
void afterNodeTriggered(ProcessNodeTriggeredEvent event);
56+
57+
/**
58+
* This listener method is invoked right before a node in a process instance is being left
59+
* (which is when the node is completed, for example when it has performed the task it was
60+
* designed for).
61+
* @param event
62+
*/
63+
void beforeNodeLeft(ProcessNodeLeftEvent event);
64+
65+
/**
66+
* This listener method is invoked right after a node in a process instance has been left
67+
* (which is when the node was completed, for example when it performed the task it was
68+
* designed for).
69+
* @param event
70+
*/
71+
void afterNodeLeft(ProcessNodeLeftEvent event);
72+
73+
/**
74+
* This listener method is invoked right before the value of a process variable is being changed.
75+
* @param event
76+
*/
77+
void beforeVariableChanged(ProcessVariableChangedEvent event);
78+
79+
/**
80+
* This listener method is invoked right after the value of a process variable has been changed.
81+
* @param event
82+
*/
83+
void afterVariableChanged(ProcessVariableChangedEvent event);
84+
85+
/**
86+
* This listener method is invoked right before a process/node instance's SLA has been violated.
87+
* @param event
88+
*/
89+
default void beforeSLAViolated(SLAViolatedEvent event) {}
90+
91+
/**
92+
* This listener method is invoked right after a process/node instance's SLA has been violated.
93+
* @param event
94+
*/
95+
default void afterSLAViolated(SLAViolatedEvent event) {}
96+
97+
/**
98+
* This listener method is invoked when a signal is sent
99+
* @param event
100+
*/
101+
default void onSignal(SignalEvent event) {}
102+
103+
/**
104+
* This listener method is invoked when a message is sent
105+
* @param event
106+
*/
107+
default void onMessage(MessageEvent event) {}
108+
}
109+
----
110+
111+
You can implement any of these methods to process the corresponding event.
112+
113+
For the definition of the event classes that the {PROCESS_ENGINE} passes to the methods, see the `org.kie.api.event.process` package in the https://docs.jboss.org/drools/release/{COMMUNITY_VERSION_FINAL}/kie-api-javadoc/index.html[Java documentation].
114+
115+
You can use the methods of the event class to retrieve other classes that contain all information about the entities involved in the event.
116+
117+
The following example is a part of a node-related event, such as `afterNodeLeft()`, and retrieves the process instance and node type.
118+
119+
.Retrieving the process instance and node type in a node-related event
120+
[source,java]
121+
----
122+
WorkflowProcessInstance processInstance = event.getNodeInstance().getProcessInstance()
123+
NodeType nodeType = event.getNodeInstance().getNode().getNodeType()
124+
----
125+
126+
== Interfaces for task lifecycle event listeners
127+
128+
You can develop a class that implements the `TaskLifecycleEventListener` interface. This class can listen to events related to the lifecycle of tasks, such as assignment of an owner or completion of a task.
129+
130+
The following source code shows the different methods of the `TaskLifecycleEventListener` interface:
131+
132+
.The `TaskLifecycleEventListener` interface
133+
[source,java]
134+
----
135+
public interface TaskLifeCycleEventListener extends EventListener {
136+
137+
public enum AssignmentType {
138+
POT_OWNER,
139+
EXCL_OWNER,
140+
ADMIN;
141+
}
142+
143+
public void beforeTaskActivatedEvent(TaskEvent event);
144+
public void beforeTaskClaimedEvent(TaskEvent event);
145+
public void beforeTaskSkippedEvent(TaskEvent event);
146+
public void beforeTaskStartedEvent(TaskEvent event);
147+
public void beforeTaskStoppedEvent(TaskEvent event);
148+
public void beforeTaskCompletedEvent(TaskEvent event);
149+
public void beforeTaskFailedEvent(TaskEvent event);
150+
public void beforeTaskAddedEvent(TaskEvent event);
151+
public void beforeTaskExitedEvent(TaskEvent event);
152+
public void beforeTaskReleasedEvent(TaskEvent event);
153+
public void beforeTaskResumedEvent(TaskEvent event);
154+
public void beforeTaskSuspendedEvent(TaskEvent event);
155+
public void beforeTaskForwardedEvent(TaskEvent event);
156+
public void beforeTaskDelegatedEvent(TaskEvent event);
157+
public void beforeTaskNominatedEvent(TaskEvent event);
158+
public default void beforeTaskUpdatedEvent(TaskEvent event){};
159+
public default void beforeTaskReassignedEvent(TaskEvent event){};
160+
public default void beforeTaskNotificationEvent(TaskEvent event){};
161+
public default void beforeTaskInputVariableChangedEvent(TaskEvent event, Map<String, Object> variables){};
162+
public default void beforeTaskOutputVariableChangedEvent(TaskEvent event, Map<String, Object> variables){};
163+
public default void beforeTaskAssignmentsAddedEvent(TaskEvent event, AssignmentType type, List<OrganizationalEntity> entities){};
164+
public default void beforeTaskAssignmentsRemovedEvent(TaskEvent event, AssignmentType type, List<OrganizationalEntity> entities){};
165+
166+
public void afterTaskActivatedEvent(TaskEvent event);
167+
public void afterTaskClaimedEvent(TaskEvent event);
168+
public void afterTaskSkippedEvent(TaskEvent event);
169+
public void afterTaskStartedEvent(TaskEvent event);
170+
public void afterTaskStoppedEvent(TaskEvent event);
171+
public void afterTaskCompletedEvent(TaskEvent event);
172+
public void afterTaskFailedEvent(TaskEvent event);
173+
public void afterTaskAddedEvent(TaskEvent event);
174+
public void afterTaskExitedEvent(TaskEvent event);
175+
public void afterTaskReleasedEvent(TaskEvent event);
176+
public void afterTaskResumedEvent(TaskEvent event);
177+
public void afterTaskSuspendedEvent(TaskEvent event);
178+
public void afterTaskForwardedEvent(TaskEvent event);
179+
public void afterTaskDelegatedEvent(TaskEvent event);
180+
public void afterTaskNominatedEvent(TaskEvent event);
181+
public default void afterTaskReassignedEvent(TaskEvent event){};
182+
public default void afterTaskUpdatedEvent(TaskEvent event){};
183+
public default void afterTaskNotificationEvent(TaskEvent event){};
184+
public default void afterTaskInputVariableChangedEvent(TaskEvent event, Map<String, Object> variables){};
185+
public default void afterTaskOutputVariableChangedEvent(TaskEvent event, Map<String, Object> variables){};
186+
public default void afterTaskAssignmentsAddedEvent(TaskEvent event, AssignmentType type, List<OrganizationalEntity> entities){};
187+
public default void afterTaskAssignmentsRemovedEvent(TaskEvent event, AssignmentType type, List<OrganizationalEntity> entities){};
188+
189+
}
190+
----
191+
192+
You can implement any of these methods to process the corresponding event.
193+
194+
For the definition of the event class that the {PROCESS_ENGINE} passes to the methods, see the `org.kie.api.task` package in the https://docs.jboss.org/drools/release/{COMMUNITY_VERSION_FINAL}/kie-api-javadoc/index.html[Java documentation].
195+
196+
You can use the methods of the event class to retrieve the classes representing the task, task context, and task metadata.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[id='event-listeners-registration-con_{context}']
2+
= Registration of event listeners
3+
4+
The `KieSession` class implements the `RuleRuntimeEventManager` interface that provides methods for registering, removing, and listing event listeners, as shown in the following list.
5+
6+
.Methods of the `RuleRuntimeEventManager` interface
7+
[source,java,subs="attributes+"]
8+
----
9+
void addEventListener(AgendaEventListener listener);
10+
void addEventListener(RuleRuntimeEventListener listener);
11+
void removeEventListener(AgendaEventListener listener);
12+
void removeEventListener(RuleRuntimeEventListener listener);
13+
Collection<AgendaEventListener> getAgendaEventListeners();
14+
Collection<RuleRuntimeEventListener> getRuleRintimeEventListeners();
15+
----
16+
17+
However, in a typical case, do not use these methods.
18+
19+
If you are using the `RuntimeManager` interface, you can use the `RuntimeEnvironment` class to register event listeners.
20+
21+
If you are using the Services API, you can add fully qualified class names of event listeners to the `META-INF/services/org.jbpm.services.task.deadlines.NotificationListener` file in your project. The Services API also registers some default listeners, including `org.jbpm.services.task.deadlines.notifications.impl.email.EmailNotificationListener`, which can send email notifications for events.
22+
23+
To exclude a default listener, you can add the fully qualified name of the listener to the `org.kie.jbpm.notification_listeners.exclude` JVM system property.

0 commit comments

Comments
 (0)