org.drools.planner.examples.common.business.SolutionBusiness Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of drools-planner-examples Show documentation
Show all versions of drools-planner-examples Show documentation
Drools Planner optimizes automated planning by combining metaheuristic search algorithms with rule
engine powered score calculation. This is the drools-planner-examples module which contains examples on how to use
Drools Planner.
/*
* Copyright 2010 JBoss Inc
*
* 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.drools.planner.examples.common.business;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.drools.ClassObjectFilter;
import org.drools.WorkingMemory;
import org.drools.planner.core.Solver;
import org.drools.planner.core.event.SolverEventListener;
import org.drools.planner.core.move.Move;
import org.drools.planner.core.score.Score;
import org.drools.planner.core.score.constraint.ConstraintOccurrence;
import org.drools.planner.core.solution.Solution;
import org.drools.planner.core.solver.DefaultSolver;
import org.drools.planner.core.solver.DefaultSolverScope;
import org.drools.planner.core.solver.PlanningFactChange;
import org.drools.planner.examples.common.persistence.AbstractSolutionExporter;
import org.drools.planner.examples.common.persistence.AbstractSolutionImporter;
import org.drools.planner.examples.common.persistence.SolutionDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SolutionBusiness {
protected final transient Logger logger = LoggerFactory.getLogger(getClass());
private SolutionDao solutionDao;
private AbstractSolutionImporter importer;
private AbstractSolutionExporter exporter;
private File importDataDir;
private File unsolvedDataDir;
private File solvedDataDir;
private File exportDataDir;
// volatile because the solve method doesn't come from the event thread (like every other method call)
private volatile Solver solver;
private DefaultSolverScope solverScope; // TODO HACK Planner internal API: don't do this
public void setSolutionDao(SolutionDao solutionDao) {
this.solutionDao = solutionDao;
}
public void setImporter(AbstractSolutionImporter importer) {
this.importer = importer;
}
public void setExporter(AbstractSolutionExporter exporter) {
this.exporter = exporter;
}
public File getDataDir() {
return solutionDao.getDataDir();
}
public String getDirName() {
return solutionDao.getDirName();
}
public boolean hasImporter() {
return importer != null;
}
public boolean hasExporter() {
return exporter != null;
}
public void updateDataDirs() {
if (hasImporter()) {
importDataDir = new File(getDataDir(), "input");
if (!importDataDir.exists()) {
throw new IllegalStateException("The directory importDataDir (" + importDataDir.getAbsolutePath()
+ ") does not exist. The working directory should be set to drools-planner-examples.");
}
}
unsolvedDataDir = new File(getDataDir(), "unsolved");
if (!unsolvedDataDir.exists()) {
throw new IllegalStateException("The directory unsolvedDataDir (" + unsolvedDataDir.getAbsolutePath()
+ ") does not exist. The working directory should be set to drools-planner-examples.");
}
solvedDataDir = new File(getDataDir(), "solved");
if (!solvedDataDir.exists() && !solvedDataDir.mkdir()) {
throw new IllegalStateException("The directory solvedDataDir (" + solvedDataDir.getAbsolutePath()
+ ") does not exist and could not be created.");
}
if (hasExporter()) {
exportDataDir = new File(getDataDir(), "output");
if (!exportDataDir.exists() && !exportDataDir.mkdir()) {
throw new IllegalStateException("The directory exportDataDir (" + exportDataDir.getAbsolutePath()
+ ") does not exist and could not be created.");
}
}
}
public File getImportDataDir() {
return importDataDir;
}
public File getUnsolvedDataDir() {
return unsolvedDataDir;
}
public File getSolvedDataDir() {
return solvedDataDir;
}
public File getExportDataDir() {
return exportDataDir;
}
public void setSolver(Solver solver) {
this.solver = solver;
this.solverScope = ((DefaultSolver) solver).getSolverScope();
}
public List getUnsolvedFileList() {
List unsolvedFileList = Arrays.asList(unsolvedDataDir.listFiles(new SolverExampleFileFilter()));
Collections.sort(unsolvedFileList);
return unsolvedFileList;
}
public List getSolvedFileList() {
List solvedFileList = Arrays.asList(solvedDataDir.listFiles(new SolverExampleFileFilter()));
Collections.sort(solvedFileList);
return solvedFileList;
}
public Solution getSolution() {
return solverScope.getWorkingSolution(); // TODO HACK Planner internal API: don't do this
}
public Score getScore() {
return solverScope.calculateScoreFromWorkingMemory(); // TODO HACK Planner internal API: don't do this
}
public void addSolverEventLister(SolverEventListener eventListener) {
solver.addEventListener(eventListener);
}
public List getScoreDetailList() {
Map scoreDetailMap = new HashMap();
WorkingMemory workingMemory = solverScope.getWorkingMemory();
if (workingMemory == null) {
return Collections.emptyList();
}
Iterator it = (Iterator) workingMemory.iterateObjects(
new ClassObjectFilter(ConstraintOccurrence.class));
while (it.hasNext()) {
ConstraintOccurrence constraintOccurrence = it.next();
ScoreDetail scoreDetail = scoreDetailMap.get(constraintOccurrence.getRuleId());
if (scoreDetail == null) {
scoreDetail = new ScoreDetail(constraintOccurrence.getRuleId(), constraintOccurrence.getConstraintType());
scoreDetailMap.put(constraintOccurrence.getRuleId(), scoreDetail);
}
scoreDetail.addConstraintOccurrence(constraintOccurrence);
}
List scoreDetailList = new ArrayList(scoreDetailMap.values());
Collections.sort(scoreDetailList);
return scoreDetailList;
}
public void importSolution(File file) {
Solution solution = importer.readSolution(file);
solver.setStartingSolution(solution);
}
public void openSolution(File file) {
Solution solution = solutionDao.readSolution(file);
solver.setStartingSolution(solution);
}
public void saveSolution(File file) {
Solution solution = solverScope.getWorkingSolution();
solutionDao.writeSolution(solution, file);
}
public void exportSolution(File file) {
Solution solution = solverScope.getWorkingSolution();
exporter.writeSolution(solution, file);
}
public void doMove(Move move) {
if (!move.isMoveDoable(solverScope.getWorkingMemory())) {
logger.info("Not doing user move ({}) because it is not doable.", move);
return;
}
logger.info("Doing user move ({}).", move);
move.doMove(solverScope.getWorkingMemory());
}
public void doPlanningFactChange(PlanningFactChange planningFactChange) {
if (solver.isSolving()) {
solver.addPlanningFactChange(planningFactChange);
} else {
planningFactChange.doChange(solverScope.getSolutionDirector());
}
}
public void solve() {
solver.solve();
// Normally we would do this as the point:
// Solution solution = solver.getBestSolution();
// but since this class is hacking DefaultSolverScope, it doesn't have to.
}
public void terminateSolvingEarly() {
solver.terminateEarly();
}
public class SolverExampleFileFilter implements FileFilter {
public boolean accept(File file) {
if (file.isDirectory() || file.isHidden()) {
return false;
}
return file.getName().endsWith(".xml");
}
}
}