Friday, November 14, 2008

Invoke a Asychronous 10.1.3 BPEL service from JAX-WS

In JDeveloper the web service proxy wizard for JAX-WS will recognize when a service is asynchronous and offer to generate both the invoking proxy and a service implementation to deal with the response. The problems is that the proxy generator in JDeveloper assumes that version of WS-Addressing is going to be Final (2005) or Member Submission (2004) and that the headers are implicit. By default BPEL 10.1.3 uses the 2003 Draft version of WS-Addressing and has explicit headers. This means you are going to have to do a bit more work to make it work with JAX-WS.

This examples makes use of the AsyncBPELService that comes with the Oracle BPEL server. All it does is echo a loan request back to the user. The same steps would work with any other asynchronous example - AmericanLoan for example.

So if you already know the WSDL url use that. I cheated a little bit and created a WSIL connection in the "Resource Palette" to "http://xxxxx:8889/inspection.wsil" and navigated to the right BPEL service from there. Either way bring up the web service proxy wizard and accept all of the defaults.

An inviting client source file example will show first, but lets clean up the callback service before we do this. In this case it is "AsyncBPELServiceCallbackImpl.java". You of course need to put some code in there; but the println we generate by default is enough for this example. As I said before the WS-Addressing header is an explicit parameter so in the two methods that get generated you need to replace:

    // get the messageId to correlate this reply with the original request
    HeaderList headerList = (HeaderList)wsContext.getMessageContext().get(JAXWSProperties.INBOUND_HEADER_LIST_PROPERTY);
    Header realtesToheader = headerList.get(WS_ADDR_VER.relatesToTag, true);
    String relatesToMessageId = realtesToheader.getStringContent();
    System.out.println("RelatesTo message id: " + relatesToMessageId);

With:

     System.out.println("RelatesTo message id: " + RelatesTo.getValue());

Right lets go back to the client class "AsyncBPELServicePortClient.java" and for a change lets do a JSE client for the service and publish and endpoint as the first thing we do in the main method:

    // publish the endpoint
    //
            
    Endpoint e = Endpoint.publish(
        "http://xxxx:7001/response",
        new AsyncBPELServiceCallbackImpl());  

Although not the most direct way for this example you can use the endpoint to create the WSEndpoint object directly, so you can make this minor fix. This is more useful in the normal '2005 and '2004 cases.

    WSEndpointReference replyTo =
        new WSEndpointReference("http://......", WS_ADDR_VER);

With:

    WSEndpointReference replyTo =
        new WSEndpointReference(e.getEndpointReference(), WS_ADDR_VER);

We then comment out the next block because it generates headers in the wrong WS-Addressing version, then we put in place the right code to invoke the service:

    // Add your code to call the desired methods.

    LoanApplicationType applicationType = new LoanApplicationType();
    applicationType.setCarModel("207");
    applicationType.setCarYear("1");
    applicationType.setCreditRating(2);
    applicationType.setCustomerName("Bob");
    applicationType.setEmail("bob@bobo.com");
    applicationType.setLoanAmount(1000d);
    applicationType.setSSN("143134-134-135--1345");

    // Set the reply to address to match that of the service
    //
    EndpointReferenceType replyToType = new EndpointReferenceType();
    AttributedURI replyToTypeURI = new AttributedURI();
    replyToTypeURI.setValue(replyTo.getAddress());
    replyToType.setAddress(replyToTypeURI);
    
    // Set the message id
    AttributedURI messageId = new AttributedURI();
    messageId.setValue(uuid);
    asyncBPELService.initiate(applicationType, replyToType, messageId);
    

And that is it really, the only thing to note is that you need to do System.exit(...) at some point as the Endpoint method starts on a non daemon thread. Just don't do it in the onResult method otherwise the BPEL service might record an error if the communication is not completed properly.

2 comments:

Raj Venkat said...

do you have the source code to call bpel async service. I tried to create this using jdev but running into issues.

Gerard Davison said...

There should be enough information here, can be more specific about the problem you are seeing?