org.pascani.dsl.lib.infrastructure.rabbitmq.RabbitMQConsumer.java Source code

Java tutorial

Introduction

Here is the source code for org.pascani.dsl.lib.infrastructure.rabbitmq.RabbitMQConsumer.java

Source

/*
 * Copyright  2015 Universidad Icesi
 * 
 * This file is part of the Pascani project.
 * 
 * The Pascani project is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * 
 * The Pascani project is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with The Pascani project. If not, see <http://www.gnu.org/licenses/>.
 */
package org.pascani.dsl.lib.infrastructure.rabbitmq;

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

import org.apache.commons.lang3.SerializationUtils;
import org.pascani.dsl.lib.Event;
import org.pascani.dsl.lib.PascaniRuntime;
import org.pascani.dsl.lib.infrastructure.AbstractConsumer;
import org.pascani.dsl.lib.util.LocalEventProducer;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.ShutdownSignalException;

/**
 * Implementation of {@link AbstractConsumer} to work with the RabbitMQ queuing
 * system.
 * 
 * @author Miguel Jimnez - Initial contribution and API
 */
public class RabbitMQConsumer extends AbstractConsumer implements Consumer {

    /**
     * An end point connected to a RabbitMQ server
     */
    private final EndPoint endPoint;

    /**
     * The consumer tag
     */
    private final String consumerTag;

    /**
     * The queue from which messages are consumed
     */
    private final String queueName;

    /**
     * An event producer for delegating the event handling
     */
    private final LocalEventProducer<Event<?>> eventProducer;

    /**
     * Creates a RabbitMQ message consumer
     * 
     * @param queue
     *            The queue from which messages are consumed
     * @param tag
     *            The consumer tag for this consumer (a unique name)
     * @param context
     *            The context in which this consumer is used
     * @throws Exception
     *             if something bad happens! @see {@link EndPoint#EndPoint()}
     */
    public RabbitMQConsumer(final String queue, final String tag, final PascaniRuntime.Context context)
            throws Exception {
        this(new EndPoint(), queue, tag, context);
    }

    /**
     * Creates a RabbitMQ message consumer
     * 
     * @param endPoint
     *            The RabbitMQ end point
     * @param queue
     *            The queue from which messages are consumed
     * @param tag
     *            The consumer tag for this consumer
     * @param context
     *            The context in which this consumer is used
     * @throws IOException
     *             If an I/O problem is encountered
     * @throws TimeoutException
     *             If there is a connection time out when connecting to the
     *             RabbitMQ server
     */
    public RabbitMQConsumer(final EndPoint endPoint, final String queue, final String tag,
            final PascaniRuntime.Context context) throws IOException, TimeoutException {

        this.endPoint = endPoint;
        this.queueName = queue;
        this.consumerTag = tag;
        this.eventProducer = new LocalEventProducer<Event<?>>(context);
    }

    /**
     * Creates a RabbitMQ message consumer consuming from an exchange. To do
     * this, an anonymous non-durable queue is declared and bound to the
     * exchange.
     * 
     * @param exchange
     *            The exchange from which messages are consumed
     * @param routingKey
     *            The routing key of interest
     * @param tag
     *            The consumer tag for this consumer
     * @param context
     *            The context in which this consumer is used
     * @throws Exception
     *             if something bad happens! @see {@link EndPoint#EndPoint()}
     */
    public RabbitMQConsumer(final String exchange, final String routingKey, final String tag,
            final PascaniRuntime.Context context) throws Exception {
        this(new EndPoint(), exchange, routingKey, tag, context);
    }

    /**
     * Creates a RabbitMQ message consumer consuming from an exchange. To do
     * this, an anonymous non-durable queue is declared and bound to the
     * exchange.
     * 
     * @param endPoint
     *            The RabbitMQ end point
     * @param exchange
     *            The exchange from which messages are consumed
     * @param routingKey
     *            The routing key of interest
     * @param tag
     *            The consumer tag for this consumer
     * @param context
     *            The context in which this consumer is used
     * @throws IOException
     *             If an I/O problem is encountered
     * @throws TimeoutException
     *             If there is a connection time out when connecting to the
     *             RabbitMQ server
     */
    public RabbitMQConsumer(final EndPoint endPoint, final String exchange, final String routingKey,
            final String tag, final PascaniRuntime.Context context) throws IOException, TimeoutException {

        this.endPoint = endPoint;
        Channel channel = this.endPoint.channel();

        this.queueName = channel.queueDeclare().getQueue();
        channel.queueBind(this.queueName, exchange, routingKey);

        this.consumerTag = tag;
        this.eventProducer = new LocalEventProducer<Event<?>>(context);
    }

    /*
     * (non-Javadoc)
     * 
     * @see pascani.lang.infrastructure.AbstractConsumer#startConsuming()
     */
    @Override
    protected void startConsuming() {
        Channel channel = this.endPoint.channel();
        try {
            // start consuming (non auto-acknowledged) messages
            channel.basicConsume(this.queueName, false, this.consumerTag, this);
        } catch (IOException e) {
            logger.error("Error consuming message from RabbitMQ consumer", e);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see pascani.lang.infrastructure.AbstractConsumer#delegateEventHandling(
     * pascani.lang.Event)
     */
    @Override
    public void delegateEventHandling(final Event<?> event) {
        this.eventProducer.post(event);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.rabbitmq.client.Consumer#handleDelivery(java.lang.String,
     * com.rabbitmq.client.Envelope, com.rabbitmq.client.AMQP.BasicProperties,
     * byte[])
     */
    public void handleDelivery(final String consumerTag, final Envelope envelope, final BasicProperties props,
            final byte[] body) throws IOException {

        Event<?> event = (Event<?>) SerializationUtils.deserialize(body);
        internalDelegateHandling(event);

        // Acknowledge the received message after it has been handled
        this.endPoint.channel().basicAck(envelope.getDeliveryTag(), false);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.rabbitmq.client.Consumer#handleConsumeOk(java.lang.String)
     */
    public void handleConsumeOk(final String consumerTag) {
        logger.info("The RabbitMQ consumer " + consumerTag + " has started successfully");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.rabbitmq.client.Consumer#handleCancelOk(java.lang.String)
     */
    public void handleCancelOk(final String consumerTag) {
        logger.info("The RabbitMQ consumer " + consumerTag + " has been canceled");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.rabbitmq.client.Consumer#handleCancel(java.lang.String)
     */
    public void handleCancel(final String consumerTag) throws IOException {
        logger.warn("The RabbitMQ consumer " + consumerTag + " has been canceled by unknown reasons");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.rabbitmq.client.Consumer#handleShutdownSignal(java.lang.String,
     * com.rabbitmq.client.ShutdownSignalException)
     */
    public void handleShutdownSignal(final String consumerTag, ShutdownSignalException sig) {
        logger.info("A channel or the connection of the RabbitMQ consumer " + consumerTag + " has been shut down");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.rabbitmq.client.Consumer#handleRecoverOk(java.lang.String)
     */
    public void handleRecoverOk(final String consumerTag) {
        logger.info("The connection for the RabbitMQ consumer " + consumerTag + " has been recovered successfully");
    }

    /*
     * (non-Javadoc)
     * 
     * @see pascani.lang.infrastructure.AbstractConsumer#shutdown()
     */
    @Override
    public void shutdown() throws IOException, TimeoutException {
        this.endPoint.close();
    }
}