Claim and Check pattern with LWPF

In this blog, we will look at how to implement the Claim Check pattern with LWPF in combination with DynaCache.

LWPF was described in an earlier blog. You can view that here.

What is the Claim Check Pattern Anyway?

The Claim Check pattern is an implementation pattern of detaching the application data storage from the application and maintaining it in a database. The data can then be retrieved (claimed) and used when needed, and then checked back into the database with the changes that were made in the application.

Figure 1:  The Claim Check pattern

When to Use the Claim Check Pattern

When the application data or the business object data is large (with a size of hundreds of KB of data). This will help reduce the memory usage during process execution as we don’t need to hold the data throughout the lifecycle of the process, which will improve the application performance.

When the process has parallel flows and the data changes in one path have to be reflected in another process path.

Let us understand this using a sample hiring process.

Below is a four-step hiring process that we are going to use for this demonstration.

Figure 2: Four-step hiring process

This is the business object structure used for this process.

Figure 3: Business object structure for candidate

The tables created for the business object structure above:

Figure 4: Table structures created for the given business object

In this process, we used the Claim Check pattern with LWPF in combination with DynaCache. The checking of data (data update) happens via an asynchronous mechanism with LWPF to improve the process performance. This reduces the time needed to update the data back to database from the process execution. 

Let us look at how this data is retrieved in each of these tasks. The image below shows a snapshot of how data is retrieved, processed, and updated back to database. Each of the activities in the process have a similar pattern of implementation. 

Figure 5: Implementation pattern for the Claim Check pattern

In this pattern, the first step of each activity is the retrieval of the data from the database. The last step of each activity is the updating of data back to database. All the data processing happens between these two activities.

Now let us look at how we are updating the data back to database while concluding each task. In this process, we are using an asynchronous mechanism to update the data back to database using a UCA and Start message event with a short-running process to update the data, as shown below.

Figure 6: Short-running process to update data

This short-running process is invoked from each task while concluding the task using UCA, which will create a process instance for the short-running process above. It updates the data back to database using the LWPF and then to DynaCache for faster retrieval during the next data claim (data retrieval). If the data fails, the process just ends without failing the instance. A little later in this post, we will see how to handle data that has gone out of sync due to update failure while retrieving the data in the next task of the process.

Now let us look at how to retrieve the data at the start of each task.  

Figure 7: Human service with Claim Check implementation

The highlighted part in the service in Fig. 7 takes the process status, instance ID (or any primary key to uniquely identify the record), and the business object variable as input. This service first checks for the data with the current process status (to see if the data is updated properly during the previous transaction or update). If data is available, it gets the business object data from the database using the LWPF pull service. Otherwise, it gets the data from the short-running process instance that was used for the data update in the previous step, as shown in Fig 8.

Figure 8: Service diagram to pull the business object data

While pulling the data from the LWPF service, the service first verifies the availability of data in the cache. If the data is available, then it will be fetched from the cache. Otherwise, the LWPF service will make a call to the database to retrieve the data and map it to the business object variable for use in the task. Fig. 9 shows high-level service diagram for this.

Figure 9: Service diagram showing the implementation of LWPF data pull

When the data is not available in the database with the current status due to an update failure, the data is retrieved from the short-running process as described in the sections above. Fig. 10 and the script shown in Fig. 11 illustrate how the data is retrieved from the short-running process, which is used to update the data to the database.

Figure 10: Service diagram showing the implementation to retrieve data from a short-running process

var search=new TWSearch();


var instColumn=new TWSearchColumn();

instColumn.name=TWSearchColumn.ProcessInstanceColumns.ID;

instColumn.type=TWSearchColumn.Types.ProcessInstance;


var cond1=new TWSearchCondition();

cond1.column=new TWSearchColumn();

cond1.column.name="instanceRef";

cond1.column.type=TWSearchColumn.Types.BusinessData;

cond1.operator=TWSearchCondition.Operations.Equals;

cond1.value=tw.local.instanceIdRef;


var cond2=new TWSearchCondition();

cond2.column=new TWSearchColumn();

cond2.column.name="status";

cond2.column.type=TWSearchColumn.Types.BusinessData;

cond2.operator=TWSearchCondition.Operations.Equals;

cond2.value=tw.local.status;


var cond3=new TWSearchCondition();

cond3.column=new TWSearchColumn();

cond3.column.name=TWSearchColumn.ProcessColumns.Name;

cond3.column.type=TWSearchColumn.Types.Process;

cond3.operator=TWSearchCondition.Operations.Equals;

cond3.value="Update Data to DB";


search.columns=new Array(instColumn);

search.conditions=new Array(cond1,cond2,cond3);


search.organizedBy= TWSearch.OrganizeByTypes.ProcessInstance;

var orderBy=new TWSearchOrdering();

orderBy.column=instColumn;

orderBy.Order=TWSearchOrdering.Orders.Descending;

search.orderBy=new Array(orderBy);


var results=search.execute();


//tw.local.instanceIdRef=results.rows.length;

var instanceId="";

if(results!=null && results.rows!=null){

for(var i=0;i<results.rows.length;i++){

tw.local.instanceIdRef=String(results.rows[0].values[0]);

}

}

tw.local.data=new tw.object.Candidate();

tw.local.data.candidateId=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.candidateId");

tw.local.data.parentId=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.parentId");

tw.local.data.firstName=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.firstName");

tw.local.data.lasatName=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.lasatName");

tw.local.data.age=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.age");

tw.local.data.dateOfBirth=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.dateOfBirth");

tw.local.data.totalExperience=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.totalExperience");

tw.local.data.expectedSalary =tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.expectedSalary");

tw.local.data.status=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.status");

tw.local.data.contactDetails=new tw.object.ContactDetails();

tw.local.data.contactDetails.contactId=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.contactId");

tw.local.data.contactDetails.parentId=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.parentId");

tw.local.data.contactDetails.addLine1=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.addLine1");

tw.local.data.contactDetails.addLine2=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.addLine2");

tw.local.data.contactDetails.city=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.city");

tw.local.data.contactDetails.State=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.State");

tw.local.data.contactDetails.country=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.country");

tw.local.data.contactDetails.phone=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.phone");

tw.local.data.contactDetails.email=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.contactDetails.email");


tw.local.data.skillSet=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.skillSet");

tw.local.data.feedback=new tw.object.FeedBack();

tw.local.data.feedback.feedbackId=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.feedback.feedbackId");

tw.local.data.feedback.parentId=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.feedback.parentId");

tw.local.data.feedback.feedback=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.feedback.feedback");

tw.local.data.feedback.decision=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.feedback.decision");

tw.local.data.feedback.managerApproval=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.feedback.managerApproval");

tw.local.data.feedback.managerComments=tw.system.findProcessInstanceByID(tw.local.instanceIdRef).businessData.get("data.feedback.managerComments");

 

Figure 11: Script to retrieve data from a short-running process

This method helps keep the data in sync throughout the application while concluding the previous task in the process even though the data update fails.

Fig. 12 is the result of the execution.

Figure 12: Screen from first task with data fields

When you click Submit, the data will be saved to the database using the LWPF push service. Fig. 13 shows the data in a table in a flattened structure.

Figure 13: Business object data in the databse tables

The second task screen shows the data from the database.

Figure 14: Screen from the second task, showing data from database

This concludes our blog on the Claim Check pattern with LWPF and DynaCache.

Thanks for stopping by!

 

 

Pradeep Kumar Reddy Gunapati
Technical Specialist

Pradeep Kumar Reddy Gunapati is a Technical Specialist with 8 years of extensive experience in IBM BPM and other technologies, like Core Java, SQL, and Web 2.0 technologies. He has strong architecture, design, development, and release management experience working with various projects involving IBM BPM. He is an enthusiastic blogger who covers various IBM BPM topics in his blog.

 

Suvajit Mukhopadhyay
Technical Architect

Suvajit Mukhopadhyay is a Smarter Process evangelist with nearly 10 years of experience in BPM. He has shown varied expertise in the areas of pre-sales, architecture, design, development, and sustenance, with various Fortune 500 customers. He has proven experience with Smarter Process implementations in banking and financial services.

 

 

Tags: