Handling unchecked exceptions

Methods on the interfaces that are defined in JMS 2.0 throw unchecked exceptions. The base class for these exceptions is JMSRuntimeException. Therefore, catching JMSRuntimeExceptions provides a generic way of handling these types of exceptions.

Every JMSRuntimeException encapsulates the following information:

  • A provider specific exception message, which the application can obtain by calling the JMSRuntimeException.getMessage() method.
  • A provider specific error code, which the application can obtain by calling the JMSRuntimeException.getErrorCode() method.
  • A linked exception. An exception that is thrown by a JMS 2.0 API call is often the result of a lower level problem which is reported by another exception that is linked to this exception. Your application can obtain a linked exception by calling the JMSRuntimeException.getCause() method.

When you call methods on the interfaces that are provided by the JMS 2.0 API, most exceptions that are thrown by the IBM MQ classes for JMS are instances of subclasses of JMSRuntimeException. These subclasses implement the com.ibm.msg.client.jms.JmsExceptionDetail interface, which provides the following additional information:

  • An explanation of the exception message. Your application can obtain this message by calling the JmsExceptionDetail.getExplanation() method.
  • A recommended user response to the exception. Your application can obtain this message by calling the JmsExceptionDetail.getUserAction() method.
  • The keys for the message inserts in the exception message. Your application can obtain 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 the application to access that name. Your application can obtain the message insert corresponding to a specified key by calling the JmsExceptionDetail.getValue() method.

All the methods in the JmsExceptionDetail interface return null if no details are available. For example, if an application tries to create a JMSProducer for an IBM 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 IBM 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 that is thrown, com.ibm.msg.client.jms.DetailedInvalidDestinationException, is a subclass of javax.jms.InvalidDestinationException and implements the com.ibm.msg.client.jms.JmsExceptionDetail interface.


Chained exceptions

Typically, exceptions are caused by other exceptions. Therefore, for each JMSRuntimeException that is thrown, the application should check the linked exception.

The cause of the JMSRuntimeException might be another exception. These exceptions form a chain that leads back to the original underlying problem. The cause of an exception is implemented by using the chained exception mechanism of the java.lang.Throwable class, and the application can obtain a linked exception by calling 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
        |
        +--->
            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 JMSRuntimeException, is thrown by the common layer in IBM MQ classes for JMS.
  • The next exception, an instance of com.ibm.mq.MQException, is thrown by the IBM MQ messaging provider.
  • The next two exceptions, both of which are instances of com.ibm.mq.jmqi.JmqiException, are thrown by the Java Message Queueing Interface (JMQI). The JMQI is the component that is used by the IBM MQ classes for JMS to communicate with a queue manager.
  • 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 MQ classes for JMS, see IBM MQ classes for JMS architecture. We can code the application to iterate through this chain to extract all the appropriate information, as shown in the following example:

import com.ibm.msg.client.jms.JmsExceptionDetail;
import com.ibm.mq.MQException;
import com.ibm.mq.jmqi.JmqiException;
import javax.jms.JMSRuntimeException;
.
.
.
catch (JMSRuntimeException je) {
  System.err.println("Caught JMSRuntimeException");
  // Check for linked exceptions in JMSRuntimeException
  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 JMSRuntimeException) {
      JMSRuntimeException je1 = (JMSRuntimeException) 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 the 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 MQ specific information about a problem

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

An MQException encapsulates the following information:

  • A completion code, which the application can obtain by calling the getCompCode() method.
  • A reason code, which the application can obtain by calling the getReason() method.

For examples of how to use these methods, see the sample code in chained exceptions.

A JmqiException also encapsulates a completion code and a reason code. In addition to this, a JmqiException contains the information in an AMQ nnnn or CSQ nnnn message, if one is associated with the exception. Your application can obtain the various components of this message by calling the following methods:

  • The getWmqMsgExplanation() method returns the explanation of the AMQ nnnn or CSQ nnnn message.
  • The getWmqMsgSeverity() method returns the severity of the AMQ nnnn or CSQ nnnn message.
  • The getWmqMsgSummary() method returns the summary of the AMQ nnnn or CSQ nnnn message.
  • The getWmqMsgUserResponse() method returns the user response that is associated with the AMQ nnnn or CSQ nnnn message.

Parent topic: Exceptions in IBM MQ classes for JMS