All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rabbitmq.jms.admin.RMQConnectionFactory Maven / Gradle / Ivy

There is a newer version: 3.4.0
Show newest version
/* Copyright (c) 2013 Pivotal Software, Inc. All rights reserved. */
package com.rabbitmq.jms.admin;

import static com.rabbitmq.jms.util.UriCodec.encHost;
import static com.rabbitmq.jms.util.UriCodec.encSegment;
import static com.rabbitmq.jms.util.UriCodec.encUserinfo;

import java.io.IOException;
import java.io.Serializable;
import java.util.concurrent.TimeoutException;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.net.ssl.SSLException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rabbitmq.jms.client.RMQConnection;
import com.rabbitmq.jms.util.RMQJMSException;
import com.rabbitmq.jms.util.RMQJMSSecurityException;

/**
 * RabbitMQ Implementation of JMS {@link ConnectionFactory}
 * TODO - implement SslContext option
 */
public class RMQConnectionFactory implements ConnectionFactory, Referenceable, Serializable, QueueConnectionFactory,
                                 TopicConnectionFactory {
    private final Logger logger = LoggerFactory.getLogger(RMQConnectionFactory.class);

    private static final long serialVersionUID = -4953157213762979615L;

    private static final int DEFAULT_RABBITMQ_SSL_PORT = com.rabbitmq.client.ConnectionFactory.DEFAULT_AMQP_OVER_SSL_PORT;

    private static final int DEFAULT_RABBITMQ_PORT = com.rabbitmq.client.ConnectionFactory.DEFAULT_AMQP_PORT;

    /** Default not to use ssl */
    private boolean ssl = false;
    /** Default username to RabbitMQ broker */
    private String username = "guest";
    /** Default password to RabbitMQ broker */
    private String password = "guest";
    /** Default virtualhost */
    private String virtualHost = "/";
    /** Default host to RabbitMQ broker */
    private String host = "localhost";
    /** Default port NOT SET - determined by the type of connection (ssl or non-ssl) */
    private int port = -1;

    /** The maximum number of messages to read on a queue browser, which must be non-negative;
     *  0 means unlimited and is the default; negative values are interpreted as 0. */
    private int queueBrowserReadMax = Math.max(0, Integer.getInteger("rabbit.jms.queueBrowserReadMax", 0));

    /** The time to wait for threads/messages to terminate during {@link Connection#close()} */
    private volatile long terminationTimeout = Long.getLong("rabbit.jms.terminationTimeout", 15000);

    /**
     * {@inheritDoc}
     */
    @Override
    public Connection createConnection() throws JMSException {
        return this.createConnection(username, password);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Connection createConnection(String username, String password) throws JMSException {
        logger.trace("Creating a connection for username '{}', password 'xxxxxxxx'.", username);
        this.username = username;
        this.password = password;
        // Create a new factory and set the properties
        com.rabbitmq.client.ConnectionFactory factory = new com.rabbitmq.client.ConnectionFactory();
        resetSsl(factory);
        setRabbitUri(logger, this, factory, this.getUri());
        com.rabbitmq.client.Connection rabbitConnection = getRabbitConnection(factory);

        RMQConnection conn = new RMQConnection(rabbitConnection, getTerminationTimeout(), getQueueBrowserReadMax());
        logger.debug("Connection {} created.", conn);
        return conn;
    }

    private com.rabbitmq.client.Connection getRabbitConnection(com.rabbitmq.client.ConnectionFactory factory) throws JMSException {
        try {
            return factory.newConnection();
        } catch (SSLException ssle) {
            throw new RMQJMSSecurityException("SSL Exception establishing RabbitMQ Connection", ssle);
        } catch (Exception x) {
            if (x instanceof IOException) {
                IOException ioe = (IOException) x;
                String msg = ioe.getMessage();
                if (msg!=null) {
                    if (msg.contains("authentication failure") || msg.contains("refused using authentication"))
                        throw new RMQJMSSecurityException(ioe);
                    else if (msg.contains("Connection refused"))
                        throw new RMQJMSException("RabbitMQ connection was refused. RabbitMQ broker may not be available.", ioe);
                }
                throw new RMQJMSException(ioe);
            } else if (x instanceof TimeoutException) {
                TimeoutException te = (TimeoutException) x;
                throw new RMQJMSException("Timed out establishing RabbitMQ Connection", te);
            } else {
                throw new RMQJMSException("Unexpected exception thrown by newConnection()", x);
            }
        }
    }

    /**
     * Returns the current factory connection parameters in a URI String.
     * @return URI for RabbitMQ connection (as a coded String)
     */
    public String getUri() {
        StringBuilder sb = new StringBuilder(scheme(isSsl())).append("://");
        sb.append(uriUInfoEscape(this.username, this.password)).append('@');
        sb.append(uriHostEscape(this.host)).append(':').append(this.getPort()).append("/");
        sb.append(uriVirtualHostEscape(this.virtualHost));

        return sb.toString();
    }

    public String toString() {
        StringBuilder sb = new StringBuilder("RMQConnectionFactory{");
        return (this.isSsl() ? sb.append("SSL, ") : sb)
        .append("user='").append(this.username)
        .append("', password").append(this.password!=null ? "=xxxxxxxx" : " not set")
        .append(", host='").append(this.host)
        .append("', port=").append(this.getPort())
        .append(", virtualHost='").append(this.virtualHost)
        .append("', queueBrowserReadMax=").append(this.queueBrowserReadMax)
        .append('}').toString();
    }

    /**
     * Set connection factory parameters by URI String.
     * @param uriString URI to use for instantiated connection
     * @throws JMSException
     */
    public void setUri(String uriString) throws JMSException {
        logger.trace("Set connection factory parameters by URI '{}'", uriString);
        // Create a temp factory and set the properties by uri
        com.rabbitmq.client.ConnectionFactory factory = new com.rabbitmq.client.ConnectionFactory();
        setRabbitUri(logger, this, factory, uriString);
        // Now extract our properties from this factory, leaving the rest unchanged.
        this.host = factory.getHost();
        this.password = factory.getPassword();
        this.port = factory.getPort();
        this.ssl = factory.isSSL();
        this.username = factory.getUsername();
        this.virtualHost = factory.getVirtualHost();
    }

    private static final void setRabbitUri(Logger logger, RMQConnectionFactory rmqFactory, com.rabbitmq.client.ConnectionFactory factory, String uriString) throws RMQJMSException {
        if (uriString != null) { // we get the defaults if the uri is null
            try {
                factory.setUri(uriString);
            } catch (Exception e) {
                logger.error("Could not set URI on {}", rmqFactory, e);
                throw new RMQJMSException("Could not set URI on RabbitMQ connection factory.", e);
            }
        }
    }

    private void resetSsl(com.rabbitmq.client.ConnectionFactory factory) {
        if (this.ssl)
        try {
            factory.useSslProtocol();
        } catch (Exception e1) {
            this.logger.warn("Could not set SSL protocol on connection factory, {}. SSL set off.", this, e1);
            this.ssl=false;
        }
    }

    public boolean isSsl() {
        return this.ssl;
    }

    public void setSsl(boolean ssl) {
        this.ssl = ssl;
    }

    private static final String scheme(boolean isSsl) {
        return (isSsl ? "amqps" : "amqp");
    }

    private static final String uriUInfoEscape(String user, String pass) {
        if (null==user) return null;
        if (null==pass) return encUserinfo(user, "UTF-8");
        return encUserinfo(user + ":" + pass, "UTF-8");
    }

    private static final String uriHostEscape(String host) {
        return encHost(host, "UTF-8");
    }

    private static final String uriVirtualHostEscape(String vHost) {
        return encSegment(vHost, "UTF-8");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Reference getReference() throws NamingException {
        Reference ref = new Reference(RMQConnectionFactory.class.getName());
        addStringRefProperty(ref, "uri", this.getUri());
        addIntegerRefProperty(ref, "queueBrowserReadMax", this.getQueueBrowserReadMax());
        return ref;
    }

    /**
     * Adds a String valued property to a Reference (as a RefAddr)
     * @param ref - the reference to contain the value
     * @param propertyName - the name of the property
     * @param value - the value to store with the property
     */
    private static final void addStringRefProperty(Reference ref,
                                                   String propertyName,
                                                   String value) {
        if (value==null || propertyName==null) return;
        RefAddr ra = new StringRefAddr(propertyName, value);
        ref.add(ra);
    }

    /**
     * Adds an integer valued property to a Reference (as a RefAddr).
     * @param ref - the reference to contain the value
     * @param propertyName - the name of the property
     * @param value - the value to store with the property
     */
    private static final void addIntegerRefProperty(Reference ref,
                                                    String propertyName,
                                                    Integer value) {
        if (value==null || propertyName==null) return;
        RefAddr ra = new StringRefAddr(propertyName, String.valueOf(value));
        ref.add(ra);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TopicConnection createTopicConnection() throws JMSException {
        return (TopicConnection) this.createConnection();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TopicConnection createTopicConnection(String userName, String password) throws JMSException {
        return (TopicConnection) this.createConnection(userName, password);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public QueueConnection createQueueConnection() throws JMSException {
        return (QueueConnection) this.createConnection();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public QueueConnection createQueueConnection(String userName, String password) throws JMSException {
        return (QueueConnection) this.createConnection(userName, password);
    }

    /**
     * Returns the configured username used when creating a connection If
     * {@link RMQConnectionFactory#setUsername(String)} has not been called the default value of 'guest' is returned.
     *
     * @return a string representing the username for a RabbitMQ connection
     */
    public String getUsername() {
        return username;
    }

    /**
     * Sets the username to be used when creating a connection to the RabbitMQ broker.
     * If the parameter is null the current username is not changed.
     *
     * @param username - username to be used when creating a connection to the RabbitMQ broker
     */
    public void setUsername(String username) {
        if (username != null) this.username = username;
        else this.logger.warn("Cannot set username to null (on {})", this);
    }

    /**
     * Returns the configured password used when creating a connection If
     * {@link RMQConnectionFactory#setPassword(String)} has not been called the default value of 'guest' is returned.
     *
     * @return a string representing the password for a Rabbit connection
     */
    public String getPassword() {
        return password;
    }

    /**
     * Sets the password to be used when creating a connection to the RabbitMQ broker
     *
     * @param password - password to be used when creating a connection to the RabbitMQ broker
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * Returns the virtual host used when creating a connection.  If
     * {@link RMQConnectionFactory#setVirtualHost(String)} has not been called the default value of '/' is returned.
     *
     * @return a String representing the virtual host for a RabbitMQ connection
     */
    public String getVirtualHost() {
        return virtualHost;
    }

    /**
     * Sets the virtualHost to be used when creating a connection to the RabbitMQ broker.
     * If the parameter is null the current virtualHost is not changed.
     *
     * @param virtualHost - virtual host to be used when creating a connection to the RabbitMQ broker
     */
    public void setVirtualHost(String virtualHost) {
        if (virtualHost != null) this.virtualHost = virtualHost;
        else this.logger.warn("Cannot set virtualHost to null (on {})", this);
    }

    /**
     * Returns the host name to be used when creating a connection to the RabbitMQ broker.
     *
     * @return the host name of the RabbitMQ broker
     */
    public String getHost() {
        return host;
    }

    /**
     * Sets the host of the RabbitMQ broker. The host name can be an IP address or a host name.
     * If the parameter is null the current host name is not changed.
     *
     * @param host - IP address or a host name of the RabbitMQ broker, in String form
     */
    public void setHost(String host) {
        if (host != null) this.host = host;
        else this.logger.warn("Cannot set host to null (on {})", this);
    }

    /**
     * Returns the port the RabbitMQ broker listens to; this port is used to connect to the broker.
     * If the port has not been set (defaults to -1) then the default port for this type of connection is returned.
     *
     * @return the port the RabbitMQ broker listens to
     */
    public int getPort() {
        return this.port!=-1 ? this.port
             : isSsl() ? DEFAULT_RABBITMQ_SSL_PORT
             : DEFAULT_RABBITMQ_PORT;
    }

    /**
     * Set the port to be used when making a connection to the RabbitMQ broker.  This is the port number the broker will listen on.
     * Setting this to -1 means take the RabbitMQ default (which depends on the type of connection).
     *
     * @param port - a TCP port number
     */
    public void setPort(int port) {
        this.port = port;
    }

    /**
     * Returns the time to wait in milliseconds when {@link Connection#close()} has been called for listeners and threads to
     * complete.
     *
     * @return the duration in milliseconds for which the {@link Connection#close()} waits before continuing shutdown sequence
     */
    public long getTerminationTimeout() {
        return terminationTimeout;
    }

    /**
     * Sets terminationTimeout: the time in milliseconds a {@link Connection#close()} should wait for threads/tasks/listeners to complete
     *
     * @param terminationTimeout - duration in milliseconds
     */
    public void setTerminationTimeout(long terminationTimeout) {
        this.terminationTimeout = terminationTimeout;
    }

    /**
     * Returns the maximum number of messages to read on a queue browser, or zero if there is no limit.
     *
     * @return the maximum number of messages to read on a queue browser
     */
    public int getQueueBrowserReadMax() {
        return this.queueBrowserReadMax;
    }

    /**
     * Sets queueBrowserReadMax: the maximum number of messages to read on a queue browser.
     * Non-positive values are set to zero, which is interpreted as no limit.
     *
     * @param queueBrowserReadMax - read no more than this number of messages on a queue browser.
     */
    public void setQueueBrowserReadMax(int queueBrowserReadMax) {
        this.queueBrowserReadMax = Math.max(0, queueBrowserReadMax);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy