001package com.mrivanplays.process;
002
003import java.util.concurrent.Executor;
004import java.util.concurrent.ExecutorService;
005import java.util.concurrent.Executors;
006import java.util.concurrent.ThreadFactory;
007import java.util.concurrent.atomic.AtomicInteger;
008
009/**
010 * Represents a scheduler of {@link Process Processes}.
011 *
012 * @since 0.0.1
013 * @author <a href="mailto:[email protected]">Ivan Pekov</a>
014 */
015public final class ProcessScheduler {
016
017  private final Executor async;
018  private final ExecutorService service;
019
020  /** Create a new {@code ProcessScheduler} which also creates a new {@link ExecutorService} */
021  public ProcessScheduler() {
022    this(
023        Executors.newCachedThreadPool(
024            new ThreadFactory() {
025
026              private AtomicInteger count = new AtomicInteger(0);
027
028              @Override
029              public Thread newThread(Runnable r) {
030                Thread thread = new Thread(r);
031                thread.setName("ProcessScheduler Thread #" + count.getAndIncrement());
032                return thread;
033              }
034            }));
035  }
036
037  /**
038   * Create a new {@code ProcessScheduler}
039   *
040   * @param async executor in which processes are executed
041   */
042  public ProcessScheduler(Executor async) {
043    this.async = async;
044    this.service = async instanceof ExecutorService ? (ExecutorService) async : null;
045  }
046
047  /**
048   * Runs all the specified {@link Process} {@code processes} whilst also returning a {@link
049   * ProcessesCompletion}.
050   *
051   * @param processes the processes to run
052   * @return a process completion
053   * @see Process
054   * @see ProcessesCompletion
055   */
056  public ProcessesCompletion runProcesses(Process... processes) {
057    ProcessesCompletion ret = new ProcessesCompletion(processes.length, this.async);
058    for (int i = 0; i < processes.length; i++) {
059      int processNum = i + 1;
060      Process process = processes[i];
061      this.async.execute(
062          () -> {
063            process.processNum(processNum);
064            process.runProcess(ret);
065          });
066    }
067    return ret;
068  }
069
070  /**
071   * Runs all the specified {@link ResultedProcess} whilst also returning a {@link
072   * ResultedProcessesCompletion}.
073   *
074   * @param processes the resulted processes to run
075   * @return a process completion
076   * @param <T> result value type parameter
077   * @see ResultedProcess
078   * @see ResultedProcessesCompletion
079   */
080  @SafeVarargs
081  public final <T> ResultedProcessesCompletion<T> runProcesses(ResultedProcess<T>... processes) {
082    ResultedProcessesCompletion<T> ret =
083        new ResultedProcessesCompletion<>(processes.length, this.async);
084    for (ResultedProcess<T> process : processes) {
085      this.async.execute(() -> process.runProcess(ret));
086    }
087    return ret;
088  }
089
090  /**
091   * If an {@link ExecutorService} has been created/detected whilst this {@code ProcessScheduler}
092   * was created, this will call it's {@link ExecutorService#shutdown()} method.
093   */
094  public void shutdownExecutorService() {
095    if (this.service != null) {
096      this.service.shutdown();
097    }
098  }
099}