org.springframework.amqp.rabbit.connection.RabbitUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.amqp.rabbit.connection.RabbitUtils.java

Source

/*
 * 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 && channel.isOpen()) {
            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;
        }
    }

}