Thursday, January 30, 2014

Cyclant: Bike Tours In Antwerp


One of my best friends started his own business: Cyclant, organising bike tours in Antwerp.
When you visit our beautiful city, make sure you book a tour with Cyclant, you'll like it!



Tuesday, December 3, 2013

Creating async request reply web service over jms on WebSphere (SOAP over JMS)

Introduction

I started with this developerworks tutorial and its files.

It has a section Asynchronous JAX-WS Web service invocations with SOAP over JMS, but the article is not doing any implementation, it is just a theoretical explanation. Let me show you how to call the web service asynchronously using soap over jms.

Software used:
  • IBM Integration Designer 7.5.1 
  • IBM Process Server 7.5.1.0 on WAS 7.0.0.19

Service code generation

Generate your server code as described in the tutorial. Use "Top down EJB Web Service" to create a soap over jms service. The same service code is used for both sync and async calls.

Client code generation

Right click the wsdl file in RAD or WID, and select web services > generate client

Make sure you flag "enable asynchronous invocation for generated client"



Now in the client code, the *Async operations are important. Three methods are generated for each request reply operation in the wsdl.

This wsdl does not contain one way (fire and forget) operations, but if it did, it would result in one method in the client code. Because one way operations are alway async when using JMS, they have only one method in the generated class.

One method (without Async postfix) is for sync calling, one returns a response handler (for polling), and the third accepts a callbackhandler.

The standard synchronous method

public EchoStringResponse echoOperation(EchoStringInput parameter);

The asynchronous method with polling

public Response<EchoStringResponse> echoOperationAsync(EchoStringInput parameter);

The asynchronous method with callback

public Future<?> echoOperationAsync(EchoStringInput parameter, AsyncHandler<EchoStringResponse> asyncHandler);

Calling with response

Use the response wrapper to check if the async call is finished. While it is not finished, other tasks can be executed.

Response<EchoStringResponse> asyncresp = service.getEchoServicePort().echoOperationAsync(input);

while (!asyncresp.isDone()){
    System.out.println("no response yet, let's have a nap");
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {

         System.out.println("failed to nap :(");
    }
}
try {
    System.out.println("I got a response! request send: " + request.getParameter("input") + ", got response : " + asyncresp.get().getEchoResponse());
} catch (Exception e) {
    e.printStackTrace();
}

Calling with callbackhandler

You can do the same with a callbackhandler, if it is not necessary to process the response in the same thread.

input.setEchoInput(input.getEchoInput() + " with callback");

service.getEchoServicePort().echoOperationAsync(input, new AsyncHandler<EchoStringResponse>() {

    @Override
    public void handleResponse(Response<EchoStringResponse> res) {

        try {
            System.out.println("I got a callback response! " + res.get().getEchoResponse());
        } catch (Exception e) {
            e.printStackTrace();

        }
    }});

Resources

This article in the infocenter talks about setting JVM properties for the async message listener, but I don't really understand what it is about, or why you should set these properties, it works fine without them, just define a reply queue: http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.nd.multiplatform.doc/info/ae/ae/twbs_jmsasyncresplistener.html

More info on Invoking JAX-WS Web services asynchronously: http://pic.dhe.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.base.doc/info/aes/ae/twbs_jaxwsclientasync.html

It makes the following statement:
To enable asynchronous mappings, you can add the jaxws:enableAsyncMapping binding declaration to the WSDL file.

I added that to the wsdl, and after I did the generated client will ALWAYS had the asynchronous method, even when I didn't check "enable asynchronous invocation for generated client" in the client generation wizard.


code:
<jaxws:bindings>
    <jaxws:enableAsyncMapping>true</jaxws:enableAsyncMapping>
</jaxws:bindings>

Don't forget to add the namespace declaration to the wsdl


code:
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"


If the server code is generated with the enableAsyncMapping extension added to the wsdl, you will find that also in the web service implementation class async methods have been generated

public Response<EchoStringResponse> echoOperationAsync(EchoStringInput parameter){
    // TODO Auto-generated method stub
    return null;
}

These are not valid at server side. You will get a stacktrace like this in the systemout :

[2/12/13 11:28:41:442 CET] 00000083 JMSListenerMD E   WSWS3018E: Caught exception during request processing: WSWS3163E: Error: The Web services engine could not find a target service to invoke!  targetService is EchoServicePortType
[2/12/13 11:28:42:173 CET] 0000007f SystemErr     R java.util.concurrent.ExecutionException: javax.xml.ws.soap.SOAPFaultException: WSWS3163E: Error: The Web services engine could not find a target service to invoke!  targetService is EchoServicePortType
[2/12/13 11:28:42:173 CET] 0000007f SystemErr     R         at org.apache.axis2.jaxws.client.async.AsyncResponse.onError(AsyncResponse.java:141)
[2/12/13 11:28:42:173 CET] 0000007f SystemErr     R         at org.apache.axis2.jaxws.client.async.PollingFuture.onError(PollingFuture.java:95)
[2/12/13 11:28:42:173 CET] 0000007f SystemErr     R         at org.apache.axis2.description.OutInAxisOperationClient$NonBlockingInvocationWorker.run(OutInAxisOperation.java:470)
[2/12/13 11:28:42:173 CET] 0000007f SystemErr     R         at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:897)
[2/12/13 11:28:42:173 CET] 0000007f SystemErr     R         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:919)
[2/12/13 11:28:42:174 CET] 0000007f SystemErr     R         at java.lang.Thread.run(Thread.java:736)


You can remove these *Async postfixed methods in the implementation and interface to resolve this issue.