Integrating IBM Business Process Manager V7.5 with C APIs using a JNI bridge

This article provides steps to integrate IBM® Business Process Manager V7.5 with a JNI implementation based on a Windows® platform by creating a native DLL library using JNI, configuring the library in IBM BPM to generate Java Integration Services, and integrating with Java™ components. It also discusses a simple operation scenario that invokes native methods by passing simple and array-based data.

Sharad Chandra (schandr1@in.ibm.com), Senior WebSphere Consultant, IBM

Photo of Sharad ChandraSharad Chandra is a Senior WebSphere Consultant in IBM Software Group. He has 8 years of experience in business process management and SOA technologies. He has extensive experience handling complex customer solutions that are related to BPM and middleware technologies.



Sheng Ping Zhang (shpzhang@cn.ibm.com), Software Engineer, IBM

Photo of Sheng Ping ZhangSheng Ping Zhang is a Software Engineer with the WebSphere Lombardi Edition and Business Process Manager Level 2 Support team in the IBM China Software Development Lab. She has experience supporting Asia Pacific and worldwide customers.



15 August 2012

Also available in Chinese

Introduction

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.

Prerequisites

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.


Download files

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:

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
Creating Java project in Integration Designer

Creating a Java class

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
Output folder of Integration Designer

Creating the header file

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
Creating a header file

Creating a DLL project

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
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;
}

Building the DLL

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
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
Custom JVM properties setting

Once the path is set, you need to restart the server.

Write a wrapper

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
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".

  1. 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
    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
    Adding the Java Service JAR
  2. 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
    Define the Integration Service
  3. 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
    Associate the Java Integration Service with the JAR file
  4. 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
    Define the Business Process Definition
    Figure 13. Human service including a simple data service
    Human service including a simple data service
    Figure 14. Define the Business Process Definition
    Define the Business Process Definition

Testing the solution

This section will show two test cases using a simple addition and an array.

Simple data test

  1. 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
    Entering data in the text fields
  2. 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
    Displaying the results in the text fields

Array data test

  1. 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
    Array initialized
  2. Click Step and you see the sum result as shown in Figure 18.
    Figure 18. The sum result of the array data
    The sum result of the array data

Conclusion

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.


Downloads

DescriptionNameSize
Code sample filecode_sample.zip936KB
Code sample fileJNITestProject.zip16KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Business process management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Business process management, WebSphere
ArticleID=830414
ArticleTitle=Integrating IBM Business Process Manager V7.5 with C APIs using a JNI bridge
publish-date=08152012