This time something different, a framework 🙂
From time to time, even I, professional framework “hater”, need to write or contribute to some framework. Just to prove how “bad, bad, bad” frameworks are 🙂 Just to feel “filthy” and “dirty”. Just to feel this chill down my spine, when I have to frame my thoughts within boundaries set by somebody else:)
This time I was playing with Spring Integration, an interesting approach to implementation of patterns described in a book
“Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions” by Greg Hohpe and Bobby Woolf, a real classic.
As I was playing with different adapters and channels I have noticed that there is missing implementation of JGroups transport.
So here is my short story how I have built channel adapters and XML namespace for JGroups in Spring Integration.
This small chunk of code is of course available for your eyes only and convenience at Github, https://github.com/kcrimson/spring-integration-jgroups.
If you are into Enterprise Integration Patterns, you probably know that Channel Adapter pattern allows you to access particular API or data using Message Channel semantics.Just like well known Adapter pattern from “GoF” book, it wraps one interface into another one, so you can access it without changing existing code.
Channel Adapter is one of key patterns, which allows you to “hide” complexity and different architectural styles or APIs, behind simple uniform interface of Message Channel.Thanks to this pattern you can easily access FTP sites, invoke HTTP based services and send JMS messages without diving too deep into complexities of each protocol or API, and at the same time you can easily replace FTP with email or HTTP transport, thanks to this pattern.
This is also simplest, first step, you can take when you want to implement your own transport/endpoint in Spring Integration. Of course in majority of cases, you will have to implement two Channel Adapters, one for inbound and one for outbound communication.
So let’s start with inbound channel adapter, which receives messages send to group of nodes (JGroups cluster). In the case of JGroups we deal with “push” communication.Out of many abstract endpoint implementations and styles available in Spring Integration, org.springframework.integration.endpoint.MessageProducerSupport
looked like a most obvious choice.
It has some basic code for setting Message Channel reference, convenient lifecycle methods and as well handling of messaging errors. So what’s left to do? Put some glue code which registers receiver on JGroup’s JChannel object.
@Override protected void doStart() { jgroupsChannel.setReceiver(new ReceiverAdapter() { @Override public void receive(Message msg) { Object object = msg.getObject(); Map<String, Object> headers = headerMapper.toHeaders(msg); sendMessage(MessageBuilder.withPayload(object).copyHeaders(headers).build()); } }); }
Few commits later (including “crash course” on XML Schema), I was able to connect to JGroups cluster and send received JGroups messages to any channel, with a little bit of XML which looks like this.
<?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:jgroups="http://www.springframework.org/schema/integration/jgroups" xmlns:int="http://www.springframework.org/schema/integration" xsi:schemaLocation="http://www.springframework.org/schema/integration/jgroups http://www.springframework.org/schema/integration/jgroups/spring-intergration-jgroups.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <jgroups:cluster name="mygroup"> <jgroups:xml-configurator resource="classpath:udp.xml" /> </jgroups:cluster> <jgroups:inbound-channel-adapter id="cluster-adapter" cluster="mygroup" channel="inbound"/> <int:channel id="inbound"> <int:queue/> </int:channel> </beans>
I hope you noticed, JGroups cluster name is a also name of a bean which we inject into inbound channel adapter, using attribute cluster
Outbound channel is also trivial piece of code, which extends org.springframework.integration.handler.AbstractMessageHandler
. So if you want to send message from Spring Integration to JGroups cluster, you can simply
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jgroups="http://www.springframework.org/schema/integration/jgroups" xmlns:int="http://www.springframework.org/schema/integration" xsi:schemaLocation="http://www.springframework.org/schema/integration/jgroups http://www.springframework.org/schema/integration/jgroups/spring-intergration-jgroups.xsd http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <jgroups:cluster name="mygroup"> <jgroups:xml-configurator resource="classpath:udp.xml" /> </jgroups:cluster> <int:poller fixed-rate="100" default="true"/> <int:channel id="inbound"> <int:queue/> </int:channel> <jgroups:outbound-channel-adapter id="cluster-adapter" cluster="mygroup" channel="inbound"/> </beans>
This code is not complete, works only in really basic cases, but it already has basic header mapper, and as you saw some support code to start JGroups in Spring’s application context.
I welcome any thoughts, comments and suggestions and I am happy to maintain this code if you need it :), good night.
Hello, I have a question. Is it still can be used for integration with spring 4 and recent version of jgroups? I will make two or more servers for make the backends have scalability. Many client have same one IP target address(mcast IP address) and each server can be set with same mcast IP address. And I guarantee this enable execute the request message from clients to each servers?