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/lib
directory.
cd <MiddlewareHome>wlserver_10.3/server/lib
Use the following command to createwlfullclient.jar
in theserver/lib
directory:
java -jar wljarbuilder.jar
You can now copy and bundle thewlfullclient.jar
with client applications.
Add thewlfullclient.jar
to 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
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
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
// 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
-
Use it from any Custom UI/ Workflow UI to access the process image if need be.
-
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.
-
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.
.