com.novemberain.langohr.Connection.java Source code

Java tutorial

Introduction

Here is the source code for com.novemberain.langohr.Connection.java

Source

// Copyright (c) 2011-2014 Michael S. Klishin
//
// The use and distribution terms for this software are covered by the
// Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
// which can be found in the file epl-v10.html at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license.
// You must not remove this notice, or any other, from this software.

package com.novemberain.langohr;

import clojure.lang.IFn;
import clojure.lang.IPersistentMap;
import clojure.lang.Keyword;
import clojure.lang.PersistentHashMap;
import com.rabbitmq.client.*;
import com.rabbitmq.client.impl.recovery.AutorecoveringConnection;

import java.io.IOException;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeoutException;

/**
 * Alternative {@link com.rabbitmq.client.Connection} implementation that wraps
 * {@link com.rabbitmq.client.impl.AMQConnection} and adds automatic connection
 * recovery capability to it.
 */
public class Connection implements com.rabbitmq.client.Connection, Recoverable {
    private static final IPersistentMap DEFAULT_OPTIONS = buildDefaultOptions();
    // :automatically-recover
    public static final String AUTOMATICALLY_RECOVER_KEYWORD_NAME = "automatically-recover";
    public static final Keyword AUTOMATICALLY_RECOVER_KEYWORD = Keyword.intern(null,
            AUTOMATICALLY_RECOVER_KEYWORD_NAME);
    // :automatically-recover-topology
    public static final String AUTOMATICALLY_RECOVER_TOPOLOGY_KEYWORD_NAME = "automatically-recover-topology";
    public static final Keyword AUTOMATICALLY_RECOVER_TOPOLOGY_KEYWORD = Keyword.intern(null,
            AUTOMATICALLY_RECOVER_TOPOLOGY_KEYWORD_NAME);
    // :network-recovery-delay
    private static final String NETWORK_RECOVERY_DELAY_KEYWORD_NAME = "network-recovery-delay";
    private static final Keyword NETWORK_RECOVERY_DELAY_KEYWORD = Keyword.intern(null,
            NETWORK_RECOVERY_DELAY_KEYWORD_NAME);
    private static final long DEFAULT_NETWORK_RECOVERY_DELAY = 5000;
    private static final Keyword EXECUTOR_KEYWORD = Keyword.intern(null, "executor");
    private static final Keyword HOSTS_KEYWORD = Keyword.intern(null, "hosts");
    private final IPersistentMap options;

    private com.rabbitmq.client.Connection delegate;

    //
    // recovery
    //

    private boolean automaticallyRecover;
    private boolean automaticallyRecoverTopology;

    private static IPersistentMap buildDefaultOptions() {
        Map<Keyword, Boolean> m = new HashMap<Keyword, Boolean>();

        return PersistentHashMap.create(m);
    }

    private final ConnectionFactory cf;

    public Connection(ConnectionFactory cf) {
        this(cf, DEFAULT_OPTIONS);
    }

    public Connection(ConnectionFactory cf, IPersistentMap options) {
        this.cf = cf;
        this.options = options;

        Long l = (Long) options.valAt(NETWORK_RECOVERY_DELAY_KEYWORD, DEFAULT_NETWORK_RECOVERY_DELAY);
        cf.setNetworkRecoveryInterval(l.intValue());

        this.automaticallyRecover = Util.isTruthy(options.valAt(AUTOMATICALLY_RECOVER_KEYWORD, true));
        this.automaticallyRecoverTopology = Util
                .isTruthy(options.valAt(AUTOMATICALLY_RECOVER_TOPOLOGY_KEYWORD, true));

        cf.setAutomaticRecoveryEnabled(this.automaticallyRecover);
        cf.setTopologyRecoveryEnabled(this.automaticallyRecoverTopology);
    }

    @SuppressWarnings("unused")
    public Connection init() throws IOException, TimeoutException {
        return init(new Address[] {});
    }

    @SuppressWarnings("unused")
    public Connection init(Address[] addresses) throws IOException, TimeoutException {
        ExecutorService es = (ExecutorService) this.options.valAt(EXECUTOR_KEYWORD);
        if (addresses.length > 0) {
            this.delegate = cf.newConnection(es, addresses);
        } else {
            this.delegate = cf.newConnection(es);
        }

        return this;
    }

    public boolean automaticRecoveryEnabled() {
        return automaticallyRecover;
    }

    public boolean automaticTopologyRecoveryEnabled() {
        return automaticallyRecoverTopology;
    }

    public void onRecovery(final IFn f) {
        if (this.automaticRecoveryEnabled()) {
            ((AutorecoveringConnection) this.delegate).addRecoveryListener(new RecoveryListener() {
                public void handleRecovery(com.rabbitmq.client.Recoverable recoverable) {
                    f.invoke(recoverable);
                }
            });
        }
    }

    /**
     * Abort this connection and all its channels
     * with the {@link com.rabbitmq.client.AMQP#REPLY_SUCCESS} close code
     * and message 'OK'.
     * <p/>
     * Forces the connection to close.
     * Any encountered exceptions in the close operations are silently discarded.
     */
    public void abort() {
        delegate.abort();
    }

    /**
     * Remove shutdown listener for the component.
     *
     * @param listener {@link com.rabbitmq.client.ShutdownListener} to be removed
     */
    public void removeShutdownListener(ShutdownListener listener) {
        delegate.removeShutdownListener(listener);
    }

    /**
     * Get the negotiated maximum channel number. Usable channel
     * numbers range from 1 to this number, inclusive.
     *
     * @return the maximum channel number permitted for this connection.
     */
    public int getChannelMax() {
        return delegate.getChannelMax();
    }

    /**
     * Add shutdown listener.
     * If the component is already closed, handler is fired immediately
     *
     * @param listener {@link com.rabbitmq.client.ShutdownListener} to the component
     */
    public void addShutdownListener(ShutdownListener listener) {
        delegate.addShutdownListener(listener);
    }

    /**
     * Close this connection and all its channels.
     * <p/>
     * Waits with the given timeout for all the close operations to complete.
     * When timeout is reached the socket is forced to close.
     *
     * @param closeCode    the close code (See under "Reply Codes" in the AMQP specification)
     * @param closeMessage a message indicating the reason for closing the connection
     * @param timeout      timeout (in milliseconds) for completing all the close-related
     *                     operations, use -1 for infinity
     * @throws java.io.IOException if an I/O problem is encountered
     */
    public void close(int closeCode, String closeMessage, int timeout) throws IOException {
        delegate.close(closeCode, closeMessage, timeout);
    }

    /**
     * Retrieve the port number.
     *
     * @return the port number of the peer we're connected to.
     */
    public int getPort() {
        return delegate.getPort();
    }

    /**
     * Close this connection and all its channels
     * with the {@link com.rabbitmq.client.AMQP#REPLY_SUCCESS} close code
     * and message 'OK'.
     * <p/>
     * This method behaves in a similar way as {@link #close()}, with the only difference
     * that it waits with a provided timeout for all the close operations to
     * complete. When timeout is reached the socket is forced to close.
     *
     * @param timeout timeout (in milliseconds) for completing all the close-related
     *                operations, use -1 for infinity
     * @throws java.io.IOException if an I/O problem is encountered
     */
    public void close(int timeout) throws IOException {
        delegate.close(timeout);
    }

    /**
     * Create a new channel, using an internally allocated channel number.
     *
     * @return a new channel descriptor, or null if none is available
     * @throws java.io.IOException if an I/O problem is encountered
     */
    public Channel createChannel() throws IOException {
        return delegate.createChannel();
    }

    /**
     * Create a new channel, using the specified channel number if possible.
     *
     * @param channelNumber the channel number to allocate
     * @return a new channel descriptor, or null if this channel number is already in use
     * @throws java.io.IOException if an I/O problem is encountered
     */
    public Channel createChannel(int channelNumber) throws IOException {
        return delegate.createChannel(channelNumber);
    }

    /**
     * Abort this connection and all its channels
     * with the {@link com.rabbitmq.client.AMQP#REPLY_SUCCESS} close code
     * and message 'OK'.
     * <p/>
     * This method behaves in a similar way as {@link #abort()}, with the only difference
     * that it waits with a provided timeout for all the close operations to
     * complete. When timeout is reached the socket is forced to close.
     *
     * @param timeout timeout (in milliseconds) for completing all the close-related
     *                operations, use -1 for infinity
     */
    public void abort(int timeout) {
        delegate.abort(timeout);
    }

    @SuppressWarnings("unused")
    public com.rabbitmq.client.Connection getDelegate() {
        return delegate;
    }

    /**
     * Abort this connection and all its channels.
     * <p/>
     * Forces the connection to close and waits for all the close operations to complete.
     * Any encountered exceptions in the close operations are silently discarded.
     *
     * @param closeCode    the close code (See under "Reply Codes" in the AMQP specification)
     * @param closeMessage a message indicating the reason for closing the connection
     */
    public void abort(int closeCode, String closeMessage) {
        delegate.abort(closeCode, closeMessage);
    }

    /**
     * Close this connection and all its channels
     * with the {@link com.rabbitmq.client.AMQP#REPLY_SUCCESS} close code
     * and message 'OK'.
     * <p/>
     * Waits for all the close operations to complete.
     *
     * @throws java.io.IOException if an I/O problem is encountered
     */
    public void close() throws IOException {
        delegate.close();
    }

    /**
     * Retrieve the server properties.
     *
     * @return a map of the server properties. This typically includes the product name and version of the server.
     */
    public Map<String, Object> getServerProperties() {
        return delegate.getServerProperties();
    }

    /**
     * Get a copy of the map of client properties sent to the server
     *
     * @return a copy of the map of client properties
     */
    public Map<String, Object> getClientProperties() {
        return delegate.getClientProperties();
    }

    /**
     * Close this connection and all its channels.
     * <p/>
     * Waits for all the close operations to complete.
     *
     * @param closeCode    the close code (See under "Reply Codes" in the AMQP specification)
     * @param closeMessage a message indicating the reason for closing the connection
     * @throws java.io.IOException if an I/O problem is encountered
     */
    public void close(int closeCode, String closeMessage) throws IOException {
        delegate.close(closeCode, closeMessage);
    }

    /**
     * Get the shutdown reason object
     *
     * @return ShutdownSignalException if component is closed, null otherwise
     */
    public ShutdownSignalException getCloseReason() {
        return delegate.getCloseReason();
    }

    /**
     * Retrieve the host.
     *
     * @return the hostname of the peer we're connected to.
     */
    public InetAddress getAddress() {
        return delegate.getAddress();
    }

    /**
     * Get the negotiated heartbeat interval.
     *
     * @return the heartbeat interval, in seconds; zero if none
     */
    public int getHeartbeat() {
        return delegate.getHeartbeat();
    }

    /**
     * Determine whether the component is currently open.
     * Will return false if we are currently closing.
     * Checking this method should be only for information,
     * because of the race conditions - state can change after the call.
     * Instead just execute and try to catch ShutdownSignalException
     * and IOException
     *
     * @return true when component is open, false otherwise
     */
    public boolean isOpen() {
        return delegate.isOpen();
    }

    /**
     * Protected API - notify the listeners attached to the component
     *
     * @see com.rabbitmq.client.ShutdownListener
     */
    public void notifyListeners() {
        delegate.notifyListeners();
    }

    /**
     * Get the negotiated maximum frame size.
     *
     * @return the maximum frame size, in octets; zero if unlimited
     */
    public int getFrameMax() {
        return delegate.getFrameMax();
    }

    /**
     * Abort this connection and all its channels.
     * <p/>
     * Forces the connection to close and waits with the given timeout
     * for all the close operations to complete. When timeout is reached
     * the socket is forced to close.
     * Any encountered exceptions in the close operations are silently discarded.
     *
     * @param closeCode    the close code (See under "Reply Codes" in the AMQP specification)
     * @param closeMessage a message indicating the reason for closing the connection
     * @param timeout      timeout (in milliseconds) for completing all the close-related
     *                     operations, use -1 for infinity
     */
    public void abort(int closeCode, String closeMessage, int timeout) {
        delegate.abort(closeCode, closeMessage, timeout);
    }

    public void addBlockedListener(BlockedListener listener) {
        delegate.addBlockedListener(listener);
    }

    public boolean removeBlockedListener(BlockedListener listener) {
        return delegate.removeBlockedListener(listener);
    }

    public void clearBlockedListeners() {
        delegate.clearBlockedListeners();
    }

    public ExceptionHandler getExceptionHandler() {
        return delegate.getExceptionHandler();
    }

    public void addRecoveryListener(RecoveryListener listener) {
        ((AutorecoveringConnection) this.delegate).addRecoveryListener(listener);
    }

    public void removeRecoveryListener(RecoveryListener listener) {
        ((AutorecoveringConnection) this.delegate).removeRecoveryListener(listener);
    }

    @Override
    public String toString() {
        return this.delegate.toString();
    }
}