package com.tinkerpop.pipes.util; import com.tinkerpop.pipes.Pipe; import com.tinkerpop.pipes.PipeFunction; import com.tinkerpop.pipes.util.iterators.EmptyIterator; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * PipeHelper provides a collection of static methods that are useful when dealing with Pipes. * * @author Marko A. Rodriguez (http://markorodriguez.com) */ public class PipeHelper { private PipeHelper() { } /** * This will iterate all the objects out of the iterator. * This is useful for iterators with side-effect behavior as nothing is returned from the iteration. * Note that the try/catch model is not "acceptable Java," but is more efficient given the architecture of AbstractPipe. * * @param iterator the iterator to drain */ public static <T> void iterate(final Iterator<T> iterator) { try { while (true) { iterator.next(); } } catch (final NoSuchElementException e) { } } /** * Drain an iterator into a collection. Useful for storing the results of a Pipe into a collection. * Note that the try/catch model is not "acceptable Java," but is more efficient given the architecture of AbstractPipe. * * @param iterator the iterator to drain * @param collection the collection to fill * @param <T> the object type of the iterator */ public static <T> void fillCollection(final Iterator<T> iterator, final Collection<T> collection) { try { while (true) { collection.add(iterator.next()); } } catch (final NoSuchElementException e) { } } /** * Drain an iterator into a collection. Useful for storing the results of a Pipe into a collection. * Note that the try/catch model is not "acceptable Java," but is more efficient given the architecture of AbstractPipe. * * @param iterator the iterator to drain * @param collection the collection to fill * @param number the number of objects to fill into the collection (ordered by iterator) * @param <T> the object type of the iterator */ public static <T> void fillCollection(final Iterator<T> iterator, final Collection<T> collection, final int number) { try { for (int i = 0; i < number; i++) { collection.add(iterator.next()); } } catch (final NoSuchElementException e) { } } /** * Drains the iterator into a list that is returned by the method. * * @param iterator the iterator to drain into the list * @param <T> the object type of the iterator * @return a list filled with the objects of the iterator */ public static <T> List<T> makeList(final Iterator<T> iterator) { final List<T> list = new ArrayList(50); try { while (true) { list.add(iterator.next()); } } catch (final NoSuchElementException e) { } return list; } /** * Count the number of objects in an iterator. * This will exhaust the iterator. * Note that the try/catch model is not "acceptable Java," but is more efficient given the architecture of AbstractPipe. * * @param iterator the iterator to count * @return the number of objects in the iterator */ public static long counter(final Iterator iterator) { long counter = 0; try { while (true) { iterator.next(); counter++; } } catch (final NoSuchElementException e) { } return counter; } /** * Checks if the contents of the two iterators are equal and of the same length. * Equality is determined using == operator on the internal objects. * * @param ittyA An iterator * @param ittyB An iterator * @return Returns true if the two iterators contain the same objects and are of the same length */ public static boolean areEqual(final Iterator ittyA, final Iterator ittyB) { if (ittyA.hasNext() != ittyB.hasNext()) return false; while (ittyA.hasNext()) { if (!ittyB.hasNext()) return false; if (ittyA.next() != ittyB.next()) return false; } return true; } /** * Generate a String representation of a pipe given the pipe and some arguments of the pipe. * * @param pipe the pipe's class.getSimpleName() is used * @param arguments arguments used in the configuration of the pipe (please avoid objects with massive toString() representations) * @return a String representation of the pipe */ public static String makePipeString(final Pipe pipe, final Object... arguments) { String result = pipe.getClass().getSimpleName(); if (arguments.length > 0) { result = result + "("; for (final Object arg : arguments) { result = result + arg + ","; } result = result.substring(0, result.length() - 1) + ")"; } return result; } /** * Create a PipeFunction for a static method. The method represents PipeFunction.compute(). * * @param method a single argument, static method that will be invoked for when PipeFunction.compute() is called * @return a PipeFunction based on the provided compute method */ public static PipeFunction createPipeFunction(final Method method) { return new PipeFunction() { final Method m = method; public Object compute(final Object argument) { try { return m.invoke(null, argument); } catch (final Exception e) { throw new RuntimeException(e.getMessage(), e); } } }; } /** * Create a PipeFunction for a static method. The method represents PipeFunction.compute(). * * @param clazz the class hosting the method * @param methodName the string representation of the method * @param argumentTypes the classes of the arguments * @return a PipeFunction based on the retrieved compute method */ public static PipeFunction createPipeFunction(final Class clazz, final String methodName, final Class... argumentTypes) { try { return PipeHelper.createPipeFunction(clazz.getMethod(methodName, argumentTypes)); } catch (NoSuchMethodException e) { throw new RuntimeException(e.getMessage(), e); } } public static <T> Iterator<T> emptyIterator() { return (Iterator<T>) EmptyIterator.INSTANCE; } }