Source:
public void solve(Object problemId, Solution_ planningProblem, Consumer<Solution_> onBestSolutionChangedEvent, Consumer<Solution_> onSolvingEnded, Consumer<Throwable> onException) { SolverTask<Solution_> newSolverTask; synchronized (this) { if (isProblemSubmitted(problemId)) { throw new IllegalArgumentException("Problem (" + problemId + ") already exists."); } newSolverTask = new SolverTask<>(problemId, solverFactory.buildSolver(), planningProblem); problemIdToSolverTaskMap.put(problemId, newSolverTask); logger.info("A new solver task was created with problemId ({}).", problemId); } if (onBestSolutionChangedEvent != null) { newSolverTask.addEventListener( bestSolutionChangedEvent -> eventHandlerExecutorService.submit( () -> onBestSolutionChangedEvent.accept(bestSolutionChangedEvent.getNewBestSolution()))); } CompletableFuture<Solution_> solverFuture = CompletableFuture.supplyAsync(newSolverTask::startSolving, solverExecutorService); solverFuture.handle((solution_, throwable) -> { if (throwable != null) { logger.error("Exception while solving problem (" + problemId + ").", throwable.getCause()); if (onException != null) { eventHandlerExecutorService.submit(() -> onException.accept(throwable.getCause())); } } return eventHandlerExecutorService.submit(() -> onSolvingEnded.accept(solution_)); }); }

Target:
public void solve( Object problemId, Solution_ planningProblem, Consumer<Solution_> onBestSolutionChangedEvent, Consumer<Solution_> onSolvingEnded, Consumer<Throwable> onException) { Objects.requireNonNull(problemId); Objects.requireNonNull(planningProblem); SolverTask<Solution_> newSolverTask; synchronized (this) { if (isProblemSubmitted(problemId)) { throw new IllegalArgumentException("Problem (" + problemId + ") already exists."); } newSolverTask = new SolverTask<>(problemId, solverFactory.buildSolver(), planningProblem); problemIdToSolverTaskMap.put(problemId, newSolverTask); problemIdToFuturesMap.put(problemId, new CopyOnWriteArrayList<>()); logger.info("A new solver task was created with problemId ({}).", problemId); } if (onBestSolutionChangedEvent != null) { newSolverTask.addEventListener(bestSolutionChangedEvent -> { Future<?> bestSolutionChangedEventFuture = eventHandlerExecutorService.submit( () -> onBestSolutionChangedEvent.accept(bestSolutionChangedEvent.getNewBestSolution())); problemIdToFuturesMap.get(problemId).add(bestSolutionChangedEventFuture); }); } CompletableFuture<Solution_> solverFuture = CompletableFuture.supplyAsync(newSolverTask::startSolving, solverExecutorService); solverFuture.handle((solution_, throwable) -> { handleThrowable(throwable, onException, "Exception while solving problem ({" + problemId + "})."); if (onSolvingEnded != null) { CompletableFuture<Void> solvingEndedFuture = CompletableFuture.supplyAsync(() -> { onSolvingEnded.accept(solution_); return null; }, eventHandlerExecutorService); problemIdToFuturesMap.get(problemId).add(solvingEndedFuture); return solvingEndedFuture; } return null; }).handle((voidCompletableFuture, throwable) -> { handleThrowable(throwable, onException, "Exception while executing onSolvingEnded of problem ({" + problemId + "})."); return cleanupResources(problemId); }); problemIdToFuturesMap.get(problemId).add(solverFuture); }