com.cisco.oss.foundation.message.RabbitMQMessageConsumer.java Source code

Java tutorial

Introduction

Here is the source code for com.cisco.oss.foundation.message.RabbitMQMessageConsumer.java

Source

/*
 * Copyright 2015 Cisco Systems, Inc.
 *
 *  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.
 */

package com.cisco.oss.foundation.message;

import com.cisco.oss.foundation.configuration.ConfigUtil;
import com.cisco.oss.foundation.configuration.ConfigurationFactory;
import com.cisco.oss.foundation.flowcontext.FlowContextFactory;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.GetResponse;
import com.rabbitmq.client.QueueingConsumer;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A RabbitMQ consumerThreadLocal wrapper. NOTE: This class is thread safe although wraps RabbitMQ ClientConsumer
 * which is not thread safe. The internal implementation is to provide a single threaded consumerThreadLocal instance by using ThreadLocal
 * so this class can be used in a multi-threaded environment.
 * Created by Yair Ogen on 24/04/2014.
 */
public class RabbitMQMessageConsumer implements MessageConsumer {

    private static final Logger LOGGER = LoggerFactory.getLogger(RabbitMQMessageConsumer.class);
    public static final String DLQ = "DLQ";
    private String consumerName = "N/A";
    private Configuration configuration = ConfigurationFactory.getConfiguration();

    private String queueName = "";
    private QueueingConsumer consumer = null;
    private AtomicBoolean isRegistered = new AtomicBoolean(false);
    private String consumerTag = null;
    private int channelNumber = -1;

    private AtomicInteger nextIndex = new AtomicInteger(0);

    RabbitMQMessageConsumer(String consumerName) {
        try {
            this.consumerName = consumerName;
            Configuration subset = configuration.subset(consumerName);
            queueName = subset.getString("queue.name");

            String filter = subset.getString("queue.filter", "");
            boolean isAutoDelete = subset.getBoolean("queue.isAutoDelete", false);
            boolean isDurable = subset.getBoolean("queue.isDurable", true);
            boolean isSubscription = subset.getBoolean("queue.isSubscription", false);
            long expiration = subset.getLong("queue.expiration", 1800000);
            long maxLength = subset.getLong("queue.maxLength", -1);
            boolean deadLetterIsEnabled = subset.getBoolean("queue.deadLetterIsEnabled", true);
            String deadLetterExchangeName = subset.getString("queue.deadLetterExchangeName", DLQ);
            String subscribedTo = isSubscription ? subset.getString("queue.subscribedTo", "") : queueName;
            String exchangeType = subset.getString("queue.exchangeType", isSubscription ? "topic" : "direct");
            boolean isExclusive = subset.getBoolean("queue.isExclusive", false);
            try {
                RabbitMQMessagingFactory.INIT_LATCH.await();
            } catch (InterruptedException e) {
                LOGGER.error("error waiting for init to finish: " + e);
            }
            Channel channel = RabbitMQMessagingFactory.getChannel();
            channel.exchangeDeclare(subscribedTo, exchangeType, isDurable, false, false, null);

            Map<String, Object> args = new HashMap<String, Object>();

            if (maxLength > 0) {
                args.put("x-max-length", maxLength);
            }

            if (expiration > 0) {
                args.put("x-message-ttl", expiration);
            }

            if (deadLetterIsEnabled) {
                channel.exchangeDeclare(deadLetterExchangeName, exchangeType, isDurable, false, false, null);
                args.put("x-dead-letter-exchange", deadLetterExchangeName);
            }

            String queue = channel.queueDeclare(queueName, isDurable, isExclusive, isAutoDelete, args).getQueue();

            Map<String, String> filters = ConfigUtil.parseSimpleArrayAsMap(consumerName + ".queue.filters");
            if (filters != null && !filters.isEmpty()) {
                for (String routingKey : filters.values()) {
                    channel.queueBind(queue, subscribedTo, routingKey);
                }
            } else {
                channel.queueBind(queue, subscribedTo, "#");
            }

            consumer = new QueueingConsumer(channel);
            //            channel.basicConsume(queueName, true, consumer);
            LOGGER.info("created rabbitmq consumer: {} on exchange: {}, queue-name: {}", consumerName, subscribedTo,
                    queueName);
        } catch (IOException e) {
            throw new QueueException("Can't create consumer: " + e, e);
        }

    }

    @Override
    public Message receive() {

        try {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            GetResponse getResponse = new GetResponse(delivery.getEnvelope(), delivery.getProperties(),
                    delivery.getBody(), 0);
            RabbitMQMessage rabbitMQMessage = new RabbitMQMessage(getResponse, "");
            return rabbitMQMessage;
        } catch (InterruptedException e) {
            throw new QueueException("can't get new message: " + e, e);
        }

    }

    @Override
    public Message receive(long timeout) {
        try {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery(timeout);
            GetResponse getResponse = new GetResponse(delivery.getEnvelope(), delivery.getProperties(),
                    delivery.getBody(), 0);
            RabbitMQMessage rabbitMQMessage = new RabbitMQMessage(getResponse, "");
            return rabbitMQMessage;
        } catch (InterruptedException e) {
            throw new QueueException("can't get new message: " + e, e);
        }
    }

    public void registerMessageHandler(MessageHandler messageHandler, boolean autoAck) {
        if (isRegistered.compareAndSet(false, true)) {
            try {
                if (messageHandler instanceof AbstractRabbitMQMessageHandler) {
                    String consumerTag = FlowContextFactory.getFlowContext() != null
                            ? FlowContextFactory.getFlowContext().getUniqueId()
                            : "N/A";
                    Channel channel = RabbitMQMessagingFactory.getChannel();
                    this.channelNumber = channel.getChannelNumber();
                    ((AbstractRabbitMQMessageHandler) messageHandler).setChannelNumber(channelNumber);
                    this.consumerTag = channel.basicConsume(queueName, autoAck, consumerTag,
                            (Consumer) messageHandler);
                } else {
                    throw new IllegalArgumentException(
                            "Using RabbitMQ consumerThreadLocal you must provide a valid RabbitMQ massage handler");
                }

            } catch (IOException e) {
                //            LOGGER.error("can't register a MessageHandler: {}", e);
                throw new QueueException("can't register a MessageHandler: " + e, e);
            }
        }
    }

    public void ackMessage(Integer channelNumber, Long deliveryTag) {
        RabbitMQMessagingFactory.ackMessage(channelNumber, deliveryTag);
    }

    public void nackMessage(Integer channelNumber, Long deliveryTag) {
        RabbitMQMessagingFactory.nackMessage(channelNumber, deliveryTag);
    }

    @Override
    public void registerMessageHandler(MessageHandler messageHandler) {
        registerMessageHandler(messageHandler, true);
    }

    @Override
    public boolean unRregisterMessageHandler() {
        boolean success = false;
        if (isRegistered.compareAndSet(true, false)) {
            if (consumer != null) {
                try {
                    RabbitMQMessagingFactory.channels.get(channelNumber).basicCancel(this.consumerTag);
                    success = true;
                } catch (IOException e) {
                    LOGGER.error("can't unregsiter the handler. reaon: {}", e, e);
                }
            }
        } else {
            LOGGER.warn("can't unregister as there is no handler currently registered");
        }
        return success;

    }

    @Override
    public void close() {
        RabbitMQMessagingFactory.consumers.remove(consumerName);
    }

    public String getQueueName() {
        return queueName;
    }
}