We have had a few queries lately about how to find out what activity (or activities) will be the next to execute in a particular process instance. It is possible to do this, however you will need to use a couple of undocumented APIs. That means that they could (and probably will) change in some future release and break your code. If you understand the risks of using undocumented APIs and are prepared to accept that risk, read on…
The way to do this is to look at two things:
- The model of the process itself, i.e. what tasks and connections exist in the process model, and
- The audit trail for the specific process instance the we are interested in.
By comparing these two pieces of information, we can work out where the process instance is currently (by finding all the activities that have started but have not yet ended) and what the next activities are (by following the connections that start with these unfinsihed activities to see where they go).
I am using plurals here because, of course, you can have multiple parallel execution paths in a process, for example when you use an inclusive or complex gateway, or a multi-instance embedded subprocess, or even a non-interupting event subprocess.
Here is the sample code. You will need to edit this to suit your own environment.
package nextactivity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import oracle.bpel.services.bpm.common.IBPMContext;
import oracle.bpel.services.workflow.client.IWorkflowServiceClientConstants;
import oracle.bpm.client.BPMServiceClientFactory;
import oracle.bpm.project.SequenceFlowImpl;
import oracle.bpm.project.model.ProjectObject;
import oracle.bpm.services.client.IBPMServiceClient;
import oracle.bpm.services.instancemanagement.model.IProcessInstance;
import oracle.bpm.services.instancequery.IAuditInstance;
import oracle.bpm.services.instancequery.IInstanceQueryService;
import oracle.bpm.services.internal.processmodel.model.IProcessModelPackage;
public class NextActivity {
private static BPMServiceClientFactory bpmscf;
public NextActivity() {
super();
}
public static void main(String[] args) {
try {
// check that we have a process instance ID
if (args.length != 1) {
System.out.println("You must specify the instance ID");
System.exit(0);
}
String instanceId = args[0];
// get the BPMServiceClient
IBPMServiceClient bpmServiceClient =
getBPMServiceClientFactory().getBPMServiceClient();
// authenticate to the BPM engine
IBPMContext bpmContext =
getBPMServiceClientFactory()
.getBPMUserAuthenticationService()
.authenticate("weblogic", "welcome1".toCharArray(), null);
// get details of the process instance
IInstanceQueryService instanceQueryService =
bpmServiceClient.getInstanceQueryService();
IProcessInstance processInstance =
instanceQueryService.getProcessInstance(bpmContext,
instanceId);
if (processInstance == null) {
System.out.println("Could not find instance, aborting");
System.exit(0);
}
// get details of the process (not a specific instance of it,
// but the actual process definition itself)
// WARNING WARNING WARNING
// The ProcessModelService is an UNDOCUMENTED API - this means
// that it could (and probably will) change in some future
// release - you SHOULD NOT build any code that relies on it,
// unless you understand and accept the risks of using an
// undocumented API.
IProcessModelPackage processModelPackage =
bpmServiceClient
.getProcessModelService()
.getProcessModel(bpmContext,
processInstance.getSca().getCompositeDN(),
processInstance.getSca().getComponentName());
// get a list of the audit events that have occurred in this instance
List auditInstances =
bpmServiceClient
.getInstanceQueryService()
.queryAuditInstanceByProcessId(bpmContext, instanceId);
// work out which activities have not finished
List started = new ArrayList();
for (IAuditInstance a1 : auditInstances) {
if (a1.getAuditInstanceType().compareTo("START") == 0) {
// ingore the process instance itself, we only care
// about tasks in the process
if (a1.getActivityName().compareTo("PROCESS") != 0) {
started.add(a1);
}
}
}
next:
for (IAuditInstance a2 : auditInstances) {
if (a2.getAuditInstanceType().compareTo("END") == 0) {
for (int i = 0; i < started.size(); i++) {
if (a2.getActivityId()
.compareTo(started.get(i).getActivityId()) == 0) {
started.remove(i);
continue next;
}
}
}
}
System.out.println("\n\nLooks like the following have started but not ended:");
for (IAuditInstance s : started) {
System.out.println(s.getActivityId() + "\nwhich is a "
+ s.getActivityName() + "\ncalled "
+ s.getLabel() + "\n");
}
// now we need to find what is after these activities...
// WARNING WARNING WARNING
// The ProcessModel, ProcessObject, etc. are UNDOCUMENTED APIs -
// this means that they could (and probably will) change
// in some future release - you SHOULD NOT build any code
// that relies on them, unless you understand and
// accept the risks of using undocumented APIs.
List nextActivities = new ArrayList();
next2:
for (ProjectObject po : processModelPackage.getProcessModel().getChildren()) {
if (po instanceof SequenceFlowImpl) {
for (IAuditInstance s2 : started) {
if (((SequenceFlowImpl)po).getSource()
.getId().compareTo(s2.getActivityId()) == 0) {
nextActivities.add(po);
continue next2;
}
}
}
}
System.out.println("\n\nLooks like the next activities are:");
for (ProjectObject po2 : nextActivities) {
System.out.println(((SequenceFlowImpl)po2).getTarget().getId()
+ "\nwhich is a "
+ ((SequenceFlowImpl)po2).getTarget().getBpmnType()
+ "\ncalled "
+ ((SequenceFlowImpl)po2).getTarget().getDefaultLabel()
+ "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected static BPMServiceClientFactory getBPMServiceClientFactory() {
if (bpmscf == null) {
Map properties = new HashMap();
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,
IWorkflowServiceClientConstants.CLIENT_TYPE_REMOTE);
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,
"t3://bpmfp:8001");
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_CREDENTIALS,
"welcome1");
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_PRINCIPAL,
"weblogic");
bpmscf = BPMServiceClientFactory.getInstance(properties, null, null);
}
return bpmscf;
}
}
To run the sample, you will need to put some JAR files on the CLASSPATH. These may not all be needed, but here are the ones I am using:
Oracle_SOA1\soa\modules\oracle.soa.workflow_11.1.1\bpm-services.jar Oracle_SOA1\soa\modules\oracle.soa.fabric_11.1.1\bpm-infra.jar Oracle_SOA1\soa\modules\oracle.bpm.client_11.1.1\oracle.bpm.bpm-services.client.jar Oracle_SOA1\soa\modules\oracle.bpm.client_11.1.1\oracle.bpm.bpm-services.interface.jar oracle_common\webservices\wsclient_extended.jar oracle_common\modules\oracle.xdk_11.1.0\xmlparserv2.jar oracle_common\modules\oracle.xdk_11.1.0\xml.jar wlserver_10.3\server\lib\wlthint3client.jar Oracle_SOA1\soa\modules\oracle.bpm.project_11.1.1\oracle.bpm.project.model.jar Oracle_SOA1\soa\modules\oracle.bpm.project_11.1.1\oracle.bpm.project.io.jar Oracle_SOA1\soa\modules\oracle.bpm.project_11.1.1\oracle.bpm.project.ui.jar Oracle_SOA1\soa\modules\oracle.bpm.project_11.1.1\oracle.bpm.project.draw.jar Oracle_SOA1\soa\modules\oracle.bpm.project_11.1.1\oracle.bpm.diagram.draw.jar Oracle_SOA1\soa\modules\oracle.bpm.workspace_11.1.1\oracle.bpm.ui.jar Oracle_SOA1\soa\modules\oracle.bpm.project_11.1.1\oracle.bpm.project.compile.jar Oracle_SOA1\soa\modules\oracle.bpm.project_11.1.1\oracle.bpm.project.catalog.jar Oracle_SOA1\soa\modules\oracle.bpm.project_11.1.1\oracle.bpm.project.jar Oracle_SOA1\soa\modules\oracle.bpm.runtime_11.1.1\oracle.bpm.core.jar Oracle_SOA1\soa\modules\oracle.bpm.runtime_11.1.1\oracle.bpm.lib.jar Oracle_SOA1\soa\modules\oracle.bpm.runtime_11.1.1\oracle.bpm.xml.jar
This will produce output like this:
Looks like the following have started but not ended: ABSTRACT_ACTIVITY1824320344446 which is a USER_TASK called ChooseNextUser Looks like the next activities are: ABSTRACT_ACTIVITY1824321141176 which is a USER_TASK called DoSomething
When run on a process like this:


You must be logged in to post a comment.