/* 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.relational.tuples;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import xxl.core.functions.AbstractFunction;
import xxl.core.functions.Function;
import xxl.core.util.WrappingRuntimeException;
/**
* Implements an array-tuple where the column objects are packed together in an
* object array. This is an efficient implementation of the tuple interface
* using arrays. For convenience, the implementation extends
* <code>AbstractTuple</code>.
* <code><pre>
* Tuple tuple = new ArrayTuple(resultSet);
* </code></pre>
* creates a tuple for the given result set. An object array is used to store
* the elements.
* <code><pre>
* ArrayTuple.FACTORY_METHOD.invoke(resultSet)
* </code></pre>
* does the same.
*/
public class ArrayTuple extends AbstractTuple implements Serializable {
/**
* A factory method that constructs objects of the class ArrayTuple. The
* function can be called with one or a list of parameters (corresponding
* to the two constructors of the class):
* <ul>
* <li>
* resultSet: a {@link java.sql.ResultSet result set} from which data
* and metadata is taken.
* <code><pre>
* ResultSet resultSet = ...;
* Tuple t = ArrayTuple.FACTORY_METHOD.invoke(resultSet);
* </pre></code>
* </li>
* <li>
* objects: a list of arguments containing the objects.<br />
* Caution: tuple is linked (not copied). So, changes to the original
* variables will cause changes to the tuple!
* <code></pre>
* List<Object> objects = ...;
* Tuple t = ArrayTuple.FACTORY_METHOD.invoke(objects);
* </pre></code>
* </li>
* </ul>
* Exactly
* <ul>
* <li>
* <pre>ResultSet --> Tuple</pre>
* </li>
* <li>
* <pre>List<? extends Object> --> Tuple</pre>
* </li>
* <ul>
* This function can always be used when a createTuple-Function is needed.
*/
public static final Function<Object, ArrayTuple> FACTORY_METHOD = new AbstractFunction<Object, ArrayTuple>() {
@Override
public ArrayTuple invoke(Object resultSet) {
return new ArrayTuple((ResultSet)resultSet);
}
@Override
public ArrayTuple invoke(List<? extends Object> objects) {
return new ArrayTuple(objects.toArray());
}
};
/**
* An array containing column objects.
*/
protected Object[] tuple;
/**
* Constructs an array-tuple containing the column objects of the current
* row of the result set. The metadata is also taken from the result set.
*
* @param resultSet the underlying result set.
* @throws WrappingRuntimeException when accessing the result set fails.
*/
public ArrayTuple(ResultSet resultSet) {
try {
ResultSetMetaData metadata = resultSet.getMetaData();
tuple = new Object[metadata.getColumnCount()];
for (int i = 0; i < tuple.length; i++)
tuple[i] = resultSet.getObject(i+1);
}
catch (SQLException e) {
throw new WrappingRuntimeException(e);
}
}
/**
* Constructs an array-tuple containing the column objects of an object
* array. The metadata is taken from the passed result set metadata object.
*
* @param tuple an object array containing column objects. Caution: the
* tuple is linked (not copied). So, changes to tuple will cause
* changes in the tuple!
*/
public ArrayTuple(Object... tuple) {
this.tuple = tuple;
}
/**
* Returns the number of columns in this tuple.
*
* @return the number of columns.
*/
@Override
public int getColumnCount() {
return tuple.length;
}
/**
* Returns the object of the given column.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @return the object of the column.
*/
@Override
public Object getObject(int columnIndex) {
return tuple[columnIndex-1];
}
/**
* Creates and returns a copy of this object. The precise meaning of
* "copy" may depend on the class of the object. The general intent is
* that, for any object <tt>x</tt>, the expression:
* <pre>
* x.clone() != x
* </pre>
* will be <code>true</code>, and that the expression:
* <pre>
* x.clone().getClass() == x.getClass()
* </pre>
* will be <code>true</code>, but these are not absolute requirements.
* While it is typically the case that:
* <pre>
* x.clone().equals(x)
* </pre>
* will be <code>true</code>, this is not an absolute requirement.
*
* <p>By convention, the returned object should be obtained by calling
* <code>super.clone</code>. If a class and all of its superclasses (except
* <code>Object</code>) obey this convention, it will be the case that
* <code>x.clone().getClass() == x.getClass()</code>.</p>
*
* <p>By convention, the object returned by this method should be
* independent of this object (which is being cloned). To achieve this
* independence, it may be necessary to modify one or more fields of the
* object returned by <tt>super.clone</tt> before returning it. Typically,
* this means copying any mutable objects that comprise the internal "deep
* structure" of the object being cloned and replacing the references to
* these objects with references to the copies. If a class contains only
* primitive fields or references to immutable objects, then it is usually
* the case that no fields in the object returned by
* <code>super.clone</code> need to be modified.</p>
*
* <p>The method <code>clone</code> for class <code>Object</code> performs
* a specific cloning operation. First, if the class of this object does
* not implement the interface <code>Cloneable</code>, then a
* <code>CloneNotSupportedException</code> is thrown. Note that all arrays
* are considered to implement the interface <code>Cloneable</code>.
* Otherwise, this method creates a new instance of the class of this
* object and initializes all its fields with exactly the contents of the
* corresponding fields of this object, as if by assignment; the contents
* of the fields are not themselves cloned. Thus, this method performs a
* "shallow copy" of this object, not a "deep copy" operation.</p>
*
* <p>The class <code>Object</code> does not itself implement the
* interface <code>Cloneable</code>, so calling the <code>clone</code>
* method on an object whose class is <code>Object</code> will result in
* throwing an exception at run time.</p>
*
* @return a clone of this instance.
* @throws CloneNotSupportedException if the object's class does not
* support the <code>Cloneable</code> interface. Subclasses that
* override the <code>clone</code> method can also throw this
* exception to indicate that an instance cannot be cloned.
* @see java.lang.Cloneable
*/
@Override
public Object clone() throws CloneNotSupportedException {
ArrayTuple clone = (ArrayTuple)super.clone();
clone.tuple = tuple.clone();
return clone;
}
/**
* Copies the objects of the tuple into a new object array.
*
* @return array containing the objects of the tuple
*/
@Override
public Object[] toArray() {
return tuple.clone();
}
/**
* Outputs the content of the tuple.
*
* @return a string representation of a tuple.
*/
@Override
public String toString() {
return Arrays.toString(tuple);
}
}