net.timewalker.ffmq4.common.session.AbstractMessageConsumer.java Source code

Java tutorial

Introduction

Here is the source code for net.timewalker.ffmq4.common.session.AbstractMessageConsumer.java

Source

/*
 * This file is part of FFMQ.
 *
 * FFMQ is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * FFMQ is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with FFMQ; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package net.timewalker.ffmq4.common.session;

import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;

import net.timewalker.ffmq4.FFMQException;
import net.timewalker.ffmq4.common.message.AbstractMessage;
import net.timewalker.ffmq4.storage.message.MessageSerializationLevel;
import net.timewalker.ffmq4.utils.ErrorTools;
import net.timewalker.ffmq4.utils.id.IntegerID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <p>Base implementation for a {@link MessageConsumer}</p>
 */
public abstract class AbstractMessageConsumer extends AbstractMessageHandler implements MessageConsumer {
    private static final Log log = LogFactory.getLog(AbstractMessageConsumer.class);

    // Attributes
    protected String messageSelector;
    protected boolean noLocal;
    protected MessageListener messageListener;
    protected boolean autoAcknowledge;

    /**
     * Constructor
     */
    public AbstractMessageConsumer(AbstractSession session, Destination destination, String messageSelector,
            boolean noLocal, IntegerID consumerId) throws JMSException {
        super(session, destination, consumerId);
        this.messageSelector = messageSelector;
        this.noLocal = noLocal;
        this.autoAcknowledge = (session.getAcknowledgeMode() == Session.AUTO_ACKNOWLEDGE
                || session.getAcknowledgeMode() == Session.DUPS_OK_ACKNOWLEDGE);

        if (destination == null)
            throw new FFMQException("Message consumer destination cannot be null", "INVALID_DESTINATION");
    }

    protected abstract boolean shouldLogListenersFailures();

    /* (non-Javadoc)
     * @see javax.jms.MessageProducer#close()
     */
    @Override
    public final void close() throws JMSException {
        externalAccessLock.writeLock().lock();
        try {
            if (closed)
                return;
            closed = true;
            onConsumerClose();
        } finally {
            externalAccessLock.writeLock().unlock();
        }
        onConsumerClosed();
    }

    protected void onConsumerClose() {
        session.unregisterConsumer(this);
    }

    protected void onConsumerClosed() {
        // Nothing
    }

    /* (non-Javadoc)
     * @see javax.jms.MessageConsumer#getMessageSelector()
     */
    @Override
    public final String getMessageSelector() {
        return messageSelector;
    }

    /* (non-Javadoc)
     * @see javax.jms.MessageConsumer#getMessageListener()
     */
    @Override
    public final MessageListener getMessageListener() {
        return messageListener;
    }

    /* (non-Javadoc)
     * @see javax.jms.MessageConsumer#setMessageListener(javax.jms.MessageListener)
     */
    @Override
    public void setMessageListener(MessageListener messageListener) throws JMSException {
        externalAccessLock.readLock().lock();
        try {
            checkNotClosed();
            this.messageListener = messageListener;
        } finally {
            externalAccessLock.readLock().unlock();
        }
    }

    /* (non-Javadoc)
     * @see javax.jms.MessageConsumer#receive()
     */
    @Override
    public final Message receive() throws JMSException {
        return receive(-1);
    }

    /* (non-Javadoc)
     * @see javax.jms.MessageConsumer#receiveNoWait()
     */
    @Override
    public final Message receiveNoWait() throws JMSException {
        return receive(0);
    }

    /*
     * (non-Javadoc)
     * @see javax.jms.MessageConsumer#receive(long)
     */
    @Override
    public final Message receive(long timeout) throws JMSException {
        if (messageListener != null)
            throw new FFMQException("Cannot receive messages while a listener is active", "INVALID_OPERATION");

        AbstractMessage message = receiveFromDestination(timeout, true);
        if (message != null) {
            message.ensureDeserializationLevel(MessageSerializationLevel.FULL);

            message.setSession(session);

            // Auto acknowledge message
            if (autoAcknowledge)
                session.acknowledge();
        }
        return message;
    }

    /**
     * Receive a message from a destination
     */
    protected abstract AbstractMessage receiveFromDestination(long timeout, boolean duplicateRequired)
            throws JMSException;

    /**
     * Wake up the consumer message listener
     */
    public final void wakeUpMessageListener() {
        try {
            while (!closed) {
                synchronized (session.deliveryLock) // [JMS spec]
                {
                    AbstractMessage message = receiveFromDestination(0, true);
                    if (message == null)
                        break;

                    // Make sure the message is properly deserialized
                    message.ensureDeserializationLevel(MessageSerializationLevel.FULL);

                    // Make sure the message's session is set
                    message.setSession(session);

                    // Call the message listener
                    boolean listenerFailed = false;
                    try {
                        messageListener.onMessage(message);
                    } catch (Throwable e) {
                        listenerFailed = true;
                        if (shouldLogListenersFailures())
                            log.error("Message listener failed", e);
                    }

                    // Auto acknowledge message
                    if (autoAcknowledge) {
                        if (listenerFailed)
                            session.recover();
                        else
                            session.acknowledge();
                    }
                }
            }
        } catch (JMSException e) {
            ErrorTools.log(e, log);
        }
    }

    /**
     * Wake up the consumer (SYNCHRONOUS)
     */
    protected abstract void wakeUp() throws JMSException;
}