Using the IBM JMS extensions

IBM® MQ classes for JMS contains a set of extensions to the JMS API called the IBM JMS extensions. An application can use these extensions to create connection factories and destinations dynamically at run time, and to set the properties of IBM MQ classes for JMS objects. The extensions can be used with any messaging provider.

The IBM JMS extensions are a set of interfaces and classes in the following packages:
  • com.ibm.msg.client.jms
  • com.ibm.msg.client.services

The packages can be found in com.ibm.mqjms.jar which is located in <MQ_Install_Dir>/java/lib.

These extensions provide the following function:
  • A factory-based mechanism for creating connection factories and destinations dynamically at run time, instead of retrieving them as administered objects from a Java Naming and Directory Interface (JNDI) namespace
  • A set of methods for setting the properties of IBM MQ classes for JMS objects
  • A set of exception classes with methods for obtaining detailed information about a problem
  • A set of methods for controlling tracing
  • A set of methods for obtaining version information about IBM MQ classes for JMS

With regard to creating connection factories and destinations dynamically at run time, and setting and getting their properties, the IBM JMS extensions provide an alternative set of interfaces to the IBM MQ JMS extensions. However, whereas the IBM MQ JMS extensions are specific to the IBM MQ messaging provider, the IBM JMS extensions are not specific to IBM MQ and can be used with any messaging provider within the layered architecture described in IBM MQ classes for JMS architecture.

The interface com.ibm.msg.client.wmq.WMQConstants contains the definitions of constants, which an application can use when setting the properties of IBM MQ classes for JMS objects using the IBM JMS extensions. The interface contains constants for the IBM MQ messaging provider and JMS constants that are independent of any messaging provider.

The examples of code that follow assume that the following import statements have been run:

import com.ibm.msg.client.jms.*;
import com.ibm.msg.client.services.*;
import com.ibm.msg.client.wmq.WMQConstants;

Creating connection factories and destinations

Before an application can create connection factories and destinations using the IBM JMS extensions, it must first create a JmsFactoryFactory object. To create a JmsFactoryFactory object, the application calls the getInstance() method of the JmsFactoryFactory class, as shown in the following example:

JmsFactoryFactory ff = JmsFactoryFactory.getInstance(JmsConstants.WMQ_PROVIDER);
The parameter on the getInstance() call is a constant that identifies the IBM MQ messaging provider as the chosen messaging provider. The application can then use the JmsFactoryFactory object to create connection factories and destinations.
To create a connection factory, the application calls the createConnectionFactory() method of the JmsFactoryFactory object, as shown in the following example:

JmsConnectionFactory factory = ff.createConnectionFactory();
This statement creates a JmsConnectionFactory object with the default values for all its properties, which means that the application connects to the default queue manager in bindings mode. If you want an application to connect in client mode, or connect to a queue manager other than the default queue manager, the application must set the appropriate properties of the JmsConnectionFactory object before creating the connection. For information about how to do this, see Setting the properties of IBM MQ classes for JMS objects.
The JmsFactoryFactory class also contains methods to create connection factories of the following types:
  • JmsQueueConnectionFactory
  • JmsTopicConnectionFactory
  • JmsXAConnectionFactory
  • JmsXAQueueConnectionFactory
  • JmsXATopicConnectionFactory
To create a Queue object, the application calls the createQueue() method of the JmsFactoryFactory object, as shown in the following example:

JmsQueue q1 = ff.createQueue("Q1");
This statement creates an JmsQueue object with the default values for all its properties. The object represents an IBM MQ queue called Q1 that belongs to the local queue manager. This queue can be a local queue, an alias queue, or a remote queue definition.
The createQueue() method can also accept a queue uniform resource identifier (URI) as a parameter. A queue URI is a string that specifies the name of an IBM MQ queue and, optionally, the name of the queue manager that owns the queue, and one or more properties of the JmsQueue object. The following statement contains an example of a queue URI:

JmsQueue q2 = ff.createQueue("queue://QM2/Q2?persistence=2&priority=5");
The JmsQueue object created by this statement represents an IBM MQ queue called Q2 that is owned by queue manager QM2, and all messages sent to this destination are persistent and have a priority of 5. For more information about queue URIs, see Uniform resource identifiers (URIs). For an alternative way of setting the properties of a JmsQueue object, see Setting the properties of IBM MQ classes for JMS objects.
To create a Topic object, an application can use the createTopic() method of the JmsFactoryFactory object, as shown in the following example:

JmsTopic t1 = ff.createTopic("Sport/Football/Results");
This statement creates a JmsTopic object with the default values for all its properties. The object represents a topic called Sport/Football/Results.
The createTopic() method can also accept a topic URI as a parameter. A topic URI is a string that specifies the name of a topic and, optionally, one or more properties of the JmsTopic object. The following statements contain an example of a topic URI:

String s1 = "topic://Sport/Tennis/Results?persistence=1&priority=0";
JmsTopic t2 = ff.createTopic(s1);
The JmsTopic object created by these statements represents a topic called Sport/Tennis/Results, and all messages sent to this destination are nonpersistent and have a priority of 0. For more information about topic URIs, see Uniform resource identifiers (URIs). For an alternative way of setting the properties of a JmsTopic object, see Setting the properties of IBM MQ classes for JMS objects.

After an application has created a connection factory or destination, that object can be used only with the selected messaging provider.

Setting the properties of IBM MQ classes for JMS objects

To set the properties of IBM MQ classes for JMS objects using the IBM JMS extensions, an application uses the methods of the com.ibm.msg.client.JmsPropertyContext interface.

For each Java data type, the JmsPropertyContext interface contains a method to set the value of a property with that data type, and a method to get the value of a property with that data type. For example, an application calls the setIntProperty() method to set a property with an integer value, and calls the getIntProperty() method to get a property with an integer value.

Instances of classes in the com.ibm.mq.jms package also inherit the methods of the JmsPropertyContext interface. An application can therefore use these methods to set the properties of MQConnectionFactory, MQQueue, and MQTopic objects.

When an application creates an IBM MQ classes for JMS object, any properties with default values are set automatically. When an application sets a property, the new value replaces any previous value the property had. After a property has been set, it cannot be deleted, but its value can be changed.

If an application attempts to set a property to a value that is not valid value for the property, IBM MQ classes for JMS throws a JMSException exception. If an application attempts to get a property that has not been set, the behavior is as described in the JMS specification. IBM MQ classes for JMS throws a NumberFormatException exception for primitive data types and returns null for referenced data types.

In addition to the predefined properties of an IBM MQ classes for JMS object, an application can set its own properties. These application defined properties are ignored by IBM MQ classes for JMS.

For more information about the properties of IBM MQ classes for JMS objects, see Properties of IBM MQ classes for JMS objects.

The following code is an example of how to set properties using the IBM JMS extensions. The code sets five properties of a connection factory.

factory.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE,
WMQConstants.WMQ_CM_CLIENT);
factory.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, "QM1");
factory.setStringProperty(WMQConstants.WMQ_HOST_NAME, "HOST1");
factory.setIntProperty(WMQConstants.WMQ_PORT, 1415);
factory.setStringProperty(WMQConstants.WMQ_CHANNEL, "QM1.SVR");
factory.setStringProperty(WMQConstants.WMQ_APPLICATIONNAME, "My Application");
The effect of setting these properties is that the application connects to queue manager QM1 in client mode, using an MQI channel called QM1.SVR. The queue manager is running on a system with host name HOST1, and the listener for the queue manager is listening in port number 1415. This connection and other queue manager connections associated with sessions under it, have the application name "My Application" associated with them.
Note: Queue managers running on z/OS® platforms do not support setting application names, and this setting is therefore ignored.
The JmsPropertyContext interface also contains the setObjectProperty() method, which an application can use to set properties. The second parameter of the method is an object that encapsulates the value of the property. For example, the following code creates an Integer object that encapsulates the integer 1415, and then calls setObjectProperty() to set the PORT property of a connection factory to the value 1415:

Integer port = new Integer(1415);
factory.setObjectProperty(WMQConstants.WMQ_PORT, port);
This code is therefore equivalent to the following statement:

factory.setIntProperty(WMQConstants.WMQ_PORT, 1415);

Conversely, the getObjectProperty() method returns an object that encapsulates the value of a property.

Implicit conversion of a property value from one data type to another

When an application uses a method of the JmsPropertyContext interface to set or get the property of an IBM MQ classes for JMS object, the value of the property can be implicitly converted from one data type to another.

For example, the following statement sets the PRIORITY property of the JmsQueue object q1:

q1.setStringProperty(WMQConstants.WMQ_PRIORITY, "5");
The PRIORITY property has an integer value, and so the setStringProperty() call implicitly converts the string 5 (the source value) to the integer 5 (the target value), which then becomes the value of the PRIORITY property.
Conversely, the following statement gets the PRIORITY property of the JmsQueue object q1:

String s1 = q1.getStringProperty(WMQConstants.WMQ_PRIORITY);
The integer 5 (the source value), which is the value of the PRIORITY property, is implicitly converted to the string 5 (the target value) by the getStringProperty() call.

The conversions supported by IBM MQ classes for JMS are shown in Table 1.

Table 1. Supported conversions from one data type to another
Source data type Supported target data types
boolean String
byte int, long, short, String
char String
double String
float double, String
int long, String
long String
short int, long, String
String boolean, byte, double, float, int, long, short
The general rules governing the supported conversions are as follows:
  • Numeric values can be converted from one data type to another provided no data is lost during the conversion. For example, a value with data type int can be converted into a value with data type long, but cannot be converted into a value with data type short.
  • A value of any data type can be converted into a string.
  • A string can be converted to a value of any other data type (except char ) provided the string is in the correct format for the conversion. If an application attempts to convert a string that is not in the correct format, IBM MQ classes for JMS throws a NumberFormatException exception.
  • If an application attempts a conversion that is not supported, IBM MQ classes for JMS throws a MessageFormatException exception.
The specific rules for converting a value from one data type to another are as follows:
  • When converting a boolean value to a string, the value true is converted to the string true, and the value false is converted to the string false.
  • When converting a string to a boolean value, the string true (not case-sensitive) is converted to true, and the string false (not case-sensitive) is converted to false. Any other string is converted to false.
  • When converting a string to a value with data type byte, int, long, or short, the string must have the following format:
    • [ blanks ][ sign ] digits
    The meanings of the components of the string are as follows:
    blanks
    Optional leading blank characters.
    sign
    An optional plus sign (+) or minus sign (-).
    digits
    A contiguous sequence of digits (0-9). At least one digit must be present.

    After the sequence of digits, the string can contain other characters that are not digits, but the conversion stops as soon as the first of these characters is reached. The string is assumed to represent a decimal integer.

    If the string is not in the correct format, IBM MQ classes for JMS throws a NumberFormatException exception.

  • When converting a string to a value with data type double or float, the string must have the following format:
    • [ blanks ][ sign ] digits [ e_char [ e_sign ] e_digits ]
    The meanings of the components of the string are as follows:
    blanks
    Optional leading blank characters.
    sign
    An optional plus sign (+) or minus sign (-).
    digits
    A contiguous sequence of digits (0-9). At least one digit must be present.
    e_char
    An exponent character, which is either E or e.
    e_sign
    An optional plus sign (+) or minus sign (-) for the exponent.
    e_digits
    A contiguous sequence of digits (0-9) for the exponent. At least one digit must be present if the string contains an exponent character.

    After the sequence of digits, or the optional characters representing an exponent, the string can contain other characters that are not digits, but the conversion stops as soon as the first of these characters is reached. The string is assumed to represent a decimal floating point number with an exponent that is a power of 10.

    If the string is not in the correct format, IBM MQ classes for JMS throws a NumberFormatException exception.

  • When converting a numeric value (including a value with data type byte ) to a string, the value is converted to the string representation of the value as a decimal number, not the string containing the ASCII character for that value. For example, the integer 65 is converted to the string 65, not the string A.

Setting more than one property in a single call

The JmsPropertyContext interface also contains the setBatchProperties() method, which an application can use to set more than one property in a single call. The parameter of the method is a Map object that encapsulates a set of property name-value pairs.

For example, the following code uses the setBatchProperties() method to set the same five properties of a connection factory as shown in Setting the properties of IBM MQ classes for JMS objects. The code creates an instance of the HashMap class, which implements the Map interface.

HashMap batchProperties = new HashMap();
batchProperties.put(WMQConstants.WMQ_CONNECTION_MODE,
                    new Integer(WMQConstants.WMQ_CM_CLIENT));
batchProperties.put(WMQConstants.WMQ_QUEUE_MANAGER, "QM1");
batchProperties.put(WMQConstants.WMQ_WMQ_HOST_NAME, "HOST1");
batchProperties.put(WMQConstants.WMQ_PORT, "1414");
batchProperties.put(WMQConstants.WMQ_CHANNEL, "QM1.SVR");
factory.setBatchProperties(batchProperties);
Note that the second parameter of the Map.put() method must be an object. Therefore a property value with a primitive data type must be encapsulated within an object or represented by a string, as shown in the example.

The setBatchProperties() method validates each property. If the setBatchProperties() method cannot set a property because, for example, its value is not valid, none of the specified properties are set.

Property names and values

If an application uses the methods of the JmsPropertyContext interface to set and get the properties of IBM MQ classes for JMS objects, the application can specify the names and values of properties in any of the following ways. Each of the accompanying examples shows how to set the PRIORITY property of the JmsQueue object q1 so that a message sent to the queue has the priority specified on the send() call.
Using the property names and values that are defined as constants in the com.ibm.msg.client.wmq.WMQConstants interface
The following statement is an example of how to specify the names and values of properties in this way:

q1.setIntProperty(WMQConstants.WMQ_PRIORITY, WMQConstants.WMQ_PRI_APP);
Using the property names and values that can be used in queue and topic uniform resource identifiers (URIs)
The following statement is an example of how to specify the names and values of properties in this way:

q1.setIntProperty("priority", -2);

Only the names and values of properties of destinations can be specified in this way.

Using the property names and values that are recognized by the IBM MQ JMS administration tool
The following statement is an example of how to specify the names and values of properties in this way:

q1.setStringProperty("PRIORITY", "APP");
The short form of the property name is also acceptable, as shown in the following statement:

q1.setStringProperty("PRI", "APP");
When an application gets a property, the value returned depends on the way in which the application specifies the name of the property. For example, if an application specifies the constant WMQConstants.WMQ_PRIORITY as the property name, the value returned is the integer -2:

int n1 = getIntProperty(WMQConstants.WMQ_PRIORITY);
The same value is returned if the application specifies the string "priority" as the property name:

int n2 = getIntProperty("priority");
However, if the application specifies the string "PRIORITY" or "PRI" as the property name, the value returned is the string "APP":

String s1 = getStringProperty("PRI");

Internally, IBM MQ classes for JMS stores property names and values as the literal values defined in the com.ibm.msg.client.wmq.WMQConstants interface. This is the defined canonical format for property names and values. As a general rule, if an application sets properties using one of the other two ways of specifying property names and values, IBM MQ classes for JMS has to convert the names and values from the specified input format into the canonical format. Similarly, if an application gets properties using one of the other two ways of specifying property names and values, IBM MQ classes for JMS must convert the names from the specified input format into the canonical format, and convert the values from the canonical format into the required output format. Having to perform these conversions might have implications for performance.

Property names and values returned by exceptions, in trace files, or in the IBM MQ classes for JMS log are always in the canonical format.

Using the Map interface

The JmsPropertyContext interface extends the java.util.Map interface. An application can therefore use the methods of the Map interface to access the properties of an IBM MQ classes for JMS object.

For example, the following code prints out the names and values of all the properties of a connection factory. The code uses only the methods of the Map interface to get the names and values of the properties.

// Get the names of all the properties
Set propNames = factory.keySet();

// Loop round all the property names and get the property values
Iterator iterator = propNames.iterator();
while (iterator.hasNext()){
    String pName = (String)iterator.next();
    System.out.println(pName+"="+factory.get(pName));
}

Using the methods of the Map interface does not bypass any property validations or conversions.