/* 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.io.converters;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import xxl.core.functions.Function;
/**
* This class provides a wrapper for a converter that reads and writes uniform
* objects. Whenever the <code>read</code> method is called with an object that
* is equal to <code>null</code>, the underlying converter is called with an
* object that has been delivered by invoking function.
*
* <p>Example usage (1).
* <code><pre>
* // create two map entries
*
* MapEntry<Integer, String> me1 = new MapEntry<Integer, String>(42, "Hello world.");
* MapEntry<Integer, String> me2 = new MapEntry<Integer, String>(4711, "That's all, folks!");
*
* // create a converter that only stores the value of a map entry
*
* Converter<MapEntry<Integer, String>> converter = new Converter<MapEntry<Integer, String>>() {
*
* // how to write a map entry
*
* public void write(DataOutput dataOutput, MapEntry<Integer, String> object) throws IOException {
*
* // write the value of the map entry
*
* StringConverter.DEFAULT_INSTANCE.write(dataOutput, object.getValue());
* }
*
* // how to read a map entry
*
* public MapEntry<Integer, String> read (DataInput dataInput, MapEntry<Integer, String> object) throws IOException {
*
* // read the value of the map entry
*
* object.setValue(StringConverter.DEFAULT_INSTANCE.read(dataInput));
* return object;
* }
* };
*
* // create a factory method that produces map entries with keys of increasing integer objects
*
* Function<Object, MapEntry<Integer, String>> factory = new Function<Object, MapEntry<Integer, String>>() {
*
* // a count for the returned keys
*
* int i = 0;
*
* // how to create a map entry
*
* public MapEntry<Integer, String> invoke() {
*
* // return a map entry with an integer wrapping the counter as key and null as value
*
* return new MapEntry<Integer, String>(i++, null);
* }
* };
*
* // create an uniform converter with ...
*
* UniformConverter<MapEntry<Integer, String>> uniformConverter = new UniformConverter<MapEntry<Integer, String>>(
*
* // the created converter
*
* converter,
*
* // the created factory method
*
* factory
* );
*
* // create a byte array output stream
*
* ByteArrayOutputStream output = new ByteArrayOutputStream();
*
* // create an data output stream
*
* DataOutputStream dataOutput = new DataOutputStream(output);
*
* // write two strings to the output stream
*
* uniformConverter.write(dataOutput, me1);
* uniformConverter.write(dataOutput, me2);
*
* // create a byte array input stream on the output stream
*
* ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
*
* // create an data input stream
*
* DataInputStream dataInput = new DataInputStream(input);
*
* // read two strings from the input stream
*
* me1 = uniformConverter.read(dataInput);
* me2 = uniformConverter.read(dataInput);
*
* // print the value and the object
*
* System.out.println(me1);
* System.out.println(me2);
*
* // close the streams after use
*
* dataInput.close();
* dataOutput.close();
* </pre></code></p>
*
* @param <T> the type to be converted.
* @see DataInput
* @see DataOutput
* @see Function
* @see IOException
*/
public class UniformConverter<T> extends Converter<T> {
/**
* The converter that is wrapped. The converter must be able to read and
* write uniform objects.
*/
protected Converter<T> converter;
/**
* A factory method that is used for initializing the object to read. This
* function will be invoked when the read method is called without
* specifying an object to restore.
*/
protected Function<?, ? extends T> function;
/**
* Constructs a new uniform converter that wraps the specified converter
* and uses the specified function as factory method.
*
* @param converter the converter to be wrapped.
* @param function a factory method that is used for initializing the
* object to read when it is not specified.
*/
public UniformConverter(Converter<T> converter, Function<?, ? extends T> function) {
this.converter = converter;
this.function = function;
}
/**
* Reads the state (the attributes) for the specified object from the
* specified data input and returns the restored object.
*
* <p>This implementation calls the read method of the wrapped converter.
* When the specified object is <code>null</code> it is initialized by
* invoking the function (factory method).</p>
*
* @param dataInput the stream to read data from in order to restore the
* object.
* @param object the object to be restored. If the object is
* <code>null</code> it is initialized by invoking the function
* (factory method).
* @return the restored object.
* @throws IOException if I/O errors occur.
*/
@Override
public T read(DataInput dataInput, T object) throws IOException {
return converter.read(dataInput, object == null && function != null ? function.invoke() : object);
}
/**
* Writes the state (the attributes) of the specified object to the
* specified data output.
*
* <p>This implementation calls the write method of the wrapped
* converter.</p>
*
* @param dataOutput the stream to write the state (the attributes) of the
* object to.
* @param object the object whose state (attributes) should be written to
* the data output.
* @throws IOException includes any I/O exceptions that may occur.
*/
@Override
public void write(DataOutput dataOutput, T object) throws IOException {
converter.write(dataOutput, object);
}
}