Package org.springframework.amqp.rabbit.connection

Source Code of org.springframework.amqp.rabbit.connection.RabbitUtils

/*
* Copyright 2002-2014 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.amqp.rabbit.connection;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;

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

import org.springframework.amqp.AmqpIOException;
import org.springframework.amqp.rabbit.support.RabbitExceptionTranslator;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ShutdownSignalException;

/**
* @author Mark Fisher
* @author Mark Pollack
* @author Gary Russell
*/
public abstract class RabbitUtils {

  public static final int DEFAULT_PORT = AMQP.PROTOCOL.PORT;

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

  private static final ThreadLocal<Boolean> physicalCloseRequired = new ThreadLocal<Boolean>();

  private static final Method shutDownSignalReasonMethod;

  static {
    Method method = null;
    try {
      method = ReflectionUtils.findMethod(ShutdownSignalException.class, "getReason");
    }
    finally {
      shutDownSignalReasonMethod = method;
    }
  }

  /**
   * Close the given RabbitMQ Connection and ignore any thrown exception. This is useful for typical
   * <code>finally</code> blocks in manual RabbitMQ code.
   * @param connection the RabbitMQ Connection to close (may be <code>null</code>)
   */
  public static void closeConnection(Connection connection) {
    if (connection != null) {
      try {
        connection.close();
      } catch (Exception ex) {
        logger.debug("Ignoring Connection exception - assuming already closed: " + ex.getMessage(), ex);
      }
    }
  }

  /**
   * Close the given RabbitMQ Channel and ignore any thrown exception. This is useful for typical <code>finally</code>
   * blocks in manual RabbitMQ code.
   * @param channel the RabbitMQ Channel to close (may be <code>null</code>)
   */
  public static void closeChannel(Channel channel) {
    if (channel != null) {
      try {
        channel.close();
      }
      catch (IOException ex) {
        logger.debug("Could not close RabbitMQ Channel", ex);
      }
      catch (ShutdownSignalException sig) {
        if (!isNormalShutdown(sig)) {
          logger.debug("Unexpected exception on closing RabbitMQ Channel", sig);
        }
      }
      catch (Throwable ex) {
        logger.debug("Unexpected exception on closing RabbitMQ Channel", ex);
      }
    }
  }

  /**
   * Commit the Channel if not within a JTA transaction.
   * @param channel the RabbitMQ Channel to commit
   */
  public static void commitIfNecessary(Channel channel) {
    Assert.notNull(channel, "Channel must not be null");
    try {
      channel.txCommit();
    } catch (IOException ex) {
      throw new AmqpIOException(ex);
    }
  }

  public static void rollbackIfNecessary(Channel channel) {
    Assert.notNull(channel, "Channel must not be null");
    try {
      channel.txRollback();
    } catch (IOException ex) {
      throw new AmqpIOException(ex);
    }
  }

  public static void closeMessageConsumer(Channel channel, Collection<String> consumerTags, boolean transactional) {
    if (!channel.isOpen()) {
      return;
    }
    try {
      synchronized(consumerTags) {
        for (String consumerTag : consumerTags) {
          channel.basicCancel(consumerTag);
        }
      }
      if (transactional) {
        /*
         * Re-queue in-flight messages if any (after the consumer is cancelled to prevent the broker from simply
         * sending them back to us). Does not require a tx.commit.
         */
        channel.basicRecover(true);
      }
      /*
       * If not transactional then we are auto-acking (at least as of 1.0.0.M2) so there is nothing to recover.
       * Messages are going to be lost in general.
       */
    } catch (Exception ex) {
      throw RabbitExceptionTranslator.convertRabbitAccessException(ex);
    }
  }

  /**
   * Declare to that broker that a channel is going to be used transactionally, and convert exceptions that arise.
   *
   * @param channel the channel to use
   */
  public static void declareTransactional(Channel channel) {
    try {
      channel.txSelect();
    } catch (IOException e) {
      throw RabbitExceptionTranslator.convertRabbitAccessException(e);
    }
  }

  /**
   * Sets a ThreadLocal indicating the channel MUST be physically closed.
   * @param b true if the channel must be closed.
   */
  public static void setPhysicalCloseRequired(boolean b) {
    physicalCloseRequired.set(b);
  }

  /**
   * Gets and removes a ThreadLocal indicating the channel MUST be physically closed.
   * @return true if the channel must be physically closed
   */
  public static boolean isPhysicalCloseRequired() {
    Boolean mustClose = physicalCloseRequired.get();
    if (mustClose == null) {
      mustClose = Boolean.FALSE;
    }
    else {
      physicalCloseRequired.remove();
    }
    return mustClose;
  }

  public static boolean isNormalShutdown(ShutdownSignalException sig) {
    Object shutdownReason = determineShutdownReason(sig);
    return shutdownReason instanceof AMQP.Connection.Close
        && AMQP.REPLY_SUCCESS == ((AMQP.Connection.Close) shutdownReason).getReplyCode()
        && "OK".equals(((AMQP.Connection.Close) shutdownReason).getReplyText());
  }

  public static boolean isNormalChannelClose(ShutdownSignalException sig) {
    Object shutdownReason = determineShutdownReason(sig);
    return shutdownReason instanceof AMQP.Channel.Close
        && AMQP.REPLY_SUCCESS == ((AMQP.Channel.Close) shutdownReason).getReplyCode()
        && "OK".equals(((AMQP.Channel.Close) shutdownReason).getReplyText());
  }

  protected static Object determineShutdownReason(ShutdownSignalException sig) {
    if (shutDownSignalReasonMethod == null) {
      return false;
    }
    try {
      return ReflectionUtils.invokeMethod(shutDownSignalReasonMethod, sig);
    }
    catch (Exception e) {
      return false;
    }
  }

}
TOP

Related Classes of org.springframework.amqp.rabbit.connection.RabbitUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.