Sunday, June 16, 2013

Designing and implementing a custom inbox and My Team Performance task list with IBM Business Process Manager V8

Introduction
IBM Business Process Manager (IBM BPM) provides useful capabilities for managing business processes, including an inbox for process participants. Although it's recommended that you use the out-of-box functionality if possible, there may be some scenarios where the default implementation doesn't meet your needs. In this case, you may need to design and implement a custom inbox. This article lays out an approach and sample implementation for such a custom inbox implementation. Similarly, the default My Team Performance provides a great way for a Team Manager to monitor the tasks assigned to his or her team. However, in some cases, users may want to customize the implementation of the My Team Performance task list. This article also illustrates how to perform this customization.
In a business process, implemented in IBM BPM, all user tasks are displayed in participants' inboxes. The Inbox task list is one of the most critical components in determining work assignments and task flow. The default implementation available in Process Portal shows all the tasks that are assigned to a user or to all the roles the user is a member of.
Examples of scenarios that may require a custom inbox task list
In some cases, the IBM BPM inbox functionality may not meet your specific requirements. Following are a couple of examples of such scenarios:
  • The organization already has a employee portal
    In this situation, the organization already has a well developed and heavily used employee portal. The organizations' strategic goal is to make this portal a one-stop shop for all employees activities. The processes that are implemented using IBM BPM fit well into the kind of activities that are initiated from this portal.
    Process participants, who are also employees of this organization, do not want to learn another user interface to do their process work, but would prefer to see their inbox task list and other information from the employee portal they're familiar with.
  • Extensive customization required
    There is a need for non-trivial customization of the out-of-the-box IBM BPM inbox. The nature of these customizations is not just cosmetic, but functional. One example could be processes that involve auditing tasks. For example, whenever process participants click on an "Audit Task" in their inbox, they should be directed to the detailed audit steps. Depending on whether these steps are in their purview, they can assign the task to themselves or to somebody else. This type of customization may require implementing a custom inbox.
Comparison of design approaches
There are multiple ways to design and implement a custom inbox. Table 1 shows the advantages and disadvantages to these approaches. In this article, we'll use the JavaScript™ API approach.

Table 1. Comparison of design approaches


ApproachProsCons
REST-API
  • Can be used from external graphical user interface
  • Clean and exposed interface
REST API security model is stricter than JavaScript API. Users can only work on tasks that are assigned to them or to their group
WebAPICan be used by external applicationsStricter security model and subset of functionality as compared to JavaScript API
JavaScript API (used in this article)Extensive functionality as compared to REST-API and WebAPIThe customizations need to be implemented as services inside IBM BPM that can be called externally via REST-API or an exposed web service
Creating users and groups for the sample scenario
The sample scenario we'll use in this article contains the following groups and users, which you need to create before running the sample process application. For information on how to manage users, refer to Managing Users in IBM BPM in the Business Process Manager Information Center.
  • Service_Agents: This group contains the service agents that will receive the tasks from the process. There are three service agents in this group: Service_Agent1, Service_Agent2 and Service_Agent3.
  • Temp_Service_Agents: To illustrate that this mechanism also works for nested groups, we've added a group in the Service_Agents group called Temp_Service_Agents. This group has one service agent called Temp_Service_Agent1, as shown in Figure 1.

    Figure 1. Service_Agents and Temp_Service_Agents groups
    Service_Agents and                     Temp_Service_Agents groups
  • Service_Supervisors: This group contains users who act as supervisors or "team managers" for Service_Agents, as shown in Figure 2. There is one user in this group called Service_Supervisor1.

    Figure 2. Service_Supervisors group
    Service_Supervisors                     group
Figure 3 shows the user hierarchy of the sample scenarios in the IBM BPM Process Admin console.

Figure 3. User hierarchy
User hierarchy 
Creating a process to generate the user tasks
Figure 4 shows a very simple process that is used to generate user tasks.

Figure 4. Sample process for task generation
Sample                     process for task generation 
The participant group associated with this task is called PG_Service_Agents, as shown in Figure 5.

Figure 5. PG_Service_Agents group
PG_Service_Agents group 
We want to route all the tasks to the Service_Agents group, so you need to add that to the PG_Service_Agents participant group, as shown in Figure 6.

Figure 6. Add Service_Agents to PG_Service_Agents
Add Service_Agents                   to PG_Service_Agents 
This will route the tasks to the members of the Service_Agents group. Remember that there are three individual members and one nested group in the Service_Agents group.
Note: When running the sample code, run this process multiple times and assign tasks to different users, so that each user has few tasks in his or her inbox.
Getting the user's tasks in the inbox
A typical out-of-the-box inbox contains the following tasks, as shown in Figure 7:
  • Tasks assigned to the user
  • Tasks assigned to all groups of which the user is a member

Figure 7. Inbox tasks
Inbox tasks 
The first item, getting the tasks assigned to the user, is fairly straightforward. The second one, getting tasks for all groups of which the user is a member, is slightly tricky. To determine the tasks that exist at the group level, you need to first find out all the groups the user belongs to. Fortunately, the JavaScript TWSearch API provides an easy way to get this list.
In the process Get Custom Inbox for User, shown in Figure 8, the process activity get user’s Inbox level task internally calls the System Service get the user's inbox-level tasks.

Figure 8. Get user's inbox-level tasks
Get user's inbox-level tasks 
Listing 1 shows the code implemented in the Search for Users Inbox General System service using JavaScript APIs to search the user's inbox.

Listing 1. JavaScript API to search user's inbox
            
// 1. SET SEARCH COLUMNS
var col1 = new TWSearchColumn();
col1.name = TWSearchColumn.ProcessInstanceColumns.Name
col1.type = TWSearchColumn.Types.ProcessInstance;
//set other search columns as needed

// 2. SET SEARCH CONDITION
var searchCondition2 = new TWSearchCondition();
searchCondition2.column = mySearchCol2;
//set the criteria for seach
searchCondition2.operator = TWSearchCondition.Operations.Equals;
searchCondition2.value = “New_or_Received”;

// 3. EXECUTE SEARCH IN THE CONTEXT OF SPECIFIED USER
var results = search.execute("user:"+tw.local.searchUserName, 20, 0);

// 4. ITERATE OVER RESULTS TO POPULATE LOCAL VARS
for (var i=0; i<results.rows.length; i++)
{
 var prashaTask =  new tw.object.PrashaTaskDataType();
 prashaTask.processInstanceName = 
                     results.rows[i].values[0];
 prashaTask.processDefinitionName =  
                     results.rows[i].values[1];
}// FOR

/** COMPLETE CODE CAN BE FOUND IN THE ATTACHED FILES **/

Get the tasks assigned to peers
What if you need to find out the tasks assigned to individuals in the same group as user? The default inbox does not give us information about tasks assigned to peers. To get a peer inbox list, complete the following steps:
  1. Find the user's peers (these can come from many groups)
  2. For each peer, find the list of tasks assigned to that peer.
Figure 9 shows a sample process used to find the tasks assigned to peers.

Figure 9. Find tasks assigned to peers
Find tasks assigned                     to peers 
Listing 2, implemented in the General System service, finds all the roles the user is a member of and, for each such role, finds other users in that role. For complete code, download the attached TWX file.

Listing 2. Find peer users
            
function addUsersFromRole( myrole ) {
  var twRole = tw.system.org.findRoleByName(myrole);
  if ( twRole != null ) {
    for ( var i = 0; i < twRole.users.listLength; i++ ) {
        // don't add logged in user
        if (!( tw.local.userName == twRole.users[i].name ) ) {
          tw.local.allUsersInGroup.insertIntoList
              (tw.local.allUsersInGroup.listLength,  
               twRole.users[i].name);
          log.info("add users from role, added USER :" 
                   + twRole.users[i].name);
        }
     }//for
  }//if /** COMPLETE CODE CAN BE FOUND IN THE ATTACHED FILES **/

Get nested groups
There are situations in which a group can contain not just individual users but another nested group. In such situations, you need to write code that can traverse such nested groups and find the users in them. Listing 3 shows the code required to do this.

Listing 3. Find users in nested groups
            
function addUsersFromRoleDeepTraverse( myrole ) {
 var twRole = tw.system.org.findRoleByName(myrole);

 if ( twRole != null ) {
    for ( var i = 0; i < twRole.users.listLength; i++ ) {
        // don't add logged in user
        if (!( tw.local.userName == twRole.users[i].name ) ) {
           
           tw.local.allUsersInGroup.insertIntoList
                (tw.local.allUsersInGroup.listLength, 
                 twRole.users[i].name);
          log.info("add users from role, added USER :" + 
                    twRole.users[i].name);
        }
     }//for
     
     // now get the roles included in this role
     if ( twRole.roles != null ) {
         // if roles found iterate recursively
        for ( var i = 0; i < twRole.roles.listLength; i++ ) {     
            addUsersFromRoleDeepTraverse( twRole.roles[i].name );
        }//for
     } else {
         // no more child roles return from here.
         return;
     }
  }//if /** COMPLETE CODE CAN BE FOUND IN THE ATTACHED FILES **/
}//function

Note: Recursive logic should be used with caution, especially if there are circular references within user groups.
Find the tasks assigned to users
Once you get all the peers of users, getting the tasks assigned to them is quite straightforward and can be done using JavaScript API shown in Listing 1.
Creating a custom My Team Performance task list
Now let's look at building a custom My Team Performance task list. This is more complicated than a regular inbox task list. In this case, the user should be part of the "Team Manager Group." The following steps outline one approach to retrieving the tasks that make up the My Team Performance.
  1. Find all the teams that are managed by the Team Manager.
  2. For each of the teams, get:
    • The list of tasks at the group level
    • The list of users
  3. For each of the users, get all of the tasks assigned to the user.
Figure 10 shows a sample process to get the tasks for My Team Performance.

Figure 10. Get My Team Performance
Get My Team                     Performance 
Find the teams managed by a Team Manager user
A supervisor user can be a Team Manager for one or more teams. Our first task is to find out all the groups for which this user is a Team Manager. You can do that using the following JavaScript code:
var twTeamsManaged = 
 tw.system.org.findRoleByName(userRole).managedTeamRoles;

After this call succeeds twTeamsManaged will have the list of teams (or groups) managed by this user. You can then iterate over the list to get a list of users from each of those groups and to get the tasks assigned to each role or user.
Get a list of users in a group
To get a list of users from a given team requires a simple API call. This call returns all the users from a given group, as shown in Listing 4. Keep in mind that you need to iterate over the list of groups to get all the users and incrementally add them to the final user list.

Listing 4. Get a list of users in a group
var twRole = tw.system.org.findRoleByName(myrole);
  if ( twRole != null ) {
    for ( var i = 0; i < twRole.users.listLength; i++ ) {
        // don't add logged in user
        if (!( tw.local.userName == twRole.users[i].name ) ) {          
     
           tw.local.allUsersInGroup.insertIntoList(
                   w.local.allUsersInGroup.listLength, 
                                   twRole.users[i].name);
        }//if

Get the tasks assigned to each role
You can get the tasks assigned to each user or role using a JavaScript API simple search, similar to what you used in Listing 1, where you used a generic system service to get a user's inbox task list.
Putting it all together
As you've seen, this solution has multiple services and processes. In this section, we'll take a look at how these things come together to complete the solution.
Processes used in the solution
The following processes are included in the solution:
  1. Sample Process for Task Generation: This process is used to generate sample tasks and assign it to different users.
  2. Get Custom Inbox For User: This process contains the logic to get the details of the user's inbox using the JavaScript API.
  3. Get Tasks Assigned to All Peers: This process contains the logic to get the tasks assigned to the peers of a selected user.
  4. Get Custom My Team Performance for User: This process takes the input as a user who has Team Manager rights and retrieves tasks assigned to all subordinates to display the custom My Team Performance.
Variable definitions
Since the custom inbox retrieval or custom My Team Performance retrieval needs an object structure to store the task details, you need to define a complex business object to store it's contents. Figure 11 shows the complex object type definition created for this purpose.

Figure 11. Complex Business Object 
Complex Business Object  
The sample complex object has fields that capture the information needed to display the custom inbox, as well as the custom My Team Performance.

Figure 12. Variables for the Get Custom Inbox for User process
Variables                     for the Get Custom Inbox for User process 
Starting the process with the REST client
Since the idea is to have clients invoke these processes via the REST API, let's look at how this can be achieved using the REST client that ships with IBM BPM. The URL for the REST client is: http://<hostname:port>/bpmrest-ui/ (The default port is 9080.)
Note: Although we're using the REST UI client in our example, these processes can be called using any REST client.
For this to work, you need to expose process start to select users so that it can be invoked using the REST client. This is achieved using the Overview tab for the process. To start the process, you need to set the following fields in the REST client as follows (see Figure 13):
  1. Set the BPD ID to the BPDID of your process. You can find the BPDID on the Overview tab of the process in the System ID field using Process Designer.
  2. Set the value of the userName parameter to { “userName”: “Service_Agent1”} to retrieve inbox content for the user.
  3. Click Execute Call.
Figure 13 starts the process to get the contents of Custom Inbox. You can use a similar technique to start other processes.

Figure 13. Set the required fields in the BPM REST client
Set the required fields in                    the BPM REST client 
Note the piid field in Figure 13. This field is process instance id of the process you just started. You need to use this process instance id to get the contents of user's inbox.
Once the process finishes running, you can use the REST client to retrieve the contents of the custom inbox. The contents are displayed in JSON format. You can use a utility of your choice to convert the JSON into Java Objects or any other desired format.
To retrieve the contents of the inbox, do the following:
  1. Open the REST client in a browser.
  2. Select Process API => Current State in the left navigation pane.
  3. Specify the process instance id from the previous section and click Execute Call. The contents of the user's inbox are returned in the output variable userInboxTaskList, as shown on the right of the screen in Figure 14.

    Figure 14. Displayed results in REST client 
    Displayed results in REST client
You can retrieve custom My Team Performance and tasks assigned to peers in a similar fashion.
Conclusion
This article provided building blocks that can be combined and enhanced to easily design and implement further inbox and task list customizations. The ability to re-use these assets not only saves precious development cycles, but also helps development teams focus their efforts on implementing the actual business process.

3 comments :

  1. Thanks for putting this together. Why is this being done in a process diagram where an instance is created for each inbox retrieval? Why not in an exposed service that can be called via the REST API?

    ReplyDelete
  2. Could you please share the complete code?

    ReplyDelete
    Replies
    1. This complete code is available on below link https://www.ibm.com/developerworks/bpm/library/techarticles/1303_atgur/1303_atgur.html

      Delete