Sun Java System Message Queue 3.7 UR1 Developer's Guide for Java Clients

Working With Connections

All messaging occurs within the context of a connection. Connections are created using a connection factory encapsulating all of the needed configuration properties for connecting to a particular JMS provider. A connection’s configuration properties are completely determined by the connection factory, and cannot be changed once the connection has been created. Thus the only way to control the properties of a connection is by setting those of the connection factory you use to create it.

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 the Chapter 1, Administrative Tasks and Tools, in Sun Java System Message Queue 3.7 UR1 Administration Guidewith 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:

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 2–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 J2EE component, JNDI resources are provided by the J2EE container. In such cases, JNDI lookup code may differ from that shown here; see your J2EE provider documentation for details.



Example 2–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);
    
               

ProcedureTo Look Up a Connection Factory With JNDI

  1. 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 Security Properties in Sun Java System Message Queue 3.7 UR1 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.


  3. 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();
  4. 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 Chapter 7, Managing Security, in Sun Java System Message Queue 3.7 UR1 Administration Guidefor complete information on the available connection factory configuration properties.

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 2–2 shows how to create a connection factory object by direct instantiation and configure its properties.


Example 2–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 satement in the previous code sample.

ProcedureTo Instantiate and Configure a Connection Factory

  1. Instantiate the connection factory object.

    The name ConnectionFactory is defined both as a JMS interface (in package javax.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 javax.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 javax.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 javax.jms.ConnectionFactory after importing javax.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");

    Of course, you can also set any other configuration properties your application may require. See Connection Properties in Sun Java System Message Queue 3.7 UR1 Administration Guidefor a list of the available connection factory properties.

    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 javax.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 2–2 Connection Methods

Name 

Description 

createSession

Create session 

setClientID

Set client identifier 

getClientID

Get client identifier 

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, javax.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 and Managing Connection Services in Sun Java System Message Queue 3.7 UR1 Administration Guidefor 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 2–3) 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:

myConnection.start();

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:

myConnection.stop();

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:

myConnection.close();

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 Connctions (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 Appendix C, HTTP/HTTPS Support, in Sun Java System Message Queue 3.7 UR1 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 Sun Java System Message Queue 3.7 UR1 Administration Guide.

To set up a secure connection service, you must do the following.

  1. Generate a self-signed or signed certificate for the broker (administrator).

  2. Enable the ssljms connection service in the broker (administrator).

  3. Start the broker (administrator).

  4. Configure and run the client as explained below.

To configure a client to use a TLS/SSL connection you must do the following.

  1. 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.

  2. Make sure the client has the following Message Queue files in its class path: imq.jar, jms.jar.

  3. 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.

  4. 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