In the 26th Feb 2013 edition of BPTrends [Harmon 2013], Paul Harmon wrote about the role feedback and group activities play in business processes. In particular, he pointed out an easy to miss and difficult to model common snippet that needs to be handled when creating feedback or review tasks. Typically the feedback process looks something like figure 1.
Figure 1 Example Feedback Process
As Paul points out, typically, we would like to ensure that the review task is completed by someone in the processing department that did not do the initial task that is being reviewed. A suggestion is to give the reviewer a title, like supervisor, and add them into the process as a new lane:
Figure 2 Splitting the Process Model
This however assumes more than the brief and is a notational hack to show what we want. On reading Paul’s article and remembering back to similar structures that I have mapped for large organizations, where reviews are conducted by other team members and simply reviewing work does not make one a manager. I then popped over to the Activiti forums and looked up the general approach that is used within the execution engine. It turns out that generally these exceptions can be easily dealt with using Task and Event listeners. What this means is, that during the modelling phase, execution based listeners are placed on each task and are fired when a task or event is created, assigned and completed. Using this approach a range of very complex constraints can be encoded over a process design. In this article I will demonstrate the creation of a generic listener and constraints that could be implemented to ensure that feedback monitoring can be managed. Then I will describe the general way I would describe the constraints as part of an analyst project.
Semantic effect annotations offer a means to reason over business process models. By reasoning with process effects, we are able to capture the organizational operation model, i.e., “what does this process do?” This is important as it allows us to understand what happens as a result of a business process execution; and what execution scenarios a process designer has created for the organization. In other approaches that rely on syntactical process analysis, no information as to what processes do can be extracted from the process models. This makes pure syntactic analysis difficult when attempting to answer “what” questions about process models.
Previous work in this area [Hinge2009] has described a method for semantic annotation of business processes. This is an effective way of adding semantic descriptions to process models as it produces reusable artefacts that can be reasoned over. To construct semantically annotated business process models, analysts annotate activities in the model with descriptions of the changes that occur as a result of the activities execution. Such results are referred to as immediate effects of an activity. In my future blogs I will describe Hinge’s semantic effect annotations in greater detail; however, for today we will stick to a annotating our process with plain text descriptions of the constraints we wish to place on the design.
Figure 3 Annotated Process Model
Personally, my experience with semi-formal languages like SBVR (Semantics of Business Vocabulary and Business Rules) is not great and I am trying to learn how to use the language effectively and correctly. Due to this I make no claim that the annotations on the model are correct with respect to SBVR; however, I did attempt to use the language as best as possible, enlisting the help of an online editor (www.sbvr.co) to produce a structure of language like in Figure 4.
Figure 4 Visual display of ‘semantic’ annotation
By including a semi-structured description in the annotations on the model, we do not lose any of the intent of the process model and do not overload the BPMN structure with unclear syntactic hacks. Then, under the hood on the execution end, we can implement a listener structure that follows the constraints described in the annotations. So to follow along at this point, we’ll generate a simple deployment of the process.
public class ProcessTestProcesspool1 {
private static String filename = “C:\\Users\\e\\workspace\\FeedbackManagement\\Example.bpmn”;
public static ProcessEngine processEngine;
public static RuntimeService runtimeService;
public static TaskService taskService ;
public static void main(String[] args) throws Exception {
processEngine = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration()
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE)
.setJdbcUrl(“jdbc:”+properties.databaseServer+properties.databaseName)
.setJdbcDriver(properties.databaseDriver)
.setJdbcUsername(properties.databaseUser)
.setJdbcPassword(properties.databasePass)
.setJobExecutorActivate(true)
.buildProcessEngine();
runtimeService = processEngine.getRuntimeService();
taskService = processEngine.getTaskService();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.createDeployment().addInputStream(“process_pool1.bpmn20.xml”,
new FileInputStream(filename)).deploy();
Map<String, Object> variableMap = new HashMap<String, Object>();
variableMap.put(“name”, “Activiti”);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(“process_pool1”, variableMap);
System.out.println(“id ” + processInstance.getId() + ” “
+ processInstance.getProcessDefinitionId());
}
}
Along with a task listener:
package be.fnord.demo.Listeners;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class eTaskListen implements TaskListener{
public void notify(DelegateTask executionEvent) {
System.out.println(
executionEvent.getName() + ” was just triggered with event ” +
executionEvent.getEventName());
TaskUtil.addEvent(executionEvent, executionEvent.getProcessDefinitionId() + “”);
}
}
And an event history manager.
package be.fnord.demo.Listeners;
import java.util.ArrayList;
import java.util.List;
import org.activiti.engine.delegate.DelegateTask;
@SuppressWarnings(“unchecked”)
public class TaskUtil {
public static void addEvent(DelegateTask execution, String source) {
List<String> eventList = (List<String>)
execution.getVariable(“taskList”);
if(eventList == null) {
eventList = new ArrayList<String>();
}
eventList.add(source + “~” + execution.getName());
execution.setVariable(“taskList”, eventList);
}
}
For those of you who have a copy of Tijs Rademakers book ‘Activiti in Action’ [Rademakers 2012], you’ll most likely remember this code from Chapter 6. We’ll then associate the task listener class to the create, assignment, and completion events for each activity in the process model (shown in Figure 5).
Figure 5 Assigning Task Listener to Activities in the Process
Which when run in the Activiti execution engine, does not enforce any of the constraints yet, though will print out the firing of events for each activity.
We now want to change and modify both the listener and the task event history utility slightly. Firstly with the TaskUtil, we will store the process (ID / instance), activity name, and the user who has completed the activity. I’ve also added in a method to search through the task history to find who completed a particular activity last.
public static void addEvent(DelegateTask execution, String source) {
List<String> eventList = (List<String>)
execution.getVariable(“taskList”);
if(eventList == null) {
eventList = new ArrayList<String>();
}
String taskName = execution.getName();
String userName = execution.getAssignee();
eventList.add(source + “~” + taskName + “~” + userName);
execution.setVariable(“taskList”, eventList);
}
public static String getCompleter(DelegateTask execution, String source, String activityName){
List<String> eventList = (List<String>)
execution.getVariable(“taskList”);
if(eventList == null) {
eventList = new ArrayList<String>();
}
int i = eventList.size() – 1;
for(; i >= 0 ; i–){
String[] s = eventList.get(i).split(“~”);
if(s != null && s.length >= 3){
// 0 = source, 1 = taskName, 2 = userName
if(s[1].contains(activityName) && (s[2] != null || s[2].compareTo(“null”) != 0 ) ){
return s[2]; // Return the last name associated to the Complete task
}
}
}
return “”;
}
}
Now we add a check to the Listener to search for review task assignments. If the reviewer is the same as the user who was assigned the “Complete Task” activity, then we can flag a constraint violation.
public class eTaskListen implements TaskListener{
public void notify(DelegateTask executionEvent) {
// For all tasks save the event to the event history
TaskUtil.addEvent(executionEvent,
executionEvent.getProcessDefinitionId() + “/” +
executionEvent.getProcessInstanceId());
// For review tasks, check who was the last worker?
if(executionEvent != null)
if(executionEvent.getName() != null &&
executionEvent.getName().contains(“Review”) ){
if(executionEvent.getAssignee() != null &&
executionEvent.getAssignee().compareTo(“null”) != 0){
String lastWorker = TaskUtil.getCompleter(executionEvent,
executionEvent.getProcessDefinitionId() + “/” +
executionEvent.getProcessInstanceId(), “Complete”);
if(lastWorker != null && lastWorker.length() > 0){
if(lastWorker.compareTo(executionEvent.getAssignee()) == 0){
System.out.println(“Fire the constraint here”);
executionEvent.setAssignee(null);
String response =
lastWorker + ” is not allowed to ” +
“review this job!”;
executionEvent.setDescription(response);
}
}
}
}
}
}
In this instance, we are going to change the task description, to include a message about the review process, and remove the offending user from the assignee role. This way they can claim the task as much as they like, however the listener will take it off any user violating the constraint.
Figure 6 Resulting constrained system
As you can see, this process is long and a little more complex than assigning a supervisor role; however, as the implementation shown is a representation of what actually is happening in the workplace, it is a far better solution and can be easily explained to anyone following the process. This article is the tip of the iceberg of the importance of annotations, and over the next few months I’ll delve deeper into the benefits of annotating processes.
[Hinge2009] K. Hinge, A. K. Ghose, and G. Koliadis, “Process seer: A tool for semantic effect annotation of business process models,” in 13th IEEE International EDOC Conference, 2009.
[Harmon 2013] P. Harmon, “Processes, Feedback and Management” in Feb BPTrends Monthly Email Advisors, Vol. 11, No. 4
[Rademakers 2012] T. Rademakers, “Activiti in Action Executable business processes in BPMN 2.0” Manning Publications Co 2012.