IBM Business Process Manager V7.5 is a comprehensive and consumable business process management platform that provides visibility and management of business processes. It incorporates key functionality from WebSphere® Process Server, WebSphere Lombardi Edition, and IBM Integration Designer into a unified user environment, including unified repository, authoring tools, and runtime environment, for process design, execution, monitoring, and optimizing business processes. It is specifically designed to help process owners and business users to engage directly in the improvement of their business processes.
IBM Business Process Manager (BPM) provides integration services to integrate with external services to complete a task. Integration services include Web Services Integration and Java Integration components. However, on many occasions, external systems are implemented based on C language and customers do not want to re-engineer their existing C-based implementation due to architecture, performance, or other reasons. This may act as a bottleneck in selling Java-based products, owing to the complexity involved in integration.
To integrate Java-based applications with C based APIs, you need some sort of bridge between the two programming language APIs. The Java Native Interface (JNI) is a native programming interface that is part of the Java Software Development Kit (SDK). JNI lets Java code use code and code libraries written in other languages, such as C and C++. You can create shared libraries JNI-based implementation to exchange information between two disparate languages. There are two formats available for these libraries: .dll (dynamic link libraries) for Windows® based platforms and .so (shared objects) for Unix-based platforms.
This article will walk you through the steps of integrating IBM BPM with JNI implementation based on a Windows platform, including creating a native DLL library using JNI, configuring the library in Business Process Manager to generate Java Integration Services, and integrating with Java components.
We will discuss a simple additional operation scenario to showcase the invocation of native methods invoked by passing simple data and array-based data.
To follow the steps in this article, you need IBM WebSphere Business Process Manager V7.5, IBM Integration Designer V7.5, and IBM Process Designer V7.5.
The zip files provided with this article contain the artifacts that you can download and reference to understand and execute the scenario.
Creating a native shared library
This section will show steps to create a native shared library, such as a DLL for a Windows environment. You will:
- Create a standalone Java project.
- Create a Java class.
- Create the header file.
- Create a DLL project.
- Merge and implement the header code.
- Build the DLL.
Creating a standalone Java project
To create standalone Java project in IBM Integration Designer (hereafter called Integration Designer), go to File > New > Java Project. Give the name of the project and press Next as shown in Figure 1. Set the "Default output folder" to the classes directory, which needs to be explicitly created through Integration Designer.
Figure 1. Creating a Java project in Integration Designer
Before proceeding with the DLL creation, create a standalone Java class with methods that need to be linked with native methods, as shown in Listing 1.
The methods showcased as part of the NativeInvoke class will return the following:
- Sum of two integer values
- Sum of two double values
- Sum of double arrays
- The array with twice the value of the double arrays
Listing 1. NativeInvoke class
package com.ibm.test;
public class NativeInvoke {
public static native int sum(int a, int b);
public static native double sum(double a, double b);
public static native double sum(double[] a);
public static native double[] twice(double[] a);
} |
Compile the above class using an Eclipse-based tooling, which in our case is Integration Designer. This generates the .class file that forms the basis of creating a header file for further implementation. Once the class is compiled, go to the output folder of Integration Designer (see Figure 2), where the class is generated. Set the path to the {JAVA_HOME}\bin directory from the package root on the command prompt as shown below:
set PATH=.;%PATH%;C:\BPM751\java\bin |
Figure 2. Output folder of Integration Designer
To create a header file out of the compiled Java class, run the "javah"
command from the {APPSERVER_ROOT}/Java/bin
directory against the Java code class to generate the respective C header
files (see Figure 3). This header file forms the basis of the native
shared library.
{APPSERVER_ROOT}\java\bin>javah -o header_file_name.h com.ibm.test.NativeInvoke |
Figure 3. Creating a header file
You can create a native shared library through any of the available C/C++ editors by creating a DLL project. The project holds two important files with extension .h (dll.h) and .c (dll.c), apart from other dependent files generated by the editors. You need to incorporate the header code in this project to build the DLL. Figure 4 shows the C Editor.
Figure 4. DLL project in the C Editor
Merging and implementing the header code
The content of header file generated in Creating the
header file needs to be pasted in dll.h, starting from the ifndef
Include directive of the NativeInvoke class (see Listing 2). Remember to
add jni.h at the top in the merged code and set the path to this header
file in WebSphere Application Server at
{APPSERVER_ROOT}\Java\include in the Editor to
build the code successfully.
Listing 2. Content of the DLL header file
#include <jni.h>
#ifndef _DLL_H_
#define _DLL_H_
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */
DLLIMPORT void HelloWorld (void);
#endif /* _DLL_H_ */
/* Header for class com_ibm_test_NativeInvoke */
#ifndef _Included_com_ibm_test_NativeInvoke
#define _Included_com_ibm_test_NativeInvoke
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_ibm_test_NativeInvoke
* Method: sum
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_ibm_test_NativeInvoke_sum__II
(JNIEnv *, jclass, jint, jint);
/*
* Class: com_ibm_test_NativeInvoke
* Method: sum
* Signature: (DD)D
*/
JNIEXPORT jdouble JNICALL Java_com_ibm_test_NativeInvoke_sum__DD
(JNIEnv *, jclass, jdouble, jdouble);
/*
* Class: com_ibm_test_NativeInvoke
* Method: sum
* Signature: ([D)D
*/
JNIEXPORT jdouble JNICALL Java_com_ibm_test_NativeInvoke_sum___3D
(JNIEnv *, jclass, jdoubleArray);
/*
* Class: com_ibm_test_NativeInvoke
* Method: twice
* Signature: ([D)[D
*/
JNIEXPORT jdoubleArray JNICALL Java_com_ibm_test_NativeInvoke_twice
(JNIEnv *, jclass, jdoubleArray);
#ifdef __cplusplus
}
#endif
#endif
|
The code defined in the DLL header file needs to be implemented in the DLL C implementation class generated along with the header by the editor. See Listing 3.
Listing 3. Content of DLL C implementation class
/* Replace "dll.h" with the name of your header */
#include "dll.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
DLLIMPORT void HelloWorld ()
{
MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION);
}
/*
* Class: com_ibm_test_NativeInvoke
* Method: sum
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_ibm_test_NativeInvoke_sum__II
(JNIEnv *env, jobject jobj, jint j1, jint j2){
return j1 + j2;
}
/*
* Class: com_ibm_test_NativeInvoke
* Method: sum
* Signature: (DD)D
*/
JNIEXPORT jdouble JNICALL Java_com_ibm_test_NativeInvoke_sum__DD
(JNIEnv *env, jobject jobj, jdouble j1, jdouble j2){
return j1 + j2;
}
/*
* Class: com_ibm_test_NativeInvoke
* Method: sum
* Signature: ([D)D
*/
JNIEXPORT jdouble JNICALL Java_com_ibm_test_NativeInvoke_sum___3D
(JNIEnv *env, jobject jobj, jdoubleArray jarray){
jdouble sum = 0.0;
int i;
jsize length = (*env)->GetArrayLength(env, jarray);
jdouble *body = (*env)->GetDoubleArrayElements(env,jarray, 0);
for (i=0;i < length; i+)
sum = sum + body[i];
(*env)->ReleaseDoubleArrayElements(env,jarray, body, 0);
return sum;
}
/*
* Class: com_ibm_test_NativeInvoke
* Method: twice
* Signature: ([D)[D
*/
JNIEXPORT jdoubleArray JNICALL Java_com_ibm_test_NativeInvoke_twice
(JNIEnv *env, jobject jobj, jdoubleArray jarray){
jdouble sum = 0.0;
jdoubleArray result;
jint fill[256];
int i;
jsize length= (*env)->GetArrayLength(env, jarray);
result = (*env)->NewDoubleArray(env, len);
jdouble *body = (*env)->GetDoubleArrayElements(env,jarray, 0);
for (i=0;i < length; i+)
(*env)->SetDoubleArrayRegion(env, result, 0, len,body);
return result;
}
BOOL APIENTRY DllMain (HINSTANCE hInst
/* Library instance handle. */ ,
DWORD reason
/* Reason this function is being called. */ ,
LPVOID reserved
/* Not used. */ )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
/* Returns TRUE on success, FALSE on failure */
return TRUE;
} |
Build the code to generate the .dll implementation in the project folder
on the file system (see Figure 5). This DLL needs to be copied to the BPM
installation location from the editor path and configured accordingly. The
DLL is copied to {WAS_ROOT}/jnilib, where
"jnilib" is created explicitly.
Figure 5. Generated DLL file
Configuring the native library with IBM BPM
Once the DLL is generated, you need to configure it in the IBM BPM runtime to be called from the application. This configuration needs to be done in the underlying WebSphere Application Server administrative console of IBM BPM.
Set the DLL directory path setting
In the JVM properties of the server, load this DLL by setting the custom JVM properties as follows: server > serverTypes > WebSphere Application Server > server1 > Java and Process Management > Process Definition > Java Virtual Machine > Custom Properties. Figure 6 shows the configuration of the native library path as the underlying WebSphere Application Server's JVM custom property.
Figure 6. Custom JVM properties setting
Once the path is set, you need to restart the server.
Create a standalone Java project and a class with the InvokeNativeWrapper name in Integration Designer (see Listing 4). Copy the Java interface holding method declarations in the same project. Define the methods which receive the data from the BPM process and pass it on to the native method call. Note that IBM BPM will pass any numeric values as a wrapper.
Listing 4. Wrapper class
package com.ibm.test;
public class InvokeNativeWrapper {
static{
System.load("WASIntegrationSharedLib");
}
public static Integer doSimpleSum(Integer num1,Integer num2){
int result=0;
if(num1!=null && num2!=null){
int val1=num1.intValue();
int val2=num2.intValue();
result=NativeInvoke.sum(val1, val2);
}
return new Integer(result);
}
public static Double doDoubleSum(Double num1,Double num2){
double result=0;
if(num1!=null && num2!=null){
double val1=num1.intValue();
double val2=num2.intValue();
result=NativeInvoke.sum(val1, val2);
}
return new Double(result);
}
public static Double doDoubleArraySum(Double[] arr){
double[] darr=new double[arr.length];
for(int i=0;i<darr.length;i++){
darr[i]=arr[i].doubleValue();
}
double result=NativeInvoke.sum(darr);
return new Double(result);
}
public static Double[] doubleTheArray(Double[] arr){
double[] darr=new double[arr.length];
for(int i=0;i<darr.length;i++){
darr[i]=arr[i].doubleValue();
}
double[] result=NativeInvoke.twice(darr);
Double[] finalResult=new Double[result.length];
for(int k=0;k<result.length;k++){
finalResult[k]=new Double(result[k]);
}
return finalResult;
}
} |
Once the class is implemented, you can export the Java project as a JAR file and import it into Process Designer to be used with the business process as a Java Integration Service (see Figure 7).
Figure 7. Exporting InvokeNativeWrapper as a JAR
Integrating IBM BPM with the Java Service
Make sure that IBM BPM is running. Bring up Process Designer and login as "tw_admin" with a password of "tw_admin".
- Select Files (the + symbol) > Server File, as
shown in Figure 8, and browse for the JAR that was exported in the
previous steps. Press the Finish button.
Figure 8. Adding the Java Service JAR
Note: Once the import is completed successfully, you will see the JAR listed when you will click on Files, as shown in Figure 9.
Figure 9. Adding the Java Service JAR
- Define the Integration Service and the associated method defined in
the native JAR to this activity, as shown in Figure 10.
Figure 10. Define the Integration Service
- Associate the Java Integration Service with the method you want to
invoke, as shown in Figure 11.
Figure 11. Associate the Java Integration Service with the JAR file
- Create the Business Process Definition (BPD) and human service and
wire Coach to the Java Integration Service to invoke the native
methods, as shown in Figure 12, Figure 13, and Figure 14.
Figure 12. Define the Business Process Definition
Figure 13. Human service including a simple data service
Figure 14. Define the Business Process Definition
This section will show two test cases using a simple addition and an array.
- Run the human service, which includes the simple data service, in
Process Designer. Type in two numbers in each field (see Figure 15)
and click the OK button.
Figure 15. Entering data in the text fields
- Once the service ran successfully, you see the "Final Result" in the
output text box as shown in Figure 16.
Figure 16. Displaying the results in the text fields
- Debug the human service, which includes the array data addition
service, and then you will get the array initialized (see Figure 17).
Figure 17. Array initialized
- Click Step and you see the sum result as shown in
Figure 18.
Figure 18. The sum result of the array data
This article discussed how to integrate IBM Business Process Manager with a JNI implementation. It covered how to create a native DLL library using JNI, configure the library in Business Process Manager to generate Java Integration Services, and integrate with Java components. Lastly, the solution was tested in Process Designer.
| Description | Name | Size | Download method |
|---|---|---|---|
| Code sample file | code_sample.zip | 936KB | HTTP |
| Code sample file | JNITestProject.zip | 16KB | HTTP |
Information about download methods






