/* 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.cursors; import java.util.Iterator; import java.util.NoSuchElementException; /** * A cursor extends the interface {@link java.util.Iterator} by adding * functionality for opening and closing the cursor, i.e., reserving and * releasing of system resources, taking a look at the next element that would * be returned by call to <code>next</code>, updating elements of the * underlying data structure and traversing it another time without * constructing a new cursor. * * <p>Cursors <i>differ</i> from iterators in some points: * <ul> * <li> * <code>open</code>: before using a cursor the caller must open it in * order to reserve resources, open files, etc. * </li> * <li> * <code>close</code>: after using a cursor it must be closed by the * caller in order to clean up resources, close files, etc. * </li> * <li> * <code>peek</code>: cursors allow the caller to show the next element * in the iteration without proceeding the iteration. * </li> * <li> * <code>supportsPeek</code>: a method that returns <code>true</code> * if an instance of a cursor supports the <code>peek</code> operation, * otherwise it returns <code>false</code>. * </li> * <li> * <code>supportsRemove</code>: a method that returns <code>true</code> * if an instance of a cursor supports the <code>remove</code> * operation, otherwise it returns <code>false</code>. * </li> * <li> * <code>update</code>: cursors allow the caller to update the element * in the iteration returned by the <code>next</code> or * <code>peek</code> method and replacing it in the underlying * collection. * </li> * <li> * <code>supportsUpdate</code>: a method that returns <code>true</code> * if an instance of a cursor supports the <code>update</code> * operation, otherwise it returns <code>false</code>. * </li> * <li> * <code>reset</code>: cursors allow the caller to traverse the * underlying collection again without constructing a new cursor. * </li> * <li> * <code>supportsReset</code>: a method that returns <code>true</code> * if an instance of a cursor supports the <code>reset</code> * operation, otherwise it returns <code>false</code>. * </li> * </ul></p> * * <p><b>General contract:</b><br /> * If an exception is thrown by a cursor consecutive calls to methods are not * guaranteed to produce correct results.</p> * * <p> * <b>Important:</b> In order to guarantee a certain semantics, an * implementation of a <code>Cursor</code> has to ensure that a call of * <code>hasNext</code> always returns <code>false</code> after the first time * <code>false</code> is delivered. Thus, it should not be possible to receive * an element by calling <code>hasNext</code> and <code>next</code> at a later * point in time, if <code>hasNext</code> returned <code>false</code> before * (even if the underlying data structure received a new element meanwhile). * </p> * * <p><b>General order of method invocations:</b> * <code><pre> * // creating a new instance of an arbitrary cursor * * Cursor<Object> cursor = ... * * // opening the cursor for first use * * cursor.open(); * * // consuming the cursor in a loop; checking if there is a next element * * while(cursor.hasNext()) { * * ... * * // taking a look at the next element, but do not remove it from the * // underlying collection (optional) * * Object peek = cursor.peek(); * * ... * * // consuming the next element * * Object next = cursor.next(); * * ... * * // removing object 'next' from the underyling collection (optional) * * cursor.remove(); * * } * * ... * * // cursor will be used again, so reset it (optional) * * cursor.reset(); * * ... * * // cursor is not needed any more; release resources * * cursor.close(); * </pre></code></p> * * @param <E> the type of the elements returned by this iteration. * @see java.util.Iterator */ public interface Cursor<E> extends Iterator<E> { /** * Opens the cursor, i.e., signals the cursor to reserve resources, open * files, etc. Before a cursor has been opened calls to methods like * <code>next</code> or <code>peek</code> are not guaranteed to yield * proper results. Therefore <code>open</code> must be called before a * cursor's data can be processed. Multiple calls to <code>open</code> do * not have any effect, i.e., if <code>open</code> was called the cursor * remains in the state <i>opened</i> until its <code>close</code> method * is called. * * <p>Note, that a call to the <code>open</code> method of a closed cursor * 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 abstract void open(); /** * Closes the cursor, i.e., signals the cursor to clean up resources, close * files, etc. When a cursor has been closed calls to methods like * <code>next</code> or <code>peek</code> are not guaranteed to yield * proper results. Multiple calls to <code>close</code> do not have any * effect, i.e., if <code>close</code> was called the cursor remains in the * state <i>closed</i>. * * <p>Note, that a closed cursor usually cannot be opened again because of * the fact that its state generally cannot be restored when resources are * released respectively files are closed.</p> */ public abstract void close(); /** * Returns <code>true</code> if the iteration has more elements. (In other * words, returns <code>true</code> if <code>next</code> or * <code>peek</code> would return an element rather than throwing an * exception.) * * <p>This operation should be implemented idempotent, i.e., consequent * calls to <code>hasNext</code> do not have any effect.</p> * * <p><b>Important:</b> In order to guarantee a certain semantics, an * implementation of a <code>Cursor</code> has to ensure that a call of * <code>hasNext</code> always returns <code>false</code> after the first * time <code>false</code> is delivered. Thus, it should not be possible * to receive an element by calling <code>hasNext</code> and * <code>next</code> at a later point in time, if <code>hasNext</code> * returned <code>false</code> before (even if the underlying data * structure received a new element meanwhile).</p> * * @return <code>true</code> if the cursor has more elements. * @throws IllegalStateException if the cursor is already closed when this * method is called. */ public abstract boolean hasNext() throws IllegalStateException; /** * Returns the next element in the iteration. This element will be * accessible by some of the cursor's methods, e.g., <code>update</code> or * <code>remove</code>, until a call to <code>next</code> or * <code>peek</code> occurs. This is calling <code>next</code> or * <code>peek</code> proceeds the iteration and therefore its previous * element will not be accessible any more. * * @return the next element in the iteration. * @throws IllegalStateException if the cursor is already closed when this * method is called. * @throws NoSuchElementException if the iteration has no more elements. */ public abstract E next() throws IllegalStateException, NoSuchElementException; /** * Shows the next element in the iteration without proceeding the iteration * (optional operation). After calling <code>peek</code> the returned * element is still the cursor's next one such that a call to * <code>next</code> would be the only way to proceed the iteration. But be * aware that an implementation of this method uses a kind of * buffer-strategy, therefore it is possible that the returned element will * be removed from the <i>underlying</i> iteration, e.g., the caller can * use an instance of a cursor depending on an iterator, so the next * element returned by a call to <code>peek</code> will be removed from the * underlying iterator which does not support the <code>peek</code> * operation and therefore the iterator has to be wrapped and buffered. * * <p>Note, that this operation is optional and might not work for all * cursors. After calling the <code>peek</code> method a call to * <code>next</code> is strongly recommended.</p> * * @return the next element in the iteration. * @throws IllegalStateException if the cursor is already closed when this * method is called. * @throws NoSuchElementException iteration has no more elements. * @throws UnsupportedOperationException if the <code>peek</code> operation * is not supported by the cursor. */ public abstract E peek() throws IllegalStateException, NoSuchElementException, UnsupportedOperationException; /** * Returns <code>true</code> if the <code>peek</code> operation is * supported by the cursor. Otherwise it returns <code>false</code>. * * @return <code>true</code> if the <code>peek</code> operation is * supported by the cursor, otherwise <code>false</code>. */ public abstract boolean supportsPeek(); /** * Removes from the underlying data structure the last element returned by * the cursor (optional operation). This method can be called only once per * call to <code>next</code> or <code>peek</code> and removes the element * returned by this method. Note, that between a call to <code>next</code> * and <code>remove</code> the invocation of <code>peek</code> or * <code>hasNext</code> is forbidden. The behaviour of a cursor is * unspecified if the underlying data structure is modified while the * iteration is in progress in any way other than by calling this method. * * <p>Note, that this operation is optional and might not work for all * cursors.</p> * * @throws IllegalStateException if the <code>next</code> or * <code>peek</code> method has not yet been called, or the * <code>remove</code> method has already been called after the * last call to the <code>next</code> or <code>peek</code> method. * @throws UnsupportedOperationException if the <code>remove</code> * operation is not supported by the cursor. */ public abstract void remove() throws IllegalStateException, UnsupportedOperationException; /** * Returns <code>true</code> if the <code>remove</code> operation is * supported by the cursor. Otherwise it returns <code>false</code>. * * @return <code>true</code> if the <code>remove</code> operation is * supported by the cursor, otherwise <code>false</code>. */ public abstract boolean supportsRemove(); /** * Replaces the last element returned by the cursor in the underlying data * structure (optional operation). This method can be called only once per * call to <code>next</code> or <code>peek</code> and updates the element * returned by this method. Note, that between a call to <code>next</code> * and <code>update</code> the invocation of <code>peek</code> or * <code>hasNext</code> is forbidden. The behaviour of a cursor is * unspecified if the underlying data structure is modified while the * iteration is in progress in any way other than by calling this method. * * <p>Note, that this operation is optional and might not work for all * cursors.</p> * * @param object the object that replaces the last element returned by the * cursor. * @throws IllegalStateException if the <code>next</code> or * <code>peek</code> method has not yet been called, or the * <code>update</code> method has already been called after the * last call to the <code>next</code> or <code>peek</code> method. * @throws UnsupportedOperationException if the <code>update</code> * operation is not supported by the cursor. */ public abstract void update(E object) throws IllegalStateException, UnsupportedOperationException; /** * Returns <code>true</code> if the <code>update</code> operation is * supported by the cursor. Otherwise it returns <code>false</code>. * * @return <code>true</code> if the <code>update</code> operation is * supported by the cursor, otherwise <code>false</code>. */ public abstract boolean supportsUpdate(); /** * Resets the cursor to its initial state such that the caller is able to * traverse the underlying data structure again without constructing a new * cursor (optional operation). The modifications, removes and updates * concerning the underlying data structure, are still persistent. * * <p>Note, that this operation is optional and might not work for all * cursors.</p> * * @throws UnsupportedOperationException if the <code>reset</code> * operation is not supported by the cursor. */ public abstract void reset() throws UnsupportedOperationException; /** * Returns <code>true</code> if the <code>reset</code> operation is * supported by the cursor. Otherwise it returns <code>false</code>. * * @return <code>true</code> if the <code>reset</code> operation is * supported by the cursor, otherwise <code>false</code>. */ public abstract boolean supportsReset(); }