Using JMS from Visual Basic

Java/J2EE COM Interoperability Products Page

This example demonstrates how to access Java Message Service (JMS) from a Visual Basic application.

This example was developed using Windows 2000, JDK1.3.1, J2EESDK1.3 Beta and Visual Basic 6.0. It should also work with Windows NT4.0.

Pre-requisites

  1. Install J-Integra®.

  2. Install the latest JDK.

  3. Install J2EESDK1.3 Beta (follow the link called "Java 2 SDK, Enterprise Edition, version 1.3 beta").

  4. Install Visual Basic.

  5. You will also need Microsoft's IDL compiler (midl.exe) to compile your COM IDL. Midl.exe is part of the Visual C++ installation. Visual C++ also includes the command vcvars32.bat which will set up the environment variables required to run midl.exe.

  6. Step through the JMS tutorial. Make sure this is working as this example is based on it. On my machine the JMS tutorial was installed as part of the J2EESDK at C:\j2sdkee1.3\doc\guides\jms\html\jmsTOC.fm.html.

There are three parts to this example:

You should not need to be familiar with Visual Basic to complete this example, but any experience is an advantage.

Conclusion

After working through the examples presented here you will see how easy it is to integrate Visual Basic and JMS. Or indeed any COM client, not just Visual Basic.
Now any Visual Basic client can post messages to a JMS queue. This is becoming increasingly important as message queues are more tightly integrated with J2EE. More Visual Basic clients will need to interact with EJBs via JMS.

Although not presented here, it is also possible for any COM client to function as a receiver. To provide the service of taking messages from the queue and processing them.
An example of this would be a COM server hosted in MTS which completes some transaction processing on a Microsoft platform. It could process transactions posted to the JMS from a variety of other platforms.


Part I - Late Binding

By using late binding you do not need to generate proxies for the Java classes you wish to access. J-Integra® provides to Visual Basic an IDispatch interface which is used to create objects, invoke methods and set properties.

Usually this is the quickest way to test/experiment with accessing a Java class from a COM client. However it does have the drawback of performance overhead and you also lose Visual Basic's auto completion features (where it prompts you with method/member names).

The steps involved

  1. Configure your environment

  2. Create the COMtoJMS bridge and the MyWrappers class

  3. Start the J2EE Server and check that the JMS queue "MyQueue" still exists

  4. Start the SimpleQueueReceiver

  5. Create and Run the Visual Basic client

  6. How to cleanup

Configure your environment

This example assumes that you have installed

We will be creating this example in C:\pure\JMSExample\LateBinding. Please create this directory.

Set your PATH environment variable to include the JDK and J-Integra® bin directories, and update your CLASSPATH environment to include the J-Integra® runtime. As you also need to configure your environment for the J2EESDK you may find it convenient to create a batch file in the j2eesdk bin directory and execute that. This is what I did:

Note that the setenv.bat file which is called at the end of mysetenv.bat is part of the J2EESDK and is located in that bin directory.


Create the COMtoJMS bridge and the MyWrappers Class

  1. In the c:\pure\JMSExample\LateBinding directory create a file called COMtoJMS.java and place the following code there:

    // This is the bridge.  The VB client talks to this
    // process via DCOM, and this process talks to JMS.
    // If you have a Java server process you could add this
    // initialization there.
    
    import javax.naming.*;
    import com.linar.jintegra.*;
    
    public class COMtoJMS {
      ?FONT COLOR="#000080">public static void main(String[] args) throws Exception {
          ?FONT COLOR="#000080">try {
                ?FONT COLOR="#808080">// Generate a log just in case it all goes wrong
                ?FONT COLOR="#000000">com.linar.jintegra.Log.logImmediately(3, "jintegra.log");
    
                ?FONT COLOR="#808080">// Register the JVM name with the J-Integra® runtime
                ?FONT COLOR="#000000">Jvm.register("JMS");
    
                ?FONT COLOR="#808080">// Wait around for a while. When the process exits the objects
                ?FONT COLOR="#808080">// here will no longer be accessible from COM.
                ?FONT COLOR="#000080">while (true) {
                    ?FONT COLOR="#808080">// do nothing.
                    ?FONT COLOR="#000000">Thread.sleep(10000);
                  ?FONT COLOR="#000000">
          }
            ?FONT COLOR="#000000">
        }
          ?FONT COLOR="#000080">catch (Exception e){
              ?FONT COLOR="#000000">System.out.println(e.getMessage());
              ?FONT COLOR="#000000">e.printStackTrace();
            ?FONT COLOR="#000000">
        }
        ?FONT COLOR="#000000">
      }
    }
     
  2. Also create a file called MyWrappers.java and place the following code there:

    // This class provides wrappers to enable calling overloaded
    // member functions from Visual Basic.
    import javax.naming.*;
    import javax.jms.*;
    
    
    public class MyWrappers {
    
      ?FONT COLOR="#000080">public void QueueSender_send(
          ?FONT COLOR="#000000">QueueSender cQueueSender,
             ?FONT COLOR="#000000">Message cMessage)
        ?FONT COLOR="#000080">throws javax.jms.JMSException {
          ?FONT COLOR="#808080">// print out something so we know the method was invoked.
          ?FONT COLOR="#000000">System.out.println("+QueueSender_send.");
          ?FONT COLOR="#000000">cQueueSender.send(cMessage);
          ?FONT COLOR="#000000">System.out.println("-QueueSender_send.");
        ?FONT COLOR="#000000">
      }
    
      ?FONT COLOR="#000080">public Object InitialContext_lookup(
          ?FONT COLOR="#000000">javax.naming.InitialContext cContext,
             ?FONT COLOR="#000000">String cClassName)
        ?FONT COLOR="#000080">throws NamingException {
          ?FONT COLOR="#808080">// print out something so we know the method was invoked.
          ?FONT COLOR="#000000">System.out.println("+InitialContext_lookup.");
          ?FONT COLOR="#000000">Object obj = cContext.lookup(cClassName);
          ?FONT COLOR="#000000">System.out.println("-InitialContext_lookup.");
          ?FONT COLOR="#000080">return obj;
        ?FONT COLOR="#000000">
      }
    }

    Why? The javax.jms.QueueSender and the javax.naming.InitialContext classes have overloaded methods which take the same number of parameters. So for example, when you call QueueSender.send from Visual Basic, J-Integra® is unable to determine which send method you wish to call. (Note: if the methods took different numbers of parameters there would not be a problem).

    This wrapper class simply takes the required parameters and calls the appropriate send method. There are two wrapper methods, one for QueueSender.send and one for InitialContext.lookup.

  3. Compile the bridge and the wrapper class.

  4. Register the JVM. Note that 4000 is an arbitrarily chosen port number which was not in use on my machine. If you wish, you can check for available port numbers by using the netstat -a command which displays all the ports currently in use.

  5. Start the JVM. Note that we pass the JMS tutorial command line options to java. This is to ensure that the JMS classes are available to the JVM.

    The J-Integra® DCOM engine is now listening on port 4000 for incoming DCOM calls.


Start the J2EE Server and check that the JMS queue "MyQueue" still exists

In another console configure the J2EE environment (see above) and start the J2EE server as per JMS tutorial.

Check that the MyQueue queue still exists with the command j2eeadmin -listJmsDestination.


Start the SimpleQueueReceiver

In another console configure the J2EE environment (see above).

Start the SimpleQueueReceiver program as per JMS tutorial.


Create and Run the Visual Basic client

Start Visual BASIC, create a 'Standard EXE' project, put a button on a form, and double-click on the button to edit its action code. Change the code to the following:

Private Sub Command1_Click()
    Dim objInitialContext As Object
   ? Get the Initial Context which will allow us to create objects
    Set objInitialContext = GetObject("JMS:javax.naming.InitialContext")
   ?
   ? This is my wrapper class
    Dim objMyWrappers As Object
    Set objMyWrappers = GetObject("JMS:MyWrappers")
   ?
    Dim objQueueConnectionFactory As Object
    Set objQueueConnectionFactory = objMyWrappers.InitialContext_lookup(objInitialContext, "QueueConnectionFactory")
   ?
    Dim objQueue As Object
   ? MyQueue is the name of the queue created in the JMS tutorial
    Set objQueue = objMyWrappers.InitialContext_lookup(objInitialContext, "MyQueue")
   ?
   ?
    Dim objQueueConnection As Object
    Set objQueueConnection = objQueueConnectionFactory.createQueueConnection()
   ?
    Dim objQueueSession As Object
   ? note that the second parameter to createQueueSession should be
   ? Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE or Session.DUPS_OK_ACKNOWLEDGE
   ? and I pass zero here on the assumption that they are defined 0, 1 and 2.
    Set objQueueSession = objQueueConnection.createQueueSession(False, 0)
   ?
    Dim objQueueSender As Object
    Set objQueueSender = objQueueSession.createSender(objQueue)
   ?
    Dim objMessage As Object
    Set objMessage = objQueueSession.createTextMessage()
    objMessage.SetText ("Hello from Visual Basic")
       ?
   ? Again I use my wrapper to call the overloaded member
    Call objMyWrappers.QueueSender_send(objQueueSender, objMessage)
    MsgBox "Message sent."
End Sub

Note that the above code is simply a translation of the SimpleQueueSender.java sample in JMS tutorial.

Now run the Visual Basic application. You should see the following:

And the SimpleQueueReceive output...


How to cleanup

The only cleanup required here is to unregister the JVM with regjvmcmd /unregister COMtoJMS.
This is an optional step, skipping this will not affect J-Integra® or the remaining examples.
¡¡


Part II - Early Binding

When you use the java2com tool to generate a type library you are using EarlyBinding. When working in Visual Basic the editor has information about the java classes you are going to access. The auto completion feature of Visual Basic will prompt you with object and method names and parameters.

The most important reason for using early binding is to take advantage of the run-time advantages. There is a performance gain because the J-Integra® runtime has less work to do in calling a method, .

The steps involved

  1. Configure your environment

  2. Create the JMSEarly type library

  3. Create the COMtoJMSEarly bridge

  4. Start the J2EE Server and check that the JMS queue "MyQueue" still exists

  5. Start the SimpleQueueReceiver

  6. Create and Run the Visual Basic client

  7. How to cleanup

Configure your environment

This is identical to the LateBinding example above, so please follow those instructions once again in a new console window.


Create the JMSEarly Type Library

  1. In the c:\pure\JMSExample\EarlyBinding directory, create a new directory called JMSEarly. This is where we will instruct java2com to place it's output files.

  2. Run the java2com tool from that directory (just type java2com and hit enter).
    Click the Add ... button and locate j2ee.jar, then click OK. Select javax.naming.InitialContext by first expanding the rt.jar (JDK Home) folder, then expanding the javax package, then expanding the naming package, and then selecting InitialContext from the class list.
    Select javax.naming.QueueConnectionFactory by first expanding the j2ee.jar folder, then expanding the javax package, then expanding the jms package, and then selecting the QueueConnectionFactory class from the class list.

     

     
    When you hit the Generate button java2com will generate an IDL specification for the java class specified (javac.jms.QueueConnectionFactory and javax.naming.InitialContext) and all classes that these class reference. I chose the javax.jms.QueueConnectionFactory class because it is used in the sample code shipped with the JMS tutorial. It just happens to pull in all the classes that I need. If it did not pull them all in I would simply have listed all the classes (separated by spaces) in the dialog.

  3. As well as the IDL file, java2com generates some java source code in the JMSEarly directory. This source is required by the J-Integra® runtime to locate the appropriate classes in java. You must compile these classes as follows.


  4. Now you must compile the IDL to generate a type library and then register this library. See pre-requisites for more information on midl.


    Note that regtlb is a J-Integra® tool and that the last parameter is the JVM name JMSEarly as will be used when registering the COMtoJMSEarly bridge.

  5. To finish this step, cd to the parent directory and add the JMSEarly directory to the classpath.


    The second command here "set CLASSPATH" is not required, I did that so you could see what my classpath was.


Create the COMtoJMSEarly bridge

  1. In the c:\pure\JMSExample\EarlyBinding directory create a file called COMtoJMSEarly.java and place the following code there (the only difference between this version and the Late Binding version above is the class name and the name of the JVM that is registered, these differences have been highlighted in bold ):

    // This is the bridge.  The VB client talks to this
    // process via DCOM, and this process talks to JMS.
    // If you have a Java server process you could add this
    // initialization there.
    
    import javax.naming.*;
    
    import com.linar.jintegra.*;
    
    public class COMtoJMSEarly {
      ?FONT COLOR="#000080">public static void main(String[] args) throws Exception ?FONT COLOR="#000000">{
          ?FONT COLOR="#000080">try {
                ?FONT COLOR="#808080">// Generate a log just in case it all goes wrong
                ?FONT COLOR="#000000">com.linar.jintegra.Log.logImmediately(3, "jintegra.log");
    
                ?FONT COLOR="#808080">// Register the JVM name with the J-Integra® runtime
                ?FONT COLOR="#000000">Jvm.register("JMSEarly");
    
                ?FONT COLOR="#808080">// Wait around for a while. When the process exits the objects
                ?FONT COLOR="#808080">// here will no longer be accessible from COM.
                ?FONT COLOR="#000080">while (true) {
                    ?FONT COLOR="#808080">// do nothing.
                    ?FONT COLOR="#000000">Thread.sleep(10000);
                  ?FONT COLOR="#000000">
          }
            ?FONT COLOR="#000000">
        }
          ?FONT COLOR="#000080">catch (Exception e) {
              ?FONT COLOR="#000000">System.out.println(e.getMessage());
              ?FONT COLOR="#000000">e.printStackTrace();
            ?FONT COLOR="#000000">
        }
        ?FONT COLOR="#000000">
      }
    }
     
  2. Compile the bridge.

  3. Register the JVM. Note that 4010 is an arbitrarily chosen port number which was not in use on my machine. If you wish, you can check for available port numbers by using the netstat -a command which displays all the ports currently in use.

  4. Start the JVM. Note that we pass the JMS tutorial command line options to java. This is to ensure that the JMS classes are available to the JVM.


    The J-Integra® DCOM engine is now listening on port 4010 for incoming DCOM calls.


Start the J2EE Server and check that the JMS queue "MyQueue" still exists

In another console configure the J2EE environment (see above) and start the J2EE server as per JMS tutorial.

Check that the MyQueue queue still exists with the command j2eeadmin -listJmsDestination.


Start the SimpleQueueReceiver

In another console configure the J2EE environment (see above).

Start the SimpleQueueReceiver program as per JMS tutorial.


Create and Run the Visual Basic client

  1. Start Visual BASIC, create a 'Standard EXE" project.

  2. Open the project references dialog and check the JMSEarly library.


  3. Now place a button on the default form, and double-click on the button to edit its action code. Change the action code to the following:

    Private Sub Command1_Click()
        Dim objInitialContext As JMSEarly.JavaxNamingInitialContext
        Set objInitialContext = New JMSEarly.JavaxNamingInitialContext
       ?
        Dim objQueueConnectionFactory As JMSEarly.JavaxJmsQueueConnectionFactory
        Set objQueueConnectionFactory = objInitialContext.lookup("QueueConnectionFactory")
       ?
        Dim objQueue As JMSEarly.JavaxJmsQueue
        Set objQueue = objInitialContext.lookup("MyQueue")
           ?
       ? Note that javax.jms.QueueConnection has two createQueueConnection methods
       ? Here we call the method that takes no parameters
        Dim objQueueConnection As JMSEarly.JavaxJmsQueueConnection
        Set objQueueConnection = objQueueConnectionFactory.createQueueConnection2()
       ?
       ? Note the second parameter to createQueueSession
        Dim objQueueSession As JMSEarly.JavaxJmsQueueSession
        Set objQueueSession = objQueueConnection.createQueueSession(False, JMSEarly.JavaxJmsSession_AUTO_ACKNOWLEDGE)
       ?
       ?
        Dim objQueueSender As JMSEarly.JavaxJmsQueueSender
        Set objQueueSender = objQueueSession.createSender(objQueue)
       ?
       ? Note that there are two createTextMessage methods. We use the parameterless one.
        Dim objMessage As JMSEarly.JavaxJmsMessage
        Set objMessage = objQueueSession.createTextMessage2
        objMessage.SetText ("Hello from Early Bound Visual Basic")
       ?
        Call objQueueSender.send4(objMessage)
       ?
        MsgBox "Message sent using Early Binding."
    End Sub

    Note that the above code is simply a translation of the SimpleQueueSender.java sample in JMS tutorial.
    ¡¡

  4. Now run the Visual Basic application. You should see the following:

    And the SimpleQueueReceive output...


How to Clean Up

You do not have to do this cleanup, it is optional.
The only item you need to be concerned about is the JMSEarly type library. It is good practice to do the following cleanup before deleting the type library:

  1. cd c:\pure\JMSExample\EarlyBinding\JMSEarly

  2. regtlb /unregister JMSEarly.tlb

You may also unregister the JVM with regjvmcmd /unregister JMSEarly.


Part III - Placing objects in a JMS Queue

The previous examples placed a string in the queue which is a good proof of concept but a little limiting. It is more likely that you will want to pass structured information to the queue, for example instructions to deposit money to an account. You could format that string to contain this information, which the SimpleQueueReceiver could extract. For example, you could pass an XML document to the queue. The SimpleQueueReceiver would then access the elements of the document using an XML parser.

Another option is to place Java objects in the queue. This has the advantage that the built in Java serialization code takes care of creating an object based on the data in the queue. You can then interact directly with the object as if you had created it locally yourself.

In this example a Visual Basic client will create an instance of an class that I have defined called LogEvent. A LogEvent object represents an event that occurred which we wish to log. So it includes properties such as a timestamp, a description and severity (e.g. Info, Error, Warning). The ObjectQueueReceiver class will read messages from the "ObjectQueue" and output the LogEvent.toString() message on the console.

The steps involved

  1. Configure your environment

  2. Create the LogEvent class

  3. Create the ObjectQueueReceiver class

  4. Create the JMSObject type library

  5. Create the COMtoJMSObject bridge

  6. Start the J2EE Server and create a queue called "ObjectQueue"

  7. Start the ObjectQueueReceiver

  8. Create and Run the Visual Basic client

  9. How to clean up

Configure your environment

This is identical to the LateBinding example above, so please follow those instructions once again in a new console window.


Create the LogEvent class

  1. Create the c:\pure\JMSExample\ObjectQueue directory and then create a file called LogEvent.java containing the following code:

    import java.io.*;
    import java.util.Date;
    
    public class LogEvent implements Serializable {
      ?FONT COLOR="#808080">// Severities could include for example Warning, Info, Error, etc.
      ?FONT COLOR="#000080">public int m_nEventSeverity;
      ?FONT COLOR="#808080">// When the event occurred
      ?FONT COLOR="#000080">public Date m_cTimeStamp;
      ?FONT COLOR="#808080">// a text message describing the event
      ?FONT COLOR="#000080">public String m_cEventDescription;
    
      ?FONT COLOR="#808080">// The object must have a default constructor to be accessible from VB
      ?FONT COLOR="#000080">public LogEvent() {
        ?FONT COLOR="#000000">
      }
    
      ?FONT COLOR="#808080">// parameterized constructor initializing all fields
      ?FONT COLOR="#000080">public LogEvent(int nEventSeverity, Date cTimeStamp, String cEventDescription) {
          ?FONT COLOR="#000000">m_nEventSeverity = nEventSeverity;
          ?FONT COLOR="#000000">m_cTimeStamp = cTimeStamp;
          ?FONT COLOR="#000000">m_cEventDescription = cEventDescription;
        ?FONT COLOR="#000000">
      }
    
      ?FONT COLOR="#808080">// returns a string representation of the event
      ?FONT COLOR="#000080">public String toString() {
          ?FONT COLOR="#000080">return "[ Timestamp: " + m_cTimeStamp +
                  " Severity: " + m_nEventSeverity +
                  " Description: " + m_cEventDescription +
                  "]";
        ?FONT COLOR="#000000">
      }
    }
     
  2. Compile this with the command javac LogEvent.java.


Create the ObjectQueueReceiver class

  1. Copy the SimpleQueueReceiver.java class from the JMS tutorial to this directory (c:\pure\JMSExample\ObjectQueue) and rename it ObjectQueueReceiver.java. Edit the file to make it look like the following (note that the changes are marked in red font):

    /*
    	 *
    	 * Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
    	 *
    	 * This software is the proprietary information of Sun
    	 * Microsystems, Inc.  Use is subject to license terms.
    	 *
    	 */
    /**
     * The SimpleQueueReceiver class consists only of a main method,
     * which fetches one or more messages from a queue using
     * synchronous message delivery.  Run this program in conjunction
     * with SimpleQueueSender.  Specify a queue name on the command
     * line when you run the program.
     */
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class ObjectQueueReceiver {
    
        ?FONT COLOR="#808080">/**
           * Main method.
           *
           * @param args     the queue used by the example
           */
        ?FONT COLOR="#000080">public static void main(String[] args) {
              ?FONT COLOR="#000000">String                 ?FONT COLOR="#000000">queueName = null;
              ?FONT COLOR="#000000">Context                 jndiContext = null;
              ?FONT COLOR="#000000">QueueConnectionFactory ?FONT COLOR="#000000">queueConnectionFactory = null;
              ?FONT COLOR="#000000">QueueConnection         queueConnection = null;
              ?FONT COLOR="#000000">QueueSession           ?FONT COLOR="#000000">queueSession = null;
              ?FONT COLOR="#000000">Queue                   queue = null;
              ?FONT COLOR="#000000">QueueReceiver           queueReceiver = null;
              ?FONT COLOR="#000000">TextMessage             message = null;
    
              ?FONT COLOR="#808080">/*
             * Read queue name from command line and display it.
             */
              ?FONT COLOR="#000080">if (args.length != 1) {
                    ?FONT COLOR="#000000">System.out.println("Usage: java ObjectQueueReceiver " +
                        ?FONT COLOR="#008000">"");
                    ?FONT COLOR="#000000">System.exit(1);
                ?FONT COLOR="#000000">
        }
              ?FONT COLOR="#000000">queueName = new String(args[0]);
              ?FONT COLOR="#000000">System.out.println("Queue name is " + queueName);
    
              ?FONT COLOR="#808080">/*
             * Create a JNDI InitialContext object if none exists yet.
             */
              ?FONT COLOR="#000080">try {
                    ?FONT COLOR="#000000">jndiContext = new InitialContext();
                ?FONT COLOR="#000000">
        } catch (NamingException e) {
                    ?FONT COLOR="#000000">System.out.println("Could not create JNDI " +
                        ?FONT COLOR="#008000">"context: " + e.toString());
                    ?FONT COLOR="#000000">System.exit(1);
                ?FONT COLOR="#000000">
        }
    
              ?FONT COLOR="#808080">/*
             * Look up connection factory and queue.  If either does
             * not exist, exit.
             */
              ?FONT COLOR="#000080">try {
                    ?FONT COLOR="#000000">queueConnectionFactory = (QueueConnectionFactory)
                        ?FONT COLOR="#000000">jndiContext.lookup("QueueConnectionFactory");
                    ?FONT COLOR="#000000">queue = (Queue) jndiContext.lookup(queueName);
                ?FONT COLOR="#000000">
        } catch (NamingException e) {
                    ?FONT COLOR="#000000">System.out.println("JNDI lookup failed: "
                        ?FONT COLOR="#000000">+e.toString());
                    ?FONT COLOR="#000000">System.exit(1);
                ?FONT COLOR="#000000">
        }
    
              ?FONT COLOR="#808080">/*
             * Create connection.
             * Create session from connection; false means session is
             * not transacted.
             * Create receiver, then start message delivery.
             * Receive all text messages from queue until
             * a non-text message is received indicating end of
             * message stream.
             * Close connection.
             */
              ?FONT COLOR="#000080">try {
                    ?FONT COLOR="#000000">queueConnection = queueConnectionFactory.createQueueConnection();
                    ?FONT COLOR="#000000">queueSession = queueConnection.createQueueSession(false,
                                                              ?FONT COLOR="#000000">Session.AUTO_ACKNOWLEDGE);
                    ?FONT COLOR="#000000">queueReceiver = queueSession.createReceiver(queue);
                    ?FONT COLOR="#000000">queueConnection.start();
                    ?FONT COLOR="#000080">while (true) {
                          ?FONT COLOR="#000000">Message m = queueReceiver.receive(1);
                          ?FONT COLOR="#000080">if (m != null) {
                                ?FONT COLOR="#000080">if (m instanceof TextMessage) {
                                      ?FONT COLOR="#000000">message = (TextMessage) m;
                                      ?FONT COLOR="#000000">System.out.println("Reading message: " + message.getText());
                                  ?FONT COLOR="#000000">
              }
                                ?FONT COLOR="#000080">else if (m instanceof ObjectMessage) {
                                    ?I>// cast to an ObjectMessage so we can extract the object
                                     ObjectMessage cObjectMessage = (ObjectMessage) m;
                                     Object cObject = cObjectMessage.getObject();
                                    ?I>// make sure we got the correct type of object
                                    ?B>if (cObject instanceof LogEvent) {
                                         LogEvent cLogEvent = (LogEvent) cObject;
                                         System.out.print("Reading message: received LogEvent object,");
                                        ?I>// invoke the toString method on the object
                                         System.out.println(" LogEvent.toString():" + cLogEvent.toString());
                                      ?
                }
                                    ?B>else {
                                         System.out.println("Reading message: ignoring unexpected object of type " +
                                           cObject.getClass());
                                      ?
                }
                                  ?
              }
                                ?B>else {
                                    ?B>break;
                                  ?
              } 
                            ?FONT COLOR="#000000">
            }
                      ?FONT COLOR="#000000">
          }
                ?FONT COLOR="#000000">
        } catch (JMSException e) {
                    ?FONT COLOR="#000000">System.out.println("Exception occurred: " +
                        ?FONT COLOR="#000000">e.toString());
                ?FONT COLOR="#000000">
        } finally {
                    ?FONT COLOR="#000080">if (queueConnection != null) {
                          ?FONT COLOR="#000080">try {
                                ?FONT COLOR="#000000">queueConnection.close();
                            ?FONT COLOR="#000000">
            } catch (JMSException e) {
            }
                      ?FONT COLOR="#000000">
          }
                ?FONT COLOR="#000000">
        }
          ?FONT COLOR="#000000">
      }
    }
     
  2. Compile this with the command javac ObjectQueueReceiver.java.


Create the JMSObject type library

  1. Create a new subdirectory called c:\pure\JMSExample\ObjectQueue\JMSObject. This is where we will direct the output of the java2com tool.

  2. Run java2com and generate a type library containing the LogEvent class and also the same java classes we used in the Early Binding example.

     

  3. When you hit the Generate button, an IDL specification for the classes will be generated. Also generated are the java classes that the J-Integra® runtime requires to expose the Java classes as COM objects.

  4. Compile the java code and the IDL file and then register the type library (see pre-requisites for more information on midl):


  5. You have created and registered the type library. Now you need to add the JMSObject directory to your CLASSPATH in this console window because this is where you will run the COMtoJMSObject bridge.

     

    The second call to "set CLASSPATH" is not required, I did that so you could see what my classpath was.


Create the COMtoJMSObject bridge

  1. Copy the COMtoJMSEarly.java file from the Early Binding example to a file called COMtoJMSObject.java. Change the code as follows (changes are marked on bold font):

    // This is the bridge.  The VB client talks to this
    // process via DCOM, and this process talks to JMS.
    // If you have a Java server process you could add this
    // initialization there.
    
    import javax.naming.*;
    
    import com.linar.jintegra.*;
    
    public class COMtoJMSObject {
      ?FONT COLOR="#000080">public static void main(String[] args) throws Exception {
          ?FONT COLOR="#000080">try {
                ?FONT COLOR="#808080">// Generate a log just in case it all goes wrong
                ?FONT COLOR="#000000">com.linar.jintegra.Log.logImmediately(3, "jintegra.log");
    
                ?FONT COLOR="#808080">// Register the JVM name with the J-Integra® runtime
                ?FONT COLOR="#000000">Jvm.register("JMSObject");
    
                ?FONT COLOR="#808080">// Wait around for a while. When the process exits the objects
                ?FONT COLOR="#808080">// here will no longer be accessible from COM.
                ?FONT COLOR="#000080">while (true) {
                    ?FONT COLOR="#808080">// do nothing.
                    ?FONT COLOR="#000000">Thread.sleep(10000);
                  ?FONT COLOR="#000000">
          }
            ?FONT COLOR="#000000">
        }
          ?FONT COLOR="#000080">catch (Exception e) {
              ?FONT COLOR="#000000">System.out.println(e.getMessage());
              ?FONT COLOR="#000000">e.printStackTrace();
            ?FONT COLOR="#000000">
        }
        ?FONT COLOR="#000000">
      }
    }
     
  2. Compile this with the command javac COMtoJMSObject.java.

  3. Register the bridge and then start it as follows:

     


Start the J2EE Server and create a new JMS queue called "ObjectQueue"

  1. In another console configure the J2EE environment (see above) and start the J2EE server as per JMS tutorial.

  2. In yet another console, configure the J2EE environment and issue the following command to create a new queue.j2eeadmin -addJmsDestination ObjectQueue queue. where ObjectQueue is the name of the queue. To check that this was successful use the command j2eeadmin -listJmsDestination which lists all the queues in the system

Start the ObjectQueueReceiver

  1. In the same console that you created the queue in, change directory to c:\pure\JMSExample\ObjectQueue and run the ObjectQueueReceiver as shown here:

     

     
    Note that the last parameter is the queue name.


Create and Run the Visual Basic client

  1. Start Visual BASIC, create a 'Standard EXE" project.

  2. Open the project references dialog and check the JMSObject library.


     

    ¡¡

  3. Now put a button on the default form, and double-click on the button to edit its action code. Change the action code to the following:

    Private Sub Command1_Click()
        Dim objInitialContext As JMSObject.JavaxNamingInitialContext
        Set objInitialContext = New JMSObject.JavaxNamingInitialContext
           ?
        Dim objQueueConnectionFactory As JMSObject.JavaxJmsQueueConnectionFactory
        Set objQueueConnectionFactory = objInitialContext.lookup("QueueConnectionFactory")
       ?
        Dim objQueue As JMSObject.JavaxJmsQueue
        Set objQueue = objInitialContext.lookup("ObjectQueue")
           ?
       ? Note that javax.jms.QueueConnection has two createQueueConnection methods
       ? Here we call the method that takes no parameters
        Dim objQueueConnection As JMSObject.JavaxJmsQueueConnection
        Set objQueueConnection = objQueueConnectionFactory.createQueueConnection2()
       ?
       ? Note the second parameter to createQueueSession
        Dim objQueueSession As JMSObject.JavaxJmsQueueSession
        Set objQueueSession = objQueueConnection.createQueueSession(False, JMSObject.JavaxJmsSession_AUTO_ACKNOWLEDGE)
       ?
       ?
        Dim objQueueSender As JMSObject.JavaxJmsQueueSender
        Set objQueueSender = objQueueSession.createSender(objQueue)
       ?
        Dim objEvent As JMSObject.LogEvent
        Set objEvent = New JMSObject.LogEvent
        objEvent.m_cTimeStamp = Now       ? the current time
        objEvent.m_nEventSeverity = 7
        objEvent.m_cEventDescription = "Whatever you like, from VB"
       ?
        MsgBox "Sending event " + objEvent
       ? Note that there are two createObjectMessage methods. We use the parameterless one.
        Dim objMessage As JMSObject.JavaxJmsObjectMessage
        Set objMessage = objQueueSession.createObjectMessage2
        Call objMessage.setObject(objEvent)
           ?
        Call objQueueSender.send4(objMessage)
       ?
        MsgBox "Event logged."
    End Sub
     
  4. Now run the Visual Basic application. You should see the following:

    And the ObjectQueueReceive output...


How to Clean Up

The only item you need to be concerned about is the JMSObject type library. It is good practice to do the following cleanup before deleting the type library:

  1. cd c:\pure\JMSExample\ObjectQueue\JMSObject

  2. regtlb /unregister JMSObject.tlb

You may also unregister the JVM with regjvmcmd /unregister JMSObject.