0
votes

I have a Spring Integration application that is using a Inbound/Outbound Adapter combination for sending and receiving TCP messages. I am trying to correlate the message that is sent with the response that is received for that request but am running into some issues.

My current configuration looks like this...

@Bean
public AbstractServerConnectionFactory serverConnectionFactory() {
    return new TcpNetServerConnectionFactory(15000);
}

@Bean
public TcpReceivingChannelAdapter inboundAdapter() {
    TcpReceivingChannelAdapter inboundAdapter = new TcpReceivingChannelAdapter();
    inboundAdapter.setConnectionFactory(serverConnectionFactory());
    inboundAdapter.setOutputChannel(receiveResponse());
    return inboundAdapter;
}

@Bean
@ServiceActivator(inputChannel="sendRequest")
public TcpSendingMessageHandler outboundAdapter() {
    TcpSendingMessageHandler outboundAdapter = new TcpSendingMessageHandler();
    outboundAdapter.setConnectionFactory(serverConnectionFactory());
    return outboundAdapter;
}

@Bean
public MessageChannel receiveResponse() {
    return new DirectChannel();
}

@MessagingGateway(defaultRequestChannel="sendRequest", defaultReplyChannel="receiveResponse") 
public interface RequestSender {
    public String sendRequest(@Payload String payload, @Header(IpHeaders.CONNECTION_ID) String connectionId);
}

Everything configures as expected on boot, when the RequestSender.sendRequest() method is called the message is sent, a response is sent back (I have another application that is responding) but I run into the follow error once the response hits my inboundAdapter. The error is...

org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application.receiveResponse'.

Based on what I have read about the MessagingGateway, the replyChannel is the channel for which the gateway will listen on for a reply. So I would think that whatever the inbound adapter receives, that is what would ultimately be returned from the RequestSender.sendRequest() method. However, in my case it appears the MessagingGateway is failing to subscribe to the receiveResponse channel.

Is there a way to implement a MessagingGateway in this fashion? If so, what seems to be preventing my current configuration from acting in the way that I hope for?

1

1 Answers

0
votes

First of all there is some misleading in your explanation. You talk about a receiveResponse, but error shows us a handleResponse and there is no one in your config.

Please, correct your question the way it won't confuse us.

Another concern is: what is the point to use channel adapters combination when you still have a sync gateway on top of that network interaction and going to block calling thread anyway. How about to consider to use a TcpOutboundGateway instead? BTW, starting with the latest 5.3 version that one supports an async mode, so your @MessagingGateway could be an async one, too: https://docs.spring.io/spring-integration/docs/5.3.0.BUILD-SNAPSHOT/reference/html/whats-new.html#x5.3-tcp.

Anyway the problem what you are facing is a transfer of replyChannel identificator over the network for the server and back together with a reply.

For such a task we have introduced a feature called header-channels-to-string: https://docs.spring.io/spring-integration/docs/5.3.0.M4/reference/html/message-transformation.html#header-channel-registry. So a TemporaryReplyChannel object is stored in the registry and its header in the request message is replaced with some string ID. That replyHeader has to be sent over the network and must come back in the reply message headers.

The problem is much bigger in your case since TCP/IP doesn't support headers. Therefore you need to come up with some mechanism to carry headers together with payload in the TCP package. See some approach in the docs: https://docs.spring.io/spring-integration/docs/5.3.0.M4/reference/html/ip.html#ip-headers.

But saying all of that I still think that you need to come back to the TcpOutboundGateway solution...