Category: JMS questions
How can I discover the queues or topics that I want to use?
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:
- 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. - 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. - Instantiate an InitialContext object as the root of your lookup operations.
- 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.
