/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library 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 3 of the License, or (at your option) any later version. This library 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 this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.collections.queues; import java.util.NoSuchElementException; /** * This class provides a skeletal implementation of the Queue interface, * to minimize the effort required to implement this interface. <p> * * To implement a queue, the programmer only needs to extend this class * and provide implementations for the methods <tt>dequeueObject</tt>, * <tt>enqueueObject</tt> and <tt>peekObject</tt>.<p> * * The documentation for each non-abstract method in this class describes * its implementation in detail. Each of these methods may be overridden * if the queue being implemented admits a more efficient implementation. * * @param <E> the type of the elements of this queue. * @see xxl.core.collections.queues.Queue */ public abstract class AbstractQueue<E> implements Queue<E> { /** * Internally used to store the state of this queue (if it is opened). */ protected boolean isOpened = false; /** * Internally used to store the state of this queue (if it is closed). */ protected boolean isClosed = false; /** * Internally used reference to the next element in this queue. */ protected E next = null; /** * Internally used to remember whether the next element has already been * computed or not. */ protected boolean computedNext = false; /** * Internally used to store the size (number of elements) of this queue. */ protected int size = 0; /** * Opens the queue, i.e., signals the queue to reserve resources, open * files, etc. <br> * Before a queue has been opened calls to methods like <tt>peek</tt> are * not guaranteed to yield proper results. Therefore <tt>open</tt> must be * called before a queue's data can be processed.<br> * Multiple calls to <tt>open</tt> do not have any effect, i.e., if * <tt>open</tt> was called the queue remains in the state <i>opened</i> * until its <tt>close</tt> method is called. <br> * Note that a call to the <tt>open</tt> method of a closed queue usually * does not open it again because of the fact that its state generally * cannot be restored when resources are released respectively files are * closed. */ public void open() { if (!isOpened) isOpened = true; } /** * Closes this queue and releases any system resources associated with * it (like closing files, cleaning up resources, etc.).<br> * This operation is idempotent, i.e., multiple calls of this * method take the same effect as a single call (which means that * if <tt>close</tt> was called the queue remains in the state * <i>closed</i>).<br> * <b>Note:</b> This method is very important for queues using * external resources like files or JDBC resources.<br> * This implementation is given by an empty body. */ public void close() { if (!isClosed) { clear(); isClosed = true; computedNext = false; } } /** * Appends the specified element to the <i>end</i> of this queue. The * <i>end</i> of the queue is given by its <i>strategy</i>.<br> * This method calls <tt>enqueueObject(Object object)</tt> which * has to implement the store procedure (depending on the * <i>strategy</i> and the underlying datastructure). * * @param object element to be appended to the <i>end</i> of this * queue. * @throws IllegalStateException if the queue is already closed when this * method is called. */ public final void enqueue(E object) throws IllegalStateException { if (isClosed) throw new IllegalStateException(); if (!isOpened) open(); enqueueObject(object); computedNext = false; size++; } /** * Abstract method which has to be overwritten by any class extending this * class.<br> * This method is invoked by <tt>enque(Object object)</tt> and has to * implement the store procedure depending on the <i>strategy</i> and * the used datastructure. * @param object element to be appended to the <i>end</i> of this * queue. */ protected abstract void enqueueObject(E object); /** * Returns the <i>next</i> element in the queue without removing it. * The <i>next</i> element of the queue is given by its * <i>strategy</i>.<br> * After calling <tt>peek</tt> the returned element is still the queue's * next one such that a call to <tt>dequeue</tt> and then <tt>peek</tt> would * be the only way to access the next element.<br> * This method internally calls <tt>peekObject</tt> which actually implements * the operation. * @return the <i>next</i> element in the queue. * @throws IllegalStateException if the queue is closed. * @throws NoSuchElementException if queue has no more elements. */ public final E peek() throws IllegalStateException, NoSuchElementException { if (isClosed) throw new IllegalStateException(); if (!isOpened) open(); if (!computedNext) { if (size <= 0) throw new NoSuchElementException(); next = peekObject(); computedNext = true; } return next; } /** * Returns the <i>next</i> element in the queue without removing it. * The <i>next</i> element of the queue is given by its <i>strategy</i>.<br> * This method is invoked by <tt>peek</tt> and has to implement the * peek procedure depending on the <i>strategy</i> and the used datastructure.<br> * * @return the <i>next</i> element in the queue. */ protected abstract E peekObject(); /** * Returns the <i>next</i> element in the queue and <i>removes</i> it. * The <i>next</i> element of the queue is given by its <i>strategy</i>. * This method internally calls <tt>dequeueObject</tt> which actually * implements the operation. * * @return the <i>next</i> element in the queue. * @throws IllegalStateException if the queue is already closed when this * method is called. * @throws NoSuchElementException queue has no more elements. */ public final E dequeue() throws IllegalStateException, NoSuchElementException { if (isClosed) throw new IllegalStateException(); if (!isOpened) open(); if (size <= 0) throw new NoSuchElementException(); next = dequeueObject(); computedNext = false; size--; return next; } /** * Returns the <i>next</i> element in the queue (and <i>removes</i> it). * The <i>next</i> element of the queue is given by its <i>strategy</i>.<br> * This method is invoked by <tt>dequeue</tt> and has to implement the * peek procedure depending on the <i>strategy</i> and the used datastructure. * * @return the <i>next</i> element in the queue. */ protected abstract E dequeueObject(); /** * Returns <tt>false</tt> if the queue has more elements. (In other * words, returns <tt>false</tt> if <tt>peek</tt> would return an * element rather than throwing an exception.) * * @return false if the queue has more elements. */ public final boolean isEmpty() { return size == 0; } /** * Returns the number of elements in this queue. If this queue * contains more than <tt>Integer.MAX_VALUE</tt> elements, * <tt>Integer.MAX_VALUE</tt> is returned. * * @return the number of elements in this queue. */ public final int size() { return size; } /** * Removes all elements from this queue. The queue will be * empty after this call returns so that <tt>size() == 0</tt>.<br> * Note that the elements will only be removed from the queue but not * from the underlying collection.<br> * This implementation iterates over this queue, calling the <tt>dequeue</tt> * method for every element, in turn. */ public void clear() { while (!isEmpty()) dequeue(); } }