Results 1 to 10 of 16

Thread: 2 way tcp socket adapter?

Hybrid View

  1. #1
    Join Date
    Sep 2011
    Posts
    15

    Default 2 way tcp socket adapter?

    Hello,
    I'm pretty new to Spring and Spring integration. I'd like an app that can create 2 tcp sockets for bidirectional communication. I can't quite figure out how to set up 1 socket that can do 2 way communication. It seems that the tcp adapters are 1 way only? I want a client app to connect to my 2 sockets and be able to send/receive from both of those sockets.

    Any help would be appreciated.

    Thanks,
    Walt

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

    Default

    For simple request/reply 2 way comms, use an <int-ip:outbound-gateway/> for each.

    For completely asynchronous 2-way communication, use the same client connection factory in both an outbound and inbound adapter (see section about collaborating channel adapters in the reference manual). Note, however, that the connection is not established until a message is sent. There is an open JIRA issue asking for the connection to be established independent of actually sending a message; it should be addressed soon. https://jira.springsource.org/browse/INT-1770
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  3. #3
    Join Date
    Sep 2011
    Posts
    15

    Default

    Thanks Gary. Here is my xml snippet to pass by you to make sure I understand...

    I'm hoping this sets up 1 socket that I can connect to on port 12345 and send and receive messages to/from ?

    <ip:tcp-connection-factory id="DebugEngineCommandsFactory"
    type="server"
    port="12345"
    deserializer="javaDeserializer"
    serializer="javaSerializer"
    />

    <!-- take messages from -->
    <ip:tcp-outbound-channel-adapter id="CommandsOutputAdapter"
    channel="CommandsOutputChannel"
    connection-factory="DebugEngineCommandsFactory"/>

    <ip:tcp-inbound-channel-adapter id="CommandsInputAdapter"
    channel="CommandsInputChannel"
    connection-factory="DebugEngineCommandsFactory"/>

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

    Default

    Correct.

    The only thing you have to be careful about on the server side is to make sure any outgoing messages have the correct 'ip_connection_id' header - that's how we know which connection to use. If the message originates from the inbound adapter, the header will already be filled in, but it you construct a new message, it needs the header.

    This is also true if you put an error channel on the inbound adapter, the error message won't have the header, but the failed message will. Here is an example of how to handle errors and send some response to the client - it is a modified version of the tcp-client-server sample application, modified to use adapters instead of a gateway...

    Code:
    <!-- 	<ip:tcp-inbound-gateway id="gatewayCrLf" -->
    <!-- 		connection-factory="crLfServer" -->
    <!-- 		request-channel="serverBytes2StringChannel"  -->
    <!-- 		error-channel="errorChannel"/> -->
    
    	<ip:tcp-inbound-channel-adapter
    		connection-factory="crLfServer" error-channel="errorChannel"
    		channel="serverBytes2StringChannel"/>
    		
    	<ip:tcp-outbound-channel-adapter connection-factory="crLfServer" channel="fromSA"/>
    			
    	<channel id="toSA" />
    	<channel id="fromSA" />
    
    	<service-activator input-channel="toSA"
    					   output-channel="fromSA"
    					   ref="echoService"
    					   method="test"
    	/>
    
    	<beans:bean id="echoService" 
    		  class="org.springframework.integration.samples.tcpclientserver.EchoService" />
    		  
    	<transformer id="serverBytes2String"
    		input-channel="serverBytes2StringChannel"
    		output-channel="toSA" 
    		expression="new String(payload)"/>
    		
    	<chain input-channel="errorChannel" output-channel="fromSA">
    		<header-enricher>
    			<header name="ip_connection_id" expression="payload.failedMessage.headers.ip_connection_id"/>
    		</header-enricher>
    		<transformer
    			expression="payload.failedMessage.payload + ':' + payload.cause.message"/>
    	</chain>
    The <chain/> at the end copies the header from the failed message.

    In future, please use [ code ] ... [ /code ] tags around code and config snippets (no spaces inside the brackets).
    Last edited by Gary Russell; Oct 13th, 2011 at 02:43 PM.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  5. #5
    Join Date
    Sep 2011
    Posts
    15

    Default asynchronous isn't working

    Howdy,
    I sort of have this working, but when I want to send a message without it being a response to an incoming I get a spring exception.

    Here is the scenario.
    server is the spring integration app that creates 2 tcp server adapters as described in our previous messages in this thread.

    The client app can send messages to both of the 2 tcp sockets, and the SI app can send replies to those incoming messages as a return value in the endpoint method.

    Now I need to send a message out one of the tcp sockets asynchronously to send something to the client. This is when I get an exception.

    Code:
    org.springframework.integration.MessageHandlingException: error occurred in message handler [org.springframework.integration.ip.tcp.TcpSendingMessageHandler#1]

    Here is my relevant context file

    Code:
       <ip:tcp-connection-factory id="DebugEngineEventsFactory"
        type="server"
        port="${debug.engine.events.port}"
        using-nio="false"
      />
    
        <ip:tcp-outbound-channel-adapter id="EventsOutputAdapter"
           channel="EventsOutputChannel"
           connection-factory="DebugEngineEventsFactory"/>
    
        <ip:tcp-inbound-channel-adapter id="EventsInputAdapter"
           channel="EventsInputChannel"
           connection-factory="DebugEngineEventsFactory"/>
    
        <gateway id="StudioEventGateway" service-interface="com.hp.oo.studio.debug.engine.gateways.StudioGateway"
    	         default-request-channel="SendEventsExecutorChannel" />
    
        <chain input-channel="SendCommandsExecutorChannel" output-channel="CommandsOutputChannel">
    		<integration:object-to-json-transformer object-mapper="customObjectMapper"/>
    	    <transformer expression="new String(payload)"/>
        </chain>
    
        <chain input-channel="EventsInputChannel" output-channel="ReceiveEventsExecutorChannel">
    	<transformer expression="new String(payload)"/>
    	<integration:json-to-object-transformer type="com.hp.oo.studio.debug.engine.shared.protocol.events.DebugEvent"
    	                object-mapper="customObjectMapper" />
            <header-enricher>
    		<header name="replyChannel" value="SendEventsExecutorChannel"/>
               </header-enricher>
        </chain>
    
       <service-activator input-channel="ReceiveEventsExecutorChannel"
    	                   ref="DebugExecutorService"
    	                   method="eventFromStudio" />

    Async java method

    Code:
    	
    /** 
      * this method is run asynchronously as part of an event loop in the app 
      * itself.   We need to send an "event" back to the client.  But Spring
      * fails to send the message, even though we successfully sent an 
      * message out the event channel already as a reply from an incoming
      * message.
      *
      */
    void sendDebugEvent(IDebugEvent event, boolean error) {
            if (debugMode) {
                try {            	            	
    
                    //I tried this and it fails as well.
                	/*StudioEventGateway = (StudioGateway)context.getBean("StudioEventGateway");
                	StudioEventGateway.send(event);*/
                	
                    //this doesn't work either.
                    ChannelResolver channelResolver = new BeanFactoryChannelResolver(context);		
                	MessageChannel output = channelResolver.resolveChannelName("SendEventsExecutorChannel");
    
                    //exception here....             	
                	output.send(new GenericMessage<IDebugEvent>(event));
    
                } catch (Exception e) {
                    System.err.println("Error: " + e);
                    System.exit(1);
                }
            } else if (error) {
                System.err.println("Error: " + event);
            }
        }
    
    
            /** 
              * THIS works...but is the input endpoint from the client.
              * the reply object gets sent out the channel to the client.
              *
              */
    	public IDebugEvent eventFromStudio(DebugEvent event) {		
    		IDebugEvent responseEvent = new DebugEvent();
    		return responseEvent;
    	}

  6. #6
    Join Date
    Sep 2011
    Posts
    15

    Default asynchronous isn't working

    Howdy,
    I sort of have this working, but when I want to send a message without it being a response to an incoming I get a spring exception.

    Here is the scenario.
    server is the spring integration app that creates 2 tcp server adapters as described in our previous messages in this thread.

    The client app can send messages to both of the 2 tcp sockets, and the SI app can send replies to those incoming messages as a return value in the endpoint method.

    Now I need to send a message out one of the tcp sockets asynchronously to send something to the client. This is when I get an exception.

    Code:
    org.springframework.integration.MessageHandlingException: error occurred in message handler [org.springframework.integration.ip.tcp.TcpSendingMessageHandler#1]

    Here is my relevant context file

    Code:
       <ip:tcp-connection-factory id="DebugEngineEventsFactory"
        type="server"
        port="${debug.engine.events.port}"
        using-nio="false"
      />
    
        <ip:tcp-outbound-channel-adapter id="EventsOutputAdapter"
           channel="EventsOutputChannel"
           connection-factory="DebugEngineEventsFactory"/>
    
        <ip:tcp-inbound-channel-adapter id="EventsInputAdapter"
           channel="EventsInputChannel"
           connection-factory="DebugEngineEventsFactory"/>
    
        <gateway id="StudioEventGateway" service-interface="com.hp.oo.studio.debug.engine.gateways.StudioGateway"
    	         default-request-channel="SendEventsExecutorChannel" />
    
        <chain input-channel="SendCommandsExecutorChannel" output-channel="CommandsOutputChannel">
    		<integration:object-to-json-transformer object-mapper="customObjectMapper"/>
    	    <transformer expression="new String(payload)"/>
        </chain>
    
        <chain input-channel="EventsInputChannel" output-channel="ReceiveEventsExecutorChannel">
    	<transformer expression="new String(payload)"/>
    	<integration:json-to-object-transformer type="com.hp.oo.studio.debug.engine.shared.protocol.events.DebugEvent"
    	                object-mapper="customObjectMapper" />
            <header-enricher>
    		<header name="replyChannel" value="SendEventsExecutorChannel"/>
               </header-enricher>
        </chain>
    
       <service-activator input-channel="ReceiveEventsExecutorChannel"
    	                   ref="DebugExecutorService"
    	                   method="eventFromStudio" />

    Async java method

    Code:
    	
    /** 
      * this method is run asynchronously as part of an event loop in the app 
      * itself.   We need to send an "event" back to the client.  But Spring
      * fails to send the message, even though we successfully sent an 
      * message out the event channel already as a reply from an incoming
      * message.
      *
      */
    void sendDebugEvent(IDebugEvent event, boolean error) {
            if (debugMode) {
                try {            	            	
    
                    //I tried this and it fails as well.
                	/*StudioEventGateway = (StudioGateway)context.getBean("StudioEventGateway");
                	StudioEventGateway.send(event);*/
                	
                    //this doesn't work either.
                    ChannelResolver channelResolver = new BeanFactoryChannelResolver(context);		
                	MessageChannel output = channelResolver.resolveChannelName("SendEventsExecutorChannel");
    
                    //exception here....             	
                	output.send(new GenericMessage<IDebugEvent>(event));
    
                } catch (Exception e) {
                    System.err.println("Error: " + e);
                    System.exit(1);
                }
            } else if (error) {
                System.err.println("Error: " + event);
            }
        }
    
    
            /** 
              * THIS works...but is the input endpoint from the client.
              * the reply object gets sent out the channel to the client.
              *
              */
    	public IDebugEvent eventFromStudio(DebugEvent event) {		
    		IDebugEvent responseEvent = new DebugEvent();
    		return responseEvent;
    	}

  7. #7
    Join Date
    Sep 2011
    Posts
    15

    Default

    I've tried replying to this thread twice now and neither of those posts are showing up....what gives?

    I'll try again.....

    Ok I just sent another reply after this one and I don't see it here. It included a long description of my new problem as well as code blocks. *sigh*


    I can't send asynchronous messages out a tcp adapter that's already received a message.
    Last edited by hemna; Oct 27th, 2011 at 11:07 AM.

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

    Default

    I did see your message as an email notification but when I came here it was gone; not sure why - I assumed you had (somehow) deleted it.

    I haven't had a chance to take a detailed look at your configuration but I see you have no so-timeout on your connection factory. I recently added a note about this to the reference document. There is currently a default 10 second timeout when using collaborating adapters.

    You didn't show the full stack trace so I can't be sure that's what you are seeing, but I am guessing so.

    If using 2.0, try setting so-timeout to some large number (in 2.1.M3 you can set to 0 for infinity). You can set it to some reasonable number (milliseconds), or set it to the max with a SpEL expresion #{T (java.lang.Integer).MAX_VALUE}.

    HTH
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

Posting Permissions

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