/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.optaplanner.examples.common.app; import java.util.Random; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.junit.Test; import org.optaplanner.core.api.domain.solution.PlanningSolution; import org.optaplanner.core.api.solver.Solver; import org.optaplanner.core.api.solver.SolverFactory; import org.optaplanner.core.config.solver.SolverConfig; import org.optaplanner.core.config.solver.termination.TerminationConfig; import org.optaplanner.core.impl.solver.ProblemFactChange; /** * @param <Solution_> the solution type, the class with the {@link PlanningSolution} annotation */ public abstract class RealTimePlanningTurtleTest<Solution_> extends AbstractTurtleTest { public static final int FREQUENCY = 300; public static final long SPENT_LIMIT = 5000L; protected Solver<Solution_> solver; @Test public void realTimePlanning() throws InterruptedException, ExecutionException { checkRunTurtleTests(); final SolverFactory<Solution_> solverFactory = buildSolverFactory(); final Solution_ planningProblem = readPlanningProblem(); solver = solverFactory.buildSolver(); ExecutorService executorService = Executors.newFixedThreadPool(2); Future<?> solveFuture = executorService.submit(() -> runSolve(solver, planningProblem)); Future<?> changesFuture = executorService.submit(() -> runChanges()); solveFuture.get(); changesFuture.get(); } protected SolverFactory<Solution_> buildSolverFactory() { SolverFactory<Solution_> solverFactory = SolverFactory.createFromXmlResource(createSolverConfigResource()); SolverConfig solverConfig = solverFactory.getSolverConfig(); solverConfig.setDaemon(true); TerminationConfig terminationConfig = new TerminationConfig(); terminationConfig.setMillisecondsSpentLimit(SPENT_LIMIT); solverConfig.setTerminationConfig(terminationConfig); return solverFactory; } protected abstract String createSolverConfigResource(); protected abstract Solution_ readPlanningProblem(); protected void runSolve(Solver<Solution_> solver, Solution_ planningProblem) { solver.solve(planningProblem); } protected void runChanges() { Random random = new Random(37); long startSystemTimeMillis = System.currentTimeMillis(); while (System.currentTimeMillis() - startSystemTimeMillis < 600_000L) { ProblemFactChange<Solution_> factChange = nextProblemFactChange(random); solver.addProblemFactChange(factChange); long sleepMillis = (long) random.nextInt(FREQUENCY); if (sleepMillis <= (FREQUENCY / 100)) { sleepMillis = SPENT_LIMIT + 500L; } else if (sleepMillis <= (FREQUENCY / 10)) { sleepMillis = 0; } try { Thread.sleep(sleepMillis); } catch (InterruptedException e) { solver.terminateEarly(); throw new IllegalStateException("runChanges() interrupted.", e); } } solver.terminateEarly(); } protected abstract ProblemFactChange<Solution_> nextProblemFactChange(Random random); }