All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.grinder.communication.MessageQueue Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2000 - 2011 Philip Aston
// All rights reserved.
//
// This file is part of The Grinder software distribution. Refer to
// the file LICENSE which is part of The Grinder distribution for
// licensing details. The Grinder distribution is available on the
// Internet at http://grinder.sourceforge.net/
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

package net.grinder.communication;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import net.grinder.common.UncheckedInterruptedException;


/**
 * Thread-safe queue of {@link Message}s.
 *
 * @author Philip Aston
 */
final class MessageQueue {

  private final BlockingQueue m_queue =
    new LinkedBlockingQueue();

  private final boolean m_passExceptions;

  private volatile boolean m_shutdown;

  private static final Serializable SHUTDOWN_MESSAGE = new Serializable() { };

  /**
   * Creates a new {@code MessageQueue} instance.
   *
   * @param passExceptions
   *          {@code true} => allow exceptions to be inserted into the queue and
   *          re-thrown to callers of {@link #dequeue}.
   */
  public MessageQueue(boolean passExceptions) {
    m_passExceptions = passExceptions;
  }

  /**
   * Queue the given message.
   *
   * @param message
   *          A {@link Message}.
   * @throws ShutdownException
   *           If the queue has been shut down.
   * @see #shutdown
   */
  public void queue(Message message) throws ShutdownException {

    checkIfShutdown();

    m_queue.add(message);
  }

  /**
   * Queue the given exception.
   *
   * @param exception
   *          An exception.
   * @throws AssertionError
   *           If the queue does not allow exceptions to be propagated..
   * @throws ShutdownException
   *           If the queue has been shut down.
   * @see #shutdown
   */
  public void queue(Exception exception) throws ShutdownException {

    if (!m_passExceptions) {
      throw new AssertionError(
        "This MessageQueue does not allow Exceptions to be queued");
    }

    checkIfShutdown();

    m_queue.add(exception);
  }

  /**
   * Dequeue a message.
   *
   * @param block
   *          {@code true} => block until message is available, {@code false}
   *          return {@code null} if no message is available.
   * @throws CommunicationException
   *           If the queue allows exceptions to be propagated, queued
   *           CommunicationExceptions are re-thrown to callers of this method.
   * @throws ShutdownException
   *           If the queue has been shut down.
   * @see #shutdown
   */
  public Message dequeue(boolean block) throws CommunicationException {

    checkIfShutdown();

    final Serializable result;

    if (block) {
      try {
        result = m_queue.take();
      }
      catch (InterruptedException e) {
        throw new UncheckedInterruptedException(e);
      }
    }
    else {
      result = m_queue.poll();
    }

    if (result == SHUTDOWN_MESSAGE) {
      // Handle race.
      shutdown(); // Enqueue another shut down message.
      checkIfShutdown();
    }

    if (m_passExceptions && result instanceof Exception) {
      final Exception e = (Exception) result;
      throw new CommunicationException(e.getMessage(), e);
    }

    return (Message) result;
  }

  /**
   * Shut down the MessageQueue. Any {@link Message}s in
   * the queue are discarded.
   */
  public void shutdown() {

    m_shutdown = true;
    m_queue.clear();

    m_queue.offer(SHUTDOWN_MESSAGE);
  }

  /**
   * Throw a ShutdownException if we are shut down.
   *
   * @throws ShutdownException
   *           Thrown if the {@code MessageQueue} is shut down.
   */
  public void checkIfShutdown() throws ShutdownException {

    if (m_shutdown) {
      throw new ShutdownException("ThreadSafeQueue shutdown");
    }
  }

  /**
   * Drain and return the messages in the queue.
   *
   * @return The messages.
   * @throws ShutdownException
   *           If the queue has been shut down.
   * @see #shutdown
   */
  public List drainMessages() throws ShutdownException {

    checkIfShutdown();

    final List contents =
      new ArrayList(m_queue.size());

    m_queue.drainTo(contents);

    final List result = new ArrayList(contents.size());

    for (Serializable c : contents) {
      if (c == SHUTDOWN_MESSAGE) {
        // Handle race.
        shutdown(); // Enqueue another shut down message.
        checkIfShutdown();
      }

      if (c instanceof Message) {
        result.add((Message)c);
      }
    }

    return result;
  }

  /**
   * Exception that indicates {@code MessageQueue} has been shut down.
   */
  public static final class ShutdownException extends CommunicationException {
    ShutdownException(String s) {
      super(s);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy