Java tutorial
/***************************************************************************** * * 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); } }