Archive

Posts Tagged ‘spring integration’

How Spring Integration can alleviate your life.

June 23, 2013 Leave a comment

Some time ago I began a new job in big corporation. My first task was re-implement / re-import their C# tcp client to Java’s. Existed convertors have been sucking, so I did it manually. After week or so, freshy Java tcp client & server simulator have written & waited for further use. Having met with client’s requirements we found that Java’s implementation has a lack of important features such as: fail-over & auto-reconnection. Adding such functionality required from us add some untested code and might be insufficient flows in the business logic. One of our guys said, Aha, what if …? We can replace Java’s implementation to another one, for instance – Spring Integration. The rest of us smiled thinking what the heck? Anyway, my was is a good champ trying to take best technologies ever existed. We got a green light to do research & learn something exciting. To simplify our requirements I am going to show a simulator (aka server) & a client.

   Before delving deeper, let me explain what Spring Integration intended for. As their site suggests: “it provides an extension of the Spring programming model to support the well-known Enterprise Integration Patterns”. Rephrasing, to design good enterprise application one could use a messaging more precisely asynchronous messaging that enables diverse applications to be integrated each other without nightmare or pain. One of wise guys named Martin Fowler has written famous book “Enterprise Integration Patterns”. Folk from Spring probably one day decided to materialize a theory in practice. Very pragmatic approach, isn’t it? Later you will see how wonderful fits for regular tasks. The main concept of SI is: Endpoint, Channel & Message.

Endpoint is a component which actually does something with a message. A message is a container consisting of header & payload. The header contains data that’s relevant to the messaging system where the payload contains the actual data. Channel connects two or more endpoints, it’s similar to Unix’ pipes. Two endpoints can exchange messages iff they’re connected through a channel. Pretty easy, isn’t it? The following diagram shows this.

Image

    The next step to our crash course will be defining requirements. I would say, we need a server (a tcp) & tcp client. We will write a simple application that will exchange a couple of messages with each other.

    Important thing using SI is a configuration file which contains all necessary components that we going to use. Here is a “server” part of the configuration. Simplifying a model & SI lifecycle, Spring creates objects that defined in configuration xml. More generally such a concept called declarative programming. You define a business object in the xml, and a framework will generate appropriate classes for you, injects and initializes dependencies. The mantra says: you should be concentrated only on business and not on implementation.

    Let’s define a part of the configuration xml, the server part.

http://pastebin.com/6AHQWPse


<int-ip:tcp-connection-factory id="tcpServerFactory"
type="server"
port="23234"
single-use="false"
serializer="byteArrayLenSerializer"
deserializer="byteArrayLenSerializer" />
<int-ip:tcp-inbound-channel-adapter channel="serverIn"
connection-factory="tcpServerFactory"/>

<int-ip:tcp-outbound-channel-adapter channel=”serverOut”
connection-factory=”tcpServerFactory”/>

Important things are: i. A factory (tcp-connection-factory) – creates tcp server using byte array length serializer. A serializer is needed for “packaging” our message by some way or encode it in order to transmit it over a wire. On the other hand deserializer is needed for “unpackaging” our message or decode it. Spring Integration has two factories one for client & another – for the server. The difference is – by type [server or client]. A port – means to listen to for incoming messages. IP address not mentioned here because a server runs as a localhost.

   We also defined two channels: serverIn (for incoming messages) & serverOut (for outgoing messages). In order our server will send & receive messages we define inbound & outbound adapter which are associated with factory & channels. In our case it defines the endpoints. So, when message comes somewhat should take care of it. This responsibility takes a service, i.e. file sender service. If it accepts a message afterwards will send in background a file, line by line to the client. Basically, when a server starts, it listens for incoming messages however only specific message will be accepted and if that message is gotten, than server sends line by line a file. If an error occurs it’s routed to the error channel. It’s done using interceptor.

   I would say a couple of words about SI lifecycle.  Spring framework has two “main” packages: org.springframework.beans & org.springframework.context that builds up the core utility of the dependency injection of the component. The org.springframework.beans.factory.BeanFactory interface provide a basic lifecycle methods (start & stop) for bean initialization/destruction. The org.springframework.context.ApplicationContext offers AOP integration, message resource handling and even more.

Our server is ready, I mean, completely ready. To run the example follow the below steps:

  • cd /tcpserver
  • mvn clean install
  • mvn dependency:copy-dependencies
  • mvn exec:java -Dexec.mainClass=”org.example.tcpserver.ServerRunner” -Dexec.args=”–file=”/file_to_be_sent.txt””

Our main class expresses as follows:


CommandLinePropertySource clps = processProperties(args);
/* Spring Integration context used to get desirable beans. */
AbstractApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"server-config.xml"}, false);
context.getEnvironment().getPropertySources().addFirst(clps);
context.refresh();
context.registerShutdownHook();

 The source code can be found here http://pastebin.com/6PMpWTfX.

Also we define a file send service:


String key = new String(appropriateData, "UTF-8");
LOG.info("got.message" + " [" + key + "]");
/* If message accepted */
if (key.contains(SEARCH_KEY)) {
LogReader lr = new LogReader(sender, msg);
lr.setPath2File(getFile().getAbsolutePath());
es.execute(lr);
}

http://pastebin.com/icHRdQS3
Next, denote a business runner:


/* Creates an input stream to be read. */
fstream = new FileInputStream(getPath2File());
/* Wraps an input stream in order to be able reading of a whole line */
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
while ((line = br.readLine()) != null) {
command = line;
sendAndLog(timeToWait);
}

http://pastebin.com/LZRdZ3Tg
Finally, for the server write an error handler which logs the errors:


public void handleRequestMessage(byte[] payload) {
LOG.debug("Server got an error " + new String(payload));
}

http://pastebin.com/2EQvbVR8

Until now we’ve done with our server :-).

Now, let’s define a tcp client which will connect to the server, sends an accept message & gets a file sent from the server.

Our configuration file looks as follows:

http://pastebin.com/egquzq5q


<!-- Wraps a service with two reply-request channels. -->
<int:gateway     id="client"
service-interface="org.example.tcpclient.TcpClientService"
default-reply-channel="replyChannel"
default-request-channel="requestChannel"
default-reply-timeout="1000"
default-request-timeout="1000">
</int:gateway>
<!-- Request channel -->
<int:channel id="requestChannel">
<int:queue capacity="10" />
</int:channel>
<!-- Direct channel used for reply. -->
<int:channel id="replyChannel" />

Here how to run a client:

  • Open a new terminal
  • cd /tcpclient
  • mvn clean install
  • mvn dependency:copy-dependencies
  • mvn exec:java -Dexec.mainClass=”org.example.tcpclient.ClientTcp”

Almost the same logic expresses here. Have a look.

A main class has the following lines:

/* Spring Integration context used to get desirable beans. */
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "client-config.xml" }, false);
context.refresh();
context.registerShutdownHook();
TcpClientService service = context.getBean("client", TcpClientService.class);
service.send("GIMMY");

http://pastebin.com/9mjmRyNk
In addition, define a client service:


void send(String txt);

Next, a message handler:


public void handle(byte[] s) {
String ss = new String(s);
LOG.info("r:" + ss);
}

http://pastebin.com/Wg4mscvk
And the last one is an interceptor, which will inform your application about:

i. Message sent;

ii. A connection closed;

iii. A new connection added.


public void send(Message<?> message) throws Exception {
super.send(message);
LOG.debug("Sent message [" + new String((byte[]) message.getPayload()) + "]");
}
public void close() {
super.close();
LOG.debug("Closed connection");
}

public void addNewConnection(TcpConnection connection) {
super.addNewConnection(connection);
LOG.debug("Added new connection" + connection.getHostName() + ":" +
connection.getPort());
}

http://pastebin.com/wiDm5zbH

That’s it !!! 🙂

To play with the code, have a look at here http://www.4shared.com/zip/eF4q7l0k/spring_integration_example.html.

Prerequisites:

  1. Java 1.6 or above;

  2. Maven 3 or above;

  3. Desire to learn something new & thrilling;

Pros:

  • A lot of features

  • Tested

  • Good & friendly community

  • If you have questions, the people really quickly reply

  • There are tons of examples

  • API is easy & comprehensive

Cos:

  • Takes time to learn & understand how to work with it.

  • If you got troubles, sometime it is difficult to debug it.

Peace be upon you.