Thursday, December 31, 2009

New Year, New Post, New Bonita

After being away for a long time, I am trying to restart work on this blog. A lot of things have happened and the best way to restart is to list some of them. For those of you following the Bonita project most of the things mentioned here will be already known, but it's always good to put them together.
  1. The Bonita team and Bull chose to follow separate paths last September. That led to the creation of the BonitaSoft company. This is very good for the project, since the BPM/workflow solution will be the main product and focus of the new company.
  2. The BonitaSoft company joined the OW2 consortium in October.
  3. A new community website was launched in October, 23. This has more features than the existing OW2 forge, including a source code navigator, a bug tracking tool, a blog, some forums and sections with documentation and downloads.
  4. Several milestone versions of the new major overhaul of the Bonita platform (now called Bonita Open Solution) were released. Bonita Open Solution 5.0 M5 is the latest available release. The final version is expected around February of 2010.
Here are some useful/interesting links in the new Bonita ecosystem: Please join me in wishing them the best for their newly formed company and contribute to the project to make the Bonita Open Solution a world class first order BPM solution, not just when compared to other open source solutions but among the commercial ones as well.

Wednesday, August 19, 2009

Transactional and Non-Transactional Hooks

Every method call in the Bonita API, that updates the process instance state, is executed in a transactional context. That allows the Bonita engine to roll back the whole operation if one of its steps raises an exception, guaranteeing the workflow database will remain in a consistent state and the client application will not have to deal with partially executed operations (e.g.: a task was finished but the following one was not properly initiated).

Hooks are executed in the transactional context of the calling operation. It means the Bonita engine will need to know how to process them during a roll back. The workflow developer must provide that information by identifing them as transactional or non-transactional hooks.

Non-transactional Hooks

Non-transactional hooks are safe from the point of view of the Bonita engine. They do not perform any actions that need to be rolled back in case of an error in the hook itself or somewhere else in the operation and they don’t perform any updates to the workflow database. To enforce this policy, they only expose the read access APIs of the Bonita Platform: QueryDefinitionAPI and QueryRuntimeAPI to the hook programmer. It's important to note they are safe only if the hook developer respects the policy and does not perform any tasks that need to be reverted in case of error using this kind of hook.

They are ideal for operations that do not need or cannot be undone, like sending e-mails. To properly deal with situations where an operation fails after executing a non-transactional hook, the workflow developer must rely on verifications as part of the business logic, either in the business model or in the hook code itself. For example, if a non-transactional hook is used to distribute an e-mail notification, the hook itself might need to query the e-mail system about any e-mail distribution request received from that same activity before or the client application programmer might need to include code to instruct the e-mail system to stop the distribution if the API call raised an exception.

Non-transactional hooks might be run more than once, when the same operation is retried after receiving the exception and (hopefully) cleaning the situation that lead to the error in the first place. This situation must be considered and accounted for by the hook developer.

If an exception is raised during the execution of a non-transactional hook, the Bonita engine will catch it, log it and ignore it. All other changes done as part of the same activity will be completed as if no error had happened.

To include a non-transactional hook in your business process you need to follow these steps:

  1. Create a new non-transactional hook class in ProEd, by selecting the File -> New -> Other -> Bonita BPM -> New Bonita Hook option. Please notice this sequence of commands assumes you have an open Bonita BPM project in Eclipse.
  2. Click on Next and specify a Package name and a class name in the Java Class form and click on the Finish button. This will create a new Java class in the project, implementing the org.ow2.bonita.definition.Hook interface.
  3. Replace the // TODO Auto-generated method stub text with your business logic for this hook.
  4. Go to the project’s process model (XPDL file) and double click on the activity where you want to associate the hook.
  5. Click on the Hooks tab.
  6. Click on the Add button
  7. In the Call Point frame, select the kind of hook you want to specify. The different kinds of hooks and their relationship with the task’s life cycle are discussed here.
  8. In the Hook Name text field type the fully qualified name (package name plus class name) of the Java class created in steps 1 to 3.
  9. Make sure the rollback checkbox remains unchecked. This will indicate to the workflow engine that it will be dealing with a non-transactional hook.
  10. Click on the Ok buttons of the Add Hook and the task’s properties windows.
  11. Complete and deploy the process in your Bonita Engine (e.g.: Bonita Console)

Transactional Hooks

Transactional hooks expose both read and write APIs to the hook programmer. They perform operations in the instance of the business process that will need to be reverted if an exception is raised. Both, exceptions raised by the hook itself and by other operations performed by the same API call will cause the hook’s operations to be rolled back.

Any changes done in external systems cannot be reverted by the workflow engine itself. If the error was raised during the hook’s execution, the hook itself is responsible for catching the exception and doing the cleaning work. If the hook’s execution finished and the exception is raised by the API call later on, those changes to the external systems won’t be undone.

To include a non-transactional hook in your business process you need to follow these steps:

  1. Create a new transactional hook class in ProEd, by selecting the File -> New -> Other -> Bonita BPM -> New Bonita Transactional Hook option. This will create a new Java class in the project, implementing the org.ow2.bonita.definition.TxHook interface.
  2. Perform the steps from 2 to 8 of the instructions to add a non-transactional hook to your business process. Those steps are the same for both transactional and non-transactional hooks.
  3. Make sure the rollback checkbox is checked. This will indicate to the workflow engine that it will be dealing with a transactional hook.
  4. Perform the steps from 10 to 11 of the instructions to add a non-transactional hook to your business process. Those steps are the same for both transactional and non-transactional hooks.

Monday, July 27, 2009

Basics of Automatic Activities

When modeling business processes some activities will be assigned to a person, group, department or organizational unit. Those activities are usually named Manual Activities or Tasks. Their life cycle and the mechanisms provided by Nova Bonita to work with them were briefly described here and here.

Additionally, there are other types of activities that will not be assigned to individuals or groups but that will help the business analysts to model work that needs to be done by the workflow engine itself or by other enterprise systems (like ERPs, CRMs, mail platforms, etc.). Those activities are called Automatic Activities and the Bonita Platform implements them using hooks.

Modeling / Definition

To incorporate automatic activities into your processes you need to follow the next steps:

  1. Create a Java class implementing the org.ow2.bonita.definition.Hook interface. This class will be responsible for performing the work associated with the automatic activity. The Bonita Engine also supports transactional hooks with the org.ow2.bonita.definition.TxHook interface. They will be discussed in an upcoming post.
  2. Add a basic activity to the process model (XPDL) in ProEd as described in section 3.1.3 of the Bonita Quick Start tutorial.
  3. Make sure the Performer combo box remains empty (no process participant is assigned to the activity). The process editor (ProEd) and the Bonita Engine will consider activities without a performer assigned as Automatic Activities and activities with performers associated as Manual Activities.
  4. Select the Add button in the Hooks tab of the New Activity form.
  5. In the Hook Name field of the Add Hook form, type the fully qualified name of the class implemented in step number one. For automatic activities the only kind of hook that can be specified is the OnEnter hook. The other kinds of hooks are not necessary since all the life cycle phases of the activity are controlled by the workflow engine, without manual intervention.
  6. Click in the Ok buttons of the Add Hook and New Activity forms.
  7. Complete and deploy the process in your Bonita Engine (e.g.: The Bonita Console).

Execution

The automatic activities are executed by the Bonita engine when the finishTask() method is called on the previous manual activity. For example, in the process shown below, if the finishTask() is called on an instance of Manual Activity 1, the engine will not just execute the OnFinish hook of that activity. It will also execute the OnEnter hook of Automatic Activity and the OnReady hook of Manual Activity 2.

The sequence of events for the previous process, when calling the finishTask() method for an instance of Manual Activity 1, will be as follows:

  1. Manual Activity 1: OnFinish Hook
  2. Automatic Activity: OnEnter Hook
  3. Manual Activity 2: Role Mapper
  4. Manual Activity 2: Performer Assigner
  5. Manual Activity 2: OnReady Hook

Once the execution of the OnReady hook of Manual Activity 2 is completed the finishTask() method will return control to the caller.

Exceptions

Code executed in the context of hooks can raise exceptions for various reasons. For example, an SMTP server might be down when trying to send an e-mail. The Bonita Engine will catch all exceptions raised by non-transactional hooks (those implementing the org.ow2.bonita.definition.Hook interface), report them to the Bonita logs and will them for any other purpose. That means their impact on the execution of the processes will be minimal and the API calls will return successfully. In the case of automatic activities, that means the engine will mark them as successfully finished, even if their OnEnter hooks raised an exception.

Monday, July 6, 2009

Sending E-Mails

Workflow systems usually interact with people using e-mail notifications. These e-mails help to let people know about pending tasks, approaching deadlines, events affecting them or other activities according to the nature of the business processes that were automated.

Since the Bonita engine focuses on the workflow functions and many enterprise systems already have built in e-mail functionality, there are no specific features in the engine itself to model and distribute e-mails (like an e-mail activity). This allows the workflow developers to interact with any e-mail system already deployed in their environment or to use the Java Mail API that is available in all J EE application servers.

However, for those not having an e-mail notification system already in place or unfamiliar with the Java Mail API a more simple option might be desirable. To satisfy that need, the development team has included in Nova Bonita 4.1.1 a class that makes use of the Java Mail API and the new connectors feature to allow for easy set up and distribution of e-mails.

The EmailConnector is one of the built-in connectors included with the distribution but is not hardwired in the engine itself. This allows the developers using Bonita to rely on their own e-mail solution if they what to. The connector can be called from any kind of hook and in future releases of Bonita it will be possible to set up and configure it directly from the upcoming BPM Studio.

Please notice that the connector infrastructure is just a technology preview at this time. Because of that the API can change in upcoming releases of Nova Bonita.

E-Mail Connector Set Up and usage

  1. Create a new hook in ProEd (Eclipse), which you will use to send the e-mail. If you have defined already a hook, you can perfectly add the e-mail sending logic to the existing hook.
  2. Import the bonita-server-4.1.1.jar library to your Eclipse project. The e-mail connector classes are not included in the bonita-client-4.1.1.jar library (imported by default when a new Bonita project is created). If the bonita-server-4.1.1.jar library is not imported to the project, Eclipse will report in-line errors (EmailConnector class cannot be resolved to a type) and the Bonita engine will generate runtime exceptions when trying to create an instance of the connector.
  3. Import the e-mail connector class:
    import org.ow2.bonita.connector.email.EmailConnector;
  4. Create a new instance of the connector:
    EmailConnector email = new EmailConnector();
  5. Set the connector properties with the values necessary to connect to your SMTP server and the information part of the e-mail you are generating. You can see all the available properties in the connector’s source code. The Bonita Cookbook shows an example with a minimum set of properties:
    email.setSmtpHost("127.0.0.1"); // Your SMTP server IP.

    email.setSmtpPort(25); // Your SMTP server port.

    email.setTo(“receiver@bonitaworld.org”); // Destination address.

    email.setSubject("It works!"); // The e-mail’s subject.
  6. Validate the connector configuration is correct. The validation method will return a list of errors if the parameters were not set correctly. For example, the To field was set with an invalid e-mail address. The validation is run before the execution of the connector (next step). However, the execution method will not return the list of error and will not raise an exception because of them so you will not know the execution was not done. The list returned by the validate() method must be empty for the execute() method to run the connector logic.
    List<ConnectorError> errors = email.validate();
  7. Execute the e-mail connector. If the validate() method returned an empty list of errors, the connector will proceed to execute the e-mail sending logic. If the e-mail distribution was successful, the method will return normally. If there were any problems during the process (for example the SMTP server was down) an exception will be raised. You must catch those exceptions and add code for handling those error conditions.
    email.execute();

Tuesday, June 23, 2009

Accessing Bonita Console's identity services

Nova Bonita 4.1.1 interacts with external identity services using role mappers and performer assigners. Role mappers' function is to connect to an external service (like LDAP, ActiveDirectory, etc.) and return a list of candidates for performing a task. Performer Assigners (if specified) receive a list of candidates from the workflow engine and select the one responsible for performing the task. The selected candidate will be the only one with the task on his/her task list.

An external identity service must be provided and custom role mappers must be written as part of a Nova Bonita implementation project. However, if you are using the Bonita Console for demonstration purposes it's very likely you will want to access the eXo Platform identity services from your business processes. This will allow you to assign tasks to the eXo Platform groups and users.

The procedure to access the Bonita Console identity services (summarized below) was discussed in the Bonita forums here and here. It is composed of two main steps: the creation of the group structure in the Bonita Console and the set up of the business process model to access the service.

Creating the group structure

The following steps describe the process to create a user and group structure using the Bonita Console's user management function.

  1. Create the necessary users. You can see a step by step description in the section Creating new users of the previous post.
  2. Create the group structure that match or organizational needs. To create the groups you need to:
    1. Select the Page Navigations button from the Doc Bar at the bottom of the page.
    2. Select the Administration page from the list of pages shown.
    3. Select the Community Management button from the Doc Bar.
    4. Select the Group Management Option.
    5. Navigate to the desired location of your group. It can be at the root of the structure or nested in another groups (e.g.: /Platform)
    6. Click on the Add new group option, located in the header of the Group frame, with a + sign as icon.
    7. Complete the fields in the Add new group frame and click on the Save button.
  3. Assign the users created in step 1 to the groups created in step 2. You can see a step by step description in the section Providing access to the Users Worklist portlet of the previous post. The only difference is that in step 5 you will need to navigate to the desired group rather than to the /Platform/Console/Bonita group.

Set up the business process model

To access the group structure created in the previous section you need to define the process participants in ProEd, with the following restrictions:

  1. The participant name must follow this format: *:<group>. For example if you created a group called /Org/BonitaWorld/Publishers and you want to assign a task to its members (set them as candidates), the task's performer must be a participant with name *:/Org/BonitaWorld/Publishers
  2. The participant Type must be Role
  3. The participant Mapper Type must be Custom
  4. The participant mapper Class Name must be org.ow2.novabpm.admin.service.bonita.ExoOrganizationMapper

Warning

This mechanism to access the eXo Platform identity service will only work on processes deployed in the Bonita Console or from applications running on the same Tomcat instance than the console. Otherwise, the Bonita engine will not be able to locate the necessary classes during the role mapping phase.

Membership type

The eXo Platform identity service allows the users to specify different kinds of membership to a group. By default there are 4 membership types configured in the Bonita Console: user, member, manager and operator. If you want to assign a task to a subset of a group's members with a given membership type, you need to replace the * at the beginning of the participant name with the desired membership type.

For example, if you want to assign a task only to the managers in the /Org/BonitaWorld/Publishers group you need to set the participant name as manager:/Org/BonitaWorld/Publishers.

Monday, June 15, 2009

User management on Bonita Console

The Nova Bonita console has three main functions available to the users: Users Worklist, BPM Management and User Administration. The Users Worklist allows users to create new instances of deployed processes, execute tasks in their TODO list and review the history of completed tasks. The BPM Management function allows users to manage business processes (deploy, undeploy, start, remove, etc.) process instances and activities. User Management allows the creation and management of users and their assignment to groups.

Access to these functions can be manged from the Console itself using the User Management function built-in as part of the eXo Platform. The steps below describe the processes necessary to create a new Console user and grant it the necessary access rights for each one of the functions. You will be able to find further details and screenshots in the Bonita's Cookbook document, section 8.9

Creating new users

  1. Login as an user with user administration rights. By default only the root user has user management capabilities.
  2. Select the Page Navigations button from the Doc Bar at the bottom of the page.
  3. Select the Administration page from the list of pages shown.
  4. Select the New Account button from the Doc Bar.
  5. Complete all the required fields in the Account Setting tab of the portlet shown and optionally the fields from the User Profile tab.
  6. Click on the Save button. The console will show a pop-up button with the result of the operation. If the user name was not in use before, the account will be added and the console will report that “You have registered a new account successfully!
  7. Click on the Ok button of the pop up frame.

Providing access to the Users Worklist portlet

  1. Select the Page Navigations button from the Doc Bar at the bottom of the page.
  2. Select the Administration page from the list of pages shown.
  3. Select the Community Management button from the Doc Bar.
  4. Select the Group Management Option
  5. Navigate to the /Platform/Console/Bonita group
  6. In the User Name text field of the Add Member frame, type the name of the user to receive access to the Users Worklist portlet.
  7. In the Membership combo-box of the Add Member frame, select user as membership type.
  8. Click on the Save button.

Providing access to the BPM Management portlet

Repeat the steps followed to grant access to the Users Worklist portlet, but in step 7 select operator rather than user as membership type.

Providing access to the user management functions

Repeat the steps followed to grant access to the Users Worklist portlet, but in step 5, navigate to the /Platform/Administrators group and in step 7 select manager as membership type.

Friday, June 5, 2009

Task execution in Nova Bonita (part 2)

The previous post describes some basic principles related to task management in the Nova Bonita BPM platform. Hook execution, the life cycle of the tasks and the API calls necessary to manage them where among the items discussed.

A minimal application that applies those principles is provided and discussed in this post. This Java class can be compiled and run as is. Information on how build the application and set up the persistence environment can be found on previous posts. Please note some posts were written for previous versions of the Bonita platform. You will need to adjust the instructions to accommodate the changes introduced by newer versions.

Full Code

package org.bonitaworld;

import java.util.Iterator;
import javax.security.auth.login.*;
import org.ow2.bonita.facade.*;
import org.ow2.bonita.facade.exception.*;
import org.ow2.bonita.facade.runtime.*;
import org.ow2.bonita.facade.uuid.*;
import org.ow2.bonita.util.*;

public class TaskExecutionExample {

  public static void main(String[] arguments)
    throws LoginException, 
           TaskNotFoundException,
           IllegalTaskStateException,
           ActivityNotFoundException,
           VariableNotFoundException{

    TaskUUID taskUUID;
    String whatAction;
    LoginContext loginContext;
    ActivityInstance currentActivity;
  
    loginContext = 
      new LoginContext("Bonita",
                       new SimpleCallbackHandler("john", "bpm"));

    loginContext.login();
        
    RuntimeAPI runtimeAPI = AccessorUtil.getRuntimeAPI();
    QueryRuntimeAPI queryRuntimeAPI = AccessorUtil.getQueryRuntimeAPI();

    Iterator<ActivityInstance<TaskInstance>> myIterator =
      queryRuntimeAPI.getTaskList(ActivityState.READY).iterator();
     
    while (myIterator.hasNext()){

      currentActivity = myIterator.next();
      taskUUID = currentActivity.getBody().getUUID();
      runtimeAPI.startTask(taskUUID, true);

      whatAction = 
        (String)queryRuntimeAPI.getVariable(currentActivity.getUUID(),
                                            "Action");
       
      if (whatAction.compareTo("SUSPEND") == 0){
        runtimeAPI.suspendTask(taskUUID, true);
      }else {

        runtimeAPI.setVariable(currentActivity.getUUID(),
                               "Action",
                               "SUSPEND");
        
        runtimeAPI.finishTask(taskUUID, true);

      }
    }

    loginContext.logout();

  }
}

Line by Line Explanation

public static void main(String[] arguments) throws LoginException, TaskNotFoundException, IllegalTaskStateException, ActivityNotFoundException, VariableNotFoundException

Exceptions are not properly managed in this example to reduce the complexity. In production applications, each kind of exception must be managed with try/catch blocks at the points where they are originated.

loginContext = new LoginContext("Bonita", new SimpleCallbackHandler("john", "bpm"));
loginContext.login();

The default identity service included in the Bonita Platform distribution requires the applications to log in using the JAAS standard API. This sample application uses a very simple login module provided with the distribution, and the JAAS configuration file jaas-standard.cfg, located in the bonita-runtime-4.1.1/conf folder.

RuntimeAPI runtimeAPI = AccessorUtil.getRuntimeAPI();

This code provides the programmer with access to the Runtime API

QueryRuntimeAPI queryRuntimeAPI = AccessorUtil.getQueryRuntimeAPI();

This code provides the programmer with access to the Query Runtime API

Iterator<ActivityInstance<TaskInstance>> myIterator = queryRuntimeAPI.getTaskList(ActivityState.READY).iterator();

The getTaskList(ActivityState.READY) returns all the activities assigned to the currently logged in user that are in READY status. This function can be used to get a list of activities in any other status or assigned to different users if that is necessary. The method returns a java.util.Collection with elements of ActivityInstance type. This instruction directly retrieves the java.util.Iterator to process the tasks, but any other manipulation of the Collection object is allowed. All activities in this list were processed previously by the BPM engine. That preprocessing included the execution of the OnReady hook, the Role Mapper and the Performer Assigner.

taskUUID = currentActivity.getBody().getUUID();

Tasks are the body of manual activities in the Bonita API. This function retrieves the UUID (Universal Unique IDentifier) of the task. This object is necessary to manage the task's life cycle.

runtimeAPI.startTask(taskUUID, true);

The startTask() function signals to the Bonita Engine that it needs to move a task from the READY status to the EXECUTING one. This allows the system to know when a user started to work on one of the items on his/her TODO list. As part of this function call, the engine executes the OnStart hook.

whatAction = (String)queryRuntimeAPI.getVariable(currentActivity.getUUID(), "Action");

One important function that allows the communication between front-end applications and the instances of the business processes managed by the Bonita Engine is the retrieval of variable values. The getVariable() method implements that function. In this case the value of a variable called Action is retrieved to take business decisions later on.

if (whatAction.compareTo("SUSPEND") == 0){

This code makes use of a process variable value to instruct the application regarding the business logic to execute. In the case of this example, if the Action variable has the value SUSPEND, the task will be suspended. Otherwise, the task will be normally finished and the engine will move the process to the next activities.

runtimeAPI.suspendTask(taskUUID, true);

The suspendTask() function changes the status of the task refered with with UUID from EXECUTING to SUSPENDED. It will triger the execution of the OnSuspend hook as well.

runtimeAPI.setVariable(currentActivity.getUUID(), "Action", "SUSPEND");

The setVariable() function is the partner of QueryRuntimeAPI.getVariable(). It allows the front end application to change the value of the process and instance variables. It receives the UUID of the activity where the variable value is going to be updated, the variable name and the value to store.

runtimeAPI.finishTask(taskUUID, true);

Once the application users complete a human activity (task) the BPM engine needs to be notified. The finishTask() method allows the applications to do that. It moves the status of the provided task from the EXECUTING to the FINISHED status and it triggers the execution of the OnFinish hook. Additionally, it's during the execution of this method that the workflow engine works to determine the following activities to execute. Once it has reached the next manual activities, it creates the corresponding tasks, executes their Role Mappers, Performer Assigners and OnReady hooks.