class LocalComputationManager implements ComputationManager {

    private ExecutionReport execute(Path workingDir, List<CommandExecution> commandExecutionList, Map<String, String> variables, ComputationParameters computationParameters, ExecutionMonitor monitor)
            throws InterruptedException {
        // TODO concurrent
        List<ExecutionError> errors = new ArrayList<>();
        ExecutorService executionSubmitter = Executors.newCachedThreadPool();

        for (CommandExecution commandExecution : commandExecutionList) {
            Command command = commandExecution.getCommand();
            CountDownLatch latch = new CountDownLatch(commandExecution.getExecutionCount());
            IntStream.range(0, commandExecution.getExecutionCount()).forEach(idx ->
                    executionSubmitter.execute(() -> {
                        try {
                            enter();
                            logExecutingCommand(workingDir, command, idx);
                            preProcess(workingDir, command, idx);
                            int exitValue = process(workingDir, commandExecution, idx, variables, computationParameters);
                            postProcess(workingDir, commandExecution, idx, exitValue, errors, monitor);
                        } catch (Exception e) {
                            LOGGER.warn(e.getMessage());
                        } finally {
                            latch.countDown();
                            exit();
                        }
                    })
            );
            latch.await();
        }

        // TODO remove duplicated code
        executionSubmitter.shutdown();
        if (!executionSubmitter.awaitTermination(20, TimeUnit.SECONDS)) {
            executionSubmitter.shutdownNow();
            if (!executionSubmitter.awaitTermination(20, TimeUnit.SECONDS)) {
                LOGGER.error("Thread pool did not terminate");
            }
        }

        return new DefaultExecutionReport(errors);
    }

    public  LocalComputationManager();
    public  LocalComputationManager(Executor executor);
    public  LocalComputationManager(PlatformConfig platformConfig);
    public  LocalComputationManager(Path localDir);
    public  LocalComputationManager(LocalComputationConfig config);
    public  LocalComputationManager(LocalComputationConfig config, Executor executor);
    public  LocalComputationManager(LocalComputationConfig config, LocalCommandExecutor localCommandExecutor, Executor executor);

}