on Java-to-.NET interop via JMS and MQSeries

While looking around I found two articles, from SYS-CON's WebSphere Developer's Journal,  covering J2EE and .NET interop via MQSeries.

part 1: http://sys-con.com/story/?storyid=43430&DE=1#RES

part 2: http://sys-con.com/story/?storyid=43452&DE=1#RES

These articles reference ma7p, the IBM supportpac, which is no longer available.  ma7p has graduated into the MQSeries product.  Upgrade to MQ V5.3 + CSD05 or later to get the MQ classes for .NET.

Interesting: the 2nd article documents a problem I ran into while trying to connect a Java/MQ application that uses the JMS api, with a .NET application that uses the MQ Classes for .NET.  The JMS implementation essentially extracts function from the underlying MQ and embeds it into the API level.  So, things like MessageId and CorrelationId, which are indispensable for a typical MQ app, are not transferrable between a JMS/Java app and a .NET app.  JMS commandeers those MQ-isms and does not bubble them up into the application layer.   In some cases there is a similarly named JMS thing, but it is not the same thing as the underlying MQ thing.   In fact I could not find a way to set the MQ Message ID - the JMS doc I found said that the JMSMessageID on an outgoing JMS message will always be set by the JMS layer - the application is not able to set it.  (not quite true, you can set it all you want, but as soon as you send the message, your MQ MessageId is over-written with a JMS-provided value). 

The net result was that I found myself reverse-engineering the JMS implementation of message-munging.  At first it looked like it was just one or two methods, but the JMS-isms just kept coming and coming.  The correlation ID needed to have a specific prefix.  Strings had to conform to a JMS-specific encoding.   If you try to encode a simple buffer with a couple of integers and a string, you get a big hairy XML envelope (with no namespaces!  The dreaded RFH2 envelope) - the JMS message envelope. Which may be just what you DON'T want in a high-throughput messaging app.   The JMS pitfalls and traps seemed to just keep going and going.   Eventually I just punted and switched the Java app to use the "MQ Classes for Java", a package which defines, like the "MQ Classes for .NET", an IBM-only programming interface.  When I use the MQ Classes for Java, I don't get the surprises I mentioned above.

Stop and think for a minute; This is a completely ridiculous situation.  Imagine if you inserted rows into an Oracle database with a JDBC app, and then you could only read those rows with another JDBC app.  Imagine if your LDAP repository, once you accessed it with JNDI, became a resource that could only be accessed by Java apps.  Preposterous, right?  Well that's what JMS does.  You have to go to the high-fidelity MQ Classes for Java if you want to have a reasonable effort connecting Java to .NET apps. 

"Non-standard interface!"   you point out.    "Lock-in!"  Yeah, you're right.   But  Interop trumps Neutrality.  [Disclaimer, I never believed the "vendor neutrality" arguments anyway]     The designers of JMS - either the IBM implementation of it, or the specification itself - have made decisions about message formats that specifically preclude any interop between a JMS (Java) app and a non-JMS app, without lots and lots of extra effort by the non-JMS side.   The message formats are not published, so you either have to reverse-engineer them, and risk violating the JMS specification license, or ... you have to license and implement JMS.  In either case, Vaya con dios, the future holds lots of work and lots of lawyers for you.   Going with JMS, you may not get "Lock in" to a particular vendor of message middleware, but you do get "Lock out" - of anything non-Java.   

So I have some questions for you all:

  1. do you do interop between Java and .NET over MQ ?  If so, do you use JMS?  How do you resolve the issues I mentioned?
  2. anyone have any helper classes in C# or VB that unpacks the JMS envelope?
  3. what did you do about JMSMessageID? 


Comments (8)

  1. Krishna says:

    Take a look at this


    Dont know if it helps you. When I last looked at it, it supported a couple of JMS implementations like JBoss and OpenJMS. Not sure if it works with MQ though. It provides a COM interface but I dont know if it fine grained enough to provide CorrelationIDs etc.

    Actually if you want to use MQ for interop and you are free to chose any interface, I would go for MQ API. JMS adds its own headers to the actual message and can only be consumed by another JMS implementation on the otherside. Infact I find MQ API is much simpler than JMS API(cos you need a NamingServer to bind your queues/factories) unless you are entirely a Java shop.

  2. Max Kington says:

    I’ve looked at developing a C# library for use with ActiveMQ (A JMS Server). While I never got around to writing it I did do the design and considerations around this. My options were

    1) I have access the to the wire level protocol for activemq so implement that in C#. (This may not be an option in your case) This was ultimatly what I chose but I never got very far. (Although what I thought was going to be the tedious bit (writing the bits) was taken care of by DataInput and OutputStreams which was already implemented in J# and hasn’t change since jdk 1.1

    2) Build a bridging daemon in Java that uses the JMS api and then serializes to something you can use. Problem is that it then becomes a single point of failure and must be aware of how failover occurs if at all and maintain transactional integrity.

    3) use some other interop tool, like http://iiop-net.sourceforge.net/ or http://j-integra.intrinsyc.com/net/info/ etc

    With regards to precluding the non Java users when forming JMS, ultimatly if you implement a message broker, capable of dealing with remote clients then you implement it how you want. In fact most JMS message brokers have got interop libraries, typically for C and C#. I’ve long thought that the JMS API was, well, sub optimal (I’m a Java programmer fyi) and has alot of overhead that is ultmatly unnecessary.

    With regards to Krishnas comment above, the reasons for binding to a naming server is so that the method you connect to the broker can be swaped in and out, in interop libraries you normally just point at an open port, supply some credentials. If you’re lucky they will have implemented transaction support in a non-sucky way.

    I’d got with a native (to the broker) library, it’ll have support, it’ll work (probably) and it’ll get updated when they change their wire protocol.

    There will always be worries with the actual message payloads. After all if you’re shipping objects around you’ll have to deal with them somehow.

    Upshot, yes, JMS can suck, I know a few people who have implemented JMS servers and it drives them potty, so don’t use JMS unless you live in a Java world.

    So, point 1) Yes, I have done, but I fall back to vendors non Java client libraries

    2) I don’t but I’d have at this with J# if you really want to walk into this world

    3) JMSMessageID is of varying importance, I don’t know what IBM MQ looks like these days.

  3. IBM has shipped a beta of the Message Service Client for C/C++. It allows a C/C++ app to read or write JMS messages on MQ.

  4. IBM has shipped a beta of the Message Service Client for C/C++. It allows a C/C++ app to read or write JMS messages on MQ.

  5. IBM has shipped a beta of the Message Service Client for C/C++. It allows a C/C++ app to read or write JMS messages on MQ.

  6. IBM published a paper on their XMS library.

  7. IBM published a paper on their XMS library.

  8. IBM has shipped a beta of the Message Service Client for C/C++. It allows a C/C++ app to read or write JMS messages on MQ.

Skip to main content