JMS101 - part II - the sequel

Squirrels to me are evil creatures. My interactions mostly consist of watching them run along my fence and having them throw acorns down at both my car and me and chatter with malicious glee as I run into the house to avoid the shower. A good friend of mine sees them as poor maligned innocent woodland creatures, I know this because he recently found a hurt squirrel in his back yard, made it a nest on his back porch and is now feeding it dog kibble and nuts as it heals.

You are wondering where I'm going with this right ? Well, mostly I just wanted to share my squirrel pain but its also important to remember that two people look at something in different ways. Thats why administered objects exist in JMS, because two providers look at the system in different ways (see - I managed to go somewhere with it).

So - as you no doubt guessed, my plan for today is to expand the hello world example to use JNDI and administered objects. If you have no idea what I am talking about with the HelloWorld example, start with the initial blog entry on JMS 101.

Again, I'll list all of the caveats. This is an intro to MQ/JMS entry and may not be suitable for more advanced viewers, my background is on the server side not the client side so my terminology is suspect, the names might be changed to protect the innocent.

The prologue

To change a program, such as the HelloWorld example, into one that uses Administered Objects a couple of things are going to happen:

  1. select whether we use a file or LDAP based repository
  2. update the code
  3. create the administered objects

Today, I'm picking a file based repository. Its simpler as an initial example and won't require that I spend time doing screen snapshots of the Sun Directory Server. I promise to do it soon (although not next, since my plan - however tenuous - is to talk about MQ specific features next because I had a request for that).

Quick diversion... while I never specifically mentioned this in the previous JMS 101 discussion, the JMS api is all interfaces. To use it, you have to get a concrete object (usually from JNDI) which is the actual implementation class used by the provider. and then call the interface methods on the class

Before I go any farther, I should take a few seconds to talk about JNDI. If you want the really technical bits, you should take a break for the moment and go off to the Technology overview for JNDI on the java.sun.com page. If you are familiar with it, skip the next few sentences because it may cause my simplistic definition may cause you to cringe. What is does is allow you to create an object, referred to by a name, which contains a set of attributes. In our case we will have a name (HelloConnectionFactory), and we will look it up in the file based repository to retrieve the MQ specific version of that class including any properties we have set on it.

The main Event

Updating the code to use JNDI

In the last example we used the following line to create the connection factory:

ConnectionFactory cf= new com.sun.messaging.ConnectionFactory();

We are now going to replace that line with code to retrieve the object using jndi.

We also used the createQueue api to create our Queue style destination. While its valid to create a destination using that API, we are going to change to retrieve the Queue from JNDI (mostly because we can). That code was :

Destination destination = session.createQueue("HelloWorld");

Since we are using a file based repository, we need to define where its going to live. For the moment it will live in /tmp/jndi.

NOTE: I'm going to pick unix, not windows, paths because that is my primary desktop. If you are running windows, you will have to use something like C:\\\\tmp\\jndi.

Now - I have to determine the names for our connection factory objects. I'm using HelloConnectionFactory and HelloQueue

I'm show the new code, at then end I'll stick in the updated HelloConsumer source so you can see the changes. (I'm not bothering with giving you HelloProducer since the code changes are the same)

First, I'm going to create the initial Context. That is our connection to the file based JNDI store.

  • com.sun.jndi.fscontext.RefFSContextFactory Is our INITIAL_CONTEXT_FACTORY (that is the file based implementation provided by java).
  • file:///tmp/jndi
I am going to set that information in a hashtable and then create an object called InitialContext with it.

The code is:

       Hashtable env;
        Context	ctx = null;

        env = new Hashtable();

        // Store the environment variables that tell JNDI which initial context
        // to use and where to find the provider.

        // For use with the File System JNDI Service Provider
        env.put(Context.INITIAL_CONTEXT_FACTORY, 
		"com.sun.jndi.fscontext.RefFSContextFactory");
        env.put(Context.PROVIDER_URL, "file:///tmp/jndi");

        try {
	    // Create the initial context.
	    ctx = new InitialContext(env);
       } catch (NamingException ex) {
      }

Next we are going to retrieve the HelloConnectionFactory (which we haven't created yet - thats coming soon). To get the object, we use the lookup method on the context object we just created. So:

cxt.lookup("HelloConnectionFactory");

The more detailed code is:

     ConnectionFactory cf = null;
      try {
            // Lookup my connection factory from the admin object store.
            // The name used here here must match the lookup name 
            // used when the admin object was stored.
	    System.out.println("Looking up Connection Factory object with lookup name: HelloConnectionFactory");
            cf = (javax.jms.ConnectionFactory) ctx.lookup("HelloConnectionFactory");
	    System.out.println("Connection Factory object found.");
        } catch (NamingException ne)  {
	    System.err.println("Failed to lookup Connection Factory object.");
	    ne.printStackTrace();
	    System.exit(-1);
        }

Finally, we are going to look up HelloQueue. To get the object, we will use the lookup method on the context object we just created yet again. So:

cxt.lookup("HelloQueue");

The more detailed code is:


       Queue queue = null;
        try {
            // Lookup my queue from the admin object store.
            // The name I search for here must match the lookup name used when
            // the admin object was stored.
	    System.out.println("Looking up Queue object with lookup name: HelloQueue");
            queue = (javax.jms.Queue)ctx.lookup("HelloQueue");
	    System.out.println("Queue object found.");
        } catch (NamingException ne)  {
	    System.err.println("Failed to lookup Queue object.");
	    ne.printStackTrace();
	    System.exit(-1);
        }
Using imqobjmgr

imqobjmgr is the tool which is used to create MQ connection factories (although you can also use the gui based admin tool - but I'm a server side girl so I like command lines). It has five subcommands:

  • add - add an administered object
  • delete - delete an administered object
  • list - list all of the objects in this store
  • query - return the specific attributes of an administered object
  • update - change the attributes of an administered object

Since this is an extremely basic example, all I'm going to use is add. When you use the add command, at a minimum you must pass in the name and the type as well as object store attributes that allow us to connect to it (you can also pass in configuration properties which I'm also not going to use this time).

In the code above I specified:

  • file:///tmp/jndi as the location of the jdni store
  • that I am using the file context: com.sun.jndi.fscontext.RefFSContextFactory
  • that there a queue named HelloQueue
  • That there is a ConnectionFactory called HelloConnectionFactory

So the commands are are going to run are:

% imqobjmgr add -j java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory -j java.naming.provider.url=file:///tmp/jndi -l HelloConnectionFactory -t cf

% imqobjmgr add -j java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory -j java.naming.provider.url=file:///tmp/jndi -l HelloQueue -t q 

The epilogue

Ok - I'm almost done (yea !!! I'm ready to do something else, if you are reading this you are no doubt in the same state). I'll I'm going to show is the final HelloConsumer.java code and the output of the imqobjmgr commands.

The code


import javax.jms.\*;
import javax.naming.\*;

/\*\*
 \* simple hello world consumer
 \*/
public class HelloConsumer
{
    /\*\*
     \* simple consumer
     \*/
    public HelloConsumer() {
        try {
           Hashtable env;
           Context	ctx = null;

           env = new Hashtable();

           // Store the environment variables that tell JNDI which initial context
           // to use and where to find the provider.

           // For use with the File System JNDI Service Provider
           env.put(Context.INITIAL_CONTEXT_FACTORY, 
		"com.sun.jndi.fscontext.RefFSContextFactory");
           env.put(Context.PROVIDER_URL, "file:///tmp/jndi");

           try {
	        // Create the initial context.
	        ctx = new InitialContext(env);
           } catch (NamingException ex) {
               ex.printStackTrace();
               System.exit(-1);
           }

            // creating a connection factory

            ConnectionFactory cf= new com.sun.messaging.ConnectionFactory();
            ConnectionFactory cf = null;
            try {
                   // Lookup my connection factory from the admin object store.
                   // The name used here here must match the lookup name 
                   // used when the admin object was stored.
	           System.out.println("Looking up Connection Factory object with lookup name: HelloConnectionFactory");
                   cf = (javax.jms.ConnectionFactory) ctx.lookup("HelloConnectionFactory");
	           System.out.println("Connection Factory object found.");
            } catch (NamingException ne)  {
	           System.err.println("Failed to lookup Connection Factory object.");
	           ne.printStackTrace();
	           System.exit(-1);
            }


            // create a connection
            Connection connection = cf.createConnection();
           
            // create a session
            Session session = connection.createSession( 
                     false /\* not transacted \*/, Session.AUTO_ACKNOWLEDGE);

            // create destination HelloWorld
            Destination destination = session.createQueue("HelloWorld");

            Queue queue = null;
            try {
                // Lookup my queue from the admin object store.
                // The name I search for here must match the lookup name used when
                // the admin object was stored.
	        System.out.println("Looking up Queue object with lookup name: HelloQueue");
                queue = (javax.jms.Queue)ctx.lookup("HelloQueue");
	        System.out.println("Queue object found.");
            } catch (NamingException ne)  {
	        System.err.println("Failed to lookup Queue object.");
	        ne.printStackTrace();
	        System.exit(-1);
            }

            // create a consumer
            MessageConsumer consumer = session.createConsumer(destination);

            // now that everything is ready to go, start the connection
            connection.start();

            // receive our message
            TextMessage m = (TextMessage)consumer.receive();

            System.out.println(m.getText());

            // close everything
            consumer.close();
            session.close();
            connection.close();

            
        } catch (JMSException ex) {
            System.out.println("Error running program");
            ex.printStackTrace();
        }
    }


    /\*\*
     \* main method
     \*/
    public static void main(String args[]) {
        new HelloConsumer();
    }
}


creating the Connection factory



% imqobjmgr add -j java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory -j java.naming.provider.url=file:///tmp/jndi -l HelloConnectionFactory -t cf



Adding a Connection Factory object with the following attributes:



imqAckOnAcknowledge [Message Service Acknowledgement of Client Acknowledgements]              
imqAckOnProduce [Message Service Acknowledgement of Produced Messages]                        
imqAckTimeout [Message Service Acknowledgement Timeout (milliseconds)]                        0
imqAddressList [Message Server Address List]                                                  
imqAddressListBehavior [Address List Order]                                                   PRIORITY
imqAddressListIterations [Number of Address List Iterations]                                  1
imqBrokerHostName [Broker Host Name]                                                          localhost
imqBrokerHostPort [Broker Host Port]                                                          7676
imqBrokerServicePort [Broker Service Port]                                                    0
imqConfiguredClientID [Configure ClientID as]                                                 
imqConnectionFlowCount [Connection Flow Count]                                                100
imqConnectionFlowLimit [Connection Flow Limit (Unconsumed Messages per Connection)]           1000
imqConnectionFlowLimitEnabled [Connection Flow Limit Enabled]                                 false
imqConnectionType [Connection Type]                                                           TCP
imqConnectionURL [HTTP URL]                                                                   http://localhost/imq/tunnel
imqConsumerFlowLimit [Consumer Flow Limit (Unconsumed Messages per Consumer)]                 1000
imqConsumerFlowThreshold [Consumer Flow Threshold (Percent)]                                  50
imqDefaultPassword [Default Password]                                                         guest
imqDefaultUsername [Default Username]                                                         guest
imqDisableSetClientID [Disable setClientID() JMS API]                                         false
imqJMSDeliveryMode [JMSDeliveryMode value]                                                    PERSISTENT
imqJMSExpiration [JMSExpiration value]                                                        0
imqJMSPriority [JMSPriority value]                                                            4
imqLoadMaxToServerSession [Load Upto Maximum Messages to ServerSessions]                      true
imqOverrideJMSDeliveryMode [Override JMSDeliveryMode]                                         false
imqOverrideJMSExpiration [Override JMSExpiration]                                             false
imqOverrideJMSHeadersToTemporaryDestinations [Override Messages to Temporary Destinations]    false
imqOverrideJMSPriority [Override JMSPriority]                                                 false
imqPingInterval [Connection Ping Interval (seconds)]                                          30
imqQueueBrowserMaxMessagesPerRetrieve [Queue Browser Retrieve Size (# of messages)]           1000
imqQueueBrowserRetrieveTimeout [Queue Browser Retrieve Timeout (milliseconds)]                60000
imqReconnectAttempts [Number of Reconnect Attempts per Address]                               0
imqReconnectEnabled [Enable Auto-reconnect to Message Server]                                 false
imqReconnectInterval [Reconnect Interval per Address (milliseconds)]                          3000
imqSSLIsHostTrusted [SSL Host Trusted]                                                        false
imqSetJMSXAppID [Enable JMSXAppID Message Property]                                           false
imqSetJMSXConsumerTXID [Enable JMSXConsumerTXID Message Property]                             false
imqSetJMSXProducerTXID [Enable JMSXProducerTXID Message Property]                             false
imqSetJMSXRcvTimestamp [Enable JMSXRcvTimestamp Message Property]                             false
imqSetJMSXUserID [Enable JMSXUserID Message Property]                                         false

Using the following lookup name:

HelloConnectionFactory

The object's read-only state:  false

To the object store specified by:

java.naming.factory.initial    com.sun.jndi.fscontext.RefFSContextFactory
java.naming.provider.url       file:///tmp/jndi

Object successfully added.

creating the Queue


% imqobjmgr add -j java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory -j java.naming.provider.url=file:///tmp/jndi -l HelloQueue -t q 



Adding a Queue object with the following attributes:

imqDestinationDescription [Destination Description]    A Description for the Destination Object
imqDestinationName [Destination Name]                  Untitled_Destination_Object

Using the following lookup name:

HelloQueue

The object's read-only state:  false

To the object store specified by:

java.naming.factory.initial    com.sun.jndi.fscontext.RefFSContextFactory
java.naming.provider.url       file:///tmp/jndi

Object successfully added.


Comments:

Thanks Linda,
The article is perfect for me. I never knew how to set-up a queue from scratch using JNDI. I am going to download MQ and try it out myself.

Posted by Patrick Kimber on November 20, 2007 at 02:01 AM GMT #

Code snippet: env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:///tmp/jndi");

Linda, one of the benefits I see of external (JNDI) configuration is platform independence, i.e., you can switch to another JMS provider without needing to recompile your Producer/Consumer code.

But using a OpenMQ-specific class (com.sun.jndi.fscontext.RefFSContextFactory) in the producer and consumer code would seem to defeat that. Within JMS, is there a platform-independent way to refer to a file or LDAP directory for JNDI purposes? (If "no", I guess you can otherwise use Dependency Injection for the "...RefFSContextFactory" string and pass in something else if you want to use a different provider.)

Regards,
Glen

Posted by Glen Mazza on November 20, 2007 at 07:10 AM GMT #

Hi Linda,

Great introduction to this topic. There is a minor copy/paste bug in this example:

// creating a connection factory
// we are cheating here by not using jdni
ConnectionFactory cf= new com.sun.messaging.ConnectionFactory();
ConnectionFactory cf = null;

You can of course remove the 'we are cheating' comment and the first instantiation of 'cf' since we are not cheating in this version.

Regards,
John

Posted by John Gage on December 18, 2007 at 01:47 AM GMT #

Dear John,

You are right about the cut and paste error - fixing it now.

Thank you :-)

Posted by Linda Schneider on December 18, 2007 at 08:39 AM GMT #

Hello Linda,
i've created the queue and queueFactory. I use the MQ (SUN MQ4.1) with Peoplesoft Campus Solution with JMS. The export from out PS (JMStarget) works fine, the message arrives nice in the queue(inbound).
Now i want the JMS listening from PS pulls the messages form the outbound queue from the SUN MQ. But I get a error cannot instantiate claas; com.sun.jndi.fscontext.RefFSContextFactory not found. But the bindings file is in ///tmp/mq and the jar files are in /websrv/WEB-INF/lib folder. Pinging give good results..only PS gives in the errorLog this error. Can i use jave -Djava.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory?
Please, do you have experience with this error in combination with SUN MQ and PeopleSoft?
regards,
Rene Visscher

Posted by Rene Visscher on April 18, 2008 at 12:50 AM BST #

does one have to run the Message Broker daemon (imqbrokerd) for message delivery?

Posted by Kevin on November 05, 2009 at 04:23 AM GMT #

Hello Kevin,
we have running the imqbrokerd for mq 3.7
This is in combination with PeopleSoft Campus Solution and SUN Identity Manager. Peoplesoft runs a export from studentattributes and puts this is a message queue. Identity Manager with a jms listener pulss the messages out this mq.

Posted by Rene Visscher on November 08, 2009 at 11:59 PM GMT #

Dear Linda,
Thanks for your very helpful articles. I Will look for more from you.
In this article the queue object that we get from jndi in HelloConsumre is not used. We get the queue from jndi but we are still using the destination from previous article. I think this is another copy/paste issue.

Posted by Sean on December 11, 2009 at 08:20 AM GMT #

you are best of the best Linda, i tried a lot of tutorials to understand JMS but only your blog worked well without any problems and give me a good view for this subject

Posted by M.Hamoda on January 26, 2010 at 12:49 AM GMT #

Thanks for this entry Linda. I've been battling with JMS for a project picked up from a client (the developers all left...) This really helped me get to grips with how everything works.

Posted by James Morris on March 16, 2010 at 04:55 AM GMT #

Post a Comment:
Comments are closed for this entry.
About

A blog for Open Message Queue, the JMS provider in GlassFish Server, Open Source Edition

Search

Top Tags
Categories
Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today
Feeds