/* 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.containers; import java.util.Iterator; import java.util.NoSuchElementException; import xxl.core.functions.Function; import xxl.core.io.converters.FixedSizeConverter; /** * The class provides a constained decorator for a container. This class * is similar to the decorator container, but it does not exactly follow * 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). Whenever possible, the constrained * decorator uses the default implementations of the container class. * I.e., this class provides no usual decorator that simply redirects * method call to an underlying container, but a kind of partial * decorator that maps its methods to a set of <i>central</i> methods, * which are decorated. Therefore, this class provides a way to profit * from the default implementations of the container class and the * advantages of decoration.<p> * * <b>Note</b> that this class provides only a workaround that allows the * user to decorate only a single central method instead of a complete * <i>set</i> of methods and therefore to save time.<p> * * Usage example (1). * <pre> * // create a new decorated container that adds functionality to the insert method and leaves * // the other methods untouched * * DecoratorContainer container = new DecoratorContainer(new MapContainer()) { * public Object insert (Object object, boolean unfix) { * * // every desired functionality can be added to this method * * System.out.println("Before the insertion of the specified object!"); * Object object = super.insert(object, unfix); * System.out.println("After the insertion of the specified object!"); * return object; * } * } * </pre> * * @see xxl.core.io.converters.Converter * @see Function * @see Iterator * @see NoSuchElementException */ public abstract class ConstrainedDecoratorContainer extends AbstractContainer { /** * A factory method to create a new DecoratorContainer. It may * only be invoked with an array (<i>parameter list</i>) (for further * details see Function) of containers. The array (<i>parameter * list</i>) will be used to initialize the decorated container. This * field is set to * <code>{@link UnmodifiableContainer#FACTORY_METHOD UnmodifiableContainer.FACTORY_METHOD}</code>. * * @see Function */ public static final Function FACTORY_METHOD = UnmodifiableContainer.FACTORY_METHOD; /** * A reference to the container to be decorated. This reference is * used to perform method calls on the <i>original</i> container. */ protected Container container; /** * Constructs a new DecoratorContainer that decorates the specified * container. * * @param container the container to be decorated. */ public ConstrainedDecoratorContainer (Container container) { this.container = container; } /** * Returns a converter for the ids generated by this container. A * converter transforms an object to its byte representation and vice * versa - also known as serialization in Java.<br> * Since the identifier may have an arbitrary type (which has to be * known in the container), the container has to provide such a method * when the data is not stored in main memory. * * @return a converter for serializing the identifiers of the * container. */ public FixedSizeConverter objectIdConverter () { return container.objectIdConverter(); } /** * Returns the size of the ids generated by this container in bytes. * This call is forwarded to the primary Container. * @return the size in bytes of each id. */ public int getIdSize() { return container.getIdSize(); } /** * Removes all elements from the Container. After a call of this * method, <tt>size()</tt> will return 0.<br> * Note, that the implementation of this method relies on the remove * operation of the iterator returned by the method <tt>ids()</tt>. */ public void clear () { container.clear(); } /** * Closes the Container and releases all sources. For external * containers, this method closes the files immediately. MOREOVER, all * iterators operating on the container can be in illegal states. * Close can be called a second time without any impact. The default * implementation of close is empty (which is OK for a MapContainer).<br> * Note, that it would be desirable that the finalize-mechanism of * Java would already offer the functionality of close. However, * finalize does not release the sources immediately! Consequently, * the corresponding file of a "closed" Container may be opened and * some of the data is still not written back. This is a problem when * for example the JVM stops running (because of a system error). */ public void close () { container.close(); } /** * Returns true if the container contains an object for the identifier * <tt>id</tt>.<br> * Note, that when a user would like to store null objects in a * container this method has to be reimplemented. * * @param id identifier of the object. * @return true if the container contains an object for the specified * identifier. */ public boolean contains (Object id) { return container.contains(id); } /** * Flushes all modified elements from the buffer into the container. * After this call the buffer and the container are synchronized. The * default implementation of flush is empty which is OK for an * unbuffered container. */ public void flush () { container.flush(); } /** * Flushes the object with identifier <tt>id</tt> from the buffer into * the container. * * @param id identifier of the object that should be written back. */ public void flush (Object id) { container.flush(id); } /** * Returns the object associated to the identifier <tt>id</tt>. An * exception is thrown when the desired object is not found. If unfix, * the object can be removed from the underlying buffer. Otherwise * (!unfix), the object has to be kept in the buffer. * * @param id identifier of the object. * @param unfix signals whether the object can be removed from the * underlying buffer. * @return the object associated to the specified identifier. * @throws NoSuchElementException if the desired object is not found. */ public Object get (Object id, boolean unfix) throws NoSuchElementException { return container.get(id, unfix); } /** * Returns an iterator that deliver the identifiers of all objects of * the container. * * @return an iterator of object identifiers. */ public Iterator ids () { return container.ids(); } /** * Inserts a new object into the container and returns the unique * identifier that the container has been associated to the object. * The identifier can be reused again when the object is deleted from * the buffer. If unfixed, the object can be removed from the buffer. * Otherwise, it has to be kept in the buffer until an * <tt>unfix()</tt> is called.<br> * After an insertion all the iterators operating on the container can * be in an invalid state.<br> * This method also allows an insertion of a null object. In the * application would really like to have such objects in the * container, some methods have to be modified. * * @param object is the new object. * @param unfix signals whether the object can be removed from the * underlying buffer. * @return the identifier of the object. */ public Object insert (Object object, boolean unfix) { return container.insert(object, unfix); } /** * Checks whether the <tt>id</tt> has been returned previously by a * call to insert or reserve and hasn't been removed so far. * * @param id the id to be checked. * @return true exactly if the <tt>id</tt> is still in use. */ public boolean isUsed (Object id) { return container.isUsed(id); } /** * Removes the object with identifier <tt>id</tt>. An exception is * thrown when an object with an identifier <tt>id</tt> is not in the * container.<br> * After a call of <tt>remove()</tt> all the iterators (and cursors) * can be in an invalid state. * * @param id an identifier of an object. * @throws NoSuchElementException if an object with an identifier * <tt>id</tt> is not in the container. */ public void remove (Object id) throws NoSuchElementException { container.remove(id); } /** * Reserves an id for subsequent use. The container may or may not * need an object to be able to reserve an id, depending on the * implementation. If so, it will call the parameterless function * provided by the parameter <tt>getObject</tt>. * * @param getObject A parameterless function providing the object for * that an id should be reserved. * @return the reserved id. */ public Object reserve (Function getObject) { return container.reserve(getObject); } /** * Returns the number of elements of the container. * * @return the number of elements. */ public int size () { return container.size(); } /** * Unfixes the Object with identifier <tt>id</tt>. This method throws * an exception when no element with an identifier <tt>id</tt> is in * the container. After one call of unfix the buffer is allowed to * remove the object (although the objects have been fixed more than * once).<br> * The default implementation only checks whether an object with * identifier <tt>id</tt> is in the buffer. * * @param id identifier of an object that should be unfixed in the * buffer. * @throws NoSuchElementException if no element with an identifier * <tt>id</tt> is in the container. */ public void unfix (Object id) throws NoSuchElementException { container.unfix(id); } /** * Overwrites an existing (id,*)-element by (id, object). This method * throws an exception if an object with an identifier <tt>id</tt> * does not exist in the container. * * @param id identifier of the element. * @param object the new object that should be associated to * <tt>id</tt>. * @param unfix signals whether the object can be removed from the * underlying buffer. * @throws NoSuchElementException if an object with an identifier * <tt>id</tt> does not exist in the container. */ public void update (Object id, Object object, boolean unfix) throws NoSuchElementException { container.update(id, object, unfix); } @Override public Object[] batchInsert(Object[] blocks) { return container.batchInsert(blocks); } }