Communication between C# .NET and Java via ActiveMQ messaging – Part 2


The C# client side.

In Part 1 we defined and generated the ExampleMessage POJO/PONO.

We have to configure the logging part to enable the debug/info output getting Spring.NET to work.

   ...
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 
  <configSections>
    <sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
    </sectionGroup>
    <sectionGroup name="spring">
      <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core"/>
      <section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/>
      <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core"/>
    </sectionGroup>
  </configSections>
 
 
  <common>
    <logging>
      <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
        <arg key="level" value="DEBUG" />
        <arg key="showLogName" value="true" />
        <arg key="showDataTime" value="true" />
        <arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff" />
      </factoryAdapter>
    </logging>
  </common>
 
  <spring>
 
   ...
 
    <objects>
      <import resource="objects.xml"/>
    </objects>
 
  </spring>
 
</configuration>

objects.xml looks like:

 
<objects xmlns="http://www.springframework.net"
  xmlns:nms="http://www.springframework.net/nms">
 
<object id="ActiveMqConnectionFactory" type="Apache.NMS.ActiveMQ.ConnectionFactory, Apache.NMS.ActiveMQ">
    <constructor-arg index="0" value="tcp://localhost:61616"/>
  </object>
 
  <!-- use caching connection factory  -->
  <object id="ConnectionFactory" type="Spring.Messaging.Nms.Connections.CachingConnectionFactory, Spring.Messaging.Nms">
    <constructor-arg index="0" ref="ActiveMqConnectionFactory" />
    <property name="SessionCacheSize" value="10"/>
  </object>
 
  <!-- message converter for hashmap-message <=> examplemessage -->
  <object id="ExampleMessageConverter" type="ClientApp.ExampleMessageConverter"/>
 
  <!-- template for automatic conversion -->
  <object id="NmsTemplate" type="Spring.Messaging.Nms.Core.NmsTemplate">
    <property name="ConnectionFactory" ref="ConnectionFactory" />
    <property name="DefaultDestinationName" value="test.queue" />
    <property name="SessionAcknowledgeMode" value="AutoAcknowledge" />
    <property name="MessageConverter" ref="ExampleMessageConverter" />
  </object>
 
  <!-- service ;) to send  -->
  <object name="ExempleService" type="ClientApp.ExampleService">
    <property name="NmsTemplate"  ref="NmsTemplate"/>
  </object>
 
   ...
 
</objects>

Lets go top down.

 
<objects xmlns="http://www.springframework.net"
  xmlns:nms="http://www.springframework.net/nms">
 
   ...
 
  <!-- service ;) to send  -->
  <object name="ExempleService" type="ClientApp.ExampleService">
    <property name="NmsTemplate"  ref="NmsTemplate"/>
  </object>
 
 
   ...
 
</objects>

To provide the message sending functionality to the client application lets create a simple “service”.

using System;
using System.Collections.Generic;
using System.Text;
using Spring.Messaging.Nms.Core;
using Common.Logging;
 
namespace ClientApp
{
    public class ExampleService : NmsGatewaySupport
    {
        private ILog logger = LogManager.GetLogger(typeof(ExampleService ));
 
        public ExampleService()
        {
            logger.Info("ExampleService created");
        }
 
        public void send(ExampleMessage mes)
        {
            if(logger.IsDebugEnabled)
                 logger.Debug("sending ExampleMessage "+mes);
            NmsTemplate.ConvertAndSend(mes);
        }
    }
}

The implementation of ExampleService inherits from Spring.Messaging.Nms.Core.NmsGatewaySupport which is a helper class providing easy access to a NmsTemplate.
The NmsTemplate is similar to JmsTemplate from the Java Spring world.
We have to set some properties such as a ConnectionFactory for NmsConnctions and a destination to specify which Topic/Queue the message should be sent to.

<objects xmlns="http://www.springframework.net"
  xmlns:nms="http://www.springframework.net/nms">
 
   ...
 
  <!-- template for message sending-->
  <object id="NmsTemplate" type="Spring.Messaging.Nms.Core.NmsTemplate">
    <property name="ConnectionFactory" ref="ConnectionFactory" />
    <property name="DefaultDestinationName" value="test.queue" />
    <property name="SessionAcknowledgeMode" value="AutoAcknowledge" />
   ...
  </object>
 
 
   ...
 
</objects>

JMS specifies TextMessages, MapMessages and ObjectMessages. I decided to use a MapMessage for exchanging data beween client and server.
NMS tries to follow the JMS standard, but there is no de facto standard messaging API in .NET
To enable convertion between ExampleMessage object and MapMessage object we make use of the MessageConverter interface.

namespace Spring.Messaging.Nms.Support.Converter
{
   public interface IMessageConverter
   {
      public Object FromMessage(IMessage mes);
      public IMessage ToMessage(Object mesobj, ISession session);
   }
}

The ExampleMessageConverter functionality is very simple. The ToMessage code has to take care of putting all the transmit data from the ExampleMessage to the MapMessage.
The FromMessage do it vice versa. I assumed there is a SetBytes method like in JMS MapMessage interface.
Thought wrong! Did i overlook something maybe? Nevermind!
A conversion from a byte array to a Base64 encoded string is also quite easy.

using System;
using System.Collections.Generic;
using System.Text;
using Spring.Messaging.Nms.Support.Converter;
using Apache.NMS;
using Apache.NMS.ActiveMQ;
using Common.Logging;
 
namespace ClientApp
{
 
    public class ExampleMessageConverter : IMessageConverter
    {
        ILog logger = LogManager.GetLogger(typeof(ExampleMessageConverter));
 
	// called to convert a JMS/NMS message to a object
        public Object FromMessage(IMessage mes)
        {
 
            logger.Info("fromMessage()");
            ExampleMessage examplemsg= new ExampleMessage();
            IMapMessage mm = (IMapMessage)mes;
            if (examplemsg == null)
            {
                throw new MessageConversionException("ExampleMessageConverter can not convert object of type " +
                        mes.GetType());
            }
            try
            {
                examplemsg.Messagetext = mm.Body.GetString("messageText");
                if(mm.Body.GetString("pictureBytes")!=null)
                    examplemsg.PictureBytes = System.Convert.FromBase64String(mm.Body.GetString("pictureBytes"));
 
                logger.Info("got ExampleMessage: " + examplemsg);
                return examplemsg;
            }
            catch (Exception e)
            {
                throw new MessageConversionException("Could not convert ExampleMessage to message", e);
            }
        }
 
	// called to convert a object to a JMS/NMS message
        public IMessage ToMessage(Object mesobj, ISession session)
        {
            logger.Info("toMessage()");
            ExampleMessage examplemsg = (ExampleMessage)mesobj;
            if (examplemsg == null)
            {
                throw new MessageConversionException("ExampleMessageConverter can not convert object of type " +
                        mesobj.GetType());
            }
            try
            {
                IMapMessage mm = session.CreateMapMessage();
                mm.Body.SetString("messageText", examplemsg.Messagetext);
                if(tradeRequest.PictureBytes!=null)
                    mm.Body.SetString("pictureBytes", System.Convert.ToBase64String(examplemsg.PictureBytes));
                else
                    mm.Body.SetString("pictureBytes",null);
                return mm;
 
            }
            catch (Exception e)
            {
                throw new MessageConversionException("Could not convert ExampleMessage to message", e);
            }
        }
    }
}

Now we add the ExampleMessageConverter to the NmsTemplate configuration.
Whenever a ExampleMessage is passed via the ConvertAndSend method, all the hard work is done by the NmsTemlate.
We do not have to care about connections, sessions, message conversion and all that stuff.
As long as we did the correct configuration ­čśë

<objects xmlns="http://www.springframework.net"
  xmlns:nms="http://www.springframework.net/nms">
 
   ...
 
  <!-- message converter for mapmessage <=> examplemessage -->
  <object id="ExampleMessageConverter" type="ClientApp.ExampleMessageConverter"/>
 
  <!-- template for automatic conversion -->
  <object id="NmsTemplate" type="Spring.Messaging.Nms.Core.NmsTemplate">
   ...
    <property name="MessageConverter" ref="ExampleMessageConverter" />
  </object>
 
 
   ...
 
</objects>

Receiving example will be shown in
Part 3.

Please feel free to leave any comments!

Be Sociable, Share!

, , , , ,

  1. No comments yet.
(will not be published)