All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jabb.util.parallel.RecursivePipelineImpl Maven / Gradle / Ivy

There is a newer version: 1.0.73
Show newest version
/**
 * 
 */
package net.sf.jabb.util.parallel;

import java.util.Collection;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;

import com.google.common.util.concurrent.MoreExecutors;

/**
 * The simple and efficient recursive implementation of pipeline.
 * It requires you to build it in reversed order - from the last stage to the first stage.
 * 
 * @author James Hu
 *
 * @param 	type of input
 * @param 	type of output
 */
public class RecursivePipelineImpl implements Pipeline{
	ExecutorService executor;
	Function> feedFunction;
	
	/**
	 * Start building a pipeline, and specify a collection that all the final output will be put into.
	 * @param outputCollection	the collection that will be used to hold all the output.
	 * @param  type of output
	 * @return	a new pipeline that you can prepend stages
	 */
	public static  RecursivePipelineImpl outputTo(Collection outputCollection){
		return new RecursivePipelineImpl(MoreExecutors.newDirectExecutorService(), input -> {
			outputCollection.add(input);
			return input;
		});
	}

	/**
	 * Start building a pipeline, and specify another pipeline that all the final output from this 
	 * pipleline will be fed to.
	 * @param downstreamPipeline	another pipeline
	 * @param  type of the output of this pipeline which is also the input of the downstream pipeline
	 * @param  type of the output of the downstream pipeline
	 * @return	a new pipeline that you can prepend stages
	 */
	public static  RecursivePipelineImpl> outputTo(Pipeline downstreamPipeline){
		return new RecursivePipelineImpl>(MoreExecutors.newDirectExecutorService(), input -> {
			Future future = downstreamPipeline.feed(input);
			Pipeline.IntermediateOutput intermediateOutput = new Pipeline.IntermediateOutput(input, future);
			return intermediateOutput;
		});
	}

	/**
	 * Start building a pipleline that doesn't put the final output anywhere.
	 * Usage example: PipelineRecursiveImpl.<Integer>noOutput()
	 * @param  type of the output
	 * @return a pipeline that does not output to anywhere
	 */
	public static  RecursivePipelineImpl noOutput(){
		return new RecursivePipelineImpl(MoreExecutors.newDirectExecutorService(), input -> input);
	}


	private RecursivePipelineImpl(ExecutorService executor, Function function){
		this.executor = executor;
		this.feedFunction = input -> {
			O output = function.apply(input);
			Future outputFuture = new Future(){		// this future is actually present!

				@Override
				public boolean cancel(boolean mayInterruptIfRunning) {
					return false;
				}

				@Override
				public boolean isCancelled() {
					return false;
				}

				@Override
				public boolean isDone() {
					return true;
				}

				@Override
				public O get() throws InterruptedException, ExecutionException {
					return output;
				}

				@Override
				public O get(long timeout, TimeUnit unit)
						throws InterruptedException, ExecutionException,
						TimeoutException {
					return output;
				}
				
			};
			return outputFuture;
		};
	}
	
	private  RecursivePipelineImpl(ExecutorService executor, Function function, RecursivePipelineImpl downstream){
		this.executor = executor;
		this.feedFunction = input -> {
			OI intermediate = function.apply(input);
			Future outputFuture = downstream.feed(intermediate);
			return outputFuture;
		};
	}
	
	/**
	 * Prepend a stage to the pipeline
	 * @param executor		the executor service for the processing in the prepended stage
	 * @param function		the function to be applied in the prepended stage
	 * @param  type of the new input
	 * @return		the new pipeline with the stage prepended
	 */
	public  RecursivePipelineImpl prepend(ExecutorService executor, Function function){
		return new RecursivePipelineImpl(executor, function, this);
	}
	
	/**
	 * Prepend a stage to the pipeline. A new thread pool will be created and that thread pool will only be eligible for 
	 * garbage collection when the pipleline itself is eligible for garbage collection. 
	 * @param fixedThreadPoolSize		the thread pool size of a fixed size thread pool which will be used for the processing in the prepended stage
	 * @param function		the function to be applied in the prepended stage
	 * @param  type of the new input
	 * @return		the new pipeline with the stage prepended
	 */
	public  RecursivePipelineImpl prepend(int fixedThreadPoolSize, Function function){
		ExecutorService executor = Executors.newFixedThreadPool(fixedThreadPoolSize);
		return new RecursivePipelineImpl(executor, function, this);
	}
	
	@Override
	public Future feed(I input){
		 Future> futureOfFuture = executor.submit(()->feedFunction.apply(input));
		 return new Future(){

			@Override
			public boolean cancel(boolean mayInterruptIfRunning) {
				if (futureOfFuture.cancel(mayInterruptIfRunning)){
					return true;
				}
				if (!futureOfFuture.isCancelled()){	// is done normally
					try {
						Future future = futureOfFuture.get();
						return future.cancel(mayInterruptIfRunning);
					} catch (InterruptedException | ExecutionException e) {
						// just ignore exceptions;
						return true;
					}
				}else{ // already been cancelled
					return false;
				}
			}

			@Override
			public boolean isCancelled() {
				if (futureOfFuture.isCancelled()){
					return true;
				}else{
					if (futureOfFuture.isDone()){
						Future future;
						try {
							future = futureOfFuture.get();
							return future.isCancelled();
						} catch (CancellationException e){
							return true;
						} catch (InterruptedException | ExecutionException e) {
							return false;
						}
					}else{
						return false;
					}
				}
			}

			@Override
			public boolean isDone() {
				if (futureOfFuture.isDone()){
					try {
						Future future = futureOfFuture.get();
						return future.isDone();
					} catch (InterruptedException | ExecutionException e) {
						// just ignore exceptions;
						return true;
					}
				}else{
					return false;
				}
			}

			@Override
			public O get() throws InterruptedException, ExecutionException {
				Future future = futureOfFuture.get();
				return future.get();
			}

			@Override
			public O get(long timeout, TimeUnit unit)
					throws InterruptedException, ExecutionException,
					TimeoutException {
				long remainingNanos = unit.toNanos(timeout);
			    long end = System.nanoTime() + remainingNanos;
			    
			    Future future = futureOfFuture.get(timeout, unit);
			    remainingNanos = end - System.nanoTime();
			    
			    if (remainingNanos > 0){
			    	return future.get(remainingNanos, TimeUnit.NANOSECONDS);
			    }else{
			    	throw new TimeoutException();
			    }
			}
			 
		 };
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy