Java tutorial
/*************************************************************************** * Copyright (c) 2013 VMware, Inc. All Rights Reserved. * 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. ***************************************************************************/ /*************************************************************************** * Copyright (c) 2012 VMware, Inc. All Rights Reserved. * 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 com.vmware.vhadoop.vhm.rabbit; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.QueueingConsumer; import com.rabbitmq.client.ShutdownListener; import com.rabbitmq.client.ShutdownSignalException; import com.vmware.vhadoop.api.vhm.QueueClient.CannotConnectException; /** * Encapsulates the details of connecting to a RabbitMQ queue * */ public class RabbitConnection { private static final Logger _log = Logger.getLogger(RabbitConnection.class.getName()); interface RabbitCredentials { public String getHostName(); public String getExchangeName(); public String getRouteKeyCommand(); public String getRouteKeyStatus(); } private ConnectionFactory _connectionFactory; private RabbitCredentials _credentials; private Channel _channel = null; private Object _channelLock = new Object(); private Connection _connection = null; private Object _connectionLock = new Object(); private String _queueName = null; private QueueingConsumer _consumer = null; private Object _consumerLock = new Object(); private volatile boolean _started = false; /* For testing only */ protected RabbitConnection() { } public RabbitConnection(RabbitCredentials credentials) { _credentials = credentials; _connectionFactory = new ConnectionFactory(); _connectionFactory.setHost(credentials.getHostName()); } private Connection getConnection() throws IOException { synchronized (_connectionLock) { if (_connection == null || !_connection.isOpen()) { _connection = null; _connection = _connectionFactory.newConnection(); _connection.addShutdownListener(new ShutdownListener() { @Override public void shutdownCompleted(ShutdownSignalException cause) { _log.info("Connection shut down"); _log.log(Level.FINE, "{0}", cause.getReason()); synchronized (_connectionLock) { _connection = null; _channel = null; _queueName = null; } _started = false; } }); _started = true; _log.fine("Created new connection"); } return _connection; } } private Channel getChannel() throws IOException { synchronized (_channelLock) { if (_channel == null || !_channel.isOpen()) { _log.fine("Creating new channel"); _channel = null; Connection connection = getConnection(); _channel = connection.createChannel(); _channel.addShutdownListener(new ShutdownListener() { @Override public void shutdownCompleted(ShutdownSignalException cause) { _log.info("Channel shut down"); _log.log(Level.FINE, "{0}", cause.getReason()); synchronized (_channelLock) { _channel = null; _queueName = null; } _started = false; } }); } return _channel; } } private synchronized String getQueueName() throws IOException { if (_queueName == null) { String exchangeName = _credentials.getExchangeName(); Channel channel = getChannel(); channel.exchangeDeclare(exchangeName, "direct", true, false, null); /* TODO: Externalize? */ _queueName = channel.queueDeclare().getQueue(); channel.queueBind(_queueName, exchangeName, _credentials.getRouteKeyCommand()); _log.fine("Created transient queue: " + _queueName); } return _queueName; } /* TODO: Can we cache the consumer object? */ QueueingConsumer getConsumer() throws CannotConnectException { synchronized (_consumerLock) { if (_consumer == null) { _log.fine("Creating new consumer"); try { Channel channel = getChannel(); _consumer = new QueueingConsumer(channel) { @Override public void handleShutdownSignal(java.lang.String consumerTag, ShutdownSignalException sig) { super.handleShutdownSignal(consumerTag, sig); _log.info("Consumer received shutdown notification"); _log.log(Level.FINE, "{0}", sig.getReason()); synchronized (_consumerLock) { _consumer = null; } } }; channel.basicConsume(getQueueName(), true, _consumer); } catch (Exception e) { throw new CannotConnectException("Unable to get message consumer", e); } } return _consumer; } } boolean connect() { Connection connection = null; try { connection = getConnection(); } catch (IOException e) { /* squash */ } return connection != null; } protected void sendMessage(String routeKey, byte[] data) throws CannotConnectException { boolean retry = false; do { try { Channel channel = getChannel(); if (channel != null) { channel.basicPublish(_credentials.getExchangeName(), routeKey, null, data); } retry = false; } catch (Exception e) { if (!retry) { connect(); retry = true; } else { throw new CannotConnectException("Unable to send message", e); } } } while (retry); } protected void sendMessage(byte[] data) throws CannotConnectException { sendMessage(_credentials.getRouteKeyStatus(), data); } public boolean isShutdown() { return (_started == false); } }