Java and .NET interop via MSMQ
How to connect a Java app to MSMQ, the queuing system that is integrated into Windows? The question gets asked often. There are a number of third party bridges, COM bridges, or even JMS layers on top of MSMQ. But I haven't seen any simple or free mechanisms. It's possible, though.
MSMQ is exposed via at least 3 different programming interfaces: the C library interface; the COM interface, suitable for VB apps and other COM environments; and the System.Messaging namespace in the .NET base class library. Connecting Java to MSMQ means bridging from Java into one of those existing layers. The Java Native Interface is Java's way to integrate C/C++ libraries with Java applications. But JNI is not what you'd call "easy to use". It requires both Java and C/C++ skills, so not very accessible for most developers. But JNI is powerful, as this example shows.
The C api for MSMQ includes functions like MQOpenQueue(), MQCreateQueue, MQReceiveMessage() and so on. They provide all the low-level function an app needs, but it's an old-style library: not organized into classes. The interface is a typical C library: based on return codes (HRESULTS), no exception handling, lots of handles and pointers. All very un-OO. So what we'll do is build an object layer in Java on top of those library functions.
The main Java class is called Queue, and looks like this:
public class Queue
{
public Queue(String queueName)
throws MessageQueueException ;
public static Queue create(String queuePath, String queueLabel, boolean isTransactional)
throws MessageQueueException ;
public static void delete(String queuePath)
throws MessageQueueException ;
public void send(Message msg)
throws MessageQueueException ;
public void send(String s)
throws MessageQueueException ;
public ionic.Msmq.Message receive(int timeout)
throws MessageQueueException ;
public ionic.Msmq.Message receive()
throws MessageQueueException ;
public ionic.Msmq.Message peek()
throws MessageQueueException ;
public ionic.Msmq.Message peek(int timeout)
throws MessageQueueException ;
public void close()
throws MessageQueueException ;
public String getName();
public String getLabel();
public String getFormatName();
public boolean isTransactional();
}
Instantiating a queue object implicitly opens the named backing queue. There's a static create() method , which also opens the newly created queue. This is roughly modelled on the System.Messaging.MessageQueue class from .NET. The basic programming model is similar, but of course this Queue class is much more basic.
The supporting Message class provides the abstraction for the message, including encapsulating the message body, label, and correlationId.
public class Message
{
public void setMessage(String value) ;
public String getMessage() ;
public void setLabel(String value) ;
public String getLabel() ;
public void setCorrelationId(String value) ;
public String getCorrelationId() ;
public void setTransactionFlag(int value) ;
public int getTransactionFlag() ;
public int getStatus() ;
public Message(String message, String label, String correlationId, int transactionFlag);
public Message(String message, String label, String correlationId, int transactionFlag, int status) ;
}
How does it work?
Building a Java app that uses this JNI interface to MSMQ works like building any other Java application. Some caveats though: The Queue class depends on a set of native functions defined in a DLL. So won't work with a Java applet, since you need the DLL to be installed on the local machine. You need the directory for the DLL to be on your search path (either in the current working directory, or on the PATH environment variable. Also, It works only on Windows, but that shouldn't be much of a concern since we are talking about MSMQ here.
It should work with public or private MSMQ queues, although I tested it only with private queues. It should work with any sort of data, but the class I provide sends or receives only strings.
It's Not JMS
To head off any questions: As you can see above, this is not a JMS provider for MSMQ. It doesn't do transactions, it doesn't do pub/sub or the data-munging that JMS does that I commented on earlier. This is just a simple class that lets you access MSMQ from Java.
It's Limited
You can't do everything with this simple JNI library that you can do with the System.Messaging class library, or with the C api for MSMQ. You cannot enumerate queues, or interrogate properties of queues or messages. The send() and receive() methods work only with Strings. It's pretty basic.
Wait.... Really? only strings? This is a joke!
The strings that your apps exchange via MSMQ can be anything: plain old strings, XML documents, base64 encoded byte arrays of arbitrary binary data, encrypted blobs, digital signatures, or whatever you like. You could take the base Queue class and extend it to provide support for these more advanced scenarios. For example, you could integrate this class with a Java-to-XML data binding framework like Apache's XMLBeans or Sun's JAXB, in order to be able to ship XML documents across the queue in an interoperable fashion.
There is undoubtedly overhead associated to encoding all data as strings. But this is just a demo, an illustration. If you need something optimized for binary data, it shouldn't be hard for you to produce a send() method that handles it nicely.
Not a substitute for MQSeries.
All you MQ loyalists, don't get your knickers in a twist. I am not suggesting that the arrival of this JNI library for MSMQ means that MQSeries, or any other message queue system, is now irrelevant. All this example does is show one more way to interconnect Java-based and .NET apps, VB6 apps, or any other MSMQ-enabled system. MQ still works, too, but MSMQ may be a bit more "available" for typical developers, since it is included in Windows.
Get the original source
Get the latest source
[Update: As of February 2008, The JNI library for MSMQ has been promoted to a CodePlex project. Find it at www.codeplex.com/MsmqJava ]
Enjoy. -Dino
Comments
Anonymous
March 03, 2005
Another option is to use the HTTP handler MSMQ has. If you use a packet filter, you can see that the messages an MSMQ client sends to an MSMQ server over http are just soap messages with attachments for the body of the MSMQ message. I have considered doing this before for clients that I did not want to have to install the the MSMQ client stuff on, but still wanted to be able to send messages to a queue on a server.Anonymous
March 03, 2005
Hi,
This looks great -- exactly what I needed! Would you mind posting the JNIMSMQ.dll?
Thanks!Anonymous
March 03, 2005
ok, Brad, I updated the zip referenced in the post; it now includes the JNIMSMQ.dll. Having said that, remember that anyone should be able to build it themselves using the VC++ toolkit (free, if you use Windows) and the .NET SDK (also free).Anonymous
March 03, 2005
Hey Chris, yes, I had seen Doron mention that, but he indicated there would be some additional protocol handling required, I think?Anonymous
March 21, 2005
The JNI approach would still only work for a java application running on a Windows platform, right? I am looking for a way to access a Windows MSMQ server from a linux client. It seems that there is no "ideal" way of accomplishing this. If MS would release a linux (or java) client, it would increase the popularity of MSMQ, IMHO.
That said, does anyone know how this can currently be done?
JeffAnonymous
April 15, 2005
Thanks for the great implementation. This works pretty cool if my message queue is on the same machine that I'm running the sample clients from. But I can't get the Java version to work if the message queue is on another machine. I edited both the C# and the Java versions of "getQueueFullName" so they specify a remote queue name:
return "FormatName:DIRECT=OS:remoteMachineName\private$" + queueShortName;
And the C# version still works, but the Java version always returns
Queue open failure: Cannot open queue. (hr=MQ_ERROR_REMOTE_MACHINE_NOT_AVAILABLE)
Am I doing something wrong? Or is this a limitation of the JNI implementation?
Thanks in advance!
-DaveAnonymous
April 18, 2005
> The JNI approach would still only work for a java application running on a Windows platform, right?
Yes, the JNI approach used here involves Java code calling into a Windows-specific DLL. JNI is, in general, platform specific. You can do JNI on Linux, but you will lack the MSMQ DLL on Linux, so that won't get you what you want.Anonymous
April 18, 2005
@Dave,
> Am I doing something wrong? Or is this a limitation of the JNI implementation?
Yes, you are doing something wrong! Use the FormatName: prefix in the C# client, but not in the Java client.
Also, for Java to work, you'll have to apply the DIRECT=OS: prefix, in either the client code, or in the native layer, in the MsmqQueue.cpp module. But not in both ! To keep it parallel to the C# client, that prefix should be applied in the TestClient.java (and thus removed from the MsmqQueue.cpp module).Anonymous
April 18, 2005
I updated the example to support remote private queues. If you click the download link, you'll get the update.
-DinoAnonymous
April 18, 2005
I was checking the source code, and it would seem that the file JniMsmq.h is missing from the .zip file.
Will/can it be fixed ?
/azriAnonymous
April 18, 2005
Azri, JniMsmq.h is a generated file, so it was not included in the zip.
You can build JniMsmq.h with the makefile.Anonymous
April 27, 2005
The idea to use MSMQ and XML to have Java speak with Windows apps is a super idea, just what I was looking for. I have a small problem though, there seems to be a problem with character encodings. I've made some javascripts(WSH) that sends/receives text to a queue, but the Testclient and the javascripts don't understand eachother. The text "ABC" looks like 41 00 42 00 43 00 from the javascript side and 41 42 43 from the java side. I suppose the double byte characters are some kind of Unicode (UTF-16LE??) While the 1 byte characters are ISO-8859-1 (Windows maybe??). What can be done to fix this?. Can the Strings be furnished at the Java layer to fix this or has the dll to be modified?Anonymous
July 12, 2005
In my original post on Java interop with MSMQ, I gave a sample implementation of a Queue class for...Anonymous
July 12, 2005
In my original post on Java interop with MSMQ, I gave a sample implementation of a Queue class for...Anonymous
July 12, 2005
In my original post on Java interop with MSMQ, I gave a sample implementation of a Queue class for...Anonymous
March 15, 2007
PingBack from http://tssblog.techtarget.com/index.php/interoperability/the-messaging-way-msmq-jms/Anonymous
August 09, 2007
JavaOne2006 - Interop Session I went to a few sessions at JavaOne 2006. One was called Best PracticesAnonymous
August 09, 2007
In my original post on Java interop with MSMQ , I gave a sample implementation of a Queue class for JavaAnonymous
September 26, 2008
I want to read messages when they has been arrived to the queue. How can i set or fire a event which reads messages when they just arrived to the queue? RegardsAnonymous
September 29, 2008
There are a couple of ways to do what you want in MQ. One is to poll the queue endlessly. Another way is to use something called a "trigger monitor" in MQ. This is a program that runs constantly, and upon arrival of a message on the desinated queue, the trigger monitor can start an application and send to that application relevant information from the queue message. The application itself can start up and dequeue from the queue, or do whatever it wants. You can read more about polling and the MQ Trigger Monitor Interface (TMI) in the MQ docs.Anonymous
September 30, 2008
hi, thanks for answer Sorry, MQ is Message Queue? in the first option "One is to poll the queue endlessly" you're talking about make a infinite loop or set a timer and check the queue?, what if there are two apps. reading the same queue, one in vb which has the notifyenabled to read the a message when it is arrived to that queue, and another one in java which have the loop what will happen if the the message is read by the vb app. first, the java app. never realize whether that message were arrived to the queue right?. In the second option, the app (in java), needs to know automatically when a message was arrived, so if i will create a trigger on the queue, what useful could be running another application which will has to connect to java too? so there's no way to just add a ActionListener or something to catch the arriving of a message, like we can do it in vb? hope understand RegardsAnonymous
October 02, 2008
Wow, for some reason I understood you were asking about IBM MQSeries. That's what I meant when I wrote "MQ". So my prior answer is not what you wanted, I think. There are triggers as well in MSMQ. MSMQ Triggers allows you to configure an app (.exe) to start when a message arrives on a message queue. See here for an article: http://www.codeproject.com/KB/IP/msmq_triggers.aspx It may be that you don't want to start an exe. Maybe you want to just notify a thread inside your own Java applications. Yes, this is also possible. To do it, though, you need to write your Java application to have multiple threads. The first thread (T1) kicks off Thread #2 (T2). T1 then calls wait() on a monitor object. While T1 waits, T2 calls the Queue.receive() method specifying as a timeout some large number. When the Queue.receive() returns, T2 can check to see if the timeout expired, or if the queue was actually successfully read. In the latter case, T2 calls notify() on the monitor. This awakens T1. You may need to read up on Java threads ....Anonymous
October 05, 2008
If you are facing problems related crashing of dll. you can also use this dll. http://dllforjava.blogspot.com/Anonymous
November 09, 2008
Anyone used this method with multiple queues? I tried connecting to two queues. Sending data to any of the two results in messages arriving at the second queue only even though the two queue instances show correct (differing) instance details when stepping the code. ThanksAnonymous
November 10, 2008
Dave, can you show me your application code? There is a private member variable that holds the queue handle for each instance of the MsmqQueue class that you create. Is it possible that somehow the instances are getting munged?Anonymous
November 16, 2008
The comment has been removedAnonymous
November 17, 2008
Managed to get it sending messages by changing the queue label from using "DIRECT:TCP...." to "DIRECT:OS...."Anonymous
November 19, 2008
Hi, has anyone enhanced MSMQ java code to support Transactional MSMQ Queue's? I am not able to compile the dll.Anonymous
December 16, 2009
The code for JAVA MSMQ which working fine for me.http://javamsmq.codeplex.com/Anonymous
February 21, 2010
The comment has been removedAnonymous
June 19, 2012
If anyone wants the 64 bits version of this I made visual studio 2010 projects for 32 and 64 bits with compiled dll included and submitted them to the codeplex issue tracker, the direct link is msmqjava.codeplex.com/.../12272Anonymous
March 17, 2014
thank you very very big much for Alastors!!!!!!!!!!!!!!!!!!