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

com.github.burningwave.graph.Functions Maven / Gradle / Ivy

package com.github.burningwave.graph;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;

import com.github.burningwave.Throwables;
import com.github.burningwave.core.CommandWrapper;
import com.github.burningwave.core.Component;
import com.github.burningwave.core.Group;
import com.github.burningwave.core.iterable.IterableObjectHelper;
import com.github.burningwave.core.reflection.PropertyAccessor;
import com.github.burningwave.graph.ControllableContext.Directive;


public class Functions extends Group> {
	protected Map onException;
		
	Functions() {
		super();
		onException = new LinkedHashMap<>();
	}
	
	void setOnException(Map onException) {
		this.onException = onException;
	}
	
	static Functions create(
		PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
		PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
		IterableObjectHelper iterableObjectHelper
	) {
		return new Functions();
	}
	
	static Context.Abst castContext (Context context) {
		return ((Context.Abst)context);
	}	

	
	public void executeOn(Object object) {
		Context context = (Context)object;
		logDebug("Start executing functions group {}", getName());
		for (CommandWrapper functionWrapper : elements) {
			try {
				context = functionWrapper.executeOn(context);
			} catch (Throwable exc) {
				logError("Exception occurred", exc);
				castContext(context).putAllDirectives(onException);					
			}
			if (context.containsOneOf(getName(), Directive.Functions.STOP_PROCESSING)) {
				context.removeDirective(getName(), Directive.Functions.STOP_PROCESSING);
				logDebug("Stopping processing functions group {}", Optional.ofNullable(getName()).orElse(""));
				break;
			}
		}
		logDebug("End executing functions group {}", getName());
	}

	protected Function getExceptionHandlingFunction(Context context) {
		return (exc) -> {
			Optional.ofNullable(exc).ifPresent((exception) -> {
				logError("Exception occurred", exception.getCause());
				Optional.ofNullable(onException).ifPresent((onExc) -> 
					castContext(context).putAllDirectives(onExc)
				);
			});
			return null;
		};	
	}


	public static class Async extends Functions {
		protected ExecutorService executor;
		
		private Async(
				PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
				PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
				IterableObjectHelper iterableObjectHelper, ExecutorService executor
		) {
			super();
			this.executor = executor;
		}

		public static Functions.Async create(
				PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
				PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
				IterableObjectHelper iterableObjectHelper
		) {
			return new Async(byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper, null);
		}
		
		public static Functions.Async create(
				PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
				PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
				IterableObjectHelper iterableObjectHelper,
				ExecutorService executor) {
			return new Async(byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper, executor);
		}
		
		public static Functions.Async create(
				PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
				PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
				IterableObjectHelper iterableObjectHelper,
				int threadsNumber) {
			return new Async(byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper, Executors.newFixedThreadPool(threadsNumber));
		}	
		
		@Override
		public void executeOn(Object object) {
			Context context = (Context)object;
			logDebug("Start executing functions group {}", getName());
			List> completableFutureList = new CopyOnWriteArrayList<>();
			elements.stream().filter(functionWrapper -> {
				Runnable runnableFunction = () -> functionWrapper.executeOn(context);
				CompletableFuture completableFuture = (executor != null ?
					CompletableFuture.runAsync(runnableFunction, executor):
					CompletableFuture.runAsync(runnableFunction)
				).exceptionally(getExceptionHandlingFunction(context));
				completableFutureList.add(completableFuture);
				completableFuture.thenAcceptAsync(obj -> completableFutureList.remove(completableFuture));
				return context.containsOneOf(getName(), Directive.Functions.STOP_PROCESSING);
			}).findFirst().ifPresent(functionWrapper -> {
				context.removeDirective(getName(), Directive.Functions.STOP_PROCESSING);
				logDebug("Stopping processing functions group {}", Optional.ofNullable(getName()).orElse(""));
			});
			CompletableFuture.allOf(
				completableFutureList.stream().toArray(CompletableFuture[]::new)
			).join();
			completableFutureList.clear();
			logDebug("End executing functions group {}", getName());
		}
		
		@Override
		public void close() {
			if (executor != null && !executor.isShutdown()) {
				executor.shutdownNow().clear();
				executor = null;
			}
			super.close();
		}		
	}
	
	public static class ForCollection extends Functions {
		
		protected AlgorithmsSupplier algorithmsSupplier;
		
		private ForCollection(AlgorithmsSupplier algorithmsSupplier) {
			super();
			this.algorithmsSupplier = algorithmsSupplier;
		}

		protected static  Functions.ForCollection create(
				PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
				PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
				IterableObjectHelper iterableObjectHelper,
				AlgorithmsSupplier algorithmsSupplier) {
			return new Functions.ForCollection(algorithmsSupplier);
		}

		public static  Functions.ForCollection create(
				PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
				PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
				IterableObjectHelper iterableObjectHelper,
				String iterableObjectContextKey,
				String loopResultContextKey) {
			return create(
					byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper,
					AlgorithmsSupplier.create(byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper, iterableObjectContextKey, loopResultContextKey)
			);
		}
		

		@Override
		@SuppressWarnings("unchecked")
		public void executeOn(Object object) {
			Context context = (Context)object;
			logDebug("Start executing functions group {}", getName());
			algorithmsSupplier.preLoopOperationsRetriever.accept(context);
			AtomicInteger counter = new AtomicInteger(0);
			algorithmsSupplier.iterableObjectStreamRetriever.apply(context).filter(item -> {
				final int idx = counter.getAndIncrement();
				executeOnItem(context, (T) item, idx);
				return context.containsOneOf(getName(), Directive.Functions.ForCollection.STOP_ITERATION);
			}).findFirst().ifPresent(functionWrapper -> {
				context.removeDirective(getName(), Directive.Functions.ForCollection.STOP_ITERATION);
				logDebug("Stopping iteration of functions group {}", Optional.ofNullable(getName()).orElse(""));
			});
			algorithmsSupplier.postLoopOperationsRetriever.accept(context);
			logDebug("End executing functions group {}", getName());
		}
		
		
		void executeOnItem(Context context, T item, int idx) {
			//Clone context
			Context clonedContext = algorithmsSupplier.putIteratedObjectInContextRetriever.apply(new Object[]{context, item, idx});
			elements.stream().filter(functionWrapper -> {
				functionWrapper.executeOn(clonedContext);
				return clonedContext.containsOneOf(getName(), Directive.Functions.STOP_PROCESSING);
			}).findFirst().ifPresent(functionWrapper -> {
				clonedContext.removeDirective(getName(), Directive.Functions.STOP_PROCESSING);
				logDebug("Stopping processing functions group {}", Optional.ofNullable(getName()).orElse(""));
			});
			try {
				clonedContext.close();
			} catch (Exception exc) {
				throw Throwables.toRuntimeException(exc);
			}
		}
		
		@Override
		public void close() {
			algorithmsSupplier.close();
			algorithmsSupplier = null;
			super.close();
		}
		
		private static class AlgorithmsSupplier implements Component {			
			@SuppressWarnings("unused")
			PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor;
			PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor;
			IterableObjectHelper iterableObjectHelper;
			String iterableObjectContextKey;
			String loopResultContextKey;
			
			//preLoopOperations
			Consumer preLoopOperationsRetriever = context -> {
				Optional.ofNullable(loopResultContextKey).ifPresent((oCDk) -> {
					Object[] resultsContainer =
						new Object[(int)iterableObjectHelper.getSize(retrieve(context, iterableObjectContextKey))];
					byMethodOrByFieldPropertyAccessor.set(context, oCDk, resultsContainer);
				});
			};
			
			// retrieveIterableObjectStream
			Function> iterableObjectStreamRetriever = context -> 
				iterableObjectHelper.retrieveStream(retrieve(context, iterableObjectContextKey));
			
			// putIteratedObjectInContext
			Function putIteratedObjectInContextRetriever = (objects) -> {
				Context context = (Context)objects[0];
				Context clonedContext = context.createSymmetricClone();
				Object iterableObject = retrieve(context, iterableObjectContextKey);
				castContext(clonedContext).setCurrentIterationObjects(
					iterableObject, 
					Optional.ofNullable(loopResultContextKey).map((oCDk) ->
						(Object[])retrieve(context, oCDk)
					).orElse(null),
					!(iterableObject instanceof Map)? objects[1] : ((Map)iterableObject).get(objects[1]),
					(Integer)objects[2],
					!(iterableObject instanceof Map)? (Integer)objects[2] : objects[1]
				);
				return clonedContext;
			};
			
			// postLoopOperations
			Consumer postLoopOperationsRetriever = context -> {
					
			};
			
			
			private AlgorithmsSupplier(
				PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
				PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
				IterableObjectHelper iterableObjectHelper,
				String iterableObjectContextKey,
				String loopResultContextKey) {
				this.byFieldOrByMethodPropertyAccessor=byFieldOrByMethodPropertyAccessor;
				this.byMethodOrByFieldPropertyAccessor=byMethodOrByFieldPropertyAccessor;
				this.iterableObjectHelper = iterableObjectHelper;
				this.iterableObjectContextKey = iterableObjectContextKey;
				this.loopResultContextKey = loopResultContextKey;
			}
			
			static AlgorithmsSupplier create(
				PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
				PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
				IterableObjectHelper iterableObjectHelper,
				String iterableObjectContextKey,
				String loopResultContextKey) {
				return new AlgorithmsSupplier(byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper, iterableObjectContextKey, loopResultContextKey);
			}
			
			Object retrieve(Context context, String propertyPath) {
				return byMethodOrByFieldPropertyAccessor.get(context, propertyPath);
			}
			
			@Override
			public void close() {
				this.byFieldOrByMethodPropertyAccessor = null;
				this.byMethodOrByFieldPropertyAccessor = null;
				this.iterableObjectHelper = null;
				this.iterableObjectContextKey = null;
				this.loopResultContextKey = null;
			}
		}
		
		public static class Async extends Functions.ForCollection {
			protected ExecutorService executor;
			
			private Async(
					AlgorithmsSupplier algorithmsSupplier,
					ExecutorService executor) {
				super(algorithmsSupplier);
				this.executor = executor;
			}

			protected static  ForCollection.Async create(
					AlgorithmsSupplier algorithmsSupplier,
					ExecutorService executor) {
				return new ForCollection.Async(algorithmsSupplier, executor);
			}

			public static  ForCollection.Async create(
					PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
					PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
					IterableObjectHelper iterableObjectHelper,
					String iterableObjectContextKey,
					String loopResultContextKey,
					ExecutorService executor) {
				return create(
					AlgorithmsSupplier.create(
						byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper, iterableObjectContextKey, loopResultContextKey
					)
					,executor
				);
			}
			
			public static  ForCollection.Async create(
					PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
					PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
					IterableObjectHelper iterableObjectHelper, 
					String collectionContextKey,
					String loopResultContextKey) {
				return create(byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper, collectionContextKey, loopResultContextKey, (ExecutorService)null);
			}
			
			public static  ForCollection.Async create(
					PropertyAccessor.ByFieldOrByMethod byFieldOrByMethodPropertyAccessor,
					PropertyAccessor.ByMethodOrByField byMethodOrByFieldPropertyAccessor,
					IterableObjectHelper iterableObjectHelper,
					String collectionContextKey,
					String loopResultContextKey,
					Integer threadsNumber) {
				return create(byFieldOrByMethodPropertyAccessor, byMethodOrByFieldPropertyAccessor, iterableObjectHelper, collectionContextKey, loopResultContextKey, Executors.newFixedThreadPool(threadsNumber));
			}
			
			
			@Override
			@SuppressWarnings("unchecked")
			public void executeOn(Object object) {
				Context context = (Context)object;
				logDebug("Start executing functions group {}", getName());
				List> completableFutureList = new CopyOnWriteArrayList<>();
				algorithmsSupplier.preLoopOperationsRetriever.accept(context);
				AtomicInteger counter = new AtomicInteger(0);
				algorithmsSupplier.iterableObjectStreamRetriever.apply(context).filter(item -> {
					final int idx = counter.getAndIncrement();
					Runnable executeOnItemFunction = () -> executeOnItem(context, (T) item, idx);
					CompletableFuture completableFuture = (executor != null ?
						CompletableFuture.runAsync(executeOnItemFunction, executor):
						CompletableFuture.runAsync(executeOnItemFunction)
					).exceptionally(getExceptionHandlingFunction(context));
					completableFutureList.add(completableFuture);
					completableFuture.thenAcceptAsync(function -> completableFutureList.remove(completableFuture));
					return context.containsOneOf(getName(), Directive.Functions.ForCollection.STOP_ITERATION);
				}).findFirst().ifPresent(functionWrapper -> {
					context.removeDirective(getName(), Directive.Functions.ForCollection.STOP_ITERATION);
					logDebug("Stopping iteration of functions group {}", Optional.ofNullable(getName()).orElse(""));
				});
				algorithmsSupplier.postLoopOperationsRetriever.accept(context);
				CompletableFuture.allOf(
					completableFutureList.stream().toArray(CompletableFuture[]::new)
				).join();
				completableFutureList.clear();
				logDebug("End executing functions group {}", getName());
			}
			
			@Override
			public void close() {
				if (executor != null && !executor.isShutdown()) {
					executor.shutdownNow().clear();
					executor = null;
				}
				super.close();
			}
		}
	}

	
	@Override
	public void close() {
		if (elements != null) {
			for (CommandWrapper functionWrapper : elements) {
				if (functionWrapper.getTarget() instanceof Functions) {
					((Functions)functionWrapper.getTarget()).close();
				}
				functionWrapper.close();
			}
		}
		if (onException != null) {
			onException.clear();
			onException = null;
		}
		super.close();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy