package bo.gotthardt.queue.rabbitmq;
import bo.gotthardt.queue.MessageQueue;
import bo.gotthardt.queue.MessageQueueException;
import com.codahale.metrics.MetricRegistry;
import com.google.common.base.Preconditions;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import io.dropwizard.ConfiguredBundle;
import io.dropwizard.lifecycle.Managed;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.hk2.api.Factory;
import java.io.IOException;
/**
* Dropwizard bundle for using RabbitMQ message queues.
*
* @author Bo Gotthardt
*/
@Slf4j
public class RabbitMQBundle implements ConfiguredBundle<HasRabbitMQConfiguration>, Managed {
private final ConnectionFactory factory = new ConnectionFactory();
@Getter(AccessLevel.PACKAGE)
private Connection connection;
private Channel channel;
private MetricRegistry metrics;
@Override
public void initialize(Bootstrap<?> bootstrap) {
// Empty on purpose.
}
@Override
public void run(HasRabbitMQConfiguration configuration, Environment environment) throws Exception {
RabbitMQConfiguration rabbitMQ = configuration.getRabbitMq();
factory.setHost(rabbitMQ.getHost());
factory.setVirtualHost(rabbitMQ.getVirtualHost());
factory.setUsername(rabbitMQ.getUsername());
factory.setPassword(rabbitMQ.getPassword());
factory.setPort(rabbitMQ.getPort());
factory.setAutomaticRecoveryEnabled(true);
log.info("Connecting to RabbitMQ on '{}' with username '{}'.", factory.getHost(), factory.getUsername());
connection = factory.newConnection();
channel = connection.createChannel();
channel.basicQos(1);
environment.lifecycle().manage(this);
environment.healthChecks().register("rabbitmq", new RabbitMQHealthCheck(this));
metrics = environment.metrics();
}
@Override
public void start() throws Exception {
// Connection and channel init code should really be in here, but it has to be earlier in the startup to be ready when Guice/HK2 initializes.
}
@Override
public void stop() throws Exception {
if (channel != null && channel.isOpen()) {
channel.close();
}
if (connection != null && connection.isOpen()) {
connection.close();
}
}
/**
* Get the message queue with the specified name.
* @param queueName The queue name.
* @param <T> The type of messages in the queue.
* @return The queue.
*/
public <T> MessageQueue<T> getQueue(String queueName, Class<T> type) {
Preconditions.checkNotNull(channel, "Channel not initialized.");
Preconditions.checkState(channel.isOpen(), "Channel already closed.");
return new RabbitMQMessageQueue<>(channel, queueName, type, metrics);
}
public <T> Factory<MessageQueue<T>> getQueueFactory(String queueName, Class<T> type) {
return new Factory<MessageQueue<T>>() {
@Override
public MessageQueue<T> provide() {
return getQueue(queueName, type);
}
@Override
public void dispose(MessageQueue<T> instance) {}
};
}
/**
* Delete all messages in the specified queue.
* <b>ONLY for testing!</b>
* @param queue The queue.
*/
void purgeQueue(MessageQueue<?> queue) {
try {
channel.queuePurge(queue.getName());
} catch (IOException e) {
throw new MessageQueueException("Unable to purge queue.", e);
}
}
}