/* 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; import xxl.core.functions.Function; import xxl.core.util.Decorator; /** * This class provides a decorator for a queue that follows the * <i>Decorator Design Pattern</i> (for further details see Structural * Patterns, Decorator in <i>Design Patterns: Elements of Reusable * Object-Oriented Software</i> by Erich Gamma, Richard Helm, Ralph * Johnson, and John Vlissides). It provides a more flexible way to add * functionality to a queue or one of its subclasses as by inheritance.<p> * * To provide this functionality the class contains a reference to the * queue to be decorated. This reference is used to redirect method calls * to the <i>original</i> queue. This class is an abstract class although * it provides no abstract methods. That's so because it does not make any * sense to instanciate this class which redirects every method call to * the corresponding method of the decorated queue without adding any * functionality.<p> * * Usage example (1). * <pre> * // create a new decorated queue that adds functionality to the enqueue method * // and leaves the other methods untouched * * DecoratorQueue queue = new DecoratorQueue(new ListQueue()) { * public void enqueue (Object object) { * * // every desired functionality can be added to this method * * System.out.println("Before the insertion of the specified object!"); * super.enqueue(object); * System.out.println("After the insertion of the specified object!"); * } * } * </pre> * * @param <E> the type of the elements of this queue. * @see xxl.core.collections.queues.Queue */ public abstract class DecoratorQueue<E> implements Queue<E>, Decorator<Queue<E>> { /** * A factory method to create a new DecoratorQueue (see contract for * {@link Queue#FACTORY_METHOD FACTORY_METHOD} in interface Queue). In * contradiction to the contract in Queue it may only be invoked with * an array (<i>parameter list</i>) (for further details see Function) * of queues. The array (<i>parameter list</i>) will be used to * initialize the decorated queue. This field is set to * <code>{@link UnmodifiableQueue#FACTORY_METHOD UnmodifiableQueue.FACTORY_METHOD}</code>. * * @see Function */ public static final Function<Object, ? extends Queue<Object>> FACTORY_METHOD = UnmodifiableQueue.FACTORY_METHOD; /** * A reference to the queue to be decorated. This reference is used to * perform method calls on the <i>original</i> queue. */ protected Queue<E> queue; /** * 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; /** * Constructs a new DecoratorQueue that decorates the specified queue. * * @param queue the queue to be decorated. */ public DecoratorQueue(Queue<E> queue) { this.queue = queue; } /** * Opens the queue, i.e., signals the queue to reserve resources, open * files, etc. 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. 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. * * <p>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.</p> */ public void open() { if (!isOpened) { isOpened = true; queue.open(); } } /** * Closes this queue and releases any system resources associated with * it. This operation is idempotent, i.e., multiple calls of this * method take the same effect as a single call.<br> * <b>Note:</b> This method is very important for queues using * external resources like files or JDBC resources. */ public void close() { if (!isClosed) { isClosed = true; queue.close(); } } /** * 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>. * * @param object element to be appended at the <i>end</i> of this * queue. * @throws IllegalStateException if the queue is already closed when this * method is called. */ public void enqueue(E object) throws IllegalStateException { if (isClosed) throw new IllegalStateException(); if (!isOpened) open(); queue.enqueue(object); } /** * Returns the <i>next</i> element in the queue <i>without</i> removing it. * The <i>next</i> element of the queue is given by its * <i>strategy</i>. * * @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 E peek() throws IllegalStateException, NoSuchElementException { if (isClosed) throw new IllegalStateException(); if (!isOpened) open(); return queue.peek(); } /** * 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>. * * @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 E dequeue() throws IllegalStateException, NoSuchElementException { if (isClosed) throw new IllegalStateException(); if (!isOpened) open(); return queue.dequeue(); } /** * Returns <tt>false</tt> if the queue has more elements (in other * words, returns <tt>false</tt> if <tt>next</tt> would return an * element rather than throwing an exception). * * @return <tt>false</tt> if the queue has more elements. */ public boolean isEmpty() { return queue.isEmpty(); } /** * Returns the number of elements in this queue. If this queue * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns * <tt>Integer.MAX_VALUE</tt>. * * @return the number of elements in this queue. */ public int size() { return queue.size(); } /** * Removes all of the 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. */ public void clear() { queue.clear(); } @Override public Queue<E> getDecoree() { return queue; } }