Friday, January 25, 2008

Ruby and Java integration

While JRuby provides an obvious strategy for Ruby and Java integration, looser coupling via asynchronous messaging is another good way to integrate Java and Ruby systems. I have some bias here: I have been using asynchronous messaging to build distributed systems since 1987 (mostly using ISIS and Java Messaging System (JMS)). Asynchronous messaging makes it possible to tie together legacy systems, modularize development, and allow easier testing of system components by mocking up test messaging interfaces.

I have had some good experiences using Brian McCallister’s Ruby client for Stomp with the JMS implementation ActiveMQ. Installing the stomp client is easy:
sudo gem install stomp
and I have had to make a small change to the ActiveMQ configuration, adding a few lines to the conf/activemq.xml file:
<connector>
<serverTransport uri="stomp://localhost:61626"/>
</connector>
Here is a simple test client and test service:
require 'rubygems' 
require 'stomp'
client = Stomp::Client.open "mark", "mypassword", "localhost", 61626

client.subscribe "/queue/rubytest" do |message|
puts "received: #{message.body} on #{message.headers['destination']}"
end

for i in 1..100 do
client.send "/queue/rubytest", "message number #{i}"
end

sleep 10 # wait for ActiveMQ to process messages

client.close
This example is contrived: it uses Ruby client and service. A more likely scenario is using a Java service; assuming that you have ActiveMQ installed, with required JARs in your CLASSPATH, etc., it is easy to write Java services; start by creating a connection:
Connection connection = createConnection();
session = createSession(connection);
statusQueueDestination = session.createQueue(statusQueueName);
workQueueDestination = session.createQueue(workQueueName);
MessageConsumer consumer=session.createConsumer(workQueueDestination);
consumer.setMessageListener(this);
producer = createProducer(session, statusQueueDestination);
and define a message handler:
public void onMessage(Message message) {
try {
BytesMessage bytes = (BytesMessage)message;
long len = bytes.getBodyLength();
byte[] data = new byte[(int)len];
bytes.readBytes(data); // new String(data) would contain message as a new String

// calculate results and return a message:

Message a_message = session.createBytesMessage();
((BytesMessage)a_message).writeBytes("test message from Java".getBytes());
producer.send(a_message);
} catch (Exception e) { e.printStackTrace(); }
}

2 comments:

Patrick Logan said...

Have you considered XMPP?

Mark Watson, author and consultant said...

Hello Patrick,

Interesting idea but I have never done anything with the Jabber protocols. I will put that on my list to try some time.