Wednesday, August 20, 2008

WSIF: Calling native Java code from BPEL

What's the deal?
The alternatives to calling Java from BPEL aren't legion. Infact, there are only three.
  1. Using Java embedding to call the code directly
  2. Wrapping the code in a SOAP service
  3. Calling the code using Web Service Invocation Framework
Thus, it becomes all the more important to make a judicious choice amogst the three. The subject matter of this post is to acquaint the reader with calling native Java code using WSIF. But before moving on, it makes perfect sense to look at the pros and cons of all the three.

The pros and cons
Java Embedding: This is an out of box feature provided by BPEL to aid the developer to write and use Java snippets inside the BPEL environment. The greatest advantage is it lets the developer have full access to the entire BPEL environment. Consequently, direct manipulation of data inside the process is fairly easy. Add to it the ease of use, since you don't need to create auxiliary artifacts that you need with the other approaches, you are spared a lot of effort. On the flip side, it makes the BPEL code a little unreadable as you have mixed up Java with the BPEL tags. Use this to do seemingly simple tasks with short Java snippets.

SOAP Service: If you already have the Java code, wrapping it up as a SOAP service with JDeveloper is a peice of cake. Advantage is it lends a lot of reusability to the code and keeps your BPEL process clean. The disadvantage is that the reusability comes at a cost. You have to bear with the SOAP overhead, which can be tremendous especially if you are running a BPEL process that is swamped with SOAP calls. Use this when the service needs to be accessible from multiple machines and different BPEL processes or other applications.

WSIF: Without compromising much on readabiliy and resusability, WSIF provides a cleaner approach to use native code. By keeping the code separate from BPEL it makes sure that readability isn't sacrificed. Also, it calls the code directly, thereby eliminating the SOAP overhead altogether. Finally the code can easily be re-used by other BPEL processes by deploying the jar file containing the java classes and the WSDL document as part of a BPEL suitcase.

Prerequisites
Now that we have looked into the inherent positives and negatives of the three approaches, lets get ahead with the subject matter of this post - using WSIF to call java code. For the sake of demonstration, I shall use a Java class that takes a string as a parameter and concatenates it with another string. Here is code:

package com.nebulasky.blogspot;
public class ConcatString {

public ConcatString() { }
public String getConcatenation(String input)
{
return "Hello " + input;
}
}

Now, use JDeveloper and publish this as a J2EE service. Deploy and test it. Create a BPEL process and invoke this service. Fairly simple. Once these are done, we are all set to bring WSIF into the picture.

The WSIF file
To reiterate our purpose, we are going to tweak the BPEL to use WSIF to call the Java class instead of using SOAP. It makes sense to look at the WSDL file for the J2EE service. Of special interest is the binding section of the WSDL, since this tells our BPEL process how to call the service. I have omitted the rest of the file for simplicity, as they simply specify the data format for the messages. Here is an excerpt from the WSDL:

<binding name="ConcatenationSoapHttp" type="tns:Concatenation">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getConcatenation">
<soap:operation soapAction="http://blogspot.nebulasky.com/getConcatenation"/>
<input> <soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/> </output> </operation>
</binding>

Notice that SOAP binding is being used (soap:binding, soap:operation , soap:body tags). All we need to do to persuade the BPEL to use WSIF is to change the binding information without changing the structure of the contract. As long as the contract is the same and references the same operations that the Java class exposes, and the messages in the contract are in conformance with the data types and parameters of the class, changing the binding will only change the way the BPEL communicates with the class, nothing else.

Definitions tag
Open the WSDL for the J2EE service in JDeveloper. Click on the source tab because you are going to edit it. Start by defining the two namespaces used by WSIF providers in the root element of the WSDL document, the tag. The format namespace is used to define the type mappings and the java namespace to define the operation mappings and the full name of the Java class:

<definitions name="Concatenation" targetNamespace="http://blogspot.nebulasky.com/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://blogspot.nebulasky.com/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns0="http://blogspot.nebulasky.com/types/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/" xmlns:java="http://schemas.xmlsoap.org/wsdl/java/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">

Map Java types to XML Schema definitions
To generate Java to XML mapping we need to create XML facades. These façades are Oracle BPEL Process Manager's original Java-to-XML binding for WSIF. XML façades are a set of Java interfaces and classes through which you can access and modify XML data stored in BPEL variables in a relatively easy way using get/set methods. Here we need the mappings for the WSDL file for the J2EE service. For this, you need to use the schema compiler utility called schemac as:

C:\com\nebulasky\blogspot\>schemac Concatenation.wsdl

First, you indicate to the BPEL process that it is bound to native Java code and not to a SOAP service. This is how you do it:

<binding name="JavaBinding" type="tns:WSIFTestProcess">
<java:binding/>

Next, you specify that XSD types will be mapped onto Java types. For this use the format:typeMapping tag. Then you define what Java types shall be used for what xsd types by using the format:typeMap tag. Here is the snippet that does these two tasks for you:

<format:typeMapping encoding="Java" style="Java">
<format:typeMap typeName="xsd:string" formatType="String"/> </format:typeMapping>

Mapping Java methods to WSDL operations
The final step is now to map the Java method calls onto the WSDL operations. This is done using the java:operation tag to identify which Java method should be used to support a given operation:

<operation name="getConcatenation">
<java:operation methodName="getConcatenation"/>
<input/>
<output/>
</operation>
</binding>

Define the Service
We are through with most of it now. All that remains is defining the service. Here you will provide a Java address unlike a SOAP address which is how it was untill recently:

<service name="Concatenation"> <port name="JavaPort" binding="tns:JavaBinding">
<java:address className="com.nebulasky.blogspot.ConcatString"/>
</port>

Deploy the class
For it to work at runtime then the Process Manager must be able to find the Java classes referenced in the WSIF. When using WSIF the classpath for the invoked WSIF service is different to the classpath for the BPEL process. It is necessary to move the classes to the <BPEL_HOME>/system/classes directory. Here the classes are the the ones generated by the schemac command and the class responsible for the concatenation.

Test the process
If it is not already thus, ensure that the BPEL process takes the Concatenation.wsdl file from the current directory and not from the Web service itself. The bpel.xml file should look like this:

<partnerLinkBinding name="Concatenation"> <property name="wsdlLocation">Concatenation.wsdl</property>
</partnerLinkBinding>

Test the process. It should give you the expected result.

5 comments:

Anonymous said...

Well written article.

Thiago said...

I cant run schemac. With SOAP its working...
Can you explain a little more, like a tutorial?

Thanks!

Anonymous said...

Hello!
You may probably be very curious to know how one can manage to receive high yields on investments.
There is no need to invest much at first.
You may begin earning with a money that usually goes
for daily food, that's 20-100 dollars.
I have been participating in one company's work for several years,
and I'll be glad to share my secrets at my blog.

Please visit my pages and send me private message to get the info.

P.S. I make 1000-2000 per day now.

http://theinvestblog.com [url=http://theinvestblog.com]Online Investment Blog[/url]

Anonymous said...

I am doing research for my college thesis, thanks for your helpful points, now I am acting on a sudden impulse.

- Laura

Anonymous said...

have a very Strange problem, in my BPEL process I have used java embed Activity. on that activity if I am using Task class. then I am not able to deploy my process. its giving me following message.

when I remove that line then I am able to deploy that process.

following error comes when deployment.

[10:29:41 AM] ---- Deployment started. ---- [10:29:41 AM] Target platform is (Weblogic 10.3). [10:29:41 AM] Running dependency analysis... [10:29:41 AM] Building... [10:29:52 AM] Deploying profile... [10:30:19 AM] Wrote Archive Module to D:\RegistrationUpload\RegistrationUpload\RegistrationUpload\deploy\sca_RegistrationUpload_rev21.0.jar [10:30:19 AM] Deploying sca_RegistrationUpload_rev21.0.jar to partition "default" on server soa_server1 [WIN-73I7I7QL8Z3.uradevt.gov.sg:8002] [10:30:19 AM] Processing sar=/D:/RegistrationUpload/RegistrationUpload/RegistrationUpload/deploy/sca_RegistrationUpload_rev21.0.jar [10:30:19 AM] Adding sar file - D:\RegistrationUpload\RegistrationUpload\RegistrationUpload\deploy\sca_RegistrationUpload_rev21.0.jar [10:30:19 AM] Preparing to send HTTP request for deployment [10:30:19 AM] Creating HTTPS connection to host:WIN-73I7I7QL8Z3.uradevt.gov.sg, port:8002 [10:30:19 AM] Sending internal deployment descriptor [10:30:20 AM] Sending archive - sca_RegistrationUpload_rev21.0.jar [10:33:45 AM] Received HTTP response from the server, response code=500 [10:33:45 AM] Error deploying archive sca_RegistrationUpload_rev21.0.jar to partition "default" on server soa_server1 [WIN-73I7I7QL8Z3.uradevt.gov.sg:8002] [10:33:45 AM] HTTP error code returned [500] [10:33:45 AM] Error message from server: Error during deployment: Error occurred during deployment of component: OfficerList to service engine: implementation.bpel, for composite: RegistrationUpload: ORABPEL-01005

Failed to compile bpel generated classes. failure to compile the generated BPEL classes for BPEL process "OfficerList" of composite "default/RegistrationUpload!21.0*soa_27af417b-20d6-48d0-821c-4f26b3c4ce94" The class path setting is incorrect. Ensure that the class path is set correctly. If this happens on the server side, verify that the custom classes or jars which this BPEL process is depending on are deployed correctly. Also verify that the run time is using the same release/version. . [10:33:45 AM] Check server log for more details. [10:33:45 AM] Error deploying archive sca_RegistrationUpload_rev21.0.jar to partition "default" on server soa_server1 [WIN-73I7I7QL8Z3.uradevt.gov.sg:8002] [10:33:45 AM] #### Deployment incomplete. #### [10:33:45 AM] Error deploying archive file:/D:/RegistrationUpload/RegistrationUpload/RegistrationUpload/deploy/sca_RegistrationUpload_rev21.0.jar (oracle.tip.tools.ide.fabric.deploy.common.SOARemoteDeployer)

follwing code I have used in snippet.







Will anyone please tell me do I need to refer jar file in terms of BPEL process also.

even same class I can use in my java files in the same project. (for other class its working like OfficerList)

Environment is : Oracle SOA 11g, Jdeveloper

please suggest something.