Monday, September 22, 2008

invoking BPEL from java using WSIF

I had listed invoking Bpel process from Java using WSIF as one of the exciting tasks that you can try out in your free time. Today I will be explain on how to start working on this using an HelloWorld example.

Given below are some of the classes we will be using for WSIF invocation.

WSIFServiceFactory

Abstract factory class to create instances of WSIFService. Call newInstance to get a instance of the factory. newInstance() method will create WSIFServiceFactoryImpl object

WSIFServiceFactoryImpl

Factory class used to create instances of WSIFService. Create a WSIFService from WSDL document URL. If serviceName or serviceNS is null,then WSDL document must have exactly one service in it. If portTypeName or portTypeNS is null,then WSDL document must have exactly one portType in it and all ports of the selected service must implement the same portType.

WSIFService

A WSIFService is a factory via which WSIFPorts are retrieved. This follows the J2EE design pattern of accessing resources (WSIFPorts, in this case) via a factory which is retrieved from the context in which the application is running

WSIFPort

A WSIFPort represents the handle by which the operations from the <portType> of the <port> of this WSIFPort can be executed

WSIFOperation

A WSIFOperation is a handle on a particular operation of a portType that can be used to invoke web service methods. This interface is implemented by each provider

Java Code Snippet

try {

WSIFServiceFactory factory = WSIFServiceFactory.newInstance();

WSIFService service = factory.getService("http://hostname:port/orabpel/default/HelloWorld/1.0/HelloWorld?wsdl",

"http://xmlns.oracle.com/HelloWorld", "HelloWorldService",

"http://xmlns.oracle.com/HelloWorld",

"HelloWorldType");

WSIFPort port = service.getPort();

// Create the operation object for the getOutput operation in the WSDL

WSIFOperation operation = port.createOperation("getOutput", "HWReqMessage", "HWRespMessage");

WSIFMessage inputMsg = operation.createInputMessage();

WSIFMessage outputMsg = operation.createOutputMessage();

WSIFMessage faultMsg = operation.createFaultMessage();

inputMsg.setObjectPart("input", new String("geo"));

// invoke the Service

boolean success = operation.executeRequestResponseOperation(inputMsg, outputMsg, faultMsg);

String output = (String)outputMsg.getObjectPart("output");

if (success == true) {

System.out.println(" Result..!!" + output);

} else {

System.out.println("No Result..Unable to execute the Operation!!");

}

} catch (WSIFException we) {

we.printStackTrace();

} catch (Exception e) {

e.printStackTrace();

}

Here operation.executeRequestResponseOperation() method will execute a request-response operation. The signature allows for input, output and fault messages. WSDL in fact allows one to describe the set of possible faults an operation may result in, however, only one fault can occur at any one time.

inputMsg - operation.createInputMessage()

Create an input message that will be sent via this port.

outputMsg - operation.createOutputMessage()

Create an output message that will be received into via this port.

faultMsg - operation.createFaultMessage()

Create a fault message that may be received into via this port.

Now create a BPEL process HelloWorld which will take the input and assign “Hello world” and input as a concatenated string to the output.

You need to remember some points while modifying the HelloWorld WSDL which is required before invoking from java using WSIF. Add a binding part to the wsdL. In Porttype tag modify the input and output operation to add the name attribute .This name attribute value will be used in creating oeration using port. createOperation() method.

HelloWorld WSDL

<?xml version="1.0" encoding="UTF-8"?>

<definitions name="HelloWorld"

targetNamespace="http://xmlns.oracle.com/HelloWorld"

xmlns="http://schemas.xmlsoap.org/wsdl/"

xmlns:client="http://xmlns.oracle.com/HelloWorld"

xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"

xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"

xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<types>

<schema targetNamespace="http://xmlns.oracle.com/HelloWorldType"

xmlns="http://www.w3.org/2001/XMLSchema"

xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">

</schema>

</types>

<message name="HelloWorldRequestMessage">

<part name="input" type="xsd:string"/>

</message>

<message name="HelloWorldResponseMessage">

<part name="output" type="xsd:string"/>

</message>

<!-- portType implemented by the HelloWorld BPEL process -->

<portType name="HelloWorldType">

<operation name="getOutput">

<input name="HWReqMessage" message="client:HelloWorldRequestMessage" />

<output name="HWRespMessage" message="client:HelloWorldResponseMessage"/>

</operation>

</portType>

<binding name="MyBinding" type="client:HelloWorldType">

<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>

<operation name="getOutput">

<soap:operation style="rpc" soapAction=""/>

<input name="HWReqMessage">

<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>

</input>

<output name="HWRespMessage">

<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>

</output>

</operation>

</binding>

<plnk:partnerLinkType name="HelloWorld">

<plnk:role name="HelloWorldProvider">

<plnk:portType name="client:HelloWorldType"/>

</plnk:role>

</plnk:partnerLinkType>

</definitions>

Some errors you may face during runtime are

Exception#1

org.apache.wsif.WSIFException: No provider exists for the binding http://schemas.xmlsoap.org/wsdl/soap/

or

Exception in thread "main" java.lang.NoClassDefFoundError:oracle/j2ee/ws/wsdl/extensions/wsif/schema/Schema2Java

Solution

Add wsa.jar

Exception#2

unknown prefix in QName literal: null at oracle.j2ee.ws.common.encoding.simpletype.XSDQNameEncoder.stringToObject(XSDQNameEncoder.java:75)

Solution

The xsd elements are not read properly. Then instead of having complextypes use primitive types as your message parts

Exception #3

Exception in thread "main" java.lang.NoClassDefFoundError: javax/wsdl/Definition-

Solution

Add wsdl4j-1.5.1.jar

For compiling the process you need wsif.jar from webservices lib.

orabpel.jar , jaxrpc-api.jar, wsa. jar, http_client.jar, wsdl4j-1.5.1.jar are some of the jars required for runtime execution of the java program. There wil be mutiple wsif.jar’s available in your machine.Try to use the one provided by oracle since we are trying to connect to the oracle bpel process .

10 comments:

Prakash said...

sorry don't Know..

Anonymous said...

Hello, I have problem when implementing your tutorial, there is an error like this: java.lang.ClassCastException: com.ibm.wsdl.extensions.schema.SchemaImpl.
What is the solution for that exception? Thx

George Thomas said...

It has to do with the mismatch in the jars. You seem to be using a jar related to the ibm implementation of wsdl extension. try using the oracle implementation of these classes.

Anonymous said...

Thanks for your quick response, I think it's because I'm using wsdl4j-1.5.1.jar, I see that jar made by Ibm (there are package com.ibm.wsdl.*). Is there any jar that can replace that? And where I can get that? Thx a lot

Anonymous said...

Sorry, I've change wsdl4j-1.5.1.jar with wsdl.jar from webservices lib, but there are erros like this:
WARNING: Unable to connect to URL: http://localhost:9700/orabpel/default/Helloworld/v2010_04_19__38638 due to java.security.PrivilegedActionException: javax.xml.soap.SOAPException: Message send failed: Connection refused: connect
HTTP transport error: javax.xml.soap.SOAPException: java.security.PrivilegedActionException: javax.xml.soap.SOAPException: Message send failed: Connection refused: connect
at oracle.j2ee.ws.client.http.HttpClientTransport.invokeImpl(HttpClientTransport.java:174)
at oracle.j2ee.ws.client.http.HttpClientTransport.invoke(HttpClientTransport.java:150)
at oracle.j2ee.ws.client.StreamingSender._sendImpl(StreamingSender.java:176)
at oracle.j2ee.ws.client.StreamingSender._send(StreamingSender.java:113)
at oracle.j2ee.ws.client.dii.CallInvokerImpl.doInvoke(CallInvokerImpl.java:94)
at oracle.j2ee.ws.client.dii.BasicCall.invoke(BasicCall.java:792)
at com.oracle.oc4j.wsif.providers.jaxrpc.WSIFOperation_JaxRpc.invokeOperation(WSIFOperation_JaxRpc.java:1622)
at com.oracle.oc4j.wsif.providers.jaxrpc.WSIFOperation_JaxRpc.invokeRequestResponseOperation(WSIFOperation_JaxRpc.java:1403)
at com.oracle.oc4j.wsif.providers.jaxrpc.WSIFOperation_JaxRpc.executeRequestResponseOperation(WSIFOperation_JaxRpc.java:1177)
at HelloClient.test(HelloClient.java:28)
at HelloClient.main(HelloClient.java:46)


It's my java code:
WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
WSIFService service = factory.getService("http://172.16.110.140:9700/orabpel/default/Helloworld/Helloworld?wsdl", "http://xmlns.oracle.com/Helloworld", "Helloworld", "http://xmlns.oracle.com/Helloworld", "Helloworld");
WSIFPort port = service.getPort();
WSIFOperation operation = port.createOperation("process","tns:HelloworldRequestMessage","tns:HelloworldResponseMessage");
WSIFMessage inputMsg = operation.createInputMessage();
WSIFMessage outputMsg = operation.createOutputMessage();
WSIFMessage faultMsg = operation.createFaultMessage();
inputMsg.setObjectPart("payload", new String("testing"));
boolean success = operation.executeRequestResponseOperation(inputMsg, outputMsg, faultMsg);
String output = (String)outputMsg.getObjectPart("payload");
if (success == true) {
System.out.println(" Result..!!" + output);
} else {
System.out.println("No Result..Unable to execute the Operation!!");
}
So, how can I solve that problem? Thx before

George Thomas said...

The WSIF is not able to connect to the WSDL. It giving connection refused error. Try to deploy BPEL process with version 1.0 and check the runtime jars.

Anonymous said...

I've tried it, but still has the same error. Is this error not relate to proxy server setting? The Bpel is not in my localhost, but on certain server, so I must hit certain ip too.

It's my wsdl part:







Please help me, I'm already frustated right now. Thx :)

Anonymous said...

service name="HelloWorld"
port name="HelloWorldPort" binding="tns:HelloWorldBinding"
soap:address location="http://localhost:9700/orabpel/default/HelloWorld/v1.0"/

George Thomas said...

The hostname:port on which you have deployed the bpel process is not the same as you are accessing then connection error will come. You need to replace them with the correct host /port .

Anonymous said...

When I make bpel, then deploy it on the Bpel Console server, the hostname default is localhost, I can't change it. And I think localhost is right, because Bpel Console will read wsdl from it's localhost.
I can access the wsdl from my computer if I hit the server's ip (http://172.16.110.140:9700/orabpel/default/Helloworld2/v1.0/Helloworld2?wsdl)

And for note in my java code, I'm not write the version of the Bpel so I can always hit the newest Bpel version. Like this= http://172.16.110.140:9700/orabpel/default/Helloworld2/Helloworld2?wsdl.
My reason is when I deploy Bpel on Bpel Console, there will be many different version, so I don't need to change my java code.
I hope you understand. Thx :)