0

We are using spring integration application for data receiption from gps devices. For current configuration we are able to receive data from device also respose sent back to device through same connection

current configuration is as

@SpringBootApplication
@IntegrationComponentScan
public class SpringIntegrationApplication extends SpringBootServletInitializer{ 

private Integer TIMEOUT=1000*60*10;

    @Value("${TCP_PORT}")
    private Integer TCP_PORT;

    public static void main(String[] args) throws IOException {
        ConfigurableApplicationContext ctx = SpringApplication.run(SpringIntegrationApplication.class, args);       
        System.in.read();
        ctx.close();
    }

    @Bean
    TcpNetServerConnectionFactory cf(){
        TcpNetServerConnectionFactory connectionFactory=new TcpNetServerConnectionFactory(TCP_PORT);

        connectionFactory.setSerializer(new CustomSerializerDeserializer());
        connectionFactory.setDeserializer(new CustomSerializerDeserializer());
        connectionFactory.setSoTimeout(TIMEOUT);
        return connectionFactory;
    }

    @Bean
    TcpInboundGateway tcpGate(){

        TcpInboundGateway gateway=new TcpInboundGateway();
        gateway.setConnectionFactory(cf());
        gateway.setRequestChannel(requestChannel());
        gateway.setRequestTimeout(TIMEOUT);
        return gateway;
    }

    @Bean
    public MessageChannel requestChannel(){

        return new DirectChannel();
    }
}

and message end point

@MessageEndpoint 
public class Echo { 

    @ServiceActivator(inputChannel="requestChannel")
    public byte[] echo(byte[] in,@SuppressWarnings("deprecation") @Header("ip_address") String ip){
        //here we receive packet data in bytes from gps device
        return  "".getBytes();//string will contains expected result for device.
    }

Above configuartion works fine for one way communication. but we want to implement two way communication. What we want after connection established between server and device we want to send message explicitely.To send command through server we dont know ip and port of device, so how can we send command through server to connected device.

I am trying following solution

created oubound channel adapter

@Bean       
    public TcpSendingMessageHandler tcpSendingMessageHandler() {
        System.out.println("Creating outbound adapter");
        TcpSendingMessageHandler outbound = new TcpSendingMessageHandler();
        return outbound;
    }

then created gateway for explicite message send, this will be called from service where we want to send data explicitely

@MessagingGateway(defaultRequestChannel="toTcp")
    public static interface tcpSendService {    
        public byte [] send(String string);
    }

After calling gate way following service activator invoked where we are setting connection ip and port, these ip and ports will be from connection established while receiving data from device

@ServiceActivator(inputChannel="toTcp", outputChannel="fromTcp")    
    public String send(String in){              
        System.out.println(new String(in));     
        TcpNetClientConnectionFactory factory = new TcpNetClientConnectionFactory(ip_extracted_from_inbound_connection, port_extarcted_from_inbound_connection);
        factory.start();        
        tcpSendingMessageHandler.setConnectionFactory(factory);                     
        return in;
    }

// for ip and port extraction i am using following service which is inbound sevice

@ServiceActivator(inputChannel="requestChannel")
    public byte[] echo(byte[] in,@Header("ip_address") String ip){              
        System.out.println(new String(in)+ " ; IP : "+ip);

        for (String connectionId : factory.getOpenConnectionIds()) {
            if(!lastConection.contains(ip))
                lastConection = connectionId;               
        }

        return "hello".getBytes();
    }

For service activator i am setting new TcpNetClientConnectionFactory every time service called. Ip and port are extracted from TcpNetServerConnectionFactory. whenever device connects with server i am saving its connection ip and port, using these ip and port for data transmission through server but i am getting connection timeout issue.

Kindly help me out and suggest me a solution over it.

Thank you.

1 Answers1

0

Replace the gateway with a pair of Collaborating Outbound and Inbound Channel Adapters.

In order to send arbitrary messages to a connection, you must set the ip_connectionId header.

The challenge, though, is how to direct the reply to the gateway. You would need to capture the replyChannel header from the request and, when a reply is received for that ip_connectionId, set the replyChannel headers.

This will only work, though, if you have only one request/reply outstanding to each device at a time, unless there is some data in the reply that can be used to correlate it to a request.

Another challenge is race conditions, where the device and the server initiate a request at the same time. You would need to look at data in the inbound message to see if it's a request or reply.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thanks Gary. As you can see I am using TcpNetServerConnectionFactory hence how can we use same connection factory for both ie inbound and outbound Adapter. Is there any sample application present for same. – Shridhar kolsure May 03 '18 at 16:13
  • You simply inject the same factory into both; there is a sample [here](https://github.com/spring-projects/spring-integration-samples/tree/master/intermediate/tcp-client-server-multiplex). It's XML-based for configuration, but the same techniques apply. It uses an aggregator to deal with retaining the `replyChannel` but a simply Map is probably all you need. – Gary Russell May 03 '18 at 17:19