package com.tinkerpop.pipes.branch; import com.tinkerpop.pipes.AbstractPipe; import com.tinkerpop.pipes.Pipe; import com.tinkerpop.pipes.util.AbstractMetaPipe; import com.tinkerpop.pipes.util.MetaPipe; import com.tinkerpop.pipes.util.PipeHelper; import com.tinkerpop.pipes.util.Pipeline; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Queue; /** * CopySplitPipe takes a number of pipes during construction. * Every object pulled through CopySplitPipe is copied to each of the internal pipes. * * @author Marko A. Rodriguez (http://markorodriguez.com) */ public class CopySplitPipe<S> extends AbstractMetaPipe<S, S> implements MetaPipe { private final List<Pipeline> pipes = new ArrayList<Pipeline>(); public CopySplitPipe(final List<Pipe> pipes) { for (final Pipe pipe : pipes) { if (pipe instanceof Pipeline) { ((Pipeline) pipe).addPipe(0, new CopyExpandablePipe<S>(this)); this.pipes.add((Pipeline) pipe); } else { final Pipeline<S, ?> pipeline = new Pipeline<S, Object>(); pipeline.addPipe(new CopyExpandablePipe<S>(this)); pipeline.addPipe(pipe); this.pipes.add(pipeline); } } } public CopySplitPipe(final Pipe... pipes) { this(Arrays.asList(pipes)); } public S processNextStart() { final S s = this.starts.next(); List tempPath = null; if (this.pathEnabled) tempPath = new ArrayList(this.getCurrentPath()); for (final Pipeline pipeline : this.pipes) { final CopyExpandablePipe<S> temp = (CopyExpandablePipe<S>) pipeline.get(0); temp.add(s); if (this.pathEnabled) temp.addCurrentPath(tempPath); } return s; } public List getCurrentPath() { final List path = super.getCurrentPath(); path.remove(path.size() - 1); return path; } public List<Pipe> getPipes() { return (List) this.pipes; } public void enablePath(final boolean enable) { this.pathEnabled = enable; if (this.starts instanceof Pipe) ((Pipe) this.starts).enablePath(enable); } public String toString() { return PipeHelper.makePipeString(this, this.pipes); } private static class CopyExpandablePipe<S> extends AbstractPipe<S, S> { private static final Object TOKEN = new Object(); protected Queue<Object> queue = new LinkedList<Object>(); protected Queue<List> paths = new LinkedList<List>(); private CopySplitPipe<S> parentPipe; public CopyExpandablePipe(final CopySplitPipe<S> parentPipe) { this.parentPipe = parentPipe; } public S processNextStart() { while (true) { if (this.queue.isEmpty()) { this.parentPipe.processNextStart(); } else { if (pathEnabled) { final Object x = this.queue.remove(); if (x == TOKEN) { this.paths.remove(); } else { return (S) x; } } else { return (S) this.queue.remove(); } } } } public List getCurrentPath() { if (this.pathEnabled) { return new ArrayList(this.paths.peek()); } else throw new RuntimeException(Pipe.NO_PATH_MESSAGE); } public void addCurrentPath(final List path) { this.paths.add(path); } public void add(final S s) { this.queue.add(s); if (this.pathEnabled) this.queue.add(TOKEN); } public void reset() { this.queue.clear(); super.reset(); } public void enablePath(final boolean enablePath) { this.parentPipe.enablePath(enablePath); super.enablePath(enablePath); } } }