Open Source Repository

Home /spring/spring-jms-3.0.5 | Repository Home


org/springframework/jms/support/JmsUtils.java
/*
 * Copyright 2002-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.jms.support;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.QueueBrowser;
import javax.jms.QueueRequestor;
import javax.jms.Session;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.jms.InvalidClientIDException;
import org.springframework.jms.InvalidDestinationException;
import org.springframework.jms.InvalidSelectorException;
import org.springframework.jms.JmsException;
import org.springframework.jms.JmsSecurityException;
import org.springframework.jms.MessageEOFException;
import org.springframework.jms.MessageFormatException;
import org.springframework.jms.MessageNotReadableException;
import org.springframework.jms.MessageNotWriteableException;
import org.springframework.jms.ResourceAllocationException;
import org.springframework.jms.TransactionInProgressException;
import org.springframework.jms.TransactionRolledBackException;
import org.springframework.jms.UncategorizedJmsException;
import org.springframework.util.Assert;

/**
 * Generic utility methods for working with JMS. Mainly for internal use
 * within the framework, but also useful for custom JMS access code.
 *
 @author Juergen Hoeller
 @since 1.1
 */
public abstract class JmsUtils {

  private static final Log logger = LogFactory.getLog(JmsUtils.class);


  /**
   * Close the given JMS Connection and ignore any thrown exception.
   * This is useful for typical <code>finally</code> blocks in manual JMS code.
   @param con the JMS Connection to close (may be <code>null</code>)
   */
  public static void closeConnection(Connection con) {
    closeConnection(con, false);
  }

  /**
   * Close the given JMS Connection and ignore any thrown exception.
   * This is useful for typical <code>finally</code> blocks in manual JMS code.
   @param con the JMS Connection to close (may be <code>null</code>)
   @param stop whether to call <code>stop()</code> before closing
   */
  public static void closeConnection(Connection con, boolean stop) {
    if (con != null) {
      try {
        if (stop) {
          try {
            con.stop();
          }
          finally {
            con.close();
          }
        }
        else {
          con.close();
        }
      }
      catch (javax.jms.IllegalStateException ex) {
        logger.debug("Ignoring Connection state exception - assuming already closed: " + ex);
      }
      catch (JMSException ex) {
        logger.debug("Could not close JMS Connection", ex);
      }
      catch (Throwable ex) {
        // We don't trust the JMS provider: It might throw RuntimeException or Error.
        logger.debug("Unexpected exception on closing JMS Connection", ex);
      }
    }
  }

  /**
   * Close the given JMS Session and ignore any thrown exception.
   * This is useful for typical <code>finally</code> blocks in manual JMS code.
   @param session the JMS Session to close (may be <code>null</code>)
   */
  public static void closeSession(Session session) {
    if (session != null) {
      try {
        session.close();
      }
      catch (JMSException ex) {
        logger.trace("Could not close JMS Session", ex);
      }
      catch (Throwable ex) {
        // We don't trust the JMS provider: It might throw RuntimeException or Error.
        logger.trace("Unexpected exception on closing JMS Session", ex);
      }
    }
  }

  /**
   * Close the given JMS MessageProducer and ignore any thrown exception.
   * This is useful for typical <code>finally</code> blocks in manual JMS code.
   @param producer the JMS MessageProducer to close (may be <code>null</code>)
   */
  public static void closeMessageProducer(MessageProducer producer) {
    if (producer != null) {
      try {
        producer.close();
      }
      catch (JMSException ex) {
        logger.trace("Could not close JMS MessageProducer", ex);
      }
      catch (Throwable ex) {
        // We don't trust the JMS provider: It might throw RuntimeException or Error.
        logger.trace("Unexpected exception on closing JMS MessageProducer", ex);
      }
    }
  }

  /**
   * Close the given JMS MessageConsumer and ignore any thrown exception.
   * This is useful for typical <code>finally</code> blocks in manual JMS code.
   @param consumer the JMS MessageConsumer to close (may be <code>null</code>)
   */
  public static void closeMessageConsumer(MessageConsumer consumer) {
    if (consumer != null) {
      // Clear interruptions to ensure that the consumer closes successfully...
      // (working around misbehaving JMS providers such as ActiveMQ)
      boolean wasInterrupted = Thread.interrupted();
      try {
        consumer.close();
      }
      catch (JMSException ex) {
        logger.trace("Could not close JMS MessageConsumer", ex);
      }
      catch (Throwable ex) {
        // We don't trust the JMS provider: It might throw RuntimeException or Error.
        logger.trace("Unexpected exception on closing JMS MessageConsumer", ex);
      }
      finally {
        if (wasInterrupted) {
          // Reset the interrupted flag as it was before.
          Thread.currentThread().interrupt();
        }
      }
    }
  }

  /**
   * Close the given JMS QueueBrowser and ignore any thrown exception.
   * This is useful for typical <code>finally</code> blocks in manual JMS code.
   @param browser the JMS QueueBrowser to close (may be <code>null</code>)
   */
  public static void closeQueueBrowser(QueueBrowser browser) {
    if (browser != null) {
      try {
        browser.close();
      }
      catch (JMSException ex) {
        logger.trace("Could not close JMS QueueBrowser", ex);
      }
      catch (Throwable ex) {
        // We don't trust the JMS provider: It might throw RuntimeException or Error.
        logger.trace("Unexpected exception on closing JMS QueueBrowser", ex);
      }
    }
  }

  /**
   * Close the given JMS QueueRequestor and ignore any thrown exception.
   * This is useful for typical <code>finally</code> blocks in manual JMS code.
   @param requestor the JMS QueueRequestor to close (may be <code>null</code>)
   */
  public static void closeQueueRequestor(QueueRequestor requestor) {
    if (requestor != null) {
      try {
        requestor.close();
      }
      catch (JMSException ex) {
        logger.trace("Could not close JMS QueueRequestor", ex);
      }
      catch (Throwable ex) {
        // We don't trust the JMS provider: It might throw RuntimeException or Error.
        logger.trace("Unexpected exception on closing JMS QueueRequestor", ex);
      }
    }
  }

  /**
   * Commit the Session if not within a JTA transaction.
   @param session the JMS Session to commit
   @throws JMSException if committing failed
   */
  public static void commitIfNecessary(Session sessionthrows JMSException {
    Assert.notNull(session, "Session must not be null");
    try {
      session.commit();
    }
    catch (javax.jms.TransactionInProgressException ex) {
      // Ignore -> can only happen in case of a JTA transaction.
    }
    catch (javax.jms.IllegalStateException ex) {
      // Ignore -> can only happen in case of a JTA transaction.
    }
  }

  /**
   * Rollback the Session if not within a JTA transaction.
   @param session the JMS Session to rollback
   @throws JMSException if committing failed
   */
  public static void rollbackIfNecessary(Session sessionthrows JMSException {
    Assert.notNull(session, "Session must not be null");
    try {
      session.rollback();
    }
    catch (javax.jms.TransactionInProgressException ex) {
      // Ignore -> can only happen in case of a JTA transaction.
    }
    catch (javax.jms.IllegalStateException ex) {
      // Ignore -> can only happen in case of a JTA transaction.
    }
  }

  /**
   * Build a descriptive exception message for the given JMSException,
   * incorporating a linked exception's message if appropriate.
   @param ex the JMSException to build a message for
   @return the descriptive message String
   @see javax.jms.JMSException#getLinkedException()
   */
  public static String buildExceptionMessage(JMSException ex) {
    String message = ex.getMessage();
    Exception linkedEx = ex.getLinkedException();
    if (linkedEx != null) {
      if (message == null) {
        message = linkedEx.toString();
      }
      else {
        String linkedMessage = linkedEx.getMessage();
        if (linkedMessage != null && !message.contains(linkedMessage)) {
          message = message + "; nested exception is " + linkedEx;
        }
      }
    }
    return message;
  }

  /**
   * Convert the specified checked {@link javax.jms.JMSException JMSException} to a
   * Spring runtime {@link org.springframework.jms.JmsException JmsException} equivalent.
   @param ex the original checked JMSException to convert
   @return the Spring runtime JmsException wrapping the given exception
   */
  public static JmsException convertJmsAccessException(JMSException ex) {
    Assert.notNull(ex, "JMSException must not be null");

    if (ex instanceof javax.jms.IllegalStateException) {
      return new org.springframework.jms.IllegalStateException((javax.jms.IllegalStateExceptionex);
    }
    if (ex instanceof javax.jms.InvalidClientIDException) {
      return new InvalidClientIDException((javax.jms.InvalidClientIDExceptionex);
    }
    if (ex instanceof javax.jms.InvalidDestinationException) {
      return new InvalidDestinationException((javax.jms.InvalidDestinationExceptionex);
    }
    if (ex instanceof javax.jms.InvalidSelectorException) {
      return new InvalidSelectorException((javax.jms.InvalidSelectorExceptionex);
    }
    if (ex instanceof javax.jms.JMSSecurityException) {
      return new JmsSecurityException((javax.jms.JMSSecurityExceptionex);
    }
    if (ex instanceof javax.jms.MessageEOFException) {
      return new MessageEOFException((javax.jms.MessageEOFExceptionex);
    }
    if (ex instanceof javax.jms.MessageFormatException) {
      return new MessageFormatException((javax.jms.MessageFormatExceptionex);
    }
    if (ex instanceof javax.jms.MessageNotReadableException) {
      return new MessageNotReadableException((javax.jms.MessageNotReadableExceptionex);
    }
    if (ex instanceof javax.jms.MessageNotWriteableException) {
      return new MessageNotWriteableException((javax.jms.MessageNotWriteableExceptionex);
    }
    if (ex instanceof javax.jms.ResourceAllocationException) {
      return new ResourceAllocationException((javax.jms.ResourceAllocationExceptionex);
    }
    if (ex instanceof javax.jms.TransactionInProgressException) {
      return new TransactionInProgressException((javax.jms.TransactionInProgressExceptionex);
    }
    if (ex instanceof javax.jms.TransactionRolledBackException) {
      return new TransactionRolledBackException((javax.jms.TransactionRolledBackExceptionex);
    }

    // fallback
    return new UncategorizedJmsException(ex);
  }

}