Announcement Announcement Module
Collapse
No announcement yet.
Problem with pub-sub channel routing Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem with pub-sub channel routing

    Hi,

    I am having a problem getting a header from a pub-sub channel that get it's message from a web service inbound gateway. I have this working when the message is from a tcp-inbound-channel-adapter. So I am following a working pattern. I get the following error message when I try to get a header from the ws:inbound-gateway's request-channel:

    09:07:12,018 WARN [MarshallingWebServiceInboundGateway] failure occurred in gateway sendAndReceive
    org.springframework.integration.MessageHandlingExc eption: org.springframework.expression.spel.SpelEvaluation Exception: EL1004Epos 8): Method call: Method setHeader(org.springframework.integration.core.Mes sagingTemplate$TemporaryReplyChannel) cannot be found on com.intrado.isg2.bl.SaveHeader type

    Here is the part of my config that is part of this issue:

    Code:
    	<!-- SNR Socket section -->
    
    	<!-- Out-bound Message channel -->
    	<int:channel id="tcpSNRSend">
    	</int:channel>
    		 	
    	<!-- Opens a socket on the host/port specified and creates a connection factory -->
    	<int-ip:tcp-connection-factory id="cfSNRClient"
    		type="client" 
    		host="10.100.211.80"
    		port="10854"  
    		deserializer="connectionSerializeDeserialize" 
    	/>
    	
    	<int-ip:tcp-outbound-channel-adapter
    		id="tcpSNROutbound" channel="tcpSNRSend" connection-factory="cfSNRClient" />
    		
    	<int-ip:tcp-inbound-channel-adapter
    		id="tcpSNRInbound" channel="tcpSNRReceive" connection-factory="cfSNRClient" />	
    		
    	<int:publish-subscribe-channel id="channelSourceRegInput">
    	    <int:interceptors>
    	        <int:wire-tap channel="logger" />
    	    </int:interceptors>
    	</int:publish-subscribe-channel>
    	
    	<int:channel id="channelSourceRegOutput">
    	    <int:interceptors>
    	        <int:wire-tap channel="logger" />
    	    </int:interceptors>
    	</int:channel>
    	
     	<int-ws:inbound-gateway id="wsSourceRegistration" 
    				request-channel="channelSourceRegInput"
    				reply-channel="channelSourceRegOutput"
    				marshaller="xmlBeansMarshaller"
    				unmarshaller="xmlBeansMarshaller" />	
    	
    	<int:service-activator id="sourceRegRequestService"
    						   input-channel="channelSourceRegInput" 
    						   output-channel="tcpSNRSend"
    						   ref="sourceRegistrationService"
    						   method="sourceRegistration"
    						   order="2"/>
    						   
    	<int:service-activator id="sourceRegResponseService"
    						   input-channel="tcpSNRReceive" 
    						   output-channel="channelSourceRegOutputWithoutHeader"
    						   ref="sourceRegistrationService"
    						   method="sourceRegistrationResponse"/>						   					   		
    	
    	<!-- Routes the message received on the input-channel to multiple channels -->
    	<int:recipient-list-router input-channel="channelSourceRegInput"
    		order="1">
    		<int:recipient channel="saveSNRSourceRegHeader" />
    	</int:recipient-list-router>
    
    	<int:channel id="saveSNRSourceRegHeader" />
    
    	<!-- Calls the method setHeader on the object rgHeaderSaver with the data 
    		from the header replyChannel -->
    	<int:chain input-channel="saveSNRSourceRegHeader">
    		<int:transformer expression="headers.replyChannel" />
    		<int:service-activator ref="snrSourceRegHeaderSaver"
    			method="setHeader" />
    	</int:chain>
    	
    	<int:message-history/>
    	
    	<int:header-enricher input-channel="channelSourceRegOutputWithoutHeader"
    		output-channel="channelSourceRegOutput">
    		<int:header name="replyChannel" expression="@snrSourceRegHeaderSaver.header" />
    	</int:header-enricher>	
    	
    	<!-- Simple calls with a getter/setter -->
    	<bean id="snrSourceRegHeaderSaver" class="com.intrado.isg2.bl.SaveHeader" />		
    	
    	<!-- This channel will allow multiple subscribers to receive a message from this channel -->
    	<int:channel id="tcpSNRReceive" >
    		<int:interceptors>
    			<int:wire-tap channel="logger"/>
    		</int:interceptors>
    	</int:channel>
    Here is the SaveHeader class
    Code:
    package com.intrado.isg2.bl;
    
    public class SaveHeader {
    
    	private volatile String header;
    
    	public String getHeader() {
    		return header;
    	}
    
    	public void setHeader(String header) {
    		this.header = header;
    	}
    
    }

    The issue is with the channel "channelSourceRegInput" I am trying to get the replayHeader so I can add it to the message that goes to the channel "channelSourceRegOutput".

    I need to know if this error is a bug as I can do this successfully with a tcp adapter.

    Thanks,
    Frank

  • #2
    That is because the signature of your setHeader(String) method accepting String type while "headers.replyChannel" expression returns an instance of MessageChannel.
    You could change expression to "headers.replyChannel.getComponentName" which will return the name of this channel. However looking at your exception the reply channel is a temporary channel which has no name. Also since your ServiceActivator (SaveHeader.setHeader) is void the flow will end there and the ws:inbound-gateway will hang awaiting for a reply.

    Can you explain a little what are you trying to accomplish? Is the idea to store a reply channel so it could be retrieved later when reply is available? How late?. . . .

    Comment


    • #3
      Thanks for the information about the data type mismatch.

      Here is what this code is trying to accomplish:
      1. Receive a web service call, transform the incoming xml.
      2. Send the transformed xml to a server via a socket.
      3. Receive the response xml from the server via the socket.
      4. Transform the response xml and reply to the web service call.

      When I did this WITHOUT a header enhancer the web service gateway threw the error:
      org.springframework.integration.support.channel.Ch annelResolutionException: no output-channel or replyChannel header available


      I know I am going to loose the web service call headers when I send the message to the tcp socket. So I am trying to get the headers back on the message that is going back out the web service. I did not think I needed to do this. I thought once I placed the message on the web gateway's reply-channel it would sent it out. Instead I got the above exception.

      Comment


      • #4
        Then you should use TCP gateways instead of adapters. Remember in Spring Integration Gateways are for bi-directional communication and adapters are uni-directional. So instead of doing what you doing (trying to save a channel) all you need to do is this:
        1. ws:inbound-gateway -> Receive a web service call, transform the incoming xml.
        2. tcp:outbound-gateway -> Send the transformed xml to a server via a socket
        3. no need to do anything since the above component (#2) is a gateway which mens it will produce a reply for "Receive the response xml from the server via the socket."
        4 no need to do anything either since reply goes back to ws:inbound-gateway

        Hope that clarifies

        Comment


        • #5
          Oleg,

          I did that in the first place and it did work but I need the socket connection for other messages as well. So I changed it from a gateway to using 2 tcp adapters. I will receive other unsolicited messages coming in on that socket. I plan on putting a content based router in to handle those other messages.

          Any other suggestions for NOT using a tcp gateway in my web service to get this done?

          Comment


          • #6
            I am not sure I understand "I need the socket connection for other messages as well". THat is the whole point of the gateway - to correlate responses so you can send as many messages as you want and receive proper replies. In fact you can have many WS gateways all interacting with a single TCP gateway and all will get the correct response. What am I missing?

            Comment


            • #7
              Well,

              I am integrating with a legacy system that was communicating with a SOA system. The legacy system is written in C++.
              The original socket was able to send messages and receive messages. So I am using that 1 original socket for the same use. It can send me a message any time and I will forward it to a Web service call and I will send the WS response back to the socket. Also using the same socket when a Web server call is received it will be sent to the socket and the reply will be sent back out the WS call.

              So my socket is being used as a client AND a server. This is pretty typical in legacy socket based applications.

              Comment


              • #8
                I think you are getting confused with the way gateway correlation mechanism works and trying to create your own correlation when you really don't need to do that since gateway will take care of that regardless how long does it take for the reply to come in.
                For example:

                Message A comes in from WS and lands on the socket, the other side receives it and begins its processing
                Message B comes in from WS and lands on the socket, the other side receives it and begins its processing

                Message B processing happened faster then Message A and the reply for Message B ends up on the WS gateway before Message A

                Rest assured that the caller of Message B will receive a reply (not the caller of Message A). That is what those temp reply channels are for - to ensure that replies are properly correlated.

                Is that the source of confusion?

                Comment


                • #9
                  No,

                  I know that the correlation will work. The issue is when the gateway receives a message when it did not send one out.

                  I need to support both scenarios:

                  Message A comes in from WS and lands on the socket, the other side receives it and begins its processing, and responds.
                  Message B comes in from socket and is sent to a WS, which sends it, receives the reply and put the message back on the socket.

                  I am trying to use 1 socket for both scenarios.

                  Comment


                  • #10
                    I see, I'll let Gary chime in since its his domain, but you may need to wait a bit since he is on the other side of the earth at he moment tHis may not be supported currently but certainly an interesting use case.

                    Comment


                    • #11
                      BTW,

                      Getting the response channel as an object and putting it back on the outgoing web service message worked! Looks like you do support this use case. You just have to use the MessageChannel object with the header-enhancer instead of a string and it works like a champ!

                      Thanks for all your help,

                      Frank

                      Comment


                      • #12
                        I was gonna suggest the same thing, but was on the road ta the time so I am glad you figured it out.

                        Comment


                        • #13
                          Glad you figured it out; sorry I wasn't able to participate in the discussion (thanks Oleg!).

                          For other readers of the thread, there is an alternative approach to reinstating the replyChannel header when using paired adapters explored in this sample: https://github.com/SpringSource/spri...rver-multiplex

                          This probably only a good solution for simple request/response applications, rather than multi-use as in the case of this thread.

                          Comment

                          Working...
                          X