Showing posts with label WSIF. Show all posts
Showing posts with label WSIF. Show all posts

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 .

Saturday, September 13, 2008

starting with WSIF

Recently I was working on JCA using WSIF extensions that’s when I got a query on how to get started with WSIF implementations. For those who want to try out WSIF there is a good tutorial on BPEL Cookbook - Using WSIF for Integration. When ever I try out something new I always start with a HelloWorld example which I believe has grown in me from the time I started working in Java. Working example of HelloWorld will always help you in getting started with the new topics, technology and frameworks. Coming back to WSIF I had taken a session on how to create a Helloworld sample in WSIF. These are some steps I did.

Create an empty WSDL file. Add the necessary namespace imports along with the mandatory ones

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

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

I decided to go for a person object with 2 elements name and age.

So I added the xsd elements

<schema elementFormDefault="qualified"

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

targetNamespace="http://geo.com/domain/person/">

<xsd:complexType name="PersonType">

<xsd:sequence>

<xsd:element name="name" type="xsd:string" />

<xsd:element name="age" type="xsd:string" />

</xsd:sequence>

</xsd:complexType>

</schema>

Use schema compiler utility called schemac provided by BPEL PM (available in bpel/bin) to generate the corresponding java classes.

Then write another java file which has the functionality to be invoked using WSIF. It will create ObjectFactory which will return instances of the required classes.

package com.geo.service;

import com.geo.domain.PersonType;

public class HelloWorld {

public String printHelloWorld(PersonType person) {

return “Hello world from ”+person.getName()+” My Age is ”+person.getAge();

}

}

Compile this class by putting PersonType in classpath and put all these class files in BPEL’s classpath. Either put it in Oracle_Home\bpel\system\classes or add the path where you have classes to bpelcClassPath in the configuration page of BPEL Console

After creating the message types most important part is plugging in of java classes into WSDL. The binding and service tags serve this purpose.

The java class is defined in service as the”<java:address className=”…..”/>

And operation <java:operation methodName=" ….."/>

Code snippets

<binding name="HelloBinding" >

<java:binding/>

<format:typeMapping encoding="Java" style="Java">

<format:typeMap typeName="tns:PersonType"

formatType="com.geo.PersonType" />

<operation name="PrintHello">

<java:operation methodName=" printHelloWorld "/>

<input/>

<output/>

</operation>

</binding>

...

...

<service name="HelloService">

<port name="HelloPort" binding="tns:HelloBinding">

<java:address className="com.geo.HelloWorld"/>

</port>

</service>

Now you are ready to go. Create a bpel process which takes 2 inputs name and age .Create a partner link using this WSIF WSDL. Invoke it from your bpel process. Assign i/p and o/p. Compile and deploy to bpel server. Test it and see your message of HelloWorld.

In this sample we were returning a string that is a primitive type. I decided to go a step forward by replacing the return string with another object.

But that was not as easy as I had expected. We have to add another complex type in <types> and regenerate classes using schemac utility. Then modify the response message type. Add a format typemap corresponding to the new complextype.

Modify our old HelloWorld.java so that it returns new object instead of string. Place the classes in classpath. Test it using another bpel process.

While trying to run the test2 you will be faced with a null pointer exception. We tried by adding returnPart attribute to operation tag.But that also didn’t solve our problem. The issue was with Object factory which was throwing the null pointer. So the only solution that we came up was to replace the schemac created classes(POJOs and factory classes) with our own created POJOs with getters and setters. Thanks to Syam who helped me in solving this issue. Hope this will be helpful to you all who are starting with WSIF.