Archive for March, 2010
Communication between C# .NET and Java via ActiveMQ messaging – Part 3
Posted by alois koller in C#, Java on 3. March 2010
The Java server side – ‘same same … but different!’
For C# client example see Part 2.
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:amq="http://activemq.apache.org/schema/core" xmlns:jms="http://www.springframework.org/schema/jms" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.3.0.xsd http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-2.5.xsd"> ... <!-- define broker & connectors --> <amq:broker persistent="false" useJmx="false"> <amq:transportConnectors> <amq:transportConnector uri="tcp://localhost:61616" /> </amq:transportConnectors> </amq:broker> <!-- define connection factory --> <amq:connectionFactory id="jmsConnectionFactory" brokerURL="vm://localhost" /> <amq:queue id="test.queue" physicalName="test.queue" /> <!-- A cached connection factory to wrap the default factory --> <bean id="cachedConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory" p:targetConnectionFactory-ref="jmsConnectionFactory" p:sessionCacheSize="10" /> <jms:listener-container connection-factory="cachedConnectionFactory" destination-type="queue"> <jms:listener destination="test.queue" ref="MessageReceiverListener" /> </jms:listener-container> <bean id="ExampleMessageHandler" class="it.koller.interopexample.handlers.ExampleMessageHandler" /> <bean id="ExampleMessageConverter" class="it.koller.interopexample.converter.ExampleMessageConverter"/> <bean id="MessageReceiverListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter"> <property name="defaultListenerMethod" value="handleObject"/> <property name="delegate" ref="ExampleMessageHandler" /> <property name="messageConverter" ref="ExampleMessageConverter" /> </bean> ... </beans> |
We also need an ExampleMessageConverter as we have it at the C# client side.
package it.koller.interopexample.converter; import javax.jms.JMSException; import javax.jms.MapMessage; import javax.jms.Message; import javax.jms.Session; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.jms.support.converter.MessageConversionException; import org.springframework.jms.support.converter.MessageConverter; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import it.koller.interopexample.ExampleMessage; public class ExampleMessageConverter implements MessageConverter { protected Log logger = LogFactory.getLog(SoCamMessageConverter.class); @Override public Object fromMessage(Message mes) throws JMSException, MessageConversionException { if(logger.isDebugEnabled()) logger.debug("fromMessage()"); ExampleMessage examplemsg = new ExampleMessage(); BASE64Decoder decoder = new BASE64Decoder(); MapMessage mm = (MapMessage)mes; if examplemsg == null) { throw new MessageConversionException("ExampleMessageConverter can not convert object of type " + mes.getJMSType()); } try { examplemsg.setMessagetext(mm.getString("messageText")); if(mm.getString("pictureBytes")!=null) examplemsg.setPictureBytes(decoder.decodeBuffer(mm.getString("pictureBytes"))); if(logger.isDebugEnabled()) logger.debug("got Examplemessage: "+examplemsg); return tradeRequest; } catch (Exception e) { throw new MessageConversionException("Could not convert ExampleMessage", e); } } @Override public Message toMessage(Object mesobj, Session session) throws JMSException, MessageConversionException { if(logger.isDebugEnabled()) logger.debug("toMessage()"); ExampleMessage examplemsg = (ExampleMessage) mesobj; BASE64Encoder encoder = new sun.misc.BASE64Encoder(); if examplemsg == null) { throw new MessageConversionException("ExampleMessageConverter can not convert object of type " + mesobj.getClass()); } try { MapMessage mm = session.createMapMessage(); mm.setString("messageText", examplemsg.getMessagetext()); if(examplemsg.getPictureBytes()!=null) mm.setString("pictureBytes", encoder.encode(examplemsg.getPictureBytes())); return mm; } catch (Exception e) { throw new MessageConversionException("Could not convert ExampleMessage to message", e); } } } |
To receive messages from the test.queue a listener and listener-container have to be configured.
The listener-container needs a connection factory and the required destination-type (topic or queue) set.
... <jms:listener-container connection-factory="cachedConnectionFactory" destination-type="queue"> <jms:listener destination="test.queue" ref="MessageReceiverListener" /> </jms:listener-container> ... |
The listener class has to be a MessageListener, which means it has to implement the according interface.
public interface MessageListener { public void onMessage(Message message); } |
I use a default MessageListenerAdapter provided by the Spring framework and inject my custom MessageConverter as well as a MessageHandler.
... <bean id="MessageReceiverListener" class="org.springframework.jms.listener.adapter.MessageListenerAdapter"> <property name="defaultListenerMethod" value="handleObject"/> <property name="delegate" ref="ExampleMessageHandler" /> <property name="messageConverter" ref="ExampleMessageConverter" /> </bean> ... |
The received Message is passed on to the toObject method of the ExampleMessageConverter, which extracts the data from the MapMessage and returns a ExampleMessage object.
The ExampleMessage is then handed over to the ExampleMessageHandler and can be processed by the server application.
package it.koller.interopexample.receiver; import org.apache.log4j.Logger; public class ExampleMessageHandler { private Logger logger = Logger.getLogger(ExampleMessageHandler.class); public void handleObject(Object mesobj) if(logger.isDebugEnabled()) logger.debug("ExampleMessageHandler handleObject "+mesobj); ... // do something ;) } } |
The weak point in this (very) simple approach is the MessageConverter. Both are coded manually and therefore a possible source of error.
To generate the POJO/PONO and the converter from the examplemessage.xsd would provide much more safety and convenience.
Commercial message provider support this feature, i guess.
Please feel free to leave any comments!