Spring Integration – Communication with legacy servers using TCP sockets

I recently faced a situation where I had to communicate with a legacy server (which only knows TCP – Sockets as communication channel). The client side application was entirely Spring (v4.0) based and I had to lookout for a standard way from the Spring arena to make this communication happen.

Read many articles over the net regarding Spring Integration module and finally came up with the following spring context, configuration and java code to establish the communication –

geocodeViaTCPCommunicationContext.xml –


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"    
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:int="http://www.springframework.org/schema/integration"    
       xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
       xmlns:context="http://www.springframework.org/schema/context"    
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
                           http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">
    <context:property-placeholder />
    <!-- Client side -->
    <int:gateway id="tcpGateway" service-interface="com.geocode.Gateway" default-request-channel="input"/>
    <int-ip:tcp-connection-factory id="client"
        type="client"
        host="${tcp.server.host}"
        port="${tcp.server.port}"
        single-use="true"
        so-timeout="100000"        
        serializer="connectionSerializeDeserialize"
        deserializer="connectionSerializeDeserialize"/>
    <int:channel id="input" />

    <int-ip:tcp-outbound-gateway id="outGateway"
        request-channel="input"
        reply-channel="clientBytes2StringChannel"
        connection-factory="client"
        request-timeout="100000"
        reply-timeout="100000"/>

    <int:object-to-string-transformer id="clientBytes2String" input-channel="clientBytes2StringChannel" />        
    <bean id="connectionSerializeDeserialize" class="org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer"/>
</beans>

 

GeocodeServiceImpl.java –

import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.transform.JDOMSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import geocode.Gateway;
import geocode.GeocodeRequest;
import geocode.GeocodeResponse;
import service.GeocodeService; 

@Service("geocodeService")
public class GeocodeServiceImpl implements GeocodeService {

    @Autowired
    Gateway tcpGateway;

    @Override
    public GeocodeResponse geocode(GeocodeRequest request) {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(GeocodeRequest.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); 

            // output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            jaxbMarshaller.marshal(request, System.out);

            StringWriter w = new StringWriter();
            jaxbMarshaller.marshal(request, w); 

            String responseString = tcpGateway.send(w.toString()); //send the marshalled request to legacy server and get response
            SAXBuilder builder = new SAXBuilder();
            Document responseDocument = builder.build(new StringReader(responseString)); //convert response into JDOM document
            Element responseEle = responseDocument.getRootElement().getChild("RESPONSE");

            if ("FAILED".equals(responseEle.getChildText("STATUS")) || responseEle.getChild("NOMATCHFOUND") != null || responseDocument.getRootElement().getChild("RESPONSE").getChild("STATUS").getText().equalsIgnoreCase("FAILED")) {
                GeocodeResponse geocodeResponse = new GeocodeResponse();
                geocodeResponse.setStatus(GeocodeResponse.UNMATCHED);
                return geocodeResponse;
            } else {
                List candidates = responseDocument.getRootElement().getChild("RESPONSE").getChildren("CANDIDATE");
                Element candidate1 = (Element) candidates.get(0);
                Source src = new JDOMSource(candidate1);
                JAXBContext jaxbResponseContext = JAXBContext.newInstance(GeocodeResponse.class); //Un-marshall the response into java object
                Unmarshaller u = jaxbResponseContext.createUnmarshaller();
                JAXBElement element = u.unmarshal(src, GeocodeResponse.class);
                GeocodeResponse geocodeResponse = (GeocodeResponse) element.getValue();
                geocodeResponse.setStatus(GeocodeResponse.MATCHED);
                return geocodeResponse;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

The pom.xml additional dependencies include –

 <dependency>
   <groupId>org.springframework.integration</groupId>
   <artifactId>spring-integration-test</artifactId>
   <version>${org.springframework-version}</version>
   <scope>compile</scope>
 </dependency>
 
 <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-test</artifactId>
   <version>${org.springframework-version}</version>
   <scope>test</scope>
 </dependency>
 
 <dependency>
   <groupId>org.springframework.integration</groupId>
   <artifactId>spring-integration-ip</artifactId>
   <version>${org.springframework-version}</version>
   <scope>compile</scope>
 </dependency></pre>
<pre>

One thought on “Spring Integration – Communication with legacy servers using TCP sockets

  1. Hi ,
    Thanks for this article. I have to the solve the problem you just described.
    I have just started using spring ( Java actually and specifically springboot).
    I wish you could help me whip-up a spring boot version. Just the bare bones to get me started.
    Thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s