Blog‎ > ‎

Automating Business Processes

posted Jan 20, 2013, 6:50 PM by Evan Morrison

As this blog is about my interests and I've noticed that there is a surprising lack of posts about my research area I thought it may be a good idea to post a few articles that will slowly introduce readers to my research area of interest. Firstly, I'll begin with process management and executable processes.

A process model can be viewed as a representation of a set of activities, and decision rules. The purpose of process modeling is to show the activities that actors or systems perform. Each process should represent a specific, repeatable set of steps. Generally process models are created from a combination of activities, decisions and sequence flow. An activity is a single unit of operation and describes a specific step that can be completed. A decision is a point where the model splits. Depending on environmental state or a user choice, only one path is generally chosen to follow during the execution of a process. Sequence flow is the transition between two activities. Sequence gives order to the activities and decisions in a process.  Processes are created using activities representing operations at the same level of granularity, i.e. the activity `go from Australia to United States' and the activity `open envelope' should not appear in the same process. Each process may itself become an activity in a more abstract process model, i.e. the activity `open envelope' may occur in a process describing the steps for ordering airplane tickets.

The business process modeling notation, BPMN, is a standardized notation for creating process models, used to represent business specific process models. It is formed using a collection of activities, gateways, events, sequence flows, pools, swim lanes, and message flows.

When I first started working in this space in 2007, BPMN was already a standard and BPEL was the constantly discussed 'next big thing'. At the time I had my own difficulties in finding a standard file schema, and much of the initial processing I did was on models generated and saved in the XMI format. This never really made a large difference to me as most of the systems I worked on (and still do work on) were based on semantic annotations to the models, and simply translating the models into a digraph was enough. This would have been a large problem for most businesses though, as each BPMN suite did not comply with any other system standard and it meant that although the modeling was standard, that it was not possible to share processes easily or to adopt a best practise repository. In these times SAP was making all of the headway on process reference models and shareable business components.

It wasn't long though until the BPMN 2.0 standard was released which added both a standard file schema as well as the syntactic and semantic descriptions for process execution. It was around this time that businesses started to find that the SAP reference models were not great for use across all industries and that customisability was a big problem. The major players at this stage in the BPMN space were both Tibco and jBPM, which of the two I personally have favour for jBPM and it's 'replacement' Activiti.

I called Activiti the in-quote 'replacement' for jBPM in the sense that the first major release of Activiti was made by ex-jBPM developers Tom Baeyens and Joram Barrez and versioned 5.0. ‘The goal of the Activiti project is to build a rock-solid open source BPMN 2.0 process engine’ (Activiti in Action – Manning Press.

One of the things that impressed me most about the evolution of workflow and case execution engines like Activiti, is the integration and API support for general developers. While on holiday recently, I began working on a project Restful Poker game controlled by a workflow engine. The reason for this is that the workflow engine will be used to handle user management, case instances, history and execution. Each play cycle will be based on a particular workflow. In this blog entry, I demonstrate the beginnings of the game development. Note that this demonstration is not a tutorial on implementing an executable process on a process engine. This is showing how quick and easy it is to set up and create executable processes.

Firstly, a process model detailing the steps of the game was made. As shown below, it is a simple sequential flow process with a number of human and service tasks. The concept is to take human input in the human tasks and then do processing during the service tasks.

 


I have added a series of forms and variables to the user tasks for the user input component of the game. Most of my process editing has been done in the Activiti Eclipse Plugin.  


For the services, I have used a generic JavaDelegate class which is currently being called for each of the service tasks in the process.


I have created a persistent activity process engine running on Apache Tomcat connected to a local MySQL database. I then pieced together a very quick and rough Java application to interact with the process engine. To start with the process is deployed the to the process server.

 

public class ProcessTestMyProcess {

          private String filename = "C:\\workspace\\PokerDemo\\src\\main\\resources\\diagrams\\pokerGame.bpmn";
          private static final boolean redeploy = false;
          private static final boolean restart = true;

         
          TaskService taskService ;
          ManagementService managementService;
          IdentityService identityService;
          HistoryService historyService;
          FormService formService;

          public static void main (String [] args) throws Exception{
                    ProcessTestMyProcess ptp = new ProcessTestMyProcess();
                    ptp.startProcess();
          }
         
          public void startProcess() throws Exception {
                    ProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration()
                                          .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE)
                                          .setJdbcUrl("jdbc:mysql://localhost:3306/activiti")
                                          .setJdbcDriver("com.mysql.jdbc.Driver")
                                          .setJdbcUsername("root")
                                          .setJdbcPassword("")
                                          .setJobExecutorActivate(true)
                                          .buildProcessEngine();
                    if(redeploy){
                              RepositoryService repositoryService = processEngine.getRepositoryService();
                              repositoryService.createDeployment().addInputStream("myProcess.bpmn20.xml",
                                                  new FileInputStream(filename)).deploy();
                    }

 

 

The next step is to connect to the task, management, identity etc. services. Finally, we are ready to enter our main game loop checkRunningTasks().

                    RuntimeService runtimeService = processEngine.getRuntimeService();
                    if(restart){
                              ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess");
                              assertNotNull(processInstance.getId());
                              //System.out.println("id " + processInstance.getId() + " " + processInstance.getProcessDefinitionId());
                    }
                   
                    taskService = processEngine.getTaskService();
                    managementService = processEngine.getManagementService();
                    identityService = processEngine.getIdentityService();
                    historyService = processEngine.getHistoryService();
                    formService = processEngine.getFormService();
                   
                    checkRunningTasks();
          }

          private void checkRunningTasks() {

                    List<Task> tasks = taskService.createTaskQuery().taskAssignee("kermit").list();
                    for (Task task : tasks) {
                      System.out.println("Task available: " + task.getName());
                      if(task.getName().equalsIgnoreCase("Check if user wants to place bet")){
                                doCheckPlay(task);
                      }else if(task.getName().equalsIgnoreCase("User Places Bet")){
                                doPlaceBet(task); 
                      }else if(task.getName().equalsIgnoreCase("User updates Bet")){
                                System.out.println(task.getDescription());
                                doBetUpdate(task);
                      }else{
                                System.out.println("ID:" + task.getName());
                      }
                    }    
                   
                    if(tasks.size() < 1) {
                              System.out.println("Can not find any more tasks right now, please check back later.");
                              return;
                    }
                    checkRunningTasks();
                   
          }
 

When a task is executed, the task name is used to redirect the java application to an adequate form handler. I have redirected each human activity form to get input from the console. In the next iteration of this, a generic form handler will be used.

          private void doCheckPlay(Task task) {
               
                    Map<String, Object> taskVariables = new HashMap<String, Object>();

                    for(FormProperty fp : formService.getTaskFormData(task.getId()).getFormProperties()){
                              if(fp.getName().equalsIgnoreCase("Do you wish to continue?")){
                              boolean answer = getInputBool(fp.getName());
                              if(answer){
                                        System.out.println("Setting continue to true");
                                        taskVariables.put("continue","true");
                              }else{
                                        System.out.println("Setting continue to false");
                                        taskVariables.put("continue","false");
                              }
                              }
                             
                    }

                    System.out.println("Sending form to task");
                    taskService.complete(task.getId(), taskVariables);
                                                 
          }

 

The result so far is a system that will prompt the user for form data and then pipe input to a java service handler.


We can then log in to the Activiti-Explorer default front-end and view instance details of our process.


In my next article on this topic I will begin work on the service task handlers and then begin the transition into a restful application. 

Comments