Announcement Announcement Module
Collapse
No announcement yet.
Addressable webservice with JMS Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Addressable webservice with JMS

    Hi all,

    I need to implement a service that can be used with HTTP/SOAP + WS-A and it communicates with IBM WebSphere MQ. I've used Spring MVC several times but never used Integration. So I need to know if it is the preferrable tool in my usecase or should I look elsewhere.

    The flow of the service is this:

    1. Client sends SOAP to WS with WS-A options (replyTo and MessageId)
    2. Service responds with 202 Accepted
    3. Service reads WS-A options for WS client and correlation
    4. Service generates proprietary XML message from given parameters
    5. Service sends XML to JMS MQ (IBM)
    6. Service receives XML from JMS MQ (async)
    7. Service generates response data with WS-A options (To and RelatesTo)
    8. Service sends response with WS client to the replyTo address
    9. Client receives response

    In some cases the steps 4-6 might be executed several times before the final response. The JMS communication needs to be asyncronous.

    What is the best practice to implement this kind of service? And can Spring integration help?

    Do I need a local message queue of some sort or can the webservice thread handle all this by blocking the execution until it receives the mq messages?

    Should i use for example ActiveMQ or similar to queue incoming tasks and store the WS-A info into them for later processing. Then I don't need the original webservice method/thread to send the response as long I know the replyto address and message id.

    Ideas?

  • #2
    I have gotten pretty far with this and the integration seems to work ok. One problem remains which the message correlation.

    Here is my integration setup so far:
    Code:
    <!-- Channels -->
    	<int:channel id="wsInput">
    		<int:queue capacity="10"/>
    	</int:channel>
    	<int:channel id="wsOutput"/>
    	
    	<int:channel id="mqInput"/>
    	<int:channel id="mqOutput">
    		<int:interceptors>
    			<int:wire-tap channel="logger"/>
    		</int:interceptors>
    	</int:channel>
    	
    	<!-- Adapters -->
    	<int-jms:message-driven-channel-adapter id="jmsIn" 
    																					destination="inQueue" 
    																					channel="mqInput"/>
    	
    	<int-jms:outbound-channel-adapter id="jmsOut" 
    																		destination="outQueue" 
    																		channel="mqOutput"/>
    	
    	<int-file:outbound-channel-adapter channel="wsOutput" directory="/tmp"/>
    
    	<!-- Activators -->
    	<int:service-activator input-channel="wsInput" 
    												 ref="wsBroker" 
    												 method="prepare" 
    												 output-channel="mqOutput"/>
    												 
    	<int:service-activator input-channel="mqInput" 
    												 ref="mqBroker" 
    												 method="prepare" 
    												 output-channel="wsOutput"/>
    
    	<!-- Beans -->
    	<bean id="wsBroker" class="fi.aktia.vvh.ws.Broker"/>
    	<bean id="mqBroker" class="fi.aktia.vvh.jms.Broker"/>
    
    	<!-- Common -->
    	<int:poller id="poller" default="true" fixed-delay="10000"/>
    	<int:logging-channel-adapter id="logger" level="DEBUG"/>
    My EJB writes a spring message object into the wsInput channel. wsBroker service activator picks it up and creates a XML payload from the object payload created by the EJB. There are WS-A attributes stored in the first message object like correlationId and replyTo endpoint. These cannot be included in the XML that is sent to the mqOutput channel.

    So, the question is how can I store the WS-A info to be retrieved later? This needs to be "reattached" to a new message coming in from the mqInput channel if it correlates with a previous message. It will have a new XML payload that is converted to object model by the mqBroker and sent to the wsOutput channel with the WS-A info added. There is a stdout adapter at the moment but it will be switched to a ws client.

    It seems that the correlationId in the spring message is not mapped to JMS correlationId in the outgoing mq message? At least my activemq is not showing any? But, is it even safe to use it that way? I think I want to use the JMS correlation "as is" and map that to the WS-A info somehow. Because the correlation id is not the only info I need to transfer.

    Is there a way to for example store the message into a message store and attach the JMS correlation into it just before sending it to the mq? Then when I receive a message from mq I can check the JMS correlation and get the right message from db and the rest of the needed info and work my way from there?

    This might be a silly question and a default solution is there but I just haven't spotted it yet . There are also messages coming in from the mq that are not correlated, but that should not be a problem...

    Comment


    • #3
      If you use a <jms:outbound-gateway/>, the headers will be copied to the reply by the framework. You can (now, since 2.2) use a message-driven container for the reply so it effectively gives you what you want, but you don't need to worry about keeping track of headers.

      Comment


      • #4
        Ok, this module has been working ok so far and I made a messagestore between the mq queues. I also made an correlation mapper (JmsHeaderMapper) that injects and reads the correlation id against the message store.

        A new problem arrised though as the clients wants to use this module also synchronously. So instead of using the WS-A way the webservice thread should wait and return a response. If a timeout occurs, no biggie.

        I was thinking of using the same outgoing channels as for the async tasks but flag the messages with a "sync" flag. This will be stored into the messagestore with the other info. When message arrives from the mq it is then checked for the sync flag and if its true the message is sent to a different channel instead of the normal async response channel. The webservice client thread that fired up this whole process is still waiting a for a message and polls this new "sync" channel. If it get the right correlating message it is returned but if a timeout occurs no harm done.

        Hope I explained this so that you understand what I'm after . Is this approach ok because there are several ws threads polling and how do they know what message is "for me" and leave the others alone for the other threads to receive theirs?

        Thanks!

        Comment


        • #5
          Few ideas came to mind but have doubts if I'm on the right track... at all..

          What if I store the incoming "sync" messages to a separate messagestore? Then use publish-subscribe channel that all the ws threads are subscribed to. Fire up an event message with a correlation id when there is a message "ready for pickup". The subscriber that is interested on that id will pick it up and return the ws call?

          Not sure how the rendezvous channel works but sounds like it might be something to check out?

          Comment


          • #6
            I don't think the rendezvous channel is what you need.

            Take a look at this sample https://github.com/SpringSource/spri...rver-multiplex

            It uses an aggregator - uses a pub-sub channel to send a copy of the outgoing message to the aggregator (before sending it). The reply is sent to the same aggregator which does the correlation; and releases the 2 messages; a transformer then drops the first message.

            The sample uses TCP which doesn't have correlation headers, so it puts correlation data in the payload - but you should get the idea.

            Comment

            Working...
            X