Category: JMS questions

Q

How can I discover the queues or topics that I want to use?

A

You have to use the Java Naming and Directory Interface (JNDI) for that purpose. Most providers offer a built-in discovery mechanism that you can use to gain access to the factory objects for connections and and to discover queues and topics that are published by a server. In general, these are the steps you have to take:

  1. Put all required jar files on the application's classpath.
    Very often, the Java classes that you need to use for lookup operations are supplied in a vendor-specific jar file.
  2. Supply the JNDI bootstrap properties in some fashion.
    This could be done through the JNDI properties file, through -D options, or in code. We'll look at all of these options.
  3. Instantiate an InitialContext object as the root of your lookup operations.
  4. Start looking objects up by name

There's very little additional to say about the first step. The second step offers several different options and is therefore much more interesting to discuss.

You can supply the JNDI configuration properties via a jndi.properties file located on the application's classpath or in the $JAVA_HOME/lib directory, where $JAVA_HOME stands for the home directory of the JRE that you're using. This option is fairly straightforward, but it separates the JNDI configuration properties from your other Java configuration properties. In this case, you can use the default constructor for your InitialContext and you don't have to supply and JNDI configuration options in code. The following snippets show this approach:

 C++ 
 
int main( int argc, char * argv[] )
{
    xmog_jvm_loader & loader = xmog_jvm_loader::get_jvm_loader();

    loader.appendToClassPath( ... );

    InitialContext           ictx( _use_java_ctor );
    TopicConnectionFactory   tcf = 
        TopicConnectionFactory::dyna_cast( ictx.lookup(
            "TopicConnectionFactory" ) );

    ...
} 
 .NET 
 
static void Main( string args[] )
{
    IJvmLoader   loader = JvmLoader.GetJvmLoader();

    loader.AppendToClassPath( ... );

    InitialContext           ictx = new InitialContext();
    TopicConnectionFactory   tcf = 
        TopicConnectionFactoryImpl.From( ictx.Lookup(
            "TopicConnectionFactory" ) );

    ...
} 

You can also set the configuration properties as -D options, resulting in these properties being added to the System properties collection. This is an option that is suitable under many circumstances and you can use all Codemesh runtime configuration mechanisms in this approach. This is a good approach if your configuration information is statically known, configured by your installer, or known before the JVM is launched.

 C++ 
 
int main( int argc, char * argv[] )
{
    xmog_jvm_loader & loader = xmog_jvm_loader::get_jvm_loader();

    loader.appendToClassPath( ... );

    loader.setDashDOption( "java.naming.factory.initial",
                           "<classname>" );
    loader.setDashDOption( "java.naming.provider.url",
                           "<url>" );

    InitialContext           ictx( _use_java_ctor );
    TopicConnectionFactory   tcf = 
        TopicConnectionFactory::dyna_cast( ictx.lookup(
            "TopicConnectionFactory" ) );

    ...
} 
 .NET 
 
static void Main( string args[] )
{
    IJvmLoader   loader = JvmLoader.GetJvmLoader();

    loader.AppendToClassPath( ... );

    loader.DashDOption[ "java.naming.factory.initial" ] = "<classname>";
    loader.DashDOption[ "java.naming.provider.url" ] = "<url>";

    InitialContext           ictx = new InitialContext();
    TopicConnectionFactory   tcf = 
        TopicConnectionFactoryImpl.From( ictx.Lookup(
            "TopicConnectionFactory" ) );

    ...
} 

Finally, you can create a Hashtable containing the configuration properties and pass that hashtable to the InitialContext constructor. This is the most flexible approach because it allows you to configure different InitialContext instances with different JNDI properties. You could connect to more than one JMS provider this way.

 C++ 
 
int main( int argc, char * argv[] )
{
    xmog_jvm_loader & loader = xmog_jvm_loader::get_jvm_loader();

    loader.appendToClassPath( ... );

    Hashtable                ht( _use_java_ctor );

    ht.put( "java.naming.factory.initial", "<classname>" );
    ht.put( "java.naming.provider.url", "<url>" );

    InitialContext           ictx( ht );
    TopicConnectionFactory   tcf = 
        TopicConnectionFactory::dyna_cast( ictx.lookup(
            "TopicConnectionFactory" ) );

    ...
} 
 .NET 
 
static void Main( string args[] )
{
    IJvmLoader   loader = JvmLoader.GetJvmLoader();

    loader.AppendToClassPath( ... );

    Java.Util.Hashtable      ht = new Java.Util.Hashtable();

    ht.Put( "java.naming.factory.initial", "<classname>" );
    ht.Put( "java.naming.provider.url", "<url>" );

    InitialContext           ictx = new InitialContext();
    TopicConnectionFactory   tcf = 
        TopicConnectionFactoryImpl.From( ictx.Lookup(
            "TopicConnectionFactory" ) );

    ...
} 

The JNDI properties that you usually have to configure are listed below.
 

Property name Description
java.naming.factory.initial Name of the class that provides the initial context that is the root of all other lookup operations.
java.naming.provider.url URL at which instance-specific information can be found. This is usually a URL consisting of a provider-specific protocol, the name of the server and a provider-specific port number. It could also be a file URL refering to a config file.
java.naming.security.principal Sometimes required username.
java.naming.security.credentials Sometimes required password.
java.naming.factory.url.pkgs Sometimes required list of names of packages containing required URL context factories.

A full list of JNDI configuration properties is available here.

For more details on the dyna_cast() method, check out the classcast FAQ.


Copyright 2006-2011 by Codemesh, Inc., ALL RIGHTS RESERVED

:
frequently asked questions
home products support customers partners newsroom about us contact us