Chapter 19. Migration Guide


19.1. About the Business Resource Planner Migration

From Red Hat JBoss BRMS and Red Hat JBoss BPM Suite 6.1 onwards, Business Resource Planner is fully supported. Business Resource Planner is a lightweight, embeddable constraint satisfaction engine that is able to solve planning problems. Business Resource Planner includes a public API, which will be backwards compatible in later versions such as 6.2 and 6. For more information, see the Business Resource Planner documentation.

The following changes should be noted for implementation in JBoss BPM Suite/JBoss BRMS 6.1 onwards:

  • Simulated Annealing now uses the time gradient of the current step instead of the time gradient of the last step. The impact of this change is negligible.
  • On AbstractScore, the methods parseLevelStrings(…​) and buildScorePattern(…​) have been changed from public to protected. It is highly unlikely that this affects your code.
  • The Descriptor classes have been moved into a descriptor package. SolutionDescriptor.isInitialized(Solution) now requires a ScoreDirector parameter.
  • There is now a better alternative to Brute Force: Branch And Bound, see docs for more information.
  • InverseRelationShadowVariableListener has been renamed to SingletonInverseVariableListener. It, and InverseRelationShadowVariableDescriptor have moved to the package ...impl.domain.variable.inverserelation.
  • The ConstraintOccurrence classes (which were deprecated) have been remove, and should be switched to the ConstraintMatch system.
  • The interface Solution has been promoted to the public API. It has also moved package from impl.solution to api.domain.solution.

    Previously in *.java :

    import org.optaplanner.core.impl.solution.Solution;

    Now in *.java :

    import org.optaplanner.core.api.domain.solution.Solution;
  • All classes in the package impl.move have been moved to impl.heuristic.move. None of them are future-proof enough at this time to be added the public API. Prefer generic moves whenever possible.

    Previously in *.java :

    import org.optaplanner.core.impl.move.Move;
    import org.optaplanner.core.impl.move.CompositeMove;
    import org.optaplanner.core.impl.move.NoChangeMove;

    Now in *.java :

    import org.optaplanner.core.impl.heuristic.move.Move;
    import org.optaplanner.core.impl.heuristic.move.CompositeMove;
    import org.optaplanner.core.impl.heuristic.move.NoChangeMove;
  • All classpath resources must lose their leading slash, because Business Resource Planner now expects them to adhere to ClassLoader.getResource(String) instead of Class.getResource(String).

    • The SolverFactory.createFromXmlResource(String) parameter must lose its leading slash.

      Previously in *.java :

      ... = SolverFactory.createFromXmlResource(
      "/org/optaplanner/examples/cloudbalancing/solver/cloudBalancingSolverConfig.xml");

      Now in *.java :

      ... = SolverFactory.createFromXmlResource(
      "org/optaplanner/examples/cloudbalancing/solver/cloudBalancingSolverConfig.xml");
    • All elements <scoreDrl> must lose their leading slash.

      Previously in *SolverConfig.xml and *BenchmarkConfig.xml:

      <scoreDrl>/org/optaplanner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>

      Now in *SolverConfig.xml and *BenchmarkConfig.xml :

      <scoreDrl>org/optaplanner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>
    • The PlannerBenchmarkFactory.createFromXmlResource(String) parameter must lose its leading slash.

      Previously in *.java :

      ... = PlannerBenchmarkFactory.createFromXmlResource(
          "/org/optaplanner/examples/cloudbalancing/benchmark/cloudBalancingBenchmarkConfig.xml");

      Now in *.java :

      ... = PlannerBenchmarkFactory.createFromXmlResource(
          "org/optaplanner/examples/cloudbalancing/benchmark/cloudBalancingBenchmarkConfig.xml");
    • The PlannerBenchmarkFactory.createFromFreemarkerXmlResource(String) parameter must lose its leading slash.

      Previously in *.java :

      ... = PlannerBenchmarkFactory.createFromFreemarkerXmlResource(
      "/org/optaplanner/examples/cloudbalancing/benchmark/cloudBalancingBenchmarkConfigTemplate.xml.ftl");

      Now in *.java :

      ... = PlannerBenchmarkFactory.createFromFreemarkerXmlResource(
      "org/optaplanner/examples/cloudbalancing/benchmark/cloudBalancingBenchmarkConfigTemplate.xml.ftl");
  • The @PlanningVariable property chained has been refactored to graphType. This is to allow support for other graph types (such as TREE) in the future.

    Previously in *.java :

    @PlanningVariable(chained = true, ...)
    public Standstill getPreviousStandstill() {
        return previousStandstill;
    }

    Now in *.java :

    @PlanningVariable(graphType = PlanningVariableGraphType.CHAINED, ...)
    public Standstill getPreviousStandstill() {
        return previousStandstill;
    }
  • The constructionHeuristicType BEST_FIT has been renamed into WEAKEST_FIT. The terminology “Best Fit” was not correct and did not allow for STRONGEST_FIT.

    Previously in *SolverConfig.xml and *BenchmarkConfig.xml :

    <constructionHeuristic>
      <constructionHeuristicType>BEST_FIT</constructionHeuristicType>
    </constructionHeuristic>

    Now in *SolverConfig.xml and *BenchmarkConfig.xml :

    <constructionHeuristic>
      <constructionHeuristicType>WEAKEST_FIT</constructionHeuristicType>
    </constructionHeuristic>
  • The constructionHeuristicType BEST_FIT_DECREASING has been renamed into WEAKEST_FIT_DECREASING. The terminology “Best Fit” was not correct and did not allow for STRONGEST_FIT_DECREASING.

    Previously in *SolverConfig.xml and *BenchmarkConfig.xml :

    <constructionHeuristic>
      <constructionHeuristicType>BEST_FIT_DECREASING</constructionHeuristicType>
    </constructionHeuristic>

    Now in *SolverConfig.xml and *BenchmarkConfig.xml :

    <constructionHeuristic>
      <constructionHeuristicType>WEAKEST_FIT_DECREASING</constructionHeuristicType>
    </constructionHeuristic>
  • For the shadow variable of a bi-directional relationship, the declaration has changed from @PlanningVariable(mappedBy) to @InverseRelationShadowVariable(sourceVariableName).

    Previously in *.java :

    @PlanningVariable(mappedBy = "previousStandstill")
    Customer getNextCustomer();
    void setNextCustomer(Customer nextCustomer);

    Now in *.java :

    @InverseRelationShadowVariable(sourceVariableName = "previousStandstill")
    Customer getNextCustomer();
    void setNextCustomer(Customer nextCustomer);
  • Multiple <planningEntityClass> elements now need to be ordered by superclasses (and superinterfaces) first, instead of superclasses (and superinterfaces) last.

    Previously in *SolverConfig.xml and *BenchmarkConfig.xml :

    <planningEntityClass>...TimeWindowedCustomer</planningEntityClass>
    <planningEntityClass>...Customer</planningEntityClass>
    <planningEntityClass>...Standstill</planningEntityClass>

    Now in *SolverConfig.xml and *BenchmarkConfig.xml :

    <planningEntityClass>...Standstill</planningEntityClass>
    <planningEntityClass>...Customer</planningEntityClass>
    <planningEntityClass>...TimeWindowedCustomer</planningEntityClass>
  • The element <planningEntityClass> has been renamed to <entityClass>.

    Previously in *SolverConfig.xml and *BenchmarkConfig.xml :

    <planningEntityClass>org.optaplanner.examples.cloudbalancing.domain.CloudProcess</planningEntityClass>

    Now in *SolverConfig.xml and *BenchmarkConfig.xml :

    <entityClass>org.optaplanner.examples.cloudbalancing.domain.CloudProcess</entityClass>
  • XStreamScoreConverter and XStreamBendableScoreConverter have moved package.

    Previously in *.java :

    import org.optaplanner.persistence.xstream.XStreamScoreConverter;

    Now in *.java :

    import org.optaplanner.persistence.xstream.impl.score.XStreamScoreConverter;

    Previously in *.java :

    import org.optaplanner.persistence.xstream.XStreamBendableScoreConverter;

    Now in *.java :

    import org.optaplanner.persistence.xstream.impl.score.XStreamBendableScoreConverter;
  • If you have a custom Move implementation, now extract AbstractMove.

    Previously in *.java :

    public class CloudComputerChangeMove implements Move {...}

    Now in *.java :

    public class CloudComputerChangeMove extends AbstractMove {...}

19.2. Planning Values and Value Ranges

19.2.1. ValueRangeProvider

If you have a @ValueRangeProvider that returns a collection of numbers (for example List<Integer> or List<BigDecimal>), then you should switch to a ValueRange, which uses less memory and offers additional opportunities.

For example:

@ValueRangeProvider(id = "delayRange")
public List<Integer> getDelayRange() {
    List<Integer> = new ArrayList<Integer>(5000);
    for (int i = 0; i < 5000; i++) {
        delayRange.add(i);
    }
    return delayRange;
}

Is changed to:

@ValueRangeProvider(id = "delayRange")
public CountableValueRange<Integer> getDelayRange() {
    return ValueRangeFactory.createIntValueRange(0, 5000);
}
Note

The annotation @ValueRangeProvider has been moved into another package, from:

import org.optaplanner.core.api.domain.value.ValueRangeProvider;

to

import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;

19.2.2. Planning Variables

The interface PlanningVariableListener has been renamed to VariableListener.

Previously in *.java :

public class VehicleUpdatingVariableListener implements PlanningVariableListener<Customer> {

Now in *.java :

public class VehicleUpdatingVariableListener implements VariableListener<Customer> {

The class AbstractPlanningVariableListener has been removed.

Previously in *.java :

public class VehicleUpdatingVariableListener extends AbstractPlanningVariableListener<Customer> {

Now in *.java :

public class VehicleUpdatingVariableListener implements VariableListener<Customer> {

The VariableListener is now declared on the shadow side, instead of the @PlanningVariable side. This way, Business Rules Planner recognizes the shadow variables, and all shadow variables are declared in a consistent matter. Furthermore, it allows a shadow variable to based on other shadow variable.

Previously in *.java :

@PlanningVariable(valueRangeProviderRefs = {"vehicleRange", "customerRange"},
        graphType = PlanningVariableGraphType.CHAINED,
        variableListenerClasses = {VehicleUpdatingVariableListener.class, ArrivalTimeUpdatingVariableListener.class})
public Standstill getPreviousStandstill() {
    return previousStandstill;
}

public Vehicle getVehicle() {
    return vehicle;
}

public Integer getArrivalTime() {
    return arrivalTime;
}

Now in *.java :

@PlanningVariable(...)
public Standstill getPreviousStandstill() {
    return previousStandstill;
}

@CustomShadowVariable(variableListenerClass = VehicleUpdatingVariableListener.class,
        sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
public Vehicle getVehicle() {
    return vehicle;
}

@CustomShadowVariable(variableListenerClass = ArrivalTimeUpdatingVariableListener.class,
        sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
public Integer getArrivalTime() {
    return arrivalTime;
}

There is now out-of-the-box support for a shadow variable representing the anchor of a chained variable. For example, in a VRP each Customer (= entity) needs to know to which Vehicle (= anchor) it belongs. This declarative support allows build-in selectors to reuse that knowledge without duplicating the calculation.

Previously in *.java :

@PlanningEntity
public class Customer implements Standstill {

    @PlanningVariable(...)
    public Standstill getPreviousStandstill() {...}

    @CustomShadowVariable(variableListenerClass = VehicleUpdatingVariableListener.class,
            sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
    public Vehicle getVehicle() {...}

}
public class VehicleUpdatingVariableListener implements VariableListener<Customer> {
    ...
}

Now in *.java :

@PlanningEntity
public class Customer implements Standstill {

    @PlanningVariable(...)
    public Standstill getPreviousStandstill() {...}

    @AnchorShadowVariable(sourceVariableName = "previousStandstill")
    public Vehicle getVehicle() {...}
}

To scale VRP cases, Nearby Selection is critical. It is now finally completely supported and documented.

19.3. Benchmark

The internals of Benchmark have been deeply refactored to support the new aggregator functionality.

  • The phrase "time spend" has been renamed to "time spent". This includes the log output and the benchmark report.

The <warmUp*> elements have been renamed:

  • The element <warmUpTimeMillisSpend> has been renamed to <warmUpMillisecondsSpentLimit>
  • The element <warmUpSecondsSpend> has been renamed to <warmUpSecondsSpentLimit>
  • The element <warmUpMinutesSpend> has been renamed to <warmUpMinutesSpentLimit>
  • The element <warmUpHoursSpend> has been renamed to <warmUpHoursSpentLimit>

Previously in *BenchmarkConfig.xml

<plannerBenchmark>
  <warmUpTimeMillisSpend>...</warmUpTimeMillisSpend>
  <warmUpSecondsSpend>...</warmUpSecondsSpend>
  <warmUpMinutesSpend>...</warmUpMinutesSpend>
  <warmUpHoursSpend>...</warmUpHoursSpend>
  ...
</plannerBenchmark>

Now in *BenchmarkConfig.xml :

<plannerBenchmark>
  <warmUpMillisecondsSpentLimit>...</warmUpMillisecondsSpentLimit>
  <warmUpSecondsSpentLimit>...</warmUpSecondsSpentLimit>
  <warmUpMinutesSpentLimit>...</warmUpMinutesSpentLimit>
  <warmUpHoursSpentLimit>...</warmUpHoursSpentLimit>
  ...
</plannerBenchmark>

The class XmlPlannerBenchmarkFactory has been removed and replaced by static methods on PlannerBenchmarkFactory.

Previously in *.java :

PlannerBenchmarkFactory plannerBenchmarkFactory = new XmlPlannerBenchmarkFactory(...);

Now in *.java :

PlannerBenchmarkFactory plannerBenchmarkFactory = PlannerBenchmarkFactory.createFromXmlResource(...);
Note

If you used the method addXstreamAnnotations(), take a look at the non-public API class XStreamXmlPlannerBenchmarkFactory.

The element <xstreamAnnotatedClass> has been renamed to <xStreamAnnotatedClass>.

Previously in *BenchmarkConfig.xml

<problemBenchmarks>
  <xstreamAnnotatedClass>org.optaplanner.examples.nqueens.domain.NQueens</xstreamAnnotatedClass>
  ...
</problemBenchmarks>

Now in *BenchmarkConfig.xml :

<problemBenchmarks>
  <xStreamAnnotatedClass>org.optaplanner.examples.nqueens.domain.NQueens</xStreamAnnotatedClass>
  ...
</problemBenchmarks>

19.3.1. SolutionFileIO

ProblemIO has been renamed to SolutionFileIO and moved package (into the public API).

Previously in *.java :

import org.optaplanner.core.impl.solution.ProblemIO;
public class MachineReassignmentFileIO implements ProblemIO {
    ...
}

Now in *.java :

import org.optaplanner.persistence.common.api.domain.solution.SolutionFileIO;
public class MachineReassignmentFileIO implements SolutionFileIO {
    ...
}

Now in *.java :

Previously in *SolverConfig.xml and *BenchmarckConfig.xml :

<problemBenchmarks>
<problemIOClass>...MachineReassignmentProblemIO</problemIOClass>
...
</problemBenchmarks>

Now in *SolverConfig.xml and *BenchmarckConfig.xml :

<problemBenchmarks>
<solutionFileIOClass>...MachineReassignmentFileIO</solutionFileIOClass>
...
</problemBenchmarks>

The method SolutionFileIO.getFileExtension() has been split up in getInputFileExtension() and getOutputFileExtension();. It is still highly recommended to use the same input and output file extension.

Previously in *.java :

public String getFileExtension() {
    return FILE_EXTENSION;
}

Now in *.java :

public String getInputFileExtension() {
    return FILE_EXTENSION;
}
public String getOutputFileExtension() {
    return FILE_EXTENSION;
}

19.4. Solver Configuration

In Solver and BestSolutionChangedEvent, the method getTimeMillisSpend() has been renamed to getTimeMillisSpent().

Previously in *.java:

... = solver.getTimeMillisSpend();

Now in *.java:

... = solver.getTimeMillisSpent();

Previously in *.java:

public void bestSolutionChanged(BestSolutionChangedEvent event) {
    ... = event.getTimeMillisSpend();
}

Now in *.java:

public void bestSolutionChanged(BestSolutionChangedEvent event) {
    ... = event.getTimeMillisSpent();
}

The solver phase <bruteForce> has been replaced by <exhaustiveSearch>'s BRUTE_FORCE type.

Previously in *SolverConfig.xml and *BenchmarkConfig.xml :

<bruteForce/>

Now in *SolverConfig.xml and *BenchmarkConfig.xml :

<exhaustiveSearch>
  <exhaustiveSearchType>BRUTE_FORCE</exhaustiveSearchType>
</exhaustiveSearch>

The methods setPlanningProblem(Solution) and solve() have been merged as the method solve(Solution).

Previously in *.java:

solver.setPlanningProblem(planningProblem);
solver.solve();

Now in *.java:

solver.solve(planningProblem);
Note

You still need to use solver.getBestSolution() to retrieve the best solution. That is intentional due to real-time planning and to support pare to optimization in the future.

The class XmlSolverFactory (which was not part of the public API) has been removed and replaced by static methods on SolverFactory (which are part of the public API).

Previously in *.java:

SolverFactory solverFactory = new XmlSolverFactory("...solverConfig.xml");

Now in *.java:

SolverFactory solverFactory = SolverFactory.createFromXmlResource("...solverConfig.xml");

Previously in *.java:

SolverFactory solverFactory = new XmlSolverFactory().configure(inputStream);

Now in *.java:

SolverFactory solverFactory = SolverFactory.createFromXmlInputStream(inputStream);

Previously in *.java:

SolverFactory solverFactory = new XmlSolverFactory().configure(reader);

Now in *.java:

SolverFactory solverFactory = SolverFactory.createFromXmlReader(reader);
Note

If you used the method addXstreamAnnotations(), take a look at the non-public API class XStreamXmlSolverFactory.

The following changes have been made to the Custom SolverPhase:

  • The interface CustomSolverPhaseCommand has been renamed to CustomPhaseCommand.
  • The element <customSolverPhase> has been renamed to <customPhase>.
  • The element <customSolverPhaseCommandClass> has been renamed to >customPhaseCommandClass>.

Previously in *.java:

public class ToOriginalMachineSolutionInitializer implements CustomSolverPhaseCommand {
    ...
}

Now in *.java:

public class ToOriginalMachineSolutionInitializer implements CustomPhaseCommand {
    ...
}

Previously in *SolverConfig.xml and *BenchmarkConfig.xml :

<customSolverPhase>
  <customSolverPhaseCommandClass>...ToOriginalMachineSolutionInitializer</customSolverPhaseCommandClass>
</customSolverPhase>

Now in *SolverConfig.xml and *BenchmarkConfig.xml :

<customPhase>
  <customPhaseCommandClass>....ToOriginalMachineSolutionInitializer</customPhaseCommandClass>
</customPhase>

The method ScoreDefinition.getLevelCount() has been renamed to ScoreDefinition.getLevelsSize().

19.5. Optimization

19.5.1. Termination

All child elements of <termination> have been renamed:

  • The element <maximumTimeMillisSpend> has been renamed to <millisecondsSpentLimit>
  • The element <maximumSecondsSpend> has been renamed to <secondsSpentLimit>
  • The element <maximumMinutesSpend> has been renamed to <minutesSpentLimit>
  • The element <maximumHoursSpend> has been renamed to <hoursSpentLimit>
  • The element <scoreAttained> has been renamed to <bestScoreLimit>
  • The element <maximumStepCount> has been renamed to <stepCountLimit>
  • The element <maximumUnimprovedStepCount> has been renamed to <unimprovedStepCountLimit>

Configuration in *SolverConfig.xml and *BenchmarkConfig.xml has changed from:

<termination>
  <maximumTimeMillisSpend>...</maximumTimeMillisSpend>
  <maximumSecondsSpend>...</maximumSecondsSpend>
  <maximumMinutesSpend>...</maximumMinutesSpend>
  <maximumHoursSpend>...</maximumHoursSpend>
  <scoreAttained>...</scoreAttained>
  <maximumStepCount>...</maximumStepCount>
  <maximumUnimprovedStepCount>...</maximumUnimprovedStepCount>
</termination>

to:

<termination>
  <millisecondsSpentLimit>...</millisecondsSpentLimit>
  <secondsSpentLimit>...</secondsSpentLimit>
  <minutesSpentLimit>...</minutesSpentLimit>
  <hoursSpentLimit>...</hoursSpentLimit>
  <bestScoreLimit>...</bestScoreLimit>
  <stepCountLimit>...</stepCountLimit>
  <unimprovedStepCountLimit>...</unimprovedStepCountLimit>
</termination>

19.5.2. Events

Classes BestSolutionChangedEvent and SolverEventListener moved from package impl.event to api.solver.event. They are now part of the public api.

Previously in *.java :

import org.optaplanner.core.impl.event.BestSolutionChangedEvent;
import org.optaplanner.core.impl.event.SolverEventListener;

Now in *.java :

import org.optaplanner.core.api.solver.event.BestSolutionChangedEvent;
import org.optaplanner.core.api.solver.event.SolverEventListener;

19.5.4. Score Calculator

The interface SimpleScoreCalculator has been renamed to EasyScoreCalculator to avoid confusion with SimpleScore and SimpleScore: it can return other Score types. The package name has also changed.

Previously in *.java :

import org.optaplanner.core.impl.score.director.simple.SimpleScoreCalculator;

public class CloudBalancingEasyScoreCalculator implements SimpleScoreCalculator<CloudBalance> {
    ...
}

Now in *.java :

import org.optaplanner.core.impl.score.director.easy.EasyScoreCalculator;

public class CloudBalancingEasyScoreCalculator implements EasyScoreCalculator<CloudBalance> {
    ...
}

Previously in *SolverConfig.xml and *BenchmarkConfig.xml :

<simpleScoreCalculatorClass>org.optaplanner.examples.cloudbalancing.solver.score.CloudBalancingEasyScoreCalculator<simpleScoreCalculatorClass>

Now in *SolverConfig.xml and *BenchmarkConfig.xml :

<easyScoreCalculatorClass>org.optaplanner.examples.cloudbalancing.solver.score.CloudBalancingEasyScoreCalculator

The BendableScore configuration has changed: …​LevelCount has been renamed to …​LevelsSize.

Previously in *SolverConfig.xml and *BenchmarkConfig.xml :

<scoreDirectorFactory>
  <scoreDefinitionType>BENDABLE</scoreDefinitionType>
  <bendableHardLevelCount>2</bendableHardLevelCount>
  <bendableSoftLevelCount>3</bendableSoftLevelCount>
  ...
</scoreDirectorFactory>

Now in *SolverConfig.xml and *BenchmarkConfig.xml :

<scoreDirectorFactory>
  <scoreDefinitionType>BENDABLE</scoreDefinitionType>
  <bendableHardLevelsSize>2</bendableHardLevelsSize>
  <bendableSoftLevelsSize>3</bendableSoftLevelsSize>
  ...
</scoreDirectorFactory>
Red Hat logoGithubRedditYoutubeTwitter

Learn

Try, buy, & sell

Communities

About Red Hat Documentation

We help Red Hat users innovate and achieve their goals with our products and services with content they can trust.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.

About Red Hat

We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.

© 2024 Red Hat, Inc.