Results 1 to 8 of 8

Thread: inbound TCP and serviceActivator response gets stuck

  1. #1
    Join Date
    Dec 2007
    Location
    Stockholm, Sweden
    Posts
    190

    Default inbound TCP and serviceActivator response gets stuck

    I have configured inbound TCP service which is more or less like how it is described for UDP in http://blog.springsource.com/2010/03...ration-2-0-m3/

    I can execute

    PHP Code:
    echo -"Hello\r\n" nc localhost 9901 
    easily for void accumultae, but not for some thing which returns a value

    I am getting the folliwng trace
    PHP Code:
    DirectChannelpreSend on channel 'tcpChannel'message: [Payload=[B@578baf24][Headers={$ip_hostname=127.0.0.1$ip_address=127.0.0.1$timestamp=1270747841142$history=[{timestamp=1270747841144componentName=tcpChannelcomponentType=channel}], $id=90499407-bb6c-4085-9308-7c9069b6e829}]
    ServiceActivatingHandlerServiceActivator for [com.tesenso.trackandroute.biz.Persister]] received message: [Payload=[B@578baf24][Headers={$ip_hostname=127.0.0.1$ip_address=127.0.0.1$timestamp=1270747841142$history=[{timestamp=1270747841144componentName=tcpChannelcomponentType=channel}, {timestamp=1270747841145componentName=activatorcomponentType=service-activator}], $id=90499407-bb6c-4085-9308-7c9069b6e829}]
    5
    ServiceActivatingHandler
    handler 'ServiceActivator for [com.tesenso.trackandroute.biz.Persister]]' sending reply Message: [Payload=1
    ][Headers={$ip_hostname=127.0.0.1$ip_address=127.0.0.1$timestamp=1270747841142$history=[{timestamp=1270747841144componentName=tcpChannelcomponentType=channel}, {timestamp=1270747841145componentName=activatorcomponentType=service-activator}], $id=90499407-bb6c-4085-9308-7c9069b6e829}]
    DirectChannelpreSend on channel 'tcpChannel'message: [Payload=1
    ][Headers={$ip_hostname=127.0.0.1$ip_address=127.0.0.1$timestamp=1270747841142$history=[{timestamp=1270747841144componentName=tcpChannelcomponentType=channel}, {timestamp=1270747841145componentName=activatorcomponentType=service-activator}, {timestamp=1270747841209componentName=tcpChannelcomponentType=channel}], $id=90499407-bb6c-4085-9308-7c9069b6e829}]
    ServiceActivatingHandlerServiceActivator for [com.tesenso.trackandroute.biz.Persister]] received message: [Payload=1
    ][Headers={$ip_hostname=127.0.0.1$ip_address=127.0.0.1$timestamp=1270747841142$history=[{timestamp=1270747841144componentName=tcpChannelcomponentType=channel}, {timestamp=1270747841145componentName=activatorcomponentType=service-activator}, {timestamp=1270747841209componentName=tcpChannelcomponentType=channel}, {timestamp=1270747841209componentName=activatorcomponentType=service-activator}], $id=90499407-bb6c-4085-9308-7c9069b6e829}]
    GenericConversionServiceConditional converter lookup [DID NOT MATCHorg.springframework.core.convert.support.IdToEntityConverter@31dbfb7a
    GenericConversionService
    Conditional converter lookup [DID NOT MATCHorg.springframework.core.convert.support.ObjectToObjectConverter@615b2028
    GenericConversionService
    Conditional converter lookup [DID NOT MATCHorg.springframework.core.convert.support.ObjectToArrayConverter@259c5407 
    What I need is to get a message from TCP and reply to it instantly after posting it to a JMS queue. The reply needs to be tailored (ie I need to send Date, Time and some other parameters)
    Shahzada Hatim
    @geoaxis/twitter
    http://hatimonline.com

  2. #2
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,012

    Default

    In Spring Integration, Channel Adapters are unidrectional devices (inbound or outbound). You need an inbound TCP Gateway, which we are considering; vote for the JIRA here...

    https://jira.springsource.org/browse/INT-1008

  3. #3
    Join Date
    Dec 2007
    Location
    Stockholm, Sweden
    Posts
    190

    Default

    I see, for some reason I thought that Gateway only affected once you got more than one message on the same channel and needed some state to maintain to route them back.

    But in the case if JIRA issue is far away, could you suggest any modification to current implementation. I just need to send customized responses to incoming TCP requests (which I then offload to JMS for processing). So every response is essentially a success response (assuming things were put in JMS wueue) and response will include some simple text (like current time + OK, or it may include more data like advice on time of next TCP inbound message)
    Shahzada Hatim
    @geoaxis/twitter
    http://hatimonline.com

  4. #4
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,012

    Default

    @hatim

    The challenge is correlating responses to clients. If you only need to support a single client, one way to quickly do it would be as follows...

    Subclass the TcpNetReceivingChannelAdapter. Add an instance variable

    Code:
    private PollableChannel responseChannel;
    as well as a setter.

    Copy the handleSocketMethod from TcpNetReceivingChannelAdapter into the subclass. I hate copying all that code but it would need a little refactoring to provide an extension point here.

    In that method, after sendMessage(message) add the following...

    Code:
    Message<String> out = (Message<String>) responseChannel.receive();
    socket.getOutputStream().write(out.getPayload().getBytes());

    (Note this will only work if there is one client connected to the Gateway; otherwise you'd need code to look at the the message headers and correlate the response, and the receive would have to be done on another thread and the response messages distributed to the appropriate socket).


    The Spring config would look something like...

    Code:
    	<bean id="tcpGateway" class="my.TcpNetReceivingGateway">
    		<constructor-arg value="15300"/>
    		<property name="outputChannel" ref="toSA"/>
    		<property name="responseChannel" ref="fromSA"/>
    		<property name="messageFormat" value="#{T(org.springframework.integration.ip.tcp.MessageFormats).FORMAT_CRLF}" />
    	</bean>
    
    	<int:channel id="toSA" />
    	
    	<int:channel id="fromSA">
    		<int:queue capacity="1"/>
    	</int:channel>
    	
    	<int:service-activator id="SA" 
    		input-channel="toSA"
    		output-channel="fromSA"
    		ref="sa"
    		method="test"
    	/>
    	
    	<bean id="sa" class="my.TestSA" />
    TestSA
    Code:
    	public String test(byte[] bytes) {
    		System.out.println("Received " + new String(bytes));
    		return "OK";
    	}
    Result
    Code:
    echo -e "abc\r\n" | nc localhost 15300
    OK
    Note that this is not how the actual gateway will be implemented; it is just a quick and dirty way to get what you need.

    HTH

    Gary
    Last edited by Gary Russell; Apr 8th, 2010 at 07:07 PM.

  5. #5
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,012

    Default

    And, if you *do* need to support multiple clients this way, it should be relatively easy - just have a (synchronized) Map<Object,Socket> instance variable. After the send(), put the socket in the map, with the $id as a key.

    Change the responseChannel to a SubscribableChannel; implement MessageHandler and subscribe to it. In handleMessage(), examine the $id in the header and use it as a key to the Map to get the socket, send the response to the socket and remove the entry from the Map.
    Last edited by Gary Russell; Apr 9th, 2010 at 07:21 AM.

  6. #6
    Join Date
    Dec 2007
    Location
    Stockholm, Sweden
    Posts
    190

    Default

    @Gary
    I tried the newly put telnet server as well as this approach.

    The telnet server works fine with telnet client. how ever I am not getting any thing with nc echo -e "abc\r\n" | nc localhost 15300

    Also when using a service activator, If I specify a output channel, the systems goes hay wire.

    The current application I am working with sends in a TCP messages and waits for an OK or Error TCP response and then closes the socket.
    Shahzada Hatim
    @geoaxis/twitter
    http://hatimonline.com

  7. #7
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,012

    Default

    @Hatim

    Works fine for me (both telnet and nc).

    See src/test/java/.../SimpleTcpNetInboundGatewayTests.java.

    I just ran this in debug mode after setting a breakpoint on line 152 (this holds the gateways open so we can test them interactively).

    Here are my results; note that the port may not be 5200 for you if that port is already in use (the test case finds the first available port starting at 5200).

    Code:
    gpr@arwen:~$ telnet localhost 5200
    Trying ::1...
    Connected to localhost.
    Escape character is '^]'.
    abc
    echo:abc
    ^]
    
    telnet> quit
    Connection closed.
    
    
    
    gpr@arwen:~$ echo -e "abc\r\n" | nc localhost 5200
    echo:abc
    ^C
    The service in the test case is a simple echo service.

    Please explain what you mean by "goes haywire". You don't need an output channel in this case because the gateway uses a temporary channel to receive the result.

    In any case, I added an output channel to this test case without any impact.

    Thanks

  8. #8
    Join Date
    Dec 2007
    Location
    Stockholm, Sweden
    Posts
    190

    Default

    @Gary

    Actually I did find the error and that it was incorrect use of cr+lf in the message being sent (from the sensor I am working with).

    sorry for being imprecise, I just needed some food to restart my brain

    But the following is working for me,
    PHP Code:
     <int:channel id="telnetInTransformerChannel" />

            <
    ip:inbound-gateway id="telnetGateway"
                       
    pool-size="10"
                   
    port="9901"
                   
    request-channel="telnetInTransformerChannel"
                    
    message-format="crlf" />

       

       <
    int:service-activator
                    id
    ="activator"
                    
    method="accumulate"
                    
    input-channel="telnetInTransformerChannel"
                    
    ref="persister" />

            <
    bean id="persister" class="blah.service.Persister" /> 
    And the method being
    Code:
    @Service
    @Transactional
    public class Persister {
    
            @ServiceActivator
            public String accumulate(byte[] buffer) {
                    System.out.println(new String(buffer));
                    InboundMessage ibm = new InboundMessage();
                    ibm.setMessage(new String(buffer));
    
                    //we need to send UTC here
                    ibm.setTimeRecieved(new Date());
                    ibm.persist();
                    SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return "OK(" + f.format(new Date()) + ")" ;
    
            }
    
    }
    But I will try to reproduce the infinite loop again later (I think it had to do some thing with return type being bye[] and service activator in the tcpGateway code poasted before, which I think should not be used since we now have a better alternative

    Really appreciate your help
    Shahzada Hatim
    @geoaxis/twitter
    http://hatimonline.com

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •