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

com.rabbitmq.client.QueueingConsumer Maven / Gradle / Ivy

Go to download

The RabbitMQ Java client library allows Java applications to interface with RabbitMQ.

There is a newer version: 5.22.0
Show newest version
// Copyright (c) 2007-Present Pivotal Software, Inc.  All rights reserved.
//
// This software, the RabbitMQ Java client library, is triple-licensed under the
// Mozilla Public License 1.1 ("MPL"), the GNU General Public License version 2
// ("GPL") and the Apache License version 2 ("ASL"). For the MPL, please see
// LICENSE-MPL-RabbitMQ. For the GPL, please see LICENSE-GPL2.  For the ASL,
// please see LICENSE-APACHE2.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied. See the LICENSE file for specific language governing
// rights and limitations of this software.
//
// If you have any questions regarding licensing, please contact us at
// [email protected].


package com.rabbitmq.client;

import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.utility.Utility;

/**
 * Convenience class: an implementation of {@link Consumer} with
 * straightforward blocking semantics.
 *
 * Deprecated in favor of {@link DefaultConsumer} (see below for background).
 * Will be removed in next major release.
 *
 * The general pattern for using QueueingConsumer is as follows:
 *
 * 
 * // Create connection and channel.
 * {@link ConnectionFactory} factory = new ConnectionFactory();
 * Connection conn = factory.newConnection();
 * {@link Channel} ch1 = conn.createChannel();
 *
 * // Declare a queue and bind it to an exchange.
 * String queueName = ch1.queueDeclare().{@link AMQP.Queue.DeclareOk#getQueue getQueue}();
 * ch1.{@link Channel#queueBind queueBind}(queueName, exchangeName, queueName);
 *
 * // Create the QueueingConsumer and have it consume from the queue
 * QueueingConsumer consumer = new {@link QueueingConsumer#QueueingConsumer(Channel) QueueingConsumer}(ch1);
 * ch1.{@link Channel#basicConsume basicConsume}(queueName, false, consumer);
 *
 * // Process deliveries
 * while (/* some condition * /) {
 *     {@link QueueingConsumer.Delivery} delivery = consumer.{@link QueueingConsumer#nextDelivery nextDelivery}();
 *     // process delivery
 *     ch1.{@link Channel#basicAck basicAck}(delivery.{@link QueueingConsumer.Delivery#getEnvelope getEnvelope}().{@link Envelope#getDeliveryTag getDeliveryTag}(), false);
 * }
 * 
* * *

For a more complete example, see LogTail in the test/src/com/rabbitmq/examples * directory of the source distribution.

* *

Historical Perspective

* *

QueueingConsumer was introduced to allow * applications to overcome a limitation in the way Connection * managed threads and consumer dispatching. When QueueingConsumer * was introduced, callbacks to Consumers were made on the * Connection's thread. This had two main drawbacks. Firstly, the * Consumer could stall the processing of all * Channels on the Connection. Secondly, if a * Consumer made a recursive synchronous call into its * Channel the client would deadlock. *

*

* QueueingConsumer provided client code with an easy way to * obviate this problem by queueing incoming messages and processing them on * a separate, application-managed thread. *

*

* The threading behaviour of Connection and Channel * has been changed so that each Channel uses a distinct thread * for dispatching to Consumers. This prevents * Consumers on one Channel holding up * Consumers on another and it also prevents recursive calls from * deadlocking the client. * As such, it is now safe to implement Consumer directly or * to extend DefaultConsumer and QueueingConsumer * is a lot less relevant.

* * @deprecated */ public class QueueingConsumer extends DefaultConsumer { private final BlockingQueue _queue; // When this is non-null the queue is in shutdown mode and nextDelivery should // throw a shutdown signal exception. private volatile ShutdownSignalException _shutdown; private volatile ConsumerCancelledException _cancelled; // Marker object used to signal the queue is in shutdown mode. // It is only there to wake up consumers. The canonical representation // of shutting down is the presence of _shutdown. // Invariant: This is never on _queue unless _shutdown != null. private static final Delivery POISON = new Delivery(null, null, null); public QueueingConsumer(Channel ch) { this(ch, new LinkedBlockingQueue()); } public QueueingConsumer(Channel ch, BlockingQueue q) { super(ch); this._queue = q; } @Override public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) { _shutdown = sig; _queue.add(POISON); } @Override public void handleCancel(String consumerTag) throws IOException { _cancelled = new ConsumerCancelledException(); _queue.add(POISON); } @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { checkShutdown(); this._queue.add(new Delivery(envelope, properties, body)); } /** * Encapsulates an arbitrary message - simple "bean" holder structure. */ public static class Delivery { private final Envelope _envelope; private final AMQP.BasicProperties _properties; private final byte[] _body; public Delivery(Envelope envelope, AMQP.BasicProperties properties, byte[] body) { _envelope = envelope; _properties = properties; _body = body; } /** * Retrieve the message envelope. * @return the message envelope */ public Envelope getEnvelope() { return _envelope; } /** * Retrieve the message properties. * @return the message properties */ public BasicProperties getProperties() { return _properties; } /** * Retrieve the message body. * @return the message body */ public byte[] getBody() { return _body; } } /** * Check if we are in shutdown mode and if so throw an exception. */ private void checkShutdown() { if (_shutdown != null) throw Utility.fixStackTrace(_shutdown); } /** * If delivery is not POISON nor null, return it. *

* If delivery, _shutdown and _cancelled are all null, return null. *

* If delivery is POISON re-insert POISON into the queue and * throw an exception if POISONed for no reason. *

* Otherwise, if we are in shutdown mode or cancelled, * throw a corresponding exception. */ private Delivery handle(Delivery delivery) { if (delivery == POISON || delivery == null && (_shutdown != null || _cancelled != null)) { if (delivery == POISON) { _queue.add(POISON); if (_shutdown == null && _cancelled == null) { throw new IllegalStateException( "POISON in queue, but null _shutdown and null _cancelled. " + "This should never happen, please report as a BUG"); } } if (null != _shutdown) throw Utility.fixStackTrace(_shutdown); if (null != _cancelled) throw Utility.fixStackTrace(_cancelled); } return delivery; } /** * Main application-side API: wait for the next message delivery and return it. * @return the next message * @throws InterruptedException if an interrupt is received while waiting * @throws ShutdownSignalException if the connection is shut down while waiting * @throws ConsumerCancelledException if this consumer is cancelled while waiting */ public Delivery nextDelivery() throws InterruptedException, ShutdownSignalException, ConsumerCancelledException { return handle(_queue.take()); } /** * Main application-side API: wait for the next message delivery and return it. * @param timeout timeout in millisecond * @return the next message or null if timed out * @throws InterruptedException if an interrupt is received while waiting * @throws ShutdownSignalException if the connection is shut down while waiting * @throws ConsumerCancelledException if this consumer is cancelled while waiting */ public Delivery nextDelivery(long timeout) throws InterruptedException, ShutdownSignalException, ConsumerCancelledException { return handle(_queue.poll(timeout, TimeUnit.MILLISECONDS)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy