Home

When new technologies are added to a solution stack, it is usually to ease the developer’s life or add a wanted feature by the end users. In the case of the Activiti BPM engine, I would say it was for both of these reasons, and to stick as much as possible to the open source policy Alfresco tends to follow. So when BPMN 2.0 standard came out, Alfresco invested resources on implementing a new open source BPM engine to embed; this BPM engine is called Activiti.

There are plenty of blog posts and articles explaining how Activiti works, how to develop workflows, and how it differs from JBPM. This blog post is focused on one of the Activiti features that JBPM does not provide. This feature, Activiti’s History Service, can be used for auditing, reporting, and tracking all the processes a document has gone through. This service exposes information about ongoing and past process instances.

In JBPM, when a process is completed, all the data regarding that process instance is removed from the database and no trail remains in the system, unless custom code was written for the purpose of tracking. With Activiti, this data remains in specific database tables, as shown below (the ones in the orange square), and can be queried.

Activiti Tables

The History Service enables you to query those tables in a clean and easy way. This service exposes a set of methods to query all the process instances, task instances, and variables stored in the database.

The following code queries all the process instances a certain node has been involved in.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.history.HistoricDetailQuery;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.history.HistoricVariableUpdate;
...
public class WorkflowAuditService
{
    private HistoryService historyService;
    private WorkflowService workflowService;
    
    public void getNodeHistory(NodeRef nodeRef)
    {
        // Get all workflows for the given node
        List workflowInstances = workflowService.getWorkflowsForContent(nodeRef, false);
        
        // Loop through the workflow instances and retrieve all the needed data
        for(int i = 0; i< workflowInstances.size(); i++)
        {
            // Get the workflow instance
            WorkflowInstance workflowInstance = workflowInstances.get(i);
            
            HistoricTaskInstanceQuery histTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
            List taskInstanceList = histTaskInstanceQuery
                                                                        .processInstanceId(workflowInstance.getId())
                                                                        .orderByHistoricActivityInstanceStartTime()
                                                                        .asc()
                                                                        .list();
            
            // Loop through the task instances and retrieve all the needed data
            for (int j = 0; j < taskInstanceList.size(); j++)
            {
                HistoricTaskInstance taskInstance = taskInstanceList.get(j);
                
                // Get some common variables from the task
                String assignee = taskInstance.getAssignee();
                Date startDate = taskInstance.getStartTime();
                Date endDate = taskInstance.getEndTime();
                
                HistoricDetailQuery histDetailQuery = historyService.createHistoricDetailQuery();
                List historicDetailList = histDetailQuery
                                                                    .taskId(taskInstance.getId())
                                                                    .list();
                
                // Loop through the historic details and retrieve the needed data
                for(int k = 0; k < historicDetailList.size(); k++)
                {
                    HistoricDetail historicDetail = historicDetailList.get(k);
                    
                    if(historicDetail instanceof HistoricVariableUpdate)
                    {
                        HistoricVariableUpdate histVarUpdate = (HistoricVariableUpdate) historicDetail;
                    }
                    
                    
                }
            }
        }
        
    }
}

This information can be exposed to reporting systems via webscripts, or used to audit who performed which action in the workflows.

Publicités

Laisser un commentaire

Choisissez une méthode de connexion pour poster votre commentaire:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s