Obtaining a Connection Factory
Typically, a connection factory is created for you by a Message Queue
administrator and preconfigured, using the administration tools
described in "Administrative Tasks and Tools" in Open
Message Queue Administration Guide with whatever property settings are
appropriate for connecting to particular JMS provider. The factory is
then placed in a publicly available administered object store, where you
can access it by name using the Java Naming and Directory Interface
(JNDI) API. This arrangement has several benefits:
-
It allows the administrator to control the properties of client
connections to the provider, ensuring that they are properly configured.
-
It enables the administrator to tune performance and improve
throughput by adjusting configuration settings even after an application
has been deployed.
-
By relying on the predefined connection factory to handle the
configuration details, it helps keep client code provider-independent
and thus more easily portable from one JMS provider to another.
Sometimes, however, it may be more convenient to dispense with JNDI
lookup and simply create your own connection factory by direct
instantiation. Although hard-coding configuration values for a
particular JMS provider directly into your application code sacrifices
flexibility and provider-independence, this approach might make sense in
some circumstances: for example, in the early stages of application
development and debugging, or in applications where reconfigurability
and portability to other providers are not important concerns.
The following sections describe these two approaches to obtaining a
connection factory: by JNDI lookup or direct instantiation.
Looking Up a Connection Factory With JNDI
Example 4-1 shows how to look up a connection factory
object in the JNDI object store. The code example is explained in the
procedure that follows.
Note
|
If a Message Queue client is a Java EE component, JNDI resources are
provided by the Java EE container. In such cases, JNDI lookup code may
differ from that shown here; see your Java EE provider documentation for
details.
|
Example 4-1 Looking Up a Connection Factory
// Create the environment for constructing the initial JNDI
// naming context.
Hashtable env = new Hashtable();
// Store the environment attributes that tell JNDI which initial context
// factory to use and where to find the provider.//
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:///C:/imq_admin_objects");
// Create the initial context.
Context ctx = new InitialContext(env);
// Look up the connection factory object in the JNDI object store.
String CF_LOOKUP_NAME = "MyConnectionFactory";
ConnectionFactory myFactory = (ConnectionFactory) ctx.lookup
(CF_LOOKUP_NAME);
To Look Up a Connection Factory With JNDI
-
Create the environment for constructing the initial JNDI naming
context.
How you create the initial context depends on whether you are using a
file-system object store or a Lightweight Directory Access Protocol
(LDAP) server for your Message Queue administered objects. The code
shown here assumes a file-system store; for information about the
corresponding LDAP object store attributes, see "Using
an LDAP User Repository" in Open Message Queue Administration Guide.
The constructor for the initial context accepts an environment
parameter, a hash table whose entries specify the attributes for
creating the context:
Hashtable env = new Hashtable();
You can also set an environment by specifying system properties on the
command line, rather than programmatically. For instructions, see the
README
file in the JMS example applications directory.
2. Store the environment attributes that tell JNDI which initial
context factory to use and where to find the JMS provider.
The names of these attributes are defined as static constants in class
Context
:
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, "file:///C:/imq_admin_objects");
Note
|
The directory represented by `C:/`imq_admin_objects must already exist;
if necessary, you must create the directory before referencing it in
your code.
|
-
Create the initial context.
Context ctx = new InitialContext(env);
If you use system properties to set the environment, omit the
environment parameter when creating the context:
Context ctx = new InitialContext();
-
Look up the connection factory object in the administered object
store and typecast it to the appropriate class:
String CF_LOOKUP_NAME = "MyConnectionFactory";
ConnectionFactory
myFactory = (ConnectionFactory) ctx.lookup(CF_LOOKUP_NAME);
The lookup name you use, CF_LOOKUP_NAME
, must match the name used when
the object was stored.
You can now proceed to use the connection factory to create connections
to the message broker, as described under Using
Connections.
Overriding Configuration Settings
It is recommended that you use a connection factory just as you receive
it from a JNDI lookup, with the property settings originally configured
by your Message Queue administrator. However, there may be times when
you need to override the preconfigured properties with different values
of your own. You can do this from within your application code by
calling the connection factory’s setProperty
method. This method
(inherited from the superclass AdministeredObject
) takes two string
arguments giving the name and value of the property to be set. The
property names for the first argument are defined as static constants in
the Message Queue class ConnectionConfiguration
: for instance, the
statement
myFactory.setProperty(ConnectionConfiguration.imqDefaultPassword,
"mellon");
sets the default password for establishing broker connections. See
"Connection Factory Attributes" in Open Message Queue
Administration Guide for complete information on the available
connection factory configuration attributes.
It is also possible to override connection factory properties from the
command line, by using the -D
option to set their values when starting
your client application. For example, the command line
java -DimqDefaultPassword=mellon MyMQClient
starts an application named MyMQClient
with the same default password
as in the preceding example. Setting a property value this way overrides
any other value specified for it, whether preconfigured in the JNDI
object store or set programmatically with the setProperty
method.
Note
|
A Message Queue administrator can prevent a connection factory’s
properties from being overridden by specifying that the object be
read-only when placing it in the object store. The properties of such a
factory cannot be changed in any way, whether with the -D option from
the command line or using the setProperty method from within your
client application’s code. Any attempt to override the factory’s
property values will simply be ignored.
|
Instantiating a Connection Factory
Example 4-2 shows how to create a connection factory object
by direct instantiation and configure its properties.
Example 4-2 Instantiating a Connection Factory
// Instantiate the connection factory object.
com.sun.messaging.ConnectionFactory
myFactory = new com.sun.messaging.ConnectionFactory();
// Set the connection factory's configuration properties.
myFactory.setProperty(ConnectionConfiguration.imqAddressList,
"localhost:7676,broker2:5000,broker3:9999");
The following procedure explains each program statement in the previous
code sample.
To Instantiate and Configure a Connection Factory
-
Instantiate the connection factory object.
The name ConnectionFactory
is defined both as a JMS interface (in
package jakarta.jms
) and as a Message Queue class (in
com.sun.messaging
) that implements that interface. Since only a class
can be instantiated, you must use the constructor defined in
com.sun.messaging
to create your connection factory object. Note,
however, that you cannot import the name from both packages without
causing a compilation error. Hence, if you have imported the entire
package jakarta.jms.*
, you must qualify the constructor with the full
package name when instantiating the object:
com.sun.messaging.ConnectionFactory
myFactory = new com.sun.messaging.ConnectionFactory();
Notice that the type declaration for the variable myFactory
, to which
the instantiated connection factory is assigned, is also qualified with
the full package name. This is because the setProperty
method, used in
Instantiating a Connection Factory, belongs to the
ConnectionFactory
class defined in the package com.sun.messaging
,
rather than to the ConnectionFactory
interface defined in jakarta.jms
. Thus in order for the compiler to recognize this method, myFactory
must be typed explicitly as com.sun.messaging.ConnectionFactory
rather
than simply ConnectionFactory
(which would resolve to
jakarta.jms.ConnectionFactory
after importing jakarta.jms.*
).
2. Set the connection factory’s configuration properties.
The most important configuration property is imqAddressList
, which
specifies the host names and port numbers of the message brokers to
which the factory creates connections. By default, the factory returned
by the ConnectionFactory
constructor in Instantiating a
Connection Factory is configured to create connections to a broker on
host localhost
at port number 7676
. If necessary, you can use the
setProperty
method, described in the preceding section, to change that
setting:
myFactory.setProperty(ConnectionConfiguration.imqAddressList,
"localhost:7676,broker2:5000,broker3:9999");
When specifying the host name portion of a broker, you can use a literal
IPv4 or IPv6 address instead of a host name. If you use a literal IPv6
address, its format must conform to
RFC2732, Format for Literal IPv6
Addresses in URL’s.
Of course, you can also set any other configuration properties your
application may require. See "Connection Factory
Attributes" in Open Message Queue Administration Guide for a list of
the available connection factory attributes.
You can now proceed to use the connection factory to create connections
to the message service, as described in the next section.
Using Connections
Once you have obtained a connection factory, you can use it to create a
connection to the message service. The factory’s createConnection
method takes a user name and password as arguments:
Connection
myConnection = myFactory.createConnection("mithrandir", "mellon");
Before granting the connection, Message Queue authenticates the user
name and password by looking them up in its user repository. As a
convenience for developers who do not wish to go to the trouble of
populating a user repository during application development and testing,
there is also a parameterless form of the createConnection
method:
Connection myConnection = myFactory.createConnection();
This creates a connection configured for the default user identity, with
both user name and password set to guest
.
This unified-domain createConnection
method is part of the generic JMS
ConnectionFactory
interface, defined in package jakarta.jms
; the
Message Queue version in com.sun.messaging
adds corresponding methods
createQueueConnection
and createTopicConnection
for use specifically
with the point-to-point and publish/subscribe domains.
The following table shows the methods defined in the Connection
interface.
Table 4-1 Connection Methods
Name |
Description |
createSession
|
Create session |
setClientID
|
Set client identifier |
getClientID
|
Get client identifier |
setEeventListener
|
Set event listener for connection events |
setExceptionListener
|
Set exception listener |
getExceptionListener
|
Get exception listener |
getMetaData
|
Get metadata for connection |
createConnectionConsumer
|
Create connection consumer |
createDurableConnectionConsumer
|
Create durable connection consumer |
start
|
Start incoming message delivery |
stop
|
Stop incoming message delivery |
close
|
Close connection |
The main purpose of a connection is to create sessions for exchanging
messages with the message service:
myConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
The first argument to createSession
is a boolean indicating whether
the session is transacted; the second specifies its acknowledgment mode.
Possible values for this second argument are AUTO_ACKNOWLEDGE
,
CLIENT_ACKNOWLEDGE
, and DUPS_OK_ACKNOWLEDGE
, all defined as static
constants in the standard JMS Session
interface, jakarta.jms.Session
;
the extended Message Queue version of the interface,
com.sun.messaging.jms.Session
, adds another such constant,
NO_ACKNOWLEDGE
. See Acknowledgment Modes and
Transacted Sessions for further discussion.
If your client application will be using the publish/subscribe domain to
create durable topic subscriptions, it must have a client identifier to
identify itself to the message service. In general, the most convenient
arrangement is to configure the client runtime to provide a unique
client identifier automatically for each client. However, the
Connection
interface also provides a method, setClientID
, for
setting a client identifier explicitly, and a corresponding
getClientID
method for retrieving its value. See
Assigning Client Identifiers
in this guide and "Client Identifier" in Open Message
Queue Administration Guide for more information.
You should also use the setExceptionListener
method to register an
exception listener for the connection. This is an object implementing
the JMS ExceptionListener
interface, which consists of the single
method onException
:
void onException (JMSException exception)
In the event of a problem with the connection, the message broker will
call this method, passing an exception object identifying the nature of
the problem.
A connection’s getMetaData
method returns a ConnectionMetaData
object, which in turn provides methods for obtaining various items of
information about the connection, such as its JMS version and the name
and version of the JMS provider.
The createConnectionConsumer
and createDurableConnectionConsumer
methods (as well as the session methods setMessageListener
and
getMessageListener
, listed in Table 4-2) are used for
concurrent message consumption; see the Java Message Service
Specification for more information.
In order to receive incoming messages, you must 7start the connection by
calling its start
method:
It is important not to do this until after you have created any message
consumers you will be using to receive messages on the connection.
Starting the connection before creating the consumers risks missing some
incoming messages before the consumers are ready to receive them. It is
not necessary to start the connection in order to send outgoing
messages.
If for any reason you need to suspend the flow of incoming messages, you
can do so by calling the connection’s stop
method:
To resume delivery of incoming messages, call the start
method again.
Finally, when you are through with a connection, you should close it to
release any resources associated with it:
This automatically closes all sessions, message producers, and message
consumers associated with the connection and deletes any temporary
destinations. All pending message receives are terminated and any
transactions in progress are rolled back. Closing a connection does not
force an acknowledgment of client-acknowledged sessions.
Creating Secure Connections (SSL)
A connection service that is based on the Transport Layer Security
(TLS/SSL) standard is used to authenticate and encrypt messages sent
between the client and the broker. This section describes what the
client needs to do to use TLS/SSL connections. A user can also establish
a secure connection by way of an HTTPS tunnel servlet. For information
on setting up secure connections over HTTP, see
"HTTP/HTTPS Support" in Open Message Queue
Administration Guide.
Some of the work needed to set up a TLS/SSL connection is done by an
administrator. This section summarizes these steps. For complete
information about the administrative work required, please see
"Message Encryption" in Open Message Queue
Administration Guide.
To set up a secure connection service, you must do the following.
-
Generate a self-signed or signed certificate for the broker
(administrator).
-
Enable the ssljms
connection service in the broker
(administrator).
-
Start the broker (administrator).
-
Configure and run the client as explained below.
To configure a client to use a TLS/SSL connection you must do the
following.
-
If your client is not using J2SDK 1.4 (which has JSSE and JNDI
support built in), make sure the client has the following files in its
class path:jsse.jar
, jnet.jar
, jcert, jar
, jndi.jar
.
-
Make sure the client has the following Message Queue files in its
class path: imq.jar
, jms.jar
.
-
If the client is not willing to trust the broker’s self-signed
certificate, set the imqSSLIsHostTrusted
attribute to false for the
connection factory from which you get the TLS/SSL connection.
-
Connect to the broker’s ssljms
service. There are two ways to do
this. The first is to specify the service name ssljms
in the address
for the broker when you provide a value for the imqAddressList
attribute of the connection factory from which you obtain the
connection. When you run the client, it will be connected to the broker
by a TLS/SSLconnection. The second is to specify the following directive
when you run the command that starts the client.
java -DimqConnectionType=TLS clientAppName