Sunday 27 January 2013

ReplyTo in ZeroMQ using WS-Addressing

In my last post, I mentioned how one could leverage SOAP along with WS-Addressing to implement the return address pattern in ØMQ (known in the JMS world as ReplyTo and in the MSMQ world as ResponseQueue). In this post, I'll go into more detail by giving a code example using CXF's ØMQ transport.

Below is a WSDL that is similar in many respects to the WSDL of the previous post:

Like the other WSDL, this one declares that the service has an operation named sayHi. It states that ØMQ is to be used for transporting the SOAP messages (line 29). Moreover, it declares the service and consumer communication parameters: zmq:address; zmq:serviceConfig; zmq:clientConfig (lines 43-45). Unlike the other WSDL, the socket types are push for the client and pull for the service. This means that communication between the client and service is one-way and therefore the client won't receive a reply, at least not on the same channel. Remember, since we're implementing return address, the service sends its reply onto a different channel.

This is the shell command I entered for generating the SEI and proxy classes:

The -asyncMethods switch tells CXF's wsdl2java to generate, in the SEI, for each Web Service operation an asynchronous method in addition to a synchronous one. In the consumer implementation, I use the generated SEI:

doOperation() sequence of events is as follows:
  1. Publishes the endpoint that processes the service's async reply (line 10).

  2. Creates a client that has WS-Addressing enabled (lines 13-14).

  3. Adds the ReplyTo element  to the request's SOAP header (lines 17-18). The element contains the callback URL that the service will read in order to know to whom it should deliver its response and how it should deliver it.

  4. Calls asynchronously the SEI method sayHiAsync() (line 21). If the consumer invokes the synchronous method (i.e., sayHi()) instead of the async one, the consumer would block indefinitely after sending out the request because it will wait for a reply that it will never receive.
The endpoint consuming the service's reply is a plain Web Service:

The callback terminates the program as soon as it processes the reply.

I re-run wsdl2java to generate another SEI but using the following arguments:

I use the SEI generated from the above command to implement the service:

Nothing special about GreeterImpl.java except the @Addressing annotation. This annotation is required for CXF to process the request's WS-Addressing headers.

Main.java triggers the server and consumer into action:

The complete application is on GitHub. The instructions for running the demo are almost identical to the ones of the previous post. First enter the following Maven command from the project's root directory:

Then run the demo using the java command:

You should then get the following output:

Tuesday 15 January 2013

SOAP over ZeroMQ with Apache CXF

You're probably asking yourself one of these two questions on reading this post's title:
  1. Who in his right mind would use SOAP as a data format for ØMQ?
  2. Why the heck would I want to have SOAP on top of ØMQ as opposed to HTTP?
For the first question, consider a system requiring:
  • A return address pattern such as the one offered by JMS and MSMQ.
  • Guaranteed message delivery. 
  • Encryption and authentication of messages.
ØMQ wasn't designed to cover these requirements so it's up to the developer to come up with a solution. The developer can re-invent the wheel and build the solution from the ground up. But why do that when other folks have already taken the trouble of writing and implementing standards that address these concerns independent of the transport used? I'm speaking of WS-*. Using a SOAP engine, we can leverage WS-* standards like WS-Addressing, WS-Security, and WS-ReliableMessaging to address the above requirements and more. 

Focusing on the second question, several motivations exist for using SOAP on top of ØMQ. The first that may pop into mind is the desire to reduce latency as ØMQ incurs less overhead than HTTP. For me, strong motivations include:
  • Leveraging ØMQ's low-level and high-level patterns such as publish-subscribe and pipeline. 
  • Dispatching messages to services while they're in a disconnected state.

With the "Why?" out of the way, let's figure out the "How?". That is, how to process SOAP messages over ØMQ. Apache CXF is an open-source Java SOAP engine that operates over transports such as JMS, UDP, and of course HTTP. During the holidays, since I had lot of free time on my hands ;-), I extended CXF to support ØMQ as an additional transport

What follows is an example of a Web Service and a client talking with each other over the transport [1]. Consider this WSDL fragment that I wrote, and which the service and client are based on:

The contract describes a service that publishes a single operation called sayHi. sayHi accepts an empty message and returns a string. Line 29 of the WSDL informs us that the service expects sayHi to be invoked using SOAP over ØMQ. Line 43 tells us the service address whereas lines 44-45 give additional necessary details for the client and service to establish communication. Observe that I'm using socket types req and rep for the client and service respectively. This means that the communication between client and service occurs in RPC-style.

I use the the wsdl2java tool that comes with the Apache CXF distribution to generate SEI and proxy classes from the above WSDL. These classes help me develop the WSDL service implementation and the client.

Next, I implement the service:

The service is published using the following code:

From the consumer-side, here's the code:

I write an additional class that triggers the execution of the service and its consumer:

I use Maven from the project's root directory to build the example:

Finally, to run the app:

The output I get is:

You'll find the complete example on GitHub. This example is basic; its purpose is to get you up and running with the transport. In my next post I'll have a more real-world example where I'll show how WS-Addressing's ReplyTo element is be leveraged to implement the return address pattern in ØMQ.

1: You need the Java binding for ØMQ installed on your machine to run the example.