次の方法で共有


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?

    Jeff

  • Anonymous
    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!
    -Dave

  • Anonymous
    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.

    -Dino

  • Anonymous
    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 ?

    /azri

  • Anonymous
    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 Practices

  • Anonymous
    August 09, 2007
    In my original post on Java interop with MSMQ , I gave a sample implementation of a Queue class for Java

  • Anonymous
    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? Regards

  • Anonymous
    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 Regards

  • Anonymous
    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. Thanks

  • Anonymous
    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 removed

  • Anonymous
    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 removed

  • Anonymous
    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/.../12272

  • Anonymous
    March 17, 2014
    thank you very very big much for Alastors!!!!!!!!!!!!!!!!!!