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

io.bitsensor.plugins.shaded.org.springframework.amqp.rabbit.connection.LocalizedQueueConnectionFactory Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015-2016 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 io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.rabbit.connection;

import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import io.bitsensor.plugins.shaded.org.apache.commons.logging.Log;
import io.bitsensor.plugins.shaded.org.apache.commons.logging.LogFactory;

import io.bitsensor.plugins.shaded.io.bitsensor.plugins.shaded.org.springframework.amqp.AmqpException;
import io.bitsensor.plugins.shaded.org.springframework.beans.factory.DisposableBean;
import io.bitsensor.plugins.shaded.org.springframework.core.io.Resource;
import io.bitsensor.plugins.shaded.org.springframework.util.Assert;

import io.bitsensor.plugins.shaded.com.rabbitmq.http.client.Client;
import io.bitsensor.plugins.shaded.com.rabbitmq.http.client.domain.QueueInfo;


/**
 * A {@link RoutingConnectionFactory} that determines the node on which a queue is located and
 * returns a factory that connects directly to that node.
 * The RabbitMQ management plugin is called over REST to determine the node and the corresponding
 * address for that node is injected into the connection factory.
 * A single instance of each connection factory is retained in a cache.
 * If the location cannot be determined, the default connection factory is returned. This connection
 * factory is typically configured to connect to all the servers in a fail-over mode.
 * 

{@link #getTargetConnectionFactory(Object)} is invoked by the * {@code SimpleMessageListenerContainer}, when establishing a connection, with the lookup key having * the format {@code '[queueName]'}. *

All {@link ConnectionFactory} methods delegate to the default * * @author Gary Russell * @since 1.2 */ public class LocalizedQueueConnectionFactory implements ConnectionFactory, RoutingConnectionFactory, DisposableBean { private final Log logger = LogFactory.getLog(getClass()); private final Map nodeFactories = new HashMap(); private final ConnectionFactory defaultConnectionFactory; private final String[] adminUris; private final Map nodeToAddress = new HashMap(); private final String vhost; private final String username; private final String password; private final boolean useSSL; private final Resource sslPropertiesLocation; private final String keyStore; private final String trustStore; private final String keyStorePassPhrase; private final String trustStorePassPhrase; /** * @param defaultConnectionFactory the fallback connection factory to use if the queue * can't be located. * @param nodeToAddress a Map of node to address: (rabbit@server1 : server1:5672) * @param adminUris the rabbitmq admin addresses (http://host:port, ...) must be the * same length as addresses. * @param vhost the virtual host. * @param username the user name. * @param password the password. * @param useSSL use SSL. * @param sslPropertiesLocation the SSL properties location. */ public LocalizedQueueConnectionFactory(ConnectionFactory defaultConnectionFactory, Map nodeToAddress, String[] adminUris, String vhost, String username, String password, boolean useSSL, Resource sslPropertiesLocation) { Assert.notNull(defaultConnectionFactory, "'defaultConnectionFactory' cannot be null"); this.defaultConnectionFactory = defaultConnectionFactory; this.adminUris = Arrays.copyOf(adminUris, adminUris.length); this.nodeToAddress.putAll(nodeToAddress); this.vhost = vhost; this.username = username; this.password = password; this.useSSL = useSSL; this.sslPropertiesLocation = sslPropertiesLocation; this.keyStore = null; this.trustStore = null; this.keyStorePassPhrase = null; this.trustStorePassPhrase = null; } /** * @param defaultConnectionFactory the fallback connection factory to use if the queue can't be located. * @param nodeToAddress a Map of node to address: (rabbit@server1 : server1:5672) * @param adminUris the rabbitmq admin addresses (http://host:port, ...) must be the same length * as addresses. * @param vhost the virtual host. * @param username the user name. * @param password the password. * @param useSSL use SSL. * @param keyStore the key store resource (e.g. "file:/foo/keystore"). * @param trustStore the trust store resource (e.g. "file:/foo/truststore"). * @param keyStorePassPhrase the pass phrase for the key store. * @param trustStorePassPhrase the pass phrase for the trust store. */ public LocalizedQueueConnectionFactory(ConnectionFactory defaultConnectionFactory, Map nodeToAddress, String[] adminUris, String vhost, String username, String password, boolean useSSL, String keyStore, String trustStore, String keyStorePassPhrase, String trustStorePassPhrase) { Assert.notNull(defaultConnectionFactory, "'defaultConnectionFactory' cannot be null"); this.defaultConnectionFactory = defaultConnectionFactory; this.adminUris = Arrays.copyOf(adminUris, adminUris.length); this.nodeToAddress.putAll(nodeToAddress); this.vhost = vhost; this.username = username; this.password = password; this.useSSL = useSSL; this.sslPropertiesLocation = null; this.keyStore = keyStore; this.trustStore = trustStore; this.keyStorePassPhrase = keyStorePassPhrase; this.trustStorePassPhrase = trustStorePassPhrase; } /** * @param defaultConnectionFactory the fallback connection factory to use if the queue * can't be located. * @param addresses the rabbitmq server addresses (host:port, ...). * @param adminUris the rabbitmq admin addresses (http://host:port, ...) * @param nodes the rabbitmq nodes corresponding to addresses (rabbit@server1, ...) * must be the same length as addresses. * @param vhost the virtual host. * @param username the user name. * @param password the password. * @param useSSL use SSL. * @param sslPropertiesLocation the SSL properties location. */ public LocalizedQueueConnectionFactory(ConnectionFactory defaultConnectionFactory, String[] addresses, String[] adminUris, String[] nodes, String vhost, String username, String password, boolean useSSL, Resource sslPropertiesLocation) { Assert.notNull(defaultConnectionFactory, "'defaultConnectionFactory' cannot be null"); Assert.isTrue(addresses.length == nodes.length, "'addresses', 'adminAddresses', and 'nodes' properties must have equal length"); this.defaultConnectionFactory = defaultConnectionFactory; this.adminUris = Arrays.copyOf(adminUris, adminUris.length); for (int i = 0; i < addresses.length; i++) { this.nodeToAddress.put(nodes[i], addresses[i]); } this.vhost = vhost; this.username = username; this.password = password; this.useSSL = useSSL; this.sslPropertiesLocation = sslPropertiesLocation; this.keyStore = null; this.trustStore = null; this.keyStorePassPhrase = null; this.trustStorePassPhrase = null; } /** * @param defaultConnectionFactory the fallback connection factory to use if the queue can't be located. * @param addresses the rabbitmq server addresses (host:port, ...). * @param adminUris the rabbitmq admin addresses (http://host:port, ...). * @param nodes the rabbitmq nodes corresponding to addresses (rabbit@server1, ...) must be the same length * as addresses. * @param vhost the virtual host. * @param username the user name. * @param password the password. * @param useSSL use SSL. * @param keyStore the key store resource (e.g. "file:/foo/keystore"). * @param trustStore the trust store resource (e.g. "file:/foo/truststore"). * @param keyStorePassPhrase the pass phrase for the key store. * @param trustStorePassPhrase the pass phrase for the trust store. */ public LocalizedQueueConnectionFactory(ConnectionFactory defaultConnectionFactory, String[] addresses, String[] adminUris, String[] nodes, String vhost, String username, String password, boolean useSSL, String keyStore, String trustStore, String keyStorePassPhrase, String trustStorePassPhrase) { Assert.notNull(defaultConnectionFactory, "'defaultConnectionFactory' cannot be null"); Assert.isTrue(addresses.length == nodes.length, "'addresses', 'adminAddresses', and 'nodes' properties must have equal length"); this.defaultConnectionFactory = defaultConnectionFactory; this.adminUris = Arrays.copyOf(adminUris, adminUris.length); for (int i = 0; i < addresses.length; i++) { this.nodeToAddress.put(nodes[i], addresses[i]); } this.vhost = vhost; this.username = username; this.password = password; this.useSSL = useSSL; this.sslPropertiesLocation = null; this.keyStore = keyStore; this.trustStore = trustStore; this.keyStorePassPhrase = keyStorePassPhrase; this.trustStorePassPhrase = trustStorePassPhrase; } @Override public Connection createConnection() throws AmqpException { return this.defaultConnectionFactory.createConnection(); } @Override public String getHost() { return this.defaultConnectionFactory.getHost(); } @Override public int getPort() { return this.defaultConnectionFactory.getPort(); } @Override public String getVirtualHost() { return this.vhost; } @Override public String getUsername() { return this.username; } @Override public void addConnectionListener(ConnectionListener listener) { this.defaultConnectionFactory.addConnectionListener(listener); } @Override public boolean removeConnectionListener(ConnectionListener listener) { return this.defaultConnectionFactory.removeConnectionListener(listener); } @Override public void clearConnectionListeners() { this.defaultConnectionFactory.clearConnectionListeners(); } @Override public ConnectionFactory getTargetConnectionFactory(Object key) { String queue = ((String) key); queue = queue.substring(1, queue.length() - 1); Assert.isTrue(!queue.contains(","), "Cannot use LocalizedQueueConnectionFactory with more than one queue: " + key); ConnectionFactory connectionFactory = determineConnectionFactory(queue); if (connectionFactory == null) { return this.defaultConnectionFactory; } else { return connectionFactory; } } private ConnectionFactory determineConnectionFactory(String queue) { for (int i = 0; i < this.adminUris.length; i++) { String adminUri = this.adminUris[i]; if (!adminUri.endsWith("/api/")) { adminUri += "/api/"; } try { Client client = createClient(adminUri, this.username, this.password); QueueInfo queueInfo = client.getQueue(this.vhost, queue); if (queueInfo != null) { String node = queueInfo.getNode(); if (node != null) { String uri = this.nodeToAddress.get(node); if (uri != null) { return nodeConnectionFactory(queue, node, uri); } if (this.logger.isDebugEnabled()) { this.logger.debug("No match for node: " + node); } } } else { throw new AmqpException("Admin returned null QueueInfo"); } } catch (Exception e) { this.logger.warn("Failed to determine queue location for: " + queue + " at: " + adminUri + ": " + e.getMessage()); } } this.logger.warn("Failed to determine queue location for: " + queue + ", using default connection factory"); return null; } /** * Create a client instance. * @param adminUri the admin URI. * @param username the username * @param password the password. * @return The client. * @throws MalformedURLException if the URL is malformed * @throws URISyntaxException if there is a syntax error. */ protected Client createClient(String adminUri, String username, String password) throws MalformedURLException, URISyntaxException { return new Client(adminUri, username, password); } private synchronized ConnectionFactory nodeConnectionFactory(String queue, String node, String address) throws Exception { if (this.logger.isInfoEnabled()) { this.logger.info("Queue: " + queue + " is on node: " + node + " at: " + address); } ConnectionFactory cf = this.nodeFactories.get(node); if (cf == null) { cf = createConnectionFactory(address, node); if (this.logger.isInfoEnabled()) { this.logger.info("Created new connection factory: " + cf); } this.nodeFactories.put(node, cf); } return cf; } /** * Create a dedicated connection factory for the address. * @param address the address to which the factory should connect. * @param node the node. * @return the connection factory. * @throws Exception if errors occur during creation. */ protected ConnectionFactory createConnectionFactory(String address, String node) throws Exception { RabbitConnectionFactoryBean rcfb = new RabbitConnectionFactoryBean(); rcfb.setUseSSL(this.useSSL); rcfb.setSslPropertiesLocation(this.sslPropertiesLocation); rcfb.setKeyStore(this.keyStore); rcfb.setTrustStore(this.trustStore); rcfb.setKeyStorePassphrase(this.keyStorePassPhrase); rcfb.setTrustStorePassphrase(this.trustStorePassPhrase); rcfb.afterPropertiesSet(); CachingConnectionFactory ccf = new CachingConnectionFactory(rcfb.getObject()); ccf.setAddresses(address); ccf.setUsername(this.username); ccf.setPassword(this.password); ccf.setVirtualHost(this.vhost); ccf.setBeanName("node:" + node); return ccf; } @Override public void destroy() throws Exception { for (ConnectionFactory connectionFactory : this.nodeFactories.values()) { ((DisposableBean) connectionFactory).destroy(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy