/* 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.io; import java.io.InputStream; import java.io.OutputStream; import java.util.List; import xxl.core.collections.queues.FIFOQueue; import xxl.core.collections.queues.ListQueue; import xxl.core.collections.queues.Queue; import xxl.core.functions.AbstractFunction; import xxl.core.functions.Constant; import xxl.core.functions.Function; import xxl.core.io.converters.ConvertableConverter; import xxl.core.io.converters.Converter; import xxl.core.io.converters.UniformConverter; /** * This class provides a stream queue that stores the bytes of its * serialized elements in a <tt>ListQueue</tt>. The <tt>peek</tt> * method is not implemented by this queue. A converter is used for * serializing and de-serializing the elements of the queue.<p> * * <b>Note:</b> The queue can be in two states: either reading ({@link StreamQueue#openOutput()}, * {@link StreamQueue#read()}) or writing ({@link StreamQueue#openInput()}, * {@link StreamQueue#write(Object)}). * <p>When switching from input to output mode the buffer * (more precisely the input buffer) is written to the queue; so, no data will be lost. * But <b>when switching back from output to input mode the content of * the output buffer could get lost</b> if the buffer is able to store more than one * element and isn't manually emptied before switching.<br/> * So, here are two examples how to prevent data leakage:<br/> * <ul> * <li>If the buffer size is set to the size of one element no data can get * lost because the first (in this case the only) element is processed immediately.</li> * <li>If the buffer is (manually) emptied before switching from output to * input mode no anomaly will occur and no data will get lost.</li> * </ul> * </p> * <p> * * Example usage (1). * <pre> * // create a new list stream queue with ... * * ListStreamQueue queue = new ListStreamQueue( * * // an integer converter * * IntegerConverter.DEFAULT_INSTANCE, * * // an input buffer size of 4 bytes (size of an integer) * * new Constant(4), * * // an output buffer size of 4 bytes (size of an integer) * * new Constant(4) * ); * * // open the queue * * queue.open(); * * // insert the integer from 0 to 9 into the queue * * for (int i = 0; i < 10; i++) * queue.enqueue(new Integer(i)); * * // print five elements of the queue * * int i = 0; * while (i < 5 && !queue.isEmpty()) { * i = ((Integer)queue.dequeue()).intValue(); * System.out.println(i); * } * * // insert the integers from 20 to 29 * * for (i = 20; i < 30; i++) * queue.enqueue(new Integer(i)); * * // print all elements of the queue * * while (!queue.isEmpty()) * System.out.println(queue.dequeue()); * * System.out.println(); * * // close the queue * * queue.close(); * </pre> * * @see xxl.core.collections.queues.Queue * @see xxl.core.collections.queues.io.StreamQueue * @see xxl.core.collections.queues.FIFOQueue */ public class ListStreamQueue extends StreamQueue implements FIFOQueue { /** * A factory method to create a new ListStreamQueue (see contract for * {@link xxl.core.collections.queues.Queue#FACTORY_METHOD FACTORY_METHOD} in * interface Queue). In contradiction to the contract in Queue it may * only be invoked with a <i>parameter list</i> (for further * details see Function) of objects. The <i>parameter list</i> * will be used for initializing the list stream queue by calling the * constructor * <code>ListStreamQueue((Function) list.get(0), new Constant(0), new Constant(0))</code>. * * @see Function */ public static final Function<Object,ListStreamQueue> FACTORY_METHOD = new AbstractFunction<Object,ListStreamQueue>() { public ListStreamQueue invoke(List<? extends Object> list) { return new ListStreamQueue( (Function)list.get(0), new Constant(0), new Constant(0) ); } }; /** * A queue that is internally used for storing the bytes of the * serialized elements of this queue. */ protected Queue queue = new ListQueue(); /** * Constructs a new list stream queue that uses the specified * converter for serializing and de-serializing its elements. The * given functions are used for determining the size of the input * and output buffer. * * @param converter a converter that is used for serializing and * de-serializing the elements of the queue * @param inputBufferSize a function that determines the size of the * input buffer. * @param outputBufferSize a function that determines the size of the * output buffer. */ public ListStreamQueue(Converter converter, Function inputBufferSize, Function outputBufferSize) { super(converter, inputBufferSize, outputBufferSize, null, null); this.newInputStream = new AbstractFunction() { public Object invoke() { return new InputStream() { public int read() { int i = queue.size() == 0 ? -1 : ((Integer)queue.dequeue()).intValue(); return i; } }; } }; this.newOutputStream = new AbstractFunction() { public Object invoke() { return new OutputStream() { public void write(int b) { queue.enqueue(new Integer(b)); } }; } }; } /** * Constructs a new list stream queue that uses the specified * converter for serializing and de-serializing its elements. The * factory method is used for initializing the elements of the queue * before the output stream is read out. The given functions are used * for determining the size of the input and output buffer.<br> * This constructor is equivalent to the call of * <code>ListStreamQueue(new UniformConverter(converter, newObject), inputBufferSize, outputBufferSize)</code>. * * @param converter a converter that is used for serializing and * de-serializing the elements of the queue * @param newObject a factory method that is used for initializing the * elements of the queue before the input stream is read out. * @param inputBufferSize a function that determines the size of the * input buffer. * @param outputBufferSize a function that determines the size of the * output buffer. */ public ListStreamQueue(Converter converter, Function newObject, Function inputBufferSize, Function outputBufferSize) { this(new UniformConverter(converter, newObject), inputBufferSize, outputBufferSize); } /** * Constructs a new list stream queue that uses a convertable * converter for serializing and de-serializing its elements. The * factory method is used for initializing the elements of the queue * before the output stream is read out. The given functions are used * for determining the size of the input and output buffer.<br> * This constructor is equivalent to the call of * <code>ListStreamQueue(ConvertableConverter.DEFAULT_INSTANCE, newObject, inputBufferSize, outputBufferSize)</code>. * * @param newObject a factory method that is used for initializing the * elements of the queue before the input stream is read out. * @param inputBufferSize a function that determines the size of the * input buffer. * @param outputBufferSize a function that determines the size of the * output buffer. * @see ConvertableConverter#DEFAULT_INSTANCE */ public ListStreamQueue(Function newObject, Function inputBufferSize, Function outputBufferSize) { this(ConvertableConverter.DEFAULT_INSTANCE, newObject, inputBufferSize, outputBufferSize); } /** * Removes all elements from this queue. The queue will be * empty after this call returns so that <tt>size() == 0</tt>.<br> * This implementation simply clears <tt>queue</tt> and sets * <tt>size</tt> to <tt>0</tt>. */ public void clear () { queue.clear(); size = 0; } /** * Closes this queue and releases any system resources associated with * it. This operation is idempotent, i.e., multiple calls of this * method takes the same effect as a single call.<br> * This implementation simply closes <tt>queue</tt>. */ public void close () { if (isClosed) return; super.close(); queue.close(); } }