play.modules.rabbitmq.consumer.RabbitMQConsumer.java Source code

Java tutorial

Introduction

Here is the source code for play.modules.rabbitmq.consumer.RabbitMQConsumer.java

Source

/** 
 * Copyright 2011 The Apache Software Foundation
 *
 * 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.
 * 
 * @author Felipe Oliveira (http://mashup.fm)
 * 
 */
package play.modules.rabbitmq.consumer;

import play.Logger;
import play.Play;
import play.jobs.Job;
import play.modules.rabbitmq.RabbitMQPlugin;
import play.modules.rabbitmq.util.ExceptionUtil;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;

// TODO: Auto-generated Javadoc
/**
 * The Class RabbitMQConsumerJob.
 * 
 * @param <T>
 *            the generic type
 */
public abstract class RabbitMQConsumer<T> extends Job<T> {

    /**
     * This is the default value defined by "rabbitmq.retries" on
     * application.conf (please override if you need a new value)
     */
    public static int retries = RabbitMQPlugin.retries();

    /**
     * Consume.
     * 
     * @param message
     *            the message
     */
    protected abstract void consume(T message);

    /**
     * Creates the channel.
     * 
     * @param plugin
     *            the plugin
     * @return the channel
     * @throws Exception
     *             the exception
     */
    protected Channel createChannel(RabbitMQPlugin plugin) throws Exception {
        // Get Plugin
        Channel channel = plugin.createChannel(this.queue(), this.routingKey());
        return channel;
    }

    /**
     * Creates the channel.
     * 
     * @param channel
     *            the channel
     * @param plugin
     *            the plugin
     * @return the channel
     * @throws Exception
     *             the exception
     */
    protected QueueingConsumer createConsumer(Channel channel, RabbitMQPlugin plugin) throws Exception {
        // Get Plugin
        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(this.queue(), plugin.isAutoAck(), consumer);

        // Log Debug
        Logger.info("RabbitMQ Consumer - Channel: %s, Consumer: %s " + channel, consumer);

        // Return Channel
        return consumer;
    }

    /**
     * Let our baby go!.
     * 
     * @see play.jobs.Job#doJob()
     */
    @Override
    public void doJob() {
        this.goGetHerSon();
    }

    /**
     * Gets the message type.
     * 
     * @return the message type
     */
    protected abstract Class getMessageType();

    /**
     * Go get her son.
     */
    private void goGetHerSon() {
        // Get Plugin
        RabbitMQPlugin plugin = Play.plugin(RabbitMQPlugin.class);

        // Define Channel
        Channel channel = null;
        QueueingConsumer consumer = null;
        Long deliveryTag = null;

        // Get Channel
        while (true) {
            // Log Debug
            Logger.info("Entering main loop on consumer: " + this);

            // Are Consumers Running?
            boolean active = RabbitMQPlugin.areConsumersActive();

            // Only do work if consumers are running
            if (active) {
                try {
                    // Create Channel
                    if (channel == null || (channel != null && channel.isOpen() == false)) {
                        consumer = null;
                        channel = this.createChannel(plugin);
                    }

                    // Create Consumer
                    if (consumer == null) {
                        consumer = this.createConsumer(channel, plugin);
                    }

                    // Get Task
                    QueueingConsumer.Delivery task = consumer.nextDelivery();

                    // Date Night
                    if ((task != null) && (task.getBody() != null)) {
                        try {
                            // Fire job that will pass the message to the
                            // consumer,
                            // ack the queue and do the retry logic
                            deliveryTag = task.getEnvelope().getDeliveryTag();
                            T message = this.toObject(task.getBody());
                            new RabbitMQMessageConsumerJob(channel, deliveryTag, this.queue(), this, message,
                                    this.retries()).doJobWithResult();

                        } catch (Throwable t) {
                            // Handle Exception
                            Logger.error(ExceptionUtil.getStackTrace(t));
                        }

                    }

                } catch (Throwable t) {
                    Logger.error(
                            "Error creating consumer channel to RabbitMQ, retrying in a few seconds. Exception: %s",
                            ExceptionUtil.getStackTrace(t));
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        Logger.error(ExceptionUtil.getStackTrace(t));
                    }

                } finally {
                    if (channel != null) {
                        // Now tell Daddy everything is cool
                        try {
                            if (deliveryTag != null && channel.isOpen()) {
                                channel.basicAck(deliveryTag, false);
                            }
                        } catch (Throwable e) {
                            Logger.error(ExceptionUtil
                                    .getStackTrace("Error doing a basicAck for tag: " + deliveryTag, e));
                        }
                        try {
                            if (channel.getConnection() != null && channel.getConnection().isOpen()) {
                                channel.getConnection().close();
                            }
                            if (channel.isOpen() == true) {
                                channel.close();
                            }
                        } catch (Throwable t) {
                            Logger.error(ExceptionUtil.getStackTrace(t));
                        } finally {
                            channel = null;
                        }
                    }
                }
            } else {
                Logger.warn("RabbitMQ consumers are paused and napping for 10 secs...");
                try {
                    Thread.sleep(10000);
                } catch (Throwable t) {
                }
            }
        }
    }

    /**
     * Gets the queue name.
     * 
     * @return the queue name
     */
    protected abstract String queue();

    /**
     * Routing key.
     * 
     * @param t
     *            the t
     * @return the string
     */
    protected String routingKey() {
        return this.queue();
    }

    /**
     * Retries.
     * 
     * @return the int
     */
    protected int retries() {
        return retries;
    }

    /**
     * To object.
     * 
     * @param bytes
     *            the bytes
     * @return the object
     * @throws Exception
     *             the exception
     */
    protected T toObject(byte[] bytes) throws Exception {
        return (T) RabbitMQPlugin.mapper().getObject(this.getMessageType(), bytes);
    }

}