views:

628

answers:

2

One of our products implements the following one-way web service structure:

Server <--------------------- Middleware <---------------- Client
        SOAP over JMS (queue)              SOAP over HTTP

In this model, clients send SOAP messages over HTTP to our middleware (Progress SonicMQ). The messages get pushed into JMS queues by SonicMQ and our server fetches them from there. However, as you can see, the server does not send a response to the client (asynchronous JMS).

We would like to implement a response-channel to this model. The often suggested solution is to create a temporary replyTo-queue (on the fly) in the middleware, allowing server to send a response to that queue. Then, client can fetch the response and the replyTo-queue is closed. This sounds convenient enough, but unfortunately our clients operate over plain HTTP and not over JMS, so their clients can not easily set up replyTo queues.

One approach to achieving a response channel in such hybrid HTTP/JMS SOAP model would be to configure the middleware to open the replyTo queue on each succesful SOAP receive, append the replyTo-queue and sender information to the SOAP message and push the message to the queue, where it would be fetched by the server. After receiving and processing the message, the server could send a response to the indicated replyTo-queue in the middleware. Finally, the middleware would send the response (SOAP) over HTTP back to the original client by using the data from the SOAP message (the data that was inserted there in the middleware procedures when the request was first received).

While propably possible, this sounds kind of a hacky. So the question is: any cleaner ways of achieving such request/response model on our case? The server end has been implemented in Java.

The solution:

Progress SonicMQ supports "Content Reply Send" HTTP Acceptor, which allows to easily send JMS reply. The Content Reply Send acceptor works in a following way:

  • Acceptor receives the HTTP message a client sent
  • Acceptor creates a temporary JMS queue
  • Acceptor builds up a JMS message, containing the HTTP body, and adds the temporary queue's identification to the newly created JMS message
  • Acceptor pushes the JMS message into its destination queue (not the temporary queue)
  • Acceptor starts consuming the temporary reply-To queue
  • When client fetches message from original destination queue, it contains the set reply-To queue identification
  • Client consumes message
  • Client sends reply to the reply-To queue
  • Acceptor receives message from the queue
  • Acceptor sends message as HTTP to the client that originally sent the HTTP message

Should consumer ("server" in our case) fail and not send reply causing timeout, Sonic's HTTP Acceptor sends an HTTP message to the client indicating the timeout. This is a very standard feature in SonicMQ. I suppose it exists in other products as well.

This allows using standard SOAP over JMS (see skaffman's answer) in the "server" end avoids any custom programming in the middleware.

I still see some problems in the JMS model though, but this is definitely an improvement.

Update 2009-11-05:

After researching this issue even more, it turns out my suspicion against HTTP<-->middleware<-->JMS has been relevant.

There are a few critical problems in this model. Synchronous-asynchronous model with middleware simply isn't convenient. Either have both ends implement JMS connection (which should rock) or go with HTTP in both ends. Mixing them results only in headaches. Of these two, SOAP-over-HTTP is simpler and better supported than SOAP-over-JMS.

Once more: if you are designing this kind of a system... DON'T.

+3  A: 

Why not add a link to a page that lets users check to see when a response is ready, a la a Fed Ex tracker ID? Give your users the tracker ID when they send the request.

This would fit into the HTTP request/response idiom, and your users would still know that the request is "fire and forget".

duffymo
Nice out-of-box thinking! I didn't really consider that option. However, in this case we need to establish a syncrhonous communication because each client sends high amounts of messages. Requesting clients to manually check web pages for success, would be cumbersome. Of course they could automate that process as well, but then each client would need to hold each message in their databases until they can be acknowledged. I don't think we can ask for that big changes from our clients. Your suggestion opens up a few other useful functions though, so I'll keep it in mind!
Tuukka Mustonen
So why not vote the answer up? Your good opinion is appreciated, though.
duffymo
Sorry, I don't have enough reputation to do that. One of the drawbacks of the stackoverflow model I guess..
Tuukka Mustonen
+4  A: 

I don't think your suggested solution is hack at all, I think that's the right solution. You have the client-middle layer with a synchronous protocol, and then the middle-server layer using an asynchronous layer, to which you have to add a reply path in order to satisfy the synchronous semantics. That's what middleware is for. Remember that that JMS provides explicit support for temporary reply-to queues, you won't need to mess with the payload at all.

A more left-field possibility is the leverage the fact that SOAP 1.2 was designed with JMS in mind, and so you could use web service layer between middleware and server layer which does SOAP-over-JMS. That means you can keep SOAP from end-to-end, with the middleware changing only the transport.

The only web service stack that I know of that supports JMS transport is Spring Web Services, where the process and development is documented here. This would also give you the opportunity to port your SOAP layer to Spring-WS, which kicks ass :)

skaffman
Native support for SOAP over JMS sounds nice. I didn't know that existed. In addition to Spring, it seems that Metro JAX-WS implementation supports SOAP over JMS as well. I suppose either of these allow custom configuration JMS factory and queue configurations? I'm pondering that, because we need to set a few SonicMQ-specific properties. Also, SonicMQ sends a OK/fault response by default, so I need to override that in the middleware. However, I guess that should be easy. It seems I got some studying to do...
Tuukka Mustonen
Sounds like you've got some interesting engineering to do :) I'm guessing that Spring-WS uses's Spring's JMS support, which is pretty good, and should allow you to customise things as much as you need.
skaffman