org.apache.synapse.message.store.impl.rabbitmq.RabbitMQConsumer.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.synapse.message.store.impl.rabbitmq.RabbitMQConsumer.java

Source

/**
 *  Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you 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 org.apache.synapse.message.store.impl.rabbitmq;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.GetResponse;
import com.rabbitmq.client.ShutdownSignalException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.MessageContext;
import org.apache.synapse.message.MessageConsumer;

import org.apache.synapse.message.store.impl.commons.MessageConverter;
import org.apache.synapse.message.store.impl.commons.StorableMessage;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;

public class RabbitMQConsumer implements MessageConsumer {
    private static final Log logger = LogFactory.getLog(RabbitMQConsumer.class.getName());

    private Connection connection;

    private Channel channel;

    private RabbitMQStore store;

    private String queueName;

    private String idString;

    private boolean isInitialized;
    /**
     * Did last receive() call cause an error?
     */
    private boolean isReceiveError;
    /**
     * Holds the last message read from the message store.
     */
    private CachedMessage cachedMessage;

    public RabbitMQConsumer(RabbitMQStore store) {
        if (store == null) {
            logger.error("Cannot initialize.");
            return;
        }
        this.store = store;
        cachedMessage = new CachedMessage();
        isReceiveError = false;
        isInitialized = true;
    }

    public MessageContext receive() {
        if (!checkConnection()) {
            if (!reconnect()) {
                if (logger.isDebugEnabled()) {
                    logger.debug(getId() + " cannot receive message from store. Can not reconnect.");
                }
                return null;
            } else {
                logger.info(getId() + " reconnected to store.");
                isReceiveError = false;
            }
        }
        //setting channel
        if (channel != null) {
            if (!channel.isOpen()) {
                if (!setChannel()) {
                    logger.info(getId() + " unable to create the channel.");
                    return null;
                }
            }
        } else {
            if (!setChannel()) {
                logger.info(getId() + " unable to create the channel.");
                return null;
            }
        }
        //receive messages
        try {

            GetResponse delivery = null;
            delivery = channel.basicGet(queueName, false);

            if (delivery != null) {
                //deserilizing message
                StorableMessage storableMessage = null;
                ByteArrayInputStream bis = new ByteArrayInputStream(delivery.getBody());
                ObjectInput in = new ObjectInputStream(bis);
                try {
                    storableMessage = (StorableMessage) in.readObject();
                } catch (ClassNotFoundException e) {
                    logger.error(getId() + "unable to read the stored message" + e);
                    channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
                }

                bis.close();
                in.close();
                org.apache.axis2.context.MessageContext axis2Mc = store.newAxis2Mc();
                MessageContext synapseMc = store.newSynapseMc(axis2Mc);
                synapseMc = MessageConverter.toMessageContext(storableMessage, axis2Mc, synapseMc);
                updateCache(delivery, synapseMc, null, false);
                if (logger.isDebugEnabled()) {
                    logger.debug(getId() + " Received MessageId:" + delivery.getProps().getMessageId());
                }
                return synapseMc;
            }
        } catch (ShutdownSignalException sse) {
            logger.error(getId() + " connection error when receiving messages" + sse);
        } catch (IOException ioe) {
            logger.error(getId() + " connection error when receiving messages" + ioe);
        }
        return null;
    }

    public boolean ack() {
        boolean result = cachedMessage.ack();
        if (result) {
            store.dequeued();
        }
        return result;
    }

    public boolean cleanup() {
        if (logger.isDebugEnabled()) {
            logger.debug(getId() + " cleaning up...");
        }
        boolean result = store.cleanup(connection, true);
        if (result) {
            connection = null;
            return true;
        }
        return false;
    }

    @Override
    public boolean isAlive() {
        return true;
    }

    public RabbitMQConsumer setConnection(Connection connection) {
        this.connection = connection;
        return this;
    }

    public void setQueueName(String queueName) {
        this.queueName = queueName;
    }

    public boolean setChannel() {
        if (connection != null && connection.isOpen()) {
            try {
                this.channel = connection.createChannel();
                return true;
            } catch (IOException e) {
                return false;
            }
        }
        return false;
    }

    public void setId(int id) {
        idString = "[" + store.getName() + "-C-" + id + "]";
    }

    public String getId() {
        return idString;
    }

    public Connection getConnection() {
        return connection;
    }

    private boolean checkConnection() {
        if (connection == null) {
            if (logger.isDebugEnabled()) {
                logger.debug(getId() + " cannot proceed. RabbitMQ Connection is null.");
            }
            return false;
        }
        if (!connection.isOpen()) {
            if (logger.isDebugEnabled()) {
                logger.debug(getId() + " cannot proceed. RabbitMQ Connection is closed.");
            }
            return false;
        }
        return true;
    }

    private boolean reconnect() {
        RabbitMQConsumer consumer = (RabbitMQConsumer) store.getConsumer();

        if (consumer.getConnection() == null) {
            if (logger.isDebugEnabled()) {
                logger.debug(getId() + " could not reconnect to the broker.");
            }
            return false;
        }
        setConnection(consumer.getConnection());
        if (logger.isDebugEnabled()) {
            logger.debug(getId() + " ===> " + consumer.getId());
        }
        idString = consumer.getId();
        return true;
    }

    private void updateCache(GetResponse delivery, MessageContext synCtx, String messageId, boolean receiveError)
            throws IOException {
        isReceiveError = receiveError;
        cachedMessage.setMessage(delivery);
        cachedMessage.setMc(synCtx);
        cachedMessage.setId(messageId);
    }

    /**
     * This is used to store the last received message
     * if the message is successfully sent to the endpoint, ack will sent to the store
     * in order to delete message from the queue
     * <p/>
     * In RabbitMQ message ack should be using the same channel which was consumed the message
     * There for the consumed channel will also stored without closing until the message is ackd
     */
    private final class CachedMessage {
        private GetResponse message = null;
        private MessageContext mc = null;
        private String id = "";

        public CachedMessage setMessage(GetResponse message) {
            this.message = message;
            return this;
        }

        public boolean ack() {
            if (message != null && channel != null && channel.isOpen()) {
                try {
                    channel.basicAck(message.getEnvelope().getDeliveryTag(), false);
                    return true;
                } catch (IOException e) {
                    logger.error(getId() + " cannot ack last read message. Error:" + e.getLocalizedMessage(), e);
                    return false;
                }
            }
            return false;
        }

        public GetResponse getMessage() {
            return message;
        }

        public CachedMessage setMc(MessageContext mc) {
            this.mc = mc;
            return this;
        }

        public CachedMessage setId(String id) {
            this.id = id;
            return this;
        }

        public String getId() {
            return id;
        }
    }
}