org.zenoss.amqp.impl.ConsumerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.zenoss.amqp.impl.ConsumerImpl.java

Source

/*****************************************************************************
 *
 * Copyright (C) Zenoss, Inc. 2010-2011, all rights reserved.
 *
 * This content is made available according to terms specified in
 * License.zenoss under the directory where your Zenoss product is installed.
 *
 ****************************************************************************/

package org.zenoss.amqp.impl;

import com.rabbitmq.client.QueueingConsumer;
import com.rabbitmq.client.QueueingConsumer.Delivery;
import com.rabbitmq.client.ShutdownSignalException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zenoss.amqp.AmqpException;
import org.zenoss.amqp.Channel;
import org.zenoss.amqp.Consumer;
import org.zenoss.amqp.Message;
import org.zenoss.amqp.MessageConverter;
import org.zenoss.amqp.MessageDecoderException;
import org.zenoss.amqp.MessageEnvelope;
import org.zenoss.amqp.MessageProperties;
import org.zenoss.amqp.Queue;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.zip.InflaterOutputStream;

class ConsumerImpl<T> implements Consumer<T> {

    private static final Logger logger = LoggerFactory.getLogger(ConsumerImpl.class);

    static byte[] deflateDecompress(byte[] compressed) throws IOException {
        // Assume the decompressed size is 2x compressed
        ByteArrayOutputStream bos = new ByteArrayOutputStream(compressed.length * 2);
        InflaterOutputStream ios = null;
        try {
            ios = new InflaterOutputStream(bos);
            ios.write(compressed);
            ios.close();
            ios = null;
            return bos.toByteArray();
        } finally {
            if (ios != null) {
                ios.close();
            }
        }
    }

    private final ChannelImpl channel;
    private final Queue queue;
    private final boolean noAck;
    private final MessageConverter<T> converter;
    private QueueingConsumer consumer;
    private volatile String consumerTag;

    ConsumerImpl(ChannelImpl channel, Queue queue, boolean noAck) {
        this(channel, queue, noAck, null);
    }

    ConsumerImpl(ChannelImpl channel, Queue queue, boolean noAck, MessageConverter<T> converter) {
        this.channel = channel;
        this.queue = queue;
        this.noAck = noAck;
        this.converter = converter;
        this.consumer = new QueueingConsumer(this.channel.getWrapped());
    }

    @Override
    public Message<T> nextMessage() throws AmqpException, InterruptedException {
        return nextMessage(0, TimeUnit.SECONDS);
    }

    @Override
    public Message<T> nextMessage(long waitTime, TimeUnit unit) throws AmqpException, InterruptedException {
        final long timeInMillis = unit.toMillis(waitTime);
        if (consumerTag == null) {
            synchronized (this.channel) {
                try {
                    consumerTag = this.channel.getWrapped().basicConsume(queue.getName(), this.noAck, consumer);
                } catch (IOException e) {
                    throw new AmqpException(e);
                }
            }
        }
        try {
            final Delivery delivery;
            if (timeInMillis > 0) {
                delivery = consumer.nextDelivery(timeInMillis);
                if (delivery == null) {
                    return null;
                }
            } else {
                delivery = consumer.nextDelivery();
            }
            return createMessage(delivery);
        } catch (ShutdownSignalException e) {
            throw new AmqpException(e);
        }
    }

    @SuppressWarnings("unchecked")
    private Message<T> createMessage(Delivery delivery) throws AmqpException {
        final T body;
        final byte[] rawBody;
        final MessageProperties properties = new BasicPropertiesWrapper(delivery.getProperties());
        final MessageEnvelope envelope = new EnvelopeWrapper(delivery.getEnvelope());
        if ("deflate".equalsIgnoreCase(properties.getContentEncoding())) {
            try {
                rawBody = deflateDecompress(delivery.getBody());
            } catch (IOException e) {
                logger.warn("Failed to decompress message", e);
                // Throw MessageDecoderException so we don't loop attempting to read invalid message
                throw new MessageDecoderException(
                        DefaultMessage.newMessage(delivery.getBody(), properties, envelope), e);
            }
        } else {
            rawBody = delivery.getBody();
        }
        if (converter == null) {
            body = (T) rawBody;
        } else {
            try {
                body = converter.fromBytes(rawBody, properties);
            } catch (Exception e) {
                /* Throw exception with original received message on failure */
                throw new MessageDecoderException(DefaultMessage.newMessage(rawBody, properties, envelope), e);
            }
            /* Throw exception if we failed to convert the message */
            if (body == null) {
                throw new MessageDecoderException(DefaultMessage.newMessage(rawBody, properties, envelope));
            }
        }
        return DefaultMessage.newMessage(body, properties, envelope);
    }

    @Override
    public void cancel() throws AmqpException {
        synchronized (this.channel) {
            try {
                this.channel.getWrapped().basicCancel(consumerTag);
            } catch (IOException e) {
                throw new AmqpException(e);
            } catch (ShutdownSignalException e) {
                throw new AmqpException(e);
            }
        }
    }

    @Override
    public Queue getQueue() {
        return this.queue;
    }

    @Override
    public Channel getChannel() {
        return this.channel;
    }

    @Override
    public void ackMessage(Message<T> message) throws AmqpException {
        if (!this.noAck) {
            this.channel.ackMessage(message.getEnvelope().getDeliveryTag());
        }
    }

    @Override
    public void rejectMessage(Message<?> message, boolean requeue) throws AmqpException {
        this.channel.rejectMessage(message.getEnvelope().getDeliveryTag(), requeue);
    }
}