Exceptions in IBM WebSphere MQ classes for JMS

A IBM® WebSphere® MQ classes for JMS application must be able to handle exceptions that are thrown by a JMS API calls or delivered to an exception handler.

IBM WebSphere MQ classes for JMS reports runtime problems by throwing exceptions. JMSException is the root class for exceptions thrown by JMS methods, and catching JMSException exceptions provides a generic way of handling all JMS related exceptions.

Every JMSException exception encapsulates the following information:
  • A provider specific exception message, which an application obtains by calling the Throwable.getMessage() method.
  • A provider specific error code, which an application obtains by calling the JMSException.getErrorCode() method.
  • A linked exception. An exception thrown by a JMS API call is often the result of a lower level problem, which is reported by another exception linked to this exception. An application obtains a linked exception by calling the JMSException.getLinkedException() or the Throwable.getCause() method.
Most exceptions thrown by IBM WebSphere MQ classes for JMS are instances of subclasses of JMSException. These subclasses implement the com.ibm.msg.client.jms.JmsExceptionDetail interface, which provides the following additional information:
  • An explanation of the exception message, which an application obtains by calling the JmsExceptionDetail.getExplanation() method.
  • A recommended user response to the exception, which an application obtains by calling the JmsExceptionDetail.getUserAction() method.
  • The keys for the message inserts in the exception message. An application obtains an iterator for all the keys by calling the JmsExceptionDetail.getKeys() method.
  • The message inserts in the exception message. For example, a message insert might be the name of the queue that caused the exception, and it might be useful for an application to be able to access that name. An application obtains the message insert corresponding to a specified key by calling the JmsExceptionDetail.getValue() method.
All the methods in the JmsExceptionDetail interface might return null if no details are available.
For example, if an application tries to create a message producer for an IBM WebSphere MQ queue that does not exist, an exception is thrown with the following information:
Message : JMSWMQ2008: Failed to open MQ queue 'Q_test'.
Class : class com.ibm.msg.client.jms.DetailedInvalidDestinationException
Error Code : JMSWMQ2008
Explanation : JMS attempted to perform an MQOPEN, but WebSphere MQ reported an
              error.
User Action : Use the linked exception to determine the cause of this error. Check
              that the specified queue and queue manager are defined correctly.
The exception thrown, com.ibm.msg.client.jms.DetailedInvalidDestinationException, is a subclass of javax.jms.InvalidDestinationException and implements the com.ibm.msg.client.jms.JmsExceptionDetail interface.

Linked exceptions

A linked exception provides further information about a runtime problem. Therefore, for each JMSException exception that is thrown, an application should check the linked exception. The linked exception itself might have another linked exception, and so the linked exceptions form a chain leading back to the original underlying problem. A linked exception is implemented by using the chained exception mechanism of the java.lang.Throwable class, and an application obtains a linked exception by calling the Throwable.getCause() method. For a JMSException exception, the getLinkedException() method actually delegates to the Throwable.getCause() method.

For example, if an application specifies an incorrect port number when connecting to a queue manager, the exceptions form the following chain:
com.ibm.msg.client.jms.DetailIllegalStateException
   |
   +--->com.ibm.mq.MQException
           |
           +--->com.ibm.mq.jmqi.JmqiException
                   |
                   +--->java.net.ConnectionException
Typically, each exception in a chain is thrown from a different layer in the code. For example, the exceptions in the preceding chain are thrown by the following layers:
  • The first exception, an instance of a subclass of JMSException, is thrown by the common layer in IBM WebSphere MQ classes for JMS.
  • The next exception, an instance of com.ibm.mq.MQException, is thrown by the IBM WebSphere MQ messaging provider.
  • The next exception, an instance of com.ibm.mq.jmqi.JmqiException, is thrown by the common Java interface to the MQI.
  • The final exception, an instance of java.net.ConnectionException, is thrown by the Java class library.
For more information about the layered architecture of IBM WebSphere MQ classes for JMS, see IBM WebSphere MQ classes for JMS architecture.
Using code similar to the following code, an application can iterate through this chain to extract all the appropriate information:
import com.ibm.msg.client.jms.JmsExceptionDetail;
import com.ibm.mq.MQException;
import com.ibm.mq.jmqi.JmqiException;
import javax.jms.JMSException;
.
.
.
catch (JMSException je) {
    System.err.println("Caught JMSException");

    // Check for linked exceptions in JMSException
    Throwable t = je;
    while (t != null) {
        // Write out the message that is applicable to all exceptions
        System.err.println("Exception Msg: " + t.getMessage());
        // Write out the exception stack trace
        t.printStackTrace(System.err);

        // Add on specific information depending on the type of exception
        if (t instanceof JMSException) {
            JMSException je1 = (JMSException) t;
            System.err.println("JMS Error code: " + je1.getErrorCode());

            if (t instanceof JmsExceptionDetail){
                JmsExceptionDetail jed = (JmsExceptionDetail)je1;
                System.err.println("JMS Explanation: " + jed.getExplanation());
                System.err.println("JMS Explanation: " + jed.getUserAction());
            }
        } else if (t instanceof MQException) {
            MQException mqe = (MQException) t;
            System.err.println("WMQ Completion code: " + mqe.getCompCode());
            System.err.println("WMQ Reason code: " + mqe.getReason());
        } else if (t instanceof JmqiException){
            JmqiException jmqie = (JmqiException)t;
            System.err.println("WMQ Log Message: " + jmqie.getWmqLogMessage());
            System.err.println("WMQ Explanation: " + jmqie.getWmqMsgExplanation());
            System.err.println("WMQ Msg Summary: " + jmqie.getWmqMsgSummary());
            System.err.println("WMQ Msg User Response: "
                               + jmqie.getWmqMsgUserResponse());
            System.err.println("WMQ Msg Severity: " + jmqie.getWmqMsgSeverity());
        }

        // Get the next cause
        t = t.getCause();
    }
}
Note that an application should always check the type of each exception in a chain because the type of exception can vary and exceptions of different types encapsulate different information.

Obtaining IBM WebSphere MQ specific information about a problem

Instances of com.ibm.mq.MQException and com.ibm.mq.jmqi.JmqiException encapsulate IBM WebSphere MQ specific information about a problem.

An MQException exception encapsulates the following information:
  • A completion code, which an application obtains by calling the getCompCode() method
  • A reason code, which an application obtains by calling the getReason() method

A JmqiException exception also encapsulates a completion code and a reason code. Additionally, however, a JmqiException exception encapsulates the information in an AMQnnnn or CSQnnnn message, if one is associated with the exception. By calling the appropriate methods of the exception, an application can obtain the various components of this message, such as the severity, explanation, and user response.

For examples of how to use of the methods mentioned in this section, see the sample code in Linked exceptions.

Upgrading from previous versions of IBM WebSphere MQ classes for JMS

Compared to previous versions of IBM WebSphere MQ classes for JMS, most error codes and exception messages have changed in Version 7. The reason for these changes is that IBM WebSphere MQ classes for JMS now has a layered architecture and exceptions are thrown from different layers in the code.

For example, if an application tries to connect to a queue manager that does not exist, a previous version of IBM WebSphere MQ classes for JMS threw a JMSException exception with the following information:
MQJMS2005: Failed to create MQQueueManager for 'localhost:QM_test'.
This exception contained a linked MQException exception with the following information:
MQJE001: Completion Code 2, Reason 2058
By comparison in the same circumstances, Version 7 of IBM WebSphere MQ classes for JMS throws a JMSException exception with the following information:
Message : JMSWMQ0018: Failed to connect to queue manager 'QM_test' with
          connection mode 'Client' and host name 'localhost'.
Class : class com.ibm.msg.client.jms.DetailedJMSException
Error Code : JMSWMQ0018
Explanation : null
User Action : Check the queue manager is started and if running in client mode,
              check there is a listener running. Please see the linked exception
              for more information.
This exception contains a linked MQException exception with the following information:
Message : JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED')
          reason '2058' ('MQRC_Q_MGR_NAME_ERROR').
Class : class com.ibm.mq.MQException
Completion Code : 2
Reason Code : 2058

If your application parses or tests exception messages returned by the Throwable.getMessage() method, or error codes returned by the JMSException.getErrorCode() method, and you are upgrading from a release before Version 7, your application probably needs to be modified in order to use Version 7 of IBM WebSphere MQ classes for JMS.

Exception listeners

An application can register an exception listener with a Connection object. Subsequently, if a problem occurs that makes the connection unusable, IBM WebSphere MQ classes for JMS delivers an exception to the exception listener by calling its onException() method. The application then has the opportunity to reestablish the connection.

[V7.5.0.8 Jun 2017]APAR IT14820, included from IBM WebSphere MQ Version 7.5.0, Fix Pack 8, fixed a defect where an application's JMS ExceptionListener would not be invoked for non-connection broken exceptions (for example MQRC_GET_INHIBITED) even though the ASYNC_EXCEPTIONS property on the JMS Connection Factory used by the application, was set to ASYNC_EXCEPTIONS_ALL. This was the default value prior to Version 7.5.0, Fix Pack 8.

[V7.5.0.8 Jun 2017]To maintain behavior for current JMS applications that configure a JMS MessageListener and a JMS ExceptionListener, and to ensure that the IBM WebSphere MQ classes for JMS are consistent with the JMS specification, the default value for the ASYNC_EXCEPTIONS JMS ConnectionFactory property has been changed to ASYNC_EXCEPTIONS_CONNECTIONBROKEN for the IBM WebSphere MQ classes for JMS. As a result, by default, only exceptions corresponding to broken connection error codes are delivered to an application's JMS ExceptionListener.

[V7.5.0.8 Jun 2017]From Version 7.5.0, Fix Pack 8, the IBM WebSphere MQ classes for JMS have also been updated such that JMSExceptions relating to non-connection broken errors, which occur during message delivery to asynchronous message consumers, are still delivered to a registered ExceptionListener when the JMS ConnectionFactory used by the application has the ASYNC_EXCEPTIONS property set to the value ASYNC_EXCEPTIONS_ALL.

[V7.5.0.8 Jun 2017]For more information about what has changed for exception listeners for Version 7.5.0, Fix Pack 8 and why the changes have been made from earlier releases, see JMS: Exception listener changes in Version 7.5.

For any other type of problem, a JMSException exception is thrown by the current JMS API call.

If an application does not register an exception listener with a Connection object, any exceptions that would have been delivered to the exception listener are written to the IBM WebSphere MQ classes for JMS log.