1

I am supposed to interact with a legacy system where I have to setup a TCP client using spring-integration in java/kotlin to send a message to a TCP system and receive its response, parse this response and send it to other client via REST. I went through many documentations and blogs which tells how to do via xml. Not able to find corresponding annotations for everything. Any code snippet will be very helpful.

@Service
class MyService{

@Autowired
MyGateway gateway;

public String callTCPClient(String msg){
    return gateway.exchange(msg);
}

}
interface MyGateway{
String exchange (String msg)
}
Prasad
  • 368
  • 1
  • 6
  • 16
  • See [this answer](https://stackoverflow.com/questions/54057281/spring-boot-tcp-client/54057755#54057755) for a DSL example of both client and server. – Gary Russell May 14 '19 at 14:03
  • @GaryRussell I saw your post. I didnt understand few things. Please correct me if I am wrong, I create an interface and mark it as a gateway (MyGateway.java) so that when we call that interface method, spring knows it has to send that message to the client. What I didnt understand in your code is, when we receive the response from the client, it is transforming the code there itself. What should I do if I have a more complex transformation? What if I want to call a method which is in a separate service class? Can you please briefly explain it to me. – Prasad May 14 '19 at 14:22
  • @GaryRussell And also how do I tell the inbound gateway to listen to the response of the request which I sent via outbound gateway? – Prasad May 14 '19 at 14:37
  • See my answer; I don't understand the question in your second comment. – Gary Russell May 14 '19 at 14:46
  • @GaryRussell what I meant in my second comment is, when we declare a server connection to receive the response, how to tell it to listen to the response of the request which was just sent via the TCP client? In the spring documentation it is given that 'An outbound channel adapter uses a client connection factory, but you can also provide a reference to a client connection factory to an inbound channel adapter. That adapter receives any incoming messages that are received on connections created by the outbound adapter.' Can you please let me know how to achieve this? – Prasad May 14 '19 at 14:55
  • Using collaborating channel adapters is more difficult than using gateways because you have to take care of correlating requests to replies yourself. Using gateways is simpler. The server gateway listens on the port that the client connects to and the framework takes care of everything for you. – Gary Russell May 14 '19 at 15:03
  • @GaryRussell so you are telling that there is no need for me to create a separate server to listen to response and client will itself take care of listening to the response? In that case which annotation should I use on the gateway interface? Now I am using this annotation on the gateway interface @MessagingGateway(defaultRequestChannel = "toTcp") – Prasad May 14 '19 at 15:14
  • It's not clear what you are asking; that example contains both a client and a server; if you are talking to an existing server then, of course, you don't need the server configuration here. You just need to be sure the client's serializer/deserializer are compatible with your existing server with respect to message formats. – Gary Russell May 14 '19 at 15:29
  • @GaryRussell ok got that now. Sorry for the confusion :D So then I guess I dont have to use any annotation on my gateway interface then? Just create an interface with one method as you have in your example? – Prasad May 14 '19 at 15:34
  • When you use a gateway at the start of the DSL, the channel is implied; you don't need to specify it. – Gary Russell May 14 '19 at 15:36
  • @GaryRussell Thank you for the clarification :) – Prasad May 14 '19 at 15:38
  • @GaryRussell you told that I dont need to use any annotation on top of the interface. If I dont use, I am getting exception saying I have to define a bean of that type. If I use 'MessagingGateway' annotation it is throwing requestchannel is required! How to solve this problem? – Prasad May 14 '19 at 16:31
  • Did you notice the `@DependsOn` in the other answer (where the gateway is referenced)? We need to be sure the integration flow bean is created first. – Gary Russell May 14 '19 at 16:34
  • @GaryRussell Yes I noticed that, but I want to pass a message from one of my service to that interface method. When I try to autowire that interface in my service it throws the exception. – Prasad May 14 '19 at 16:37
  • Right, so your service bean needs the `@DependsOn`. – Gary Russell May 14 '19 at 16:39
  • @GaryRussell I didnt get where I should use the @DependsOn! :( Can you please provide a code snippet and help me to understand better? – Prasad May 14 '19 at 16:44
  • Spring has no information about the dependency, so we have to help it. I can't "guess" about your configuration; add the relevant `@Bean`s to your question. – Gary Russell May 14 '19 at 16:50
  • @GaryRussell I added the service code to the question from where I am trying to call the gateway interface. – Prasad May 14 '19 at 16:52
  • @GaryRussell I got to know!! Finally!!!!! :D Thanks a lot once again for being patient with me :) I was breaking my head all day for this! – Prasad May 14 '19 at 17:00
  • Add the `@DependsOn` to `MyService` (before or after the `@Service`) – Gary Russell May 14 '19 at 17:01
  • @GaryRussell Thank you once again. It worked finally. Hopefully, I can continue further :) – Prasad May 14 '19 at 17:13
  • @GaryRussell How can I handle timeout and no reply exceptions? – Prasad May 16 '19 at 13:42
  • Please don't ask new questions here; especially when this one has so many comments; the timeout exception will be thrown to the gateway called. – Gary Russell May 16 '19 at 14:00
  • ok. I will make sure to ask a new question. Thanks – Prasad May 16 '19 at 14:09

1 Answers1

1

As is shown in that answer, you can do whatever you want after the response is received...

@Bean
public IntegrationFlow client() {
    return IntegrationFlows.from(MyGateway.class)
            .handle(Tcp.outboundGateway(
                Tcp.netClient("localhost", 1234)
                    .serializer(codec()) // default is CRLF
                    .deserializer(codec()))) // default is CRLF
            .transform(Transformers.objectToString()) // byte[] -> String
            .get();
}

In this case, we simply transform the byte array to a String, but you can perform whatever operations you want on it, e.g. JSON to Object. You can add as many steps as you want - add .handle(...) elements to call arbitrary methods. Read the Spring Integration Reference Manual.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179