Archiving Audit Diagrams as Images in Oracle SOA Suite BPM Processes

Archiving Audit Diagrams as Images in Oracle SOA Suite BPMProcesses

In myprevious postI had described how we can create a custom Java Class to save custom business indicators in a formatted PDF file. It might be useful in cases where businesses wants process data be presented in a meaningful way.

Another practical case that i had encountered in the past while designing business processes is to save the Audit diagram of the process once it is complete. The audit instance diagram can be viewed in the EM console by clicking on Flow Trace for any process instance.

In the good all Oracle BPM 10g days (prior to Oracle SOA/BPM Suite 11g) we had a fully documented API’s for interacting with process instances. PAPI interfaces were available both as web service and java API’s to connect to a in-flight or completed instance and retrieve all audit data from it.

Getting an audit image from a business process instance using PAPI was a cake walk. The below code sample shows its ease

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ProcessService processService = null ;
ProcessServiceSession session = null ;
try {
processService = ProcessService.create(configuration);
session = processService.createSession(USERNAME, PASSWORD, HOSTNAME);
for (String processId : session.processesGetIds())
{
fuego.papi.Process process = session.processGet(processId);
ProcessDiagram diagram = session.processGetDiagram(processId);
diagram.setTheme(ProcessDiagram.THEME_COLOR_BPMN);
diagram.setDrawFlowOnly( true );
Image image = diagram.getImage();
File pngImage = new File(createPngFilename( "image" ));
image.write(pngImage, ImageExtension.PNG);
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
session.close();
processService.close();
}

Whoa! Pretty Simple and elegant.

However if we want to achieve something similar in Oracle SOA Suite 11g it is a lot more challenging.

Oracle BPM Suite 11g doesn’t have any published API’s that developers can refer. This makes it an even bigger nightmare.

The process instance data in Oracle SOA suite 11g is stored in the dehydration store in theSOA_INFRAschema. In all practical scenarios this store will be subjected to purging and maintenance. So many a people/project might need to archive the flow trace of a process instance as an image. As we all know how significant is historical data for business process improvements and reengineering.

In this blog post I will show how the same functionality of getting an instance image from a process can be achieved using Oracle SOA Suite 11g and explain the code in steps.

Assuming we are using Oracle SOA Suite 11g PS3 that has a running domain and a BPM process deployed with a couple of running/completed instances.

Create a Generic Java project in JDeveloper sayArchiveInstanceImage.Create a Java class of the same name inside it. Right click on the project and add the following JAR’s to the project’s classpath.

Oracle.bpm.bpm-services.client.jar
Oracle.bpm.bpm-services.interface.jar
Oracle.bpm.client.jar
Bpm-infra.jar
Bpm-services.jar
Oracle.bpm.project.model.jar
Oracle.bpm.project.draw.jar
Oracle.bpm.project.catalog.jar
Wlfullclient.jar
Wsclient_extended.jar
Oracle.bpm.core.jar
Oracle.bpm.lib.jar
Oracle.bpm.papi.jar
Oracle.bpm.xml.jar
Oracle.bpm.diagram.draw.jar
Oracle-bpm.jar
Oracle.bpm.bpm-services.implementation.jar
Oracle.bpm.bpm-services.internal.jar
Oracle.bpm.bpmobject.jar
Oracle.bpm.runtime.jar
Oracle.bpm.ui.jar

All these above JAR’s can be found at the following directories

<JDevHome>\soa\modules\oracle.bpm.client_11.1.1
<JDevHome>\soa\modules\oracle.soa.fabric_11.1.1
<JDevHome>\soa\modules\oracle.soa.workflow_11.1.1
<JDevHome>\soa\modules\oracle.bpm.project_11.1.1
<MiddlewareHome>\wlserver_10.3\server\lib
<MiddlewareHome>\oracle_common\webservices
<JDevHome>\soa\modules\oracle.bpm.runtime_11.1.1
<JDevHome>\soa\modules\oracle.bpm.workspace_11.1.1

You can createdWlfullclient.jaras under

Change directories to theserver/libdirectory.

cd <MiddlewareHome>wlserver_10.3/server/lib

Use the following command to createwlfullclient.jarin theserver/libdirectory:

java -jar wljarbuilder.jar

You can now copy and bundle thewlfullclient.jarwith client applications.

Add thewlfullclient.jarto the client application’sclasspath.

See here for more information

http://download.oracle.com/docs/cd/E12840_01/wls/docs103/client/jarbuilder.html

First and foremost like any remote client we need to get aninstanceof the SOA server runtime to be able to gain access to any running processes inside it. This is pretty simple. The following lines of code demonstrates how we can useBPMServiceClientFactoryclass to get an instance of the server runtime.

Next initialize anIBPMContextfromBPMServiceClientFactory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// URL of the SOA Server and PORT on which the application is deployed
private static String soaURL = "t3://localhost:4003" ;
public static BPMServiceClientFactory getBPMServiceClientFactory()
{
Map<IWorkflowServiceClientConstants.CONNECTION_PROPERTY,String> properties = new HashMap<IWorkflowServiceClientConstants.CONNECTION_PROPERTY,String>();
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,WorkflowServiceClientFactory.REMOTE_CLIENT);
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,soaURL);
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_PRINCIPAL, "weblogic" );
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_CREDENTIALS, "welcome123" );
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory" );
return BPMServiceClientFactory.getInstance(properties, null , null );
}
public static IBPMServiceClient getBPMServiceClient(){
return getBPMServiceClientFactory().getBPMServiceClient();
}
public static IBPMContext getIBPMContextForAuthenticatedUser() throws Exception{
return getBPMServiceClientFactory().getBPMUserAuthenticationService().getBPMContextForAuthenticatedUser();
}

We also have to get a handle to theIBPMServiceClientinterface. Create a self initializing constructor for our main class to get a hook to this interface.

1
2
3
4
5
// Get a handle to the IBPMServiceClient interface in the ArchiveInstanceImage class
public ArchiveInstanceImage(IBPMServiceClient bpmServiceClient)
{
this .bpmServiceClient = bpmServiceClient;
}

Using the IBPMContext and a searchable instance id from the process we can get process data using theIProcessInstanceinterface.

See the code snippet below that shows how we can retrieve the audit diagram for a process instance

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
public InputStream getProcessAuditImage(IBPMContext bpmContext, String instanceId)
throws BPMException
{
IInstanceQueryService instanceQueryService = this .bpmServiceClient.getInstanceQueryService();
IProcessInstance processInstance = instanceQueryService.getProcessInstance(bpmContext, instanceId);
if (processInstance == null ) {
return null ;
}
IProcessModelPackage processModelPackage = this .bpmServiceClient.getProcessModelService().getProcessModel(bpmContext, processInstance.getSca().getCompositeDN(), processInstance.getSca().getComponentName());
AuditProcessDiagrammer auditProcessImage = new AuditProcessDiagrammer(processModelPackage.getProcessModel());
return getProcessImage(auditProcessImage);
}
private InputStream getProcessImage(AuditProcessDiagrammer processImage)
throws BPMException
{
InputStream processImageStream = null ;
ByteArrayOutputStream auditImageOutputStream = new ByteArrayOutputStream();
try {
// Get base64 encoded image String from processImage
String base64Image = processImage.getImage();
Image image = Image.createFromBase64(base64Image);
BufferedImage bufferedImage = (BufferedImage)image.asAwtImage();
// Use the Image Extension that suites you from .PNG, .JPG and .GIF
ImageIOFacade.writeImage(bufferedImage, ImageExtension.PNG, auditImageOutputStream);
processImageStream = new ByteArrayInputStream(auditImageOutputStream.toByteArray());
// Archives the Process Image at any suitable location
archiveDiagramToFile(processImageStream);
}
catch (Exception e)
{
throw new BPMException(e);
}
finally {
}
return processImageStream;
}
// Utility method to Archive the InputStream into a PNG File
private void archiveDiagramToFile(InputStream istream) throws IOException {
File outputFile = new File( "C:\\Arrun\\ProcessAuditImage\\ProcessImage.png" );
OutputStream out = new FileOutputStream(outputFile);
// Transfer bytes from in to out
byte [] buf = new byte [ 1024 ];
int len;
while ((len = istream.read(buf)) > 0 ) {
out.write(buf, 0 , len);
}
istream.close();
out.close();
}

Finally to test the code that we had written add a main method to invoke getProcessAuditImage(iBPMContext, instanceId)to see the process audit image created.

1
2
3
4
5
6
public static void main (String args[]) throws BPMException, Exception
{
ArchiveInstanceImage instImage = new ArchiveInstanceImage(getBPMServiceClient());
// Use any instanceId that is existing for the process in the server
InputStream istream= instImage.getProcessAuditImage(getIBPMContextForAuthenticatedUser(), "840001" );
}

Running the standalone Java program from inside JDeveloper creates the following process image in the target archive directory.

A quick look at the image and we will realize what it is lacking. Off course we have been quite able to get the image for the process (similar to what we used to get using PAPI in OBPM 10g). However we don’t see the flow trace i.e the sequence of activities that the instance traversed in its flow.

To get that we have get aListofDiagramEventand highlight the process image by passing this list to it.

Create another private function to get a list of allEventsthat the instance encountered in its flow as below.

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
private List<DiagramEvent> getHighlightEvents(Process processModel, IAuditInstance auditInstance)
{
List events = new ArrayList();
String activityId = auditInstance.getActivityId();
Date eventDate = auditInstance.getCreateTime().getTime();
DiagramEvent nodeEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.FLOW_NODE_IN, activityId, eventDate);
events.add(nodeEvent);
String sourceActivity;
String targetActivity;
if (auditInstance.getAuditInstanceType().equalsIgnoreCase( "START" )) {
FlowNode flowNode = (FlowNode)processModel.findDescendant(FlowNode. class , auditInstance.getActivityId());
if (flowNode != null ) {
sourceActivity = auditInstance.getSourceActivity();
Sequence<SequenceFlow> incommingSequenceFlows = flowNode.getIncomingSequenceFlows();
if ((incommingSequenceFlows != null ) && (!incommingSequenceFlows.isEmpty()) && (sourceActivity != null )) {
Iterator<SequenceFlow> seqIterator = incommingSequenceFlows.iterator();
while (seqIterator.hasNext())
{
SequenceFlow sequenceFlow= seqIterator.next();
if (sequenceFlow.getSource().getId().equalsIgnoreCase(sourceActivity)) {
DiagramEvent sequenceEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.SEQUENCE_FLOW, sequenceFlow.getId(), eventDate);
events.add(sequenceEvent);
}}
}}
}
else if (auditInstance.getAuditInstanceType().equalsIgnoreCase( "END" )) {
FlowNode flowNode = (FlowNode)processModel.findDescendant(FlowNode. class , auditInstance.getActivityId());
if (flowNode != null ) {
targetActivity = auditInstance.getTargetActivity();
Sequence<SequenceFlow> outgoingSequenceFlows = flowNode.getOutgoingSequenceFlows();
if ((outgoingSequenceFlows != null ) && (!outgoingSequenceFlows.isEmpty()) &&
(targetActivity != null )) {
Iterator<SequenceFlow> seqIterator = outgoingSequenceFlows.iterator();
while (seqIterator.hasNext())
{
SequenceFlow sequenceFlow= seqIterator.next();
if (sequenceFlow.getTarget().getId().equalsIgnoreCase(targetActivity))
{
DiagramEvent sequenceEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.SEQUENCE_FLOW, sequenceFlow.getId(), eventDate);
events.add(sequenceEvent);
}}
}}
}

Add these following line to the getProcessAuditImage(IBPMContext bpmContext, String instanceId) method before the return statement to highlight the image

1
2
3
4
5
6
7
8
List auditInstances = this .bpmServiceClient.getInstanceQueryService().queryAuditInstanceByProcessId(bpmContext, instanceId);
List diagramEvents = new ArrayList();
for ( int IAuditInstance= 0 ; IAuditInstance< auditInstances.size(); IAuditInstance++)
{
diagramEvents.addAll(getHighlightEvents(process, (IAuditInstance)auditInstances.get(IAuditInstance)));
}
auditProcessImage.highlight(diagramEvents);

Run the Java program once again and view the image created this time.

This time you can see that the activities and transitions that the instance took are highlighted in the image.

The complete Java Class can be found below

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package blog.beatechnologies.soasuiteutil;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import oracle.bpel.services.bpm.common.IBPMContext;
import oracle.bpel.services.workflow.client.IWorkflowServiceClientConstants;
import oracle.bpel.services.workflow.client.WorkflowServiceClientFactory;
import oracle.bpm.client.BPMServiceClientFactory;
import oracle.bpm.collections.Sequence;
import oracle.bpm.draw.diagram.AuditProcessDiagrammer;
import oracle.bpm.draw.diagram.DiagramEvent;
import oracle.bpm.project.model.processes.FlowNode;
import oracle.bpm.project.model.processes.Process;
import oracle.bpm.project.model.processes.SequenceFlow;
import oracle.bpm.services.client.IBPMServiceClient;
import oracle.bpm.services.common.exception.BPMException;
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;
import oracle.bpm.ui.Image;
import oracle.bpm.ui.utils.ImageExtension;
import oracle.bpm.ui.utils.ImageIOFacade;
public class ArchiveInstanceImage
{
private IBPMServiceClient bpmServiceClient;
// URL of the SOA Server and PORT on which the application is deployed
private static String soaURL = "t3://soasitapp03.us.dell.com:5411" ;
public ArchiveInstanceImage(IBPMServiceClient bpmServiceClient)
{
this .bpmServiceClient = bpmServiceClient;
}
public InputStream getProcessAuditImage(IBPMContext bpmContext, String instanceId)
throws BPMException
{
IInstanceQueryService instanceQueryService = this .bpmServiceClient.getInstanceQueryService();
IProcessInstance processInstance = instanceQueryService.getProcessInstance(bpmContext, instanceId);
if (processInstance == null ) {
return null ;
}
IProcessModelPackage processModelPackage = this .bpmServiceClient.getProcessModelService().getProcessModel(bpmContext, processInstance.getSca().getCompositeDN(), processInstance.getSca().getComponentName());
AuditProcessDiagrammer auditProcessImage = new AuditProcessDiagrammer(processModelPackage.getProcessModel());
List auditInstances = this .bpmServiceClient.getInstanceQueryService().queryAuditInstanceByProcessId(bpmContext, instanceId);
List diagramEvents = new ArrayList();
for ( int IAuditInstance= 0 ; IAuditInstance< auditInstances.size(); IAuditInstance++)
{
diagramEvents.addAll(getHighlightEvents(processModelPackage.getProcessModel(), (IAuditInstance)auditInstances.get(IAuditInstance)));
}
auditProcessImage.highlight(diagramEvents);
return getProcessImage(auditProcessImage);
}
private InputStream getProcessImage(AuditProcessDiagrammer processImage)
throws BPMException
{
InputStream processImageStream = null ;
ByteArrayOutputStream auditImageOutputStream = new ByteArrayOutputStream();
try {
// Get base64 encoded image String from processImage
String base64Image = processImage.getImage();
Image image = Image.createFromBase64(base64Image);
BufferedImage bufferedImage = (BufferedImage)image.asAwtImage();
// Use the Image Extension that suites you from .PNG, .JPG and .GIF
ImageIOFacade.writeImage(bufferedImage, ImageExtension.PNG, auditImageOutputStream);
processImageStream = new ByteArrayInputStream(auditImageOutputStream.toByteArray());
// Archives the Process Image at any suitable location
archiveDiagramToFile(processImageStream);
}
catch (Exception e)
{
throw new BPMException(e);
}
finally {
}
return processImageStream;
}
private List<DiagramEvent> getHighlightEvents(Process processModel, IAuditInstance auditInstance)
{
List events = new ArrayList();
String activityId = auditInstance.getActivityId();
Date eventDate = auditInstance.getCreateTime().getTime();
DiagramEvent nodeEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.FLOW_NODE_IN, activityId, eventDate);
events.add(nodeEvent);
String sourceActivity;
String targetActivity;
if (auditInstance.getAuditInstanceType().equalsIgnoreCase( "START" )) {
FlowNode flowNode = (FlowNode)processModel.findDescendant(FlowNode. class , auditInstance.getActivityId());
if (flowNode != null ) {
sourceActivity = auditInstance.getSourceActivity();
Sequence<SequenceFlow> incommingSequenceFlows = flowNode.getIncomingSequenceFlows();
if ((incommingSequenceFlows != null ) && (!incommingSequenceFlows.isEmpty()) && (sourceActivity != null )) {
Iterator<SequenceFlow> seqIterator = incommingSequenceFlows.iterator();
while (seqIterator.hasNext())
{
SequenceFlow sequenceFlow= seqIterator.next();
if (sequenceFlow.getSource().getId().equalsIgnoreCase(sourceActivity)) {
DiagramEvent sequenceEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.SEQUENCE_FLOW, sequenceFlow.getId(), eventDate);
events.add(sequenceEvent);
}}
}}
}
else if (auditInstance.getAuditInstanceType().equalsIgnoreCase( "END" )) {
FlowNode flowNode = (FlowNode)processModel.findDescendant(FlowNode. class , auditInstance.getActivityId());
if (flowNode != null ) {
targetActivity = auditInstance.getTargetActivity();
Sequence<SequenceFlow> outgoingSequenceFlows = flowNode.getOutgoingSequenceFlows();
if ((outgoingSequenceFlows != null ) && (!outgoingSequenceFlows.isEmpty()) && (targetActivity != null )) {
Iterator<SequenceFlow> seqIterator = outgoingSequenceFlows.iterator();
while (seqIterator.hasNext())
{
SequenceFlow sequenceFlow= seqIterator.next();
if (sequenceFlow.getTarget().getId().equalsIgnoreCase(targetActivity)) {
DiagramEvent sequenceEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.SEQUENCE_FLOW, sequenceFlow.getId(), eventDate);
events.add(sequenceEvent);
}}
}}
}
return events;
}
public static BPMServiceClientFactory getBPMServiceClientFactory() {
Map<IWorkflowServiceClientConstants.CONNECTION_PROPERTY, String> properties = new HashMap<IWorkflowServiceClientConstants.CONNECTION_PROPERTY, String>();
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,WorkflowServiceClientFactory.REMOTE_CLIENT);
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,soaURL);
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_PRINCIPAL, "arun_pareek" );
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_CREDENTIALS, "#Jannu12" );
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory" );
return BPMServiceClientFactory.getInstance(properties, null , null );
}
public static IBPMServiceClient getBPMServiceClient(){
return getBPMServiceClientFactory().getBPMServiceClient();
}
public static IBPMContext getIBPMContextForAuthenticatedUser() throws Exception{
return getBPMServiceClientFactory().getBPMUserAuthenticationService().getBPMContextForAuthenticatedUser();
}
public static void main (String args[]) throws BPMException, Exception
{
ArchiveInstanceImage instImage = new ArchiveInstanceImage(getBPMServiceClient());
InputStream istream= instImage.getProcessAuditImage(getIBPMContextForAuthenticatedUser(), "10002" );
}
void archiveDiagramToFile(InputStream istream) throws IOException {
File outputFile = new File( "C:\\Arrun\\process.png" );
OutputStream out = new FileOutputStream(outputFile);
// Transfer bytes from in to out
byte [] buf = new byte [ 1024 ];
int len;
while ((len = istream.read(buf)) > 0 ) {
out.write(buf, 0 , len);
}
istream.close();
out.close();
}
}

This was all about getting this Java API’s to work with SOA Suite 11g PS3. I also tried to test the same with a PS2 domain and with PS2 libraries.

Everything was almost same except for a few things.

There is no class calledIProcessModelPackagethat I could find in PS2 BPM jar’s

So the process image was obtained usingIProcessModelServiceclass like below

1
2
3
IProcessModelService processModelService = this .bpmServiceClient.getProcessModelService();
Process process = processModelService.getProcessModel(bpmContext, processInstance.getSca().getCompositeDN(), processInstance.getSca().getComponentName());
AuditProcessDiagrammer auditProcessImage = new AuditProcessDiagrammer(process);

The additional libraries that we need to put in the project’s classspath are

Oracle.bpm.project.io.jar <JDevHome>\soa\modules\oracle.bpm.project_11.1.1
Oracle.bpm.project.jar <JDevHome>\soa\modules\oracle.bpm.project_11.1.1
Oracle.bpm.project.compile.jar <JDevHome>\soa\modules\oracle.bpm.project_11.1.1
Oracle.bpm.vfilesystem.jar <JDevHome>\soa\modules\oracle.bpm.runtime_11.1.1

In case you would need the entire class here is what you should use in case you are on Oracle SOA Suite 11g PS2

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package blog.beatechnologies.soautil;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import oracle.bpel.services.bpm.common.IBPMContext;
import oracle.bpel.services.workflow.client.IWorkflowServiceClientConstants;
import oracle.bpel.services.workflow.client.WorkflowServiceClientFactory;
import oracle.bpm.client.BPMServiceClientFactory;
import oracle.bpm.collections.Sequence;
import oracle.bpm.draw.diagram.AuditProcessDiagrammer;
import oracle.bpm.draw.diagram.DiagramEvent;
import oracle.bpm.project.model.processes.FlowNode;
import oracle.bpm.project.model.processes.Process;
import oracle.bpm.project.model.processes.SequenceFlow;
import oracle.bpm.services.client.IBPMServiceClient;
import oracle.bpm.services.common.exception.BPMException;
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.IProcessModelService;
import oracle.bpm.services.util.AuditTrail;
import oracle.bpm.ui.Image;
import oracle.bpm.ui.utils.ImageExtension;
import oracle.bpm.ui.utils.ImageIOFacade;
public class ArchiveInstanceImage
{
private IBPMServiceClient bpmServiceClient;
// URL of the SOA Server and PORT on which the application is deployed
private static String soaURL = "t3://wxp-fxhp7bs.blr.amer.dell.com:4003" ;
// Get a handle of IBPMServiceClient through the class constructor
public ArchiveInstanceImage(IBPMServiceClient bpmServiceClient)
{
this .bpmServiceClient = bpmServiceClient;
}
public InputStream getProcessAuditImage(IBPMContext bpmContext, String instanceId)
throws BPMException
{
IInstanceQueryService instanceQueryService = this .bpmServiceClient.getInstanceQueryService();
IProcessInstance processInstance = instanceQueryService.getProcessInstance(bpmContext, instanceId);
System.out.println( "Composite DN " + processInstance.getSca().getCompositeDN());
System.out.println( "Composite DN " + processInstance.getSca().getComponentName());
if (processInstance == null ) {
return null ;
}
IProcessModelService processModelService = this .bpmServiceClient.getProcessModelService();
Process process = processModelService.getProcessModel(bpmContext, processInstance.getSca().getCompositeDN(), processInstance.getSca().getComponentName());
AuditProcessDiagrammer auditProcessImage = new AuditProcessDiagrammer(process);
List auditInstances = this .bpmServiceClient.getInstanceQueryService().queryAuditInstanceByProcessId(bpmContext, instanceId);
List diagramEvents = new ArrayList();
for ( int IAuditInstance= 0 ; IAuditInstance< auditInstances.size(); IAuditInstance++)
{
diagramEvents.addAll(getHighlightEvents(process, (IAuditInstance)auditInstances.get(IAuditInstance)));
}
auditProcessImage.highlight(diagramEvents);
//auditProcessImage.getImage()
return getProcessImage(auditProcessImage);
}
private InputStream getProcessImage(AuditProcessDiagrammer processImage)
throws BPMException
{
InputStream processImageStream = null ;
ByteArrayOutputStream auditImageOutputStream = new ByteArrayOutputStream();
try {
// Get base64 encoded image String from processImage
String base64Image = processImage.getImage();
Image image = Image.createFromBase64(base64Image);
BufferedImage bufferedImage = (BufferedImage)image.asAwtImage();
// Use the Image Extension that suites you from .PNG, .JPG and .GIF
ImageIOFacade.writeImage(bufferedImage, ImageExtension.PNG, auditImageOutputStream);
processImageStream = new ByteArrayInputStream(auditImageOutputStream.toByteArray());
// Archives the Process Image at any suitable location
archiveDiagramToFile(processImageStream);
}
catch (Exception e)
{
throw new BPMException(e);
}
finally {
}
return processImageStream;
}
private List<DiagramEvent> getHighlightEvents(Process processModel, IAuditInstance auditInstance)
{
List events = new ArrayList();
String activityId = auditInstance.getActivityId();
Date eventDate = auditInstance.getCreateTime().getTime();
DiagramEvent nodeEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.FLOW_NODE_IN, activityId, eventDate);
events.add(nodeEvent);
String sourceActivity;
String targetActivity;
if (auditInstance.getAuditInstanceType().equalsIgnoreCase( "START" )) {
FlowNode flowNode = (FlowNode)processModel.findDescendant(FlowNode. class , auditInstance.getActivityId());
if (flowNode != null ) {
sourceActivity = auditInstance.getSourceActivity();
Sequence<SequenceFlow> incommingSequenceFlows = flowNode.getIncomingSequenceFlows();
if ((incommingSequenceFlows != null ) && (!incommingSequenceFlows.isEmpty()) && (sourceActivity != null )) {
Iterator<SequenceFlow> seqIterator = incommingSequenceFlows.iterator();
while (seqIterator.hasNext())
{
SequenceFlow sequenceFlow= seqIterator.next();
if (sequenceFlow.getSource().getId().equalsIgnoreCase(sourceActivity)) {
DiagramEvent sequenceEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.SEQUENCE_FLOW, sequenceFlow.getId(), eventDate);
events.add(sequenceEvent);
}}
}}
}
else if (auditInstance.getAuditInstanceType().equalsIgnoreCase( "END" )) {
FlowNode flowNode = (FlowNode)processModel.findDescendant(FlowNode. class , auditInstance.getActivityId());
if (flowNode != null ) {
targetActivity = auditInstance.getTargetActivity();
Sequence<SequenceFlow> outgoingSequenceFlows = flowNode.getOutgoingSequenceFlows();
if ((outgoingSequenceFlows != null ) && (!outgoingSequenceFlows.isEmpty()) &&
(targetActivity != null )) {
Iterator<SequenceFlow> seqIterator = outgoingSequenceFlows.iterator();
while (seqIterator.hasNext())
{
SequenceFlow sequenceFlow= seqIterator.next();
if (sequenceFlow.getTarget().getId().equalsIgnoreCase(targetActivity))
{
DiagramEvent sequenceEvent = DiagramEvent.create(DiagramEvent.DiagramEventType.SEQUENCE_FLOW, sequenceFlow.getId(), eventDate);
events.add(sequenceEvent);
}}
}}
}
return events;
}
public static BPMServiceClientFactory getBPMServiceClientFactory() {
Map<IWorkflowServiceClientConstants.CONNECTION_PROPERTY, String> properties = new HashMap<IWorkflowServiceClientConstants.CONNECTION_PROPERTY, String>();
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.CLIENT_TYPE,WorkflowServiceClientFactory.REMOTE_CLIENT);
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_PROVIDER_URL,soaURL);
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_PRINCIPAL, "weblogic" );
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_SECURITY_CREDENTIALS, "welcome123" );
properties.put(IWorkflowServiceClientConstants.CONNECTION_PROPERTY.EJB_INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory" );
return BPMServiceClientFactory.getInstance(properties, null , null );
}
public static IBPMServiceClient getBPMServiceClient(){
return getBPMServiceClientFactory().getBPMServiceClient();
}
public static IBPMContext getIBPMContextForAuthenticatedUser() throws Exception{
return getBPMServiceClientFactory().getBPMUserAuthenticationService().getBPMContextForAuthenticatedUser();
}
public static void main (String args[]) throws BPMException, Exception {
ArchiveInstanceImage instImage = new ArchiveInstanceImage(getBPMServiceClient());
InputStream istream= instImage.getProcessAuditImage(getIBPMContextForAuthenticatedUser(), "840001" );
}
// Utility method to Archive the InputStream into a PNG File
private void archiveDiagramToFile(InputStream istream) throws IOException {
File outputFile = new File( "C:\\Arrun\\ProcessAuditImage\\ProcessImage.png" );
OutputStream out = new FileOutputStream(outputFile);
// Transfer bytes from in to out
byte [] buf = new byte [ 1024 ];
int len;
while ((len = istream.read(buf)) > 0 ) {
out.write(buf, 0 , len);
}
istream.close();
out.close();
}
}

Now there are a couple of ways to use this Java Code in real practical cases

  1. Use it from any Custom UI/ Workflow UI to access the process image if need be.
  2. Create a Web service wrapper over the Java Class and use it as a WS API that can be invoked from any BPM process and hence it can be reused across multiple BPM processes.
  3. In case you would want to limit the use inside a composite then create a Spring SCA component for this custom Java class and then invoke it from inside a BPM process

In my future blogs I will try to come up with more interesting utilities with these BPM API’s. This will probably be of great use to folks who have worked with the PAPI API’s and find it a great miss in Oracle SOA Suite 11g.

Meanwhile also wondering what is stopping Oracle to publish a well document API for these interfaces.:-)

.

你可能感兴趣的:(process)