JNDI Client
Federated JNDI Context
Overview
The Federated JNDI Context is the default built-in JNDI context which directly communicates with the JNDI Swiftlet of the connected SwiftMQ Router.
InitialContextFactory
Class Name
JNDI uses a factory pattern to create a vendor specific implementation of InitialContext
. The name of the provider's
implementation of this InitialContextFactory
must be set in an environment table before creating an InitialContext object.
The name of SwiftMQ's InitialContextFactory
implementation is:
com.swiftmq.jndi.InitialContextFactoryImpl
JNDI Provider URL
The JNDI provider URL is used to set up the internal connection properties. A JNDI connection is internally backed up by a JMS connection. Hereby, any available JMS inbound listener can be used. For details please have a look at the JMS Swiftlet configuration.
The JNDI provider URL specifies the properties of the underlying JMS connection with the following format:
smqp://[[:]@](:)|"intravm"[/[host2=][port2=]
[reconnect=][retrydelay=][maxretries=][type=]
[;timeout=][;keepalive=][debug=]
Where
smqp ::= Specifies the SwiftMQ Protocol
::= Username. Default is 'anonymous'
::= User's password. Default is null.
::= DNS hostname of the router or 1st HA instance
or the keyword "intravm" to connect intra-VM
::= JMS listener port of the of the router or 1st HA instance
host2 ::= DNS hostname of the 2nd HA instance
port2 ::= JMS listener port of the 2nd HA instance
reconnect ::= Specifies whether an automatic reconnect should be done
retrydelay ::= Amount in milliseconds to wait between reconnect retries
maxretries ::= Max. number of reconnect retries
type ::= Class name of the socket factory used by this JMS listener.
In this release, com.swifmq.net.PlainSocketFactory and
com.swiftmq.net.JSSESocketFactory are available. Default is
com.swifmq.net.PlainSocketFactory. See JMS Swiftlet configuration for details.
timeout ::= Specifies a timeout in milliseconds for lookups. If no JNDI object is
received within this time, the lookup throws a NamingException. Default is no timeout;
lookups are waiting until they receive the requested JNDI objects.
keepalive ::= Specifies a keepalive interval in milliseconds. If this value is greater 0, a
timer is created on the client side to send keepalive messages to detect broken
JNDI connections. Default is 60000 (1 minute).
debug ::= If true, debug information are printed to System.out. Good for testing.
Note: Attributes "host2" and "port2" are reserved when connection to a SwiftMQ HA Router.
Examples
JNDI lookups should be performed via a JMS listener on host localhost
, port 4001
, as user anonymous
. The JMS listener
provides access via a com.swiftmq.net.PlainSocketFactory
. No lookup timeout should be set:
smqp://locahost:4001
JNDI lookups should be performed via a JMS listener on host www.swiftmq.com
, port 4020
, as user johnsmith
,
password ballaballa
. The JMS inbound listener provides access via a com.swiftmq.net.JSSESocketFactory
. The lookup timeout
should be set to 20 secs:
smqp://johnsmith:ballaballa@www.swiftmq.com:4020/type=com.swiftmq.net.JSSESocketFactory;timeout=20000
Connects to host jms1
at port 4001
. If a connection lost is detected, it reconnects with a delay of 1 second between
retries. It stops retries after 50 unsuccessful attempts. JNDI lookup timeout is set to 10 seconds.
smqp://jms1:4001/timeout=10000;reconnect=true;retrydelay=1000;maxretries=50
Performing JNDI Lookups
To use JNDI, the following import statement has to be included into the application's import list:
import javax.naming.*;
Furthermore, the JNDI and the SwiftMQ classes must be accessible through the CLASSPATH
.
Before creating an InitalContext
object, two environment properties must be set. These are the names of the InitialContextFactory
implementation and the SwiftMQ JNDI-Provider-URL:
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.swiftmq.jndi.InitialContextFactoryImpl");
env.put(Context.PROVIDER_URL,"smqp://localhost:4001");
Then, the InitialContext
is to be created:
InitialContext ctx = new InitialContext(env);
Now, a JNDI connection has been established and lookups can be performed to fetch the appropriate administered objects:
TopicConnectionFactory tcf = (TopicConnectionFactory)ctx.lookup("plainsocket@router3");
Topic topic = (Topic)ctx.lookup("iit.projects.swiftmq");
// etc pp
Bind/Rebind/Unbind
A JMS client that has created a TemporaryTopic
or a TemporaryQueue
can register this kind of objects within SwiftMQ's JNDI
implementation. It is not permitted to register other types of objects. After registration, other JMS clients are able to
lookup these objects under their registered names. This is a rare case, because the normal handling of this issue is done
by the TopicRequestor
resp. QueueRequestor
helper classes. Here, the temporary destination is set in the message by the
message producer as a JMSReplyTo
header. The receiver/subscriber gets this destination and replies to it. In special cases,
this procedure is not possible. For this cases, the destinations could be registered within JNDI.
To register a temporary destination, use Context.bind
:
TemporaryQueue tq = queueSession.createTemporaryQueue();
ctx.bind("myTempQueue",tq);
Another client is able to lookup this object and send messages to it:
TemporaryQueue tq = ctx.lookup("myTempQueue");
QueueSender sender = queueSession.createQueueSender(tq);
sender.send(msg);
A client can also change an existing registration with Context.rebind
:
ctx.rebind("myInboundQueue",tq);
And, of course, it can remove the registration with:
ctx.unbind("myInboundQueue");
JNDI registrations of temporary destinations have a lifetime of the temporary destination itself. If the temporary destination will be deleted by the client, for example with tq.delete(), or the JMS connection that has created the temporary destination will be closed (which deletes implicitly their temporary destinations), all JNDI registrations of this destinations will also be deleted automatically. So, a client does not need to explicitly call unbind for his registrations.
Closing the Context
It is recommended to fetch all administered objects only once, at application startup. If all lookups have been processed
orderly, the InitialContext object should be closed, because of the open JMS connection. Closing the InitialContext
,
the connection is dropped and all resources on client and server side are released. Otherwise the client does not
terminate, because there are running threads. In other words, close the InitialContext
object after your lookups:
Filesystem JNDI Context
Overview
The Filesystem JNDI Context is a built-in filesystem based JNDI context which uses a directory at the client to store and lookup JNDI objects.
InitialContextFactory
Class Name
JNDI uses a factory pattern to create a vendor specific implementation of InitialContext
. The name of the provider's
implementation of this InitialContextFactory
must be set in an environment table before creating an InitialContext
object.
The name of SwiftMQ's filesystem based InitialContextFactory
implementation is com.swiftmq.jndi.fs.InitialContextFactoryImpl
.
JNDI Provider URL
The JNDI provider URL is a file URL and must point to the directory where the JNDI objects are stored.
Example:
file:///home/test/myjndi
Storing JNDI Objects
There are 2 ways to store JNDI objects in the directory where the JNDI provider URL points to:
- By JNDI replication
- By manual creation
JNDI replication can be set up in the JNDI Swiftlet by using the JNDI properties described for the JNDI lookup, see below. It dumps all registered JNDI objectes to the directory specified by the JNDI provider URL. This directory then can be transferred to the clients to perform the lookups.
The other way is the manual creation of the JNDI objects. SwiftMQ uses XStream for JNDI object serialization. There are 3 types of administered objects that can be stored: Connection factories, queues and topics. JNDI objects are stored one file per object with the lookup name as the file name plus a ".xml" extension like "ConnectionFactory.xml".
Connection Factories
Various attributes can be defined. Have a look at the JMS Swiftlet for their meanings. Here is an example, stored in file "ConnectionFactory.xml", of a connection factory that was dumped in a JNDI replication:
<com.swiftmq.jms.v750.ConnectionFactoryImpl>
<listenerName>plainsocket</listenerName>
<socketFactoryClass>com.swiftmq.net.PlainSocketFactory</socketFactoryClass>
<hostname>imac-buero</hostname>
<port>4001</port>
<keepaliveInterval>60000</keepaliveInterval>
<smqpProducerReplyInterval>20</smqpProducerReplyInterval>
<smqpConsumerCacheSize>500</smqpConsumerCacheSize>
<smqpConsumerCacheSizeKB>2048</smqpConsumerCacheSizeKB>
<jmsDeliveryMode>2</jmsDeliveryMode>
<jmsPriority>4</jmsPriority>
<jmsTTL>0</jmsTTL>
<jmsMessageIdEnabled>true</jmsMessageIdEnabled>
<jmsMessageTimestampEnabled>true</jmsMessageTimestampEnabled>
<useThreadContextCL>false</useThreadContextCL>
<inputBufferSize>131072</inputBufferSize>
<inputExtendSize>65536</inputExtendSize>
<outputBufferSize>131072</outputBufferSize>
<outputExtendSize>65536</outputExtendSize>
<intraVM>false</intraVM>
<port2>-1</port2>
<reconnectEnabled>true</reconnectEnabled>
<maxRetries>50</maxRetries>
<retryDelay>10000</retryDelay>
<duplicateMessageDetection>true</duplicateMessageDetection>
<duplicateBacklogSize>30000</duplicateBacklogSize>
</com.swiftmq.jms.v750.ConnectionFactoryImpl>
Queues
An example, stored in file "testqueue@router1.xml", of a queue that was dumped in a JNDI replication
(Attribute s
is the name of the queue):
<com.swiftmq.jms.QueueImpl>
<queueName>
<s>testqueue@router1</s>
</queueName>
</com.swiftmq.jms.QueueImpl>
Topics
An example, stored in file "testtopic.xml", of a queue that was dumped in a JNDI replication (Attribute s
is the
name of the topic):
<com.swiftmq.jms.TopicImpl>
<topicName>
<s>testtopic</s>
</topicName>
</com.swiftmq.jms.TopicImpl>
Performing JNDI Lookups
To use JNDI, the following import statement has to be included into the application's import list:
import javax.naming.*;
Furthermore, the JNDI and the SwiftMQ classes must be accessible through the CLASSPATH
.
Before creating an InitalContext
object, two environment properties must be set. These are the names of the
InitialContextFactory
implementation and the JNDI-Provider-URL:
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.swiftmq.jndi.fs.InitialContextFactoryImpl");
env.put(Context.PROVIDER_URL,"file:///path/to/localjndi");
Then, the InitialContext
is to be created:
InitialContext ctx = new InitialContext(env);
Now lookups can be performed to fetch the JNDI objects:
TopicConnectionFactory tcf = (TopicConnectionFactory)ctx.lookup("plainsocket@router3");
Topic topic = (Topic)ctx.lookup("iit.projects.swiftmq");
// etc pp