Introduction
============

Drools Planner isn't always backwards compatible at this time.
This file describes how can you upgrade from earlier versions to the latest.

Starting from 5.1.0, every migration change has an indication
on how likely your code is going to be affected by this change:
- [MAJOR] Very likely affects your code.
- [MINOR] Probably does not affect your code (especially if you followed the examples), unless you have hacks.
- [RECOMMENDED] Not a backward incompatible change, but you probably want to do this.
- [README] Read this to better understand why the following MAJOR change was made.

From 5.0.0-m2 to 5.0.0
----------------------

No backwards incompatible changes.

From 5.0.0 to 5.0.1
-------------------

A score is no longer a double, now it's a Score instance,
because a SimpleScore is now just an int and a HardAndSoftScore is now 2 separated ints.


In the Solver interface, the return type of the getBestScore() method changed:
Before:
    double score = solver.getBestScore();
After:
    Score score = solver.getBestScore();


Simple scores are written "-999", and hard and soft scores are written "-999hard/-999soft".
You will see this in the examples GUI.
In the *ScoreConfig.xml, configuring a feasableScore also reflects this.
Before with simple score:
    <finish>
        <feasableScore>-123456789.0</feasableScore>
    </finish>
After:
    <finish>
        <feasableScore>-123456789</feasableScore>
    </finish>
Before with hard and soft score (Note that the hard part started from 1000000):
    <finish>
        <feasableScore>-123456789.0</feasableScore>
    </finish>
After:
    <finish>
        <feasableScore>-123hard/-456789soft</feasableScore>-->
    </finish>


In the *ScoreConfig.xml, you no longer configure a ScoreCalculator,
but now you configure a ScoreDefinition instead.

Before:
    <scoreCalculator>
        <scoreCalculatorType>SIMPLE</scoreCalculatorType>
    </scoreCalculator>
After:
    <scoreDefinition>
        <scoreDefinitionType>SIMPLE</scoreDefinitionType>
    </scoreDefinition>

Before:
    <scoreCalculator>
        <scoreCalculatorType>HARD_AND_SOFT_CONSTRAINTS</scoreCalculatorType>
    </scoreCalculator>
After:
    <scoreDefinition>
        <scoreDefinitionType>HARD_AND_SOFT</scoreDefinitionType>
    </scoreDefinition>

DYNAMIC_HARD_AND_SOFT_CONSTRAINTS was bugged and has been removed, but will be replaced
by shiftingPenalty support.
Before:
    <scoreCalculator>
        <scoreCalculatorType>DYNAMIC_HARD_AND_SOFT_CONSTRAINTS</scoreCalculatorType>
    </scoreCalculator>
After:
    <scoreDefinition>
        <scoreDefinitionType>HARD_AND_SOFT</scoreDefinitionType>
    </scoreDefinition>

From 5.0.1 to 5.1.0.M1
----------------------

In 5.1.0.m2, Drools Solver has been renamed to Drools Planner,
and it's best to do that first. See "From 5.1.0.m1 to 5.1.0.m2".


The method Solver.cancel() has been renamed to Solver.terminateEarly()
because it does not undo the solving but terminates it early and there's a best solution.
Before:
    solver.cancel();
After:
    solver.terminateEarly();

Likewise, Solver.isCancelled() has been renamed to Solver.isTerminatedEarly().
Before:
    solver.isCancelled();
After:
    solver.isTerminatedEarly();


The interface Finish has been renamed to Termination
because Termination seems the defacto standard name for it in the literature.
Before:
   ... extends Finish
After:
   ... extends Termination
Before in solver config xml's and benchmarker config xml's :
    <finish>
        ...
    </finish>
After:
    <termination>
        ...
    </termination>

Likewise FinishCompositionStyle has been renamed to TerminationCompositionStyle.
Before in solver config xml's and benchmarker config xml's :
        <finishCompositionStyle>...</finishCompositionStyle>
After:
        <terminationCompositionStyle>...</terminationCompositionStyle>

The Finish.isFinished(...) has been renamed to Termination.isTerminated().
Before:
   .isFinished(...)
After:
   .isTerminated(...)


The class FeasableScoreTermination has been renamed to ScoreAttainedTermination.
Its property feasableScore has been renamed to scoreAttained.
Before in solver config xml's and benchmarker config xml's :
    <termination>
        <feasableScore>...</feasableScore>
    </termination>
After:
    <termination>
        <scoreAttained>...</scoreAttained>
    </termination>


The interface Solution now has a Score property: Solution.getScore() and Solution.getScore()
Before:
    public class ... implements Solution {
        ...
    }
After if you use a SimpleScore:
    public class ... implements Solution {
        ...
        private SimpleScore score;
        ...
        public SimpleScore getScore() {
            return score;
        }
        public void setScore(Score score) {
            this.score = (SimpleScore) score;
        }
        ...
    }
After if you use a HardAndSoftScore:
    public class ... implements Solution {
        ...
        private HardAndSoftScore score;
        ...
        public HardAndSoftScore getScore() {
            return score;
        }
        public void setScore(Score score) {
            this.score = (HardAndSoftScore) score;
        }
        ...
    }

The score property of a Solution needs to be cloned:
Before:
    public X cloneSolution() {
        X clone = new X();
        ...
        return clone;
    }
After:
    public X cloneSolution() {
        X clone = new X();
        ...
        clone.score = score;
        return clone;
    }

The Solver interface no longer has a method Solver.getBestScore().
Before:
     solver.getBestScore()
After:
     solver.getBestSolution().getScore()


From 5.1.0.M1 to 5.1.0.M2
-------------------------

Drools Solver has been renamed to Drools Planner.

The maven dependency has been renamed to drools-planner-core.
Before in pom.xml:
    <dependency>
        <groupId>org.drools.solver</groupId>
        <artifactId>drools-solver-core</artifactId>
        ...
    </dependency>
After in pom.xml:
    <dependency>
        <groupId>org.drools.planner</groupId>
        <artifactId>drools-planner-core</artifactId>
        ...
    </dependency>
And resync your IDE (IntelliJ, Eclipse, Netbeans) from the pom.xml files.
If you're still using ANT, replace drools-solver-core-?.jar with drools-planner-core-?.jar
and adjust your ANT script and your IDE's classpath accordingly.

The package has been renamed to org.drools.planner
Before in *.java, *.drl:
    import org.drools.solver...
After in *.java, *.drl:
    import org.drools.planner...

Note that the Solver interface and several related classes have NOT been renamed to Planner (yet).


TerminationConfig's maximumHouresSpend renamed to maximumHoursSpend
Before:
     <maximumHouresSpend>2</maximumHouresSpend>
After:
     <maximumHoursSpend>2</maximumHoursSpend>


Accepter has been renamed to Acceptor
Before:
    <accepter>
        ...
    </accepter>
After:
    <acceptor>
        ...
    </acceptor>


The method DefaultDecider.setAssertUndoMoveIsUncorrupted() has been renamed.
Use the EnvironmentMode debug instead.
Before in *.java:
    (DefaultDecider ((DefaultLocalSearchSolver) solver).getDecider()).setVerifyUndoMoveIsUncorrupted(true);
Before in *.xml:
    <localSearchSolver>
        ...
    </localSearchSolver>
After in *.xml:
    <localSearchSolver>
        <environmentMode>DEBUG</environmentMode>
        ...
    </localSearchSolver>


True modify has been implemented. This is a great performance boost.
Before in *.java:
    workingMemory.modifyRetract(xHandle); // before changes are made
    x.set...;
    workingMemory.modifyInsert(xHandle, x); // after changes are made
After in *.java:
    x.set...;
    workingMemory.update(queenHandle, queen); // after changes are made


Environment mode DEBUG now checks more and therefor it is slower than before.


JBRULES-1804 has been fixed. The HACK to fix wierd truth maintenance behavior is now obsolete.
Delete any instances of that hack to make your rules easier to read and faster.
Before in *.drl:
        // HACK to fix wierd truth maintenance behavior in drools
        // because making weight part of the equals/hashcode doesn't cut it
        // Vote for https://jira.jboss.org/jira/browse/JBRULES-1804
        not IntConstraintOccurrence(
            ruleId == "...",
            constraintType == ConstraintType....,
            causes contains $..., causes contains $...,
            eval(weight != (...))
        );
    then ...
After in *.drl:
    then ...


A custom ConstraintOccurrence implementation should now use the weight in its equals/hashcode methods.
IntConstraintOccurrence and DoubleConstraintOccurrence have been changed as needed.


From 5.1.0.M2 to 5.1.0.CR1
--------------------------

Custom ScoreDefinition implementations needs to implement the Double translateScoreToGraphValue(S score) method.
After in *ScoreDefinition.java:
    public Double translateScoreToGraphValue(HardAndSoftScore score) {
        if (score.getHardScore() == 0) {
            return Double.valueOf(score.getSoftScore());
        } else {
            return null;
        }
    }

A benchmarker config no longer supports solvedSolutionVerbosity (only ALL was supported anyway).
Before in *BenchmarkConfig.xml:
   <solvedSolutionVerbosity>ALL</solvedSolutionVerbosity>

A benchmarker config now needs a benchmarkDirectory directory
and solvedSolutionFilesDirectory and solverStatisticFilesDirectory are no longer required.
Before in *BenchmarkConfig.xml:
    <solverBenchmarkSuite>
        <solvedSolutionFilesDirectory>local/data/nurserostering/solved</solvedSolutionFilesDirectory>
        ...
        <solverStatisticFilesDirectory>local/data/nurserostering/statistic</solverStatisticFilesDirectory>
        ...
After in *BenchmarkConfig.xml:
    <solverBenchmarkSuite>
        <benchmarkDirectory>local/data/nurserostering</benchmarkDirectory>
        ...

Benchmarker: the class MaxScoreSolverBenchmarkComparator has been renamed to WorstScoreSolverBenchmarkComparator.

A benchmarker no longer uses WorstScoreSolverBenchmarkComparator by default.
It now uses TotalScoreSolverBenchmarkComparator by default.

The benchmarker method writeResults(resultFile) has been removed.
The result is now always written at the end of the benchmark() method
in the benchmarkDirectory directory in a file called benchmarkResult.xml.
Before in *.java:
    solverBenchmarker.writeResults(...);


The method Score.substract(subtrahend) has been renamed to Score.subtract
Before in *Score.java:
    public ...Score substract(...Score subtrahend) {
After in *Score.java:
    public ...Score subtract(...Score subtrahend) {

Custom Score implementation: When rounding is needed, it should now be floored (as defined by Math.floor(double)).


A selector no longer supports absoluteSelection and relativeSelection, because it was inefficient.
Instead, the forager now supports minimalAcceptedSelection, which only counts doable, accepted moves
(instead of all the selected moves).
As a guideline, set your minimalAcceptedSelection to the sum of all your absoluteSelection and subtract 10%.
Before in *Config.xml:
    <selector>
        <selector>
            <moveFactoryClass>...ChangeMoveFactory</moveFactoryClass>
            <absoluteSelection>500</absoluteSelection>
        </selector>
        <selector>
            <moveFactoryClass>...SwitchMoveFactory</moveFactoryClass>
            <absoluteSelection>500</absoluteSelection>
        </selector>
    </selector>
    ...
    <forager>
        <foragerType>MAX_SCORE_OF_ALL</foragerType>
    </forager>
After in *Config.xml:
    <selector>
        <selector>
            <moveFactoryClass>...ChangeMoveFactory</moveFactoryClass>
        </selector>
        <selector>
            <moveFactoryClass>...SwitchMoveFactory</moveFactoryClass>
        </selector>
    </selector>
    ...
    <forager>
        <foragerType>MAX_SCORE_OF_ALL</foragerType>
        <minimalAcceptedSelection>900</minimalAcceptedSelection>
    </forager>
If you weighted some MoveFactory heavier than another, vote for https://jira.jboss.org/browse/JBRULES-2553.

If you use a custom selector: the Selector interface method
  List<Move> selectMoveList(StepScope stepScope)
has been replaced by the more efficient method
  Iterator<Move> moveIterator(StepScope stepScope)
Before in *Selector.java:
    public List<Move> selectMoveList(StepScope stepScope) {
        ...
        return moveList;
    }
After in *Selector.java:
    public Iterator<Move> moveIterator(StepScope stepScope) {
        ...
        return moveList.iterator();
    }

There's now a decent simulated annealing implementation.
In many use cases it clearly beats the tabu search implementation.
See the reference manual and the nurse rostering example for more info.

The ForagerType has been renamed to the PickEarlyType.
The ForagerType MAX_SCORE_OF_ALL is now the PickEarlyType NEVER. It is also the default.
Before in *Config.xml:
    <forager>
        <foragerType>MAX_SCORE_OF_ALL</foragerType>
        ...
    </forager>
After in *Config.xml:
    <forager>
        ...
    </forager>
The ForagerType FIRST_BEST_SCORE_IMPROVING is the PickEarlyType FIRST_BEST_SCORE_IMPROVING.
Before in *Config.xml:
    <forager>
        <foragerType>FIRST_BEST_SCORE_IMPROVING</foragerType>
        ...
    </forager>
After in *Config.xml:
    <forager>
        <pickEarlyType>FIRST_BEST_SCORE_IMPROVING</pickEarlyType>
        ...
    </forager>
The ForagerType FIRST_LAST_STEP_SCORE_IMPROVING is now the PickEarlyType FIRST_LAST_STEP_SCORE_IMPROVING.
Before in *Config.xml:
    <forager>
        <foragerType>FIRST_LAST_STEP_SCORE_IMPROVING</foragerType>
        ...
    </forager>
After in *Config.xml:
    <forager>
        <pickEarlyType>FIRST_LAST_STEP_SCORE_IMPROVING</pickEarlyType>
        ...
    </forager>
The ForagerType FIRST_RANDOMLY_ACCEPTED has been removed, use the PickEarlyType NEVER with minimalAcceptedSelection 1.
Before in *Config.xml:
    <forager>
        <foragerType>FIRST_RANDOMLY_ACCEPTED</foragerType>
    </forager>
After in *Config.xml:
    <forager>
        <pickEarlyType>NEVER</pickEarlyType>
        <minimalAcceptedSelection>1</minimalAcceptedSelection>
    </forager>


The benchmarker no longer sorts the solvers, because that was confusing to read.
Instead it outputs a table with a ranking column.
You can still set a custom solverBenchmarkComparator to influence that ranking.
Before in *BenchmarkConfig.xml:
    <sortSolverBenchmarks>true</sortSolverBenchmarks>


From 5.1.0 to 5.2.0.M1
----------------------

[RECOMMENDED] The example DRL's no longer use the optional character ';' at the end of lines in the LHS.
If you copied that practice from the examples, it's recommended to remove them from your DRL's too.


From 5.2.0.M1 to 5.2.0.M2
-------------------------

[MINOR] XmlSolverConfigurer.buildSolver() no longer returns a LocalSearchSolver, now it returns just a Solver.
Since LocalSearchSolver is just an empty interface which extends the Solver interface, the impact should be small.
Before in *.java:
    LocalSearchSolver solver = xmlSolverConfigurer.buildSolver();
After in *.java:
    Solver solver = xmlSolverConfigurer.buildSolver();


[MAJOR] EnvironmentMode has been moved to another package.
Before in *.java:
    import org.drools.planner.config.localsearch.EnvironmentMode;
After in *.java:
    import org.drools.planner.config.EnvironmentMode;


[MINOR] XmlSolverConfigurer's getConfig() method now returns an AbstractSolverConfig instead of a LocalSearchSolverConfig.
If you used anything LocalSearchSolverConfig specific, such as a TerminationConfig, then you have to cast it...
Before in *.java:
    configurer.getConfig().getTerminationConfig().setMaximumSecondsSpend(maximumSecondsSpend);
After in *.java:
    ((LocalSearchSolverConfig) configurer.getConfig()).getTerminationConfig()
            .setMaximumSecondsSpend(maximumSecondsSpend);


[MAJOR] The StartingSolutionInitializer methods no longer have a LocalSearchSolverScope argument,
but now have a AbstractSolverScope argument.
Before in *.java:
    public boolean isSolutionInitialized(LocalSearchSolverScope localSearchSolverScope) {
        ...
    }
    public void initializeSolution(LocalSearchSolverScope localSearchSolverScope) {
        ...
    }
After in *.java:
    public boolean isSolutionInitialized(AbstractSolverScope abstractSolverScope) {
        ...
    }
    public void initializeSolution(AbstractSolverScope abstractSolverScope) {
        ...
    }

[MINOR] StepScope has been renamed to LocalSearchStepScope.
This only impacts you if you use a custom Selector.
Before in *Selector.java:
    @Override
    public void ...(StepScope stepScope) {
        ...
    }
After in *Selector.java:
    @Override
    public void ...(LocalSearchStepScope localSearchStepScope) {
        ...
    }

[MINOR] The Score has a new method: double[] toDoubleArray()
If you use a custom Score implementation, you need to implement it:
After in *Score.java:
    public double[] toDoubleArray() {
        return new double[]{hardScore, softScore, ...};
    }

[MINOR] SelectorConfig, AcceptorConfig and ForagerConfig's build method now have a ScoreDefinition argument.
If you use any custom implementation for any of them, you need to adjust your method signature.
Before in *SelectorConfig.java:
    public Selector buildSelector() {
After in *SelectorConfig.java:
    public Selector buildSelector(ScoreDefinition scoreDefinition) {
Before in *AcceptorConfig.java:
    public Acceptor buildAcceptor() {
After in *AcceptorConfig.java:
    public Acceptor buildAcceptor(ScoreDefinition scoreDefinition) {
Before in *ForagerConfig.java:
    public Forager buildForager() {
After in *ForagerConfig.java:
    public Forager buildForager(ScoreDefinition scoreDefinition) {

[MAJOR] Simulated annealing now supports working with hard constraints too (JBRULES-2911)
The starting temperature (usually close the maximum score delta) is now a Score instead of a double.
Before in *Config.xml:
    <simulatedAnnealingStartingTemperature>20.0</simulatedAnnealingStartingTemperature>
After in *Config.xml (if you're using HardAndSoftScore):
    <simulatedAnnealingStartingTemperature>0hard/20soft</simulatedAnnealingStartingTemperature>
After in *Config.xml (if you're using SimpleScore):
    <simulatedAnnealingStartingTemperature>20</simulatedAnnealingStartingTemperature>

[MAJOR] Solution now has a generic type of Score: Solution<S extends Score> (JBRULES-2924)
Your Solution implementation itself should not be generic, but it should define it's Score type through implements.
Before in *.java if you use a SimpleScore:
    public class ... implements Solution {
        ...
        public void setScore(Score score) {
            this.score = (SimpleScore) score;
        }
        ...
    }
After in *.java if you use a SimpleScore:
    public class ... implements Solution<SimpleScore> {
        ...
        public void setScore(SimpleScore score) {
            this.score = score;
        }
        ...
    }
Before in *.java if you use a HardAndSoftScore:
    public class ... implements Solution {
        ...
        public void setScore(Score score) {
            this.score = (HardAndSoftScore) score;
        }
        ...
    }
After in *.java if you use a HardAndSoftScore:
    public class ... implements Solution<HardAndSoftScore> {
        ...
        public void setScore(HardAndSoftScore score) {
            this.score = score;
        }
        ...
    }

[RECOMMENDED] If you've followed the examples (which is normally a good thing),
check if your solutionEquals() and solutionHashCode() methods respects the hashcode/equals contract,
because some of the examples did not.
Before in *.java:
    public boolean solutionEquals(Object o) {
        ...
            return new EqualsBuilder()
                    .append(id, other.id)
                    .append(guest, other.guest)
                    .append(seat, other.seat)
                    .isEquals();
        ...
    }
    public int solutionHashCode() {
        return new HashCodeBuilder()
                .append(seat)
                .toHashCode();
    }
After in *.java:
    public boolean solutionEquals(Object o) {
        ...
            return new EqualsBuilder()
                    .append(id, other.id)
                    .append(guest, other.guest)
                    .append(seat, other.seat)
                    .isEquals();
        ...
    }
    public int solutionHashCode() {
        return new HashCodeBuilder()
                .append(id)
                .append(guest)
                .append(seat)
                .toHashCode();
    }

[MINOR] Your SolverEventListener will now a BestSolutionChangedEvent when the Solver starts too.
So when the StartingSolutionInitializer initializes, the best solution changed event won't be missed.


From 5.2.0.M2 to 5.2.0.CR1
--------------------------

[MAJOR] The Benchmarker configuration XML schema has changed.
The entities inheritedUnsolvedSolutionFile and inheritedLocalSearchSolver are now wrapped
in a inheritedSolverBenchmark entity and renamed to unsolvedSolutionFile and localSearchSolver.
Before in *BenchmarkConfig.xml:
    <inheritedUnsolvedSolutionFile>...</inheritedUnsolvedSolutionFile>
    <inheritedUnsolvedSolutionFile>...</inheritedUnsolvedSolutionFile>
    ...

    <inheritedLocalSearchSolver>
        <scoreDrl>...</scoreDrl>
        ...
    </inheritedLocalSearchSolver>
After in *BenchmarkConfig.xml:
    <inheritedSolverBenchmark>
        <unsolvedSolutionFile>...</unsolvedSolutionFile>
        <unsolvedSolutionFile>...</unsolvedSolutionFile>
        ...

        <localSearchSolver>
            <scoreDrl>...</scoreDrl>
            ...
        </localSearchSolver>
    </inheritedSolverBenchmark>

From 5.2.0 to 5.3.0.Beta1
-------------------------

[MINOR] If you implemented a custom Acceptor, the buildAcceptor method's signature has changed.
Before in *AcceptorConfig.java:
    public Acceptor buildAcceptor(ScoreDefinition scoreDefinition) {
After in *AcceptorConfig.java:
    public Acceptor buildAcceptor(EnvironmentMode environmentMode, ScoreDefinition scoreDefinition) {

[MAJOR] You need to define your solution class in the configuration now:
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
    <localSearchSolver>
      <scoreDrl>...</scoreDrl>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
    <localSearchSolver>
      <solutionClass>org.drools.planner.examples.curriculumcourse.domain.CurriculumCourseSchedule</solutionClass>
      <scoreDrl>...</scoreDrl>

[README] Understand the concept of a "planning entity" class.
The class (or classes) that change during planning (and do not implement Solution) are a planning entity.
For example: ShiftAssignment, BedDesignation, Queen, CloudAssignment, ...
The other domain classes are considered normal planning facts,
for example Shift, Employee, Bed, Room, Department, ...
They do not change during planning (at least not without pausing the solver).
Read the manual to understand the "planning entity" concept better.

[MAJOR] You need to define your planning entity class(es) in the configuration now:
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
    <localSearchSolver>
      <solutionClass>...</solutionClass>
      <scoreDrl>...</scoreDrl>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
    <localSearchSolver>
      <solutionClass>...</solutionClass>
      <planningEntityClass>org.drools.planner.examples.curriculumcourse.domain.Lecture</planningEntityClass>
      <scoreDrl>...</scoreDrl>

[MAJOR] You need to annotate your planning entity class(es) with the @PlanningEntity annotation
Before in *.java:
    public class Lecture ... {
        ...
    }
After in *.java:
    @PlanningEntity
    public class Lecture ... {
        ...
    }

[README] Understand the concept of a "planning variable" property.
The property (or properties) on a planning entity class that are changed (through their setter) during planning
are planning variables.
For example: ShiftAssignment.getEmployee(), BedDesignation.getBed(), Queen.getY(), ...
Note that most planning entities have 1 property which defines the planning entity
and that property is NOT a planning variable.
For example: ShiftAssignment.getShift(), BedDesignation.getAdmissionPart(), Queen.getX(), ...
Read the manual to understand the "planning variable" concept better.

[MAJOR] You need to annotate your planning variable property(ies) with the @PlanningVariable annotation.
Furthermore, you need to annotate a @ValueRange* annotation on to define the allowed values.
Commonly, you 'll use @ValueRangeFromSolutionProperty (recommended) which specifies a property name on the solution
which returns a collection of the allowed values for that variable.
If you can't use @ValueRangeFromSolutionProperty, use @ValueRangeUndefined instead (not recommended),
but that will exclude you from using construction heuristics.
Before in *.java:
    @PlanningEntity
    public class Lecture ... {

        private Course course;
        private int lectureIndexInCourse;

        // Changed by moves, between score calculations.
        private Period period;
        private Room room;

        public Course getCourse() {...}
        public void setCourse(Course course) {...}

        public int getLectureIndexInCourse() {...}
        public void setLectureIndexInCourse(int lectureIndexInCourse) {...}

        public Period getPeriod() {...}
        public void setPeriod(Period period) {...}

        public Room getRoom() {...}
        public void setRoom(Room room) {...}

        ...

        public int getStudentSize() {
            return course.getStudentSize();
        }

        public Day getDay() {
            return period.getDay();
        }

    }
After in *.java:
    @PlanningEntity
    public class Lecture ... {

        private Course course;
        private int lectureIndexInCourse;

        // Planning variables: changes during planning, between score calculations.
        private Period period;
        private Room room;

        // This is not a PlanningVariable: it defines the planning entity
        public Course getCourse() {...}
        public void setCourse(Course course) {...}

        // This is not a PlanningVariable: it defines the planning entity
        public int getLectureIndexInCourse() {...}
        public void setLectureIndexInCourse(int lectureIndexInCourse) {...}

        @PlanningVariable
        @ValueRangeFromSolutionProperty(propertyName = "periodList")
        public Period getPeriod() {...}
        public void setPeriod(Period period) {...}

        @PlanningVariable
        @ValueRangeFromSolutionProperty(propertyName = "roomList")
        public Room getRoom() {...}
        public void setRoom(Room room) {...}

        ...

        // This is not a PlanningVariable: no setter
        public int getStudentSize() {
            return course.getStudentSize();
        }

        // This is not a PlanningVariable: no setter
        public Day getDay() {
            return period.getDay();
        }

    }

[MAJOR] Annotate every property on your Solution that returns a collection of planning entities
with @PlanningEntityCollectionProperty.
Before in *.java:
    public class CurriculumCourseSchedule ... implements Solution<...> {

        private List<Lecture> lectureList;

        ...

        public List<Lecture> getLectureList() {...}
        public void setLectureList(List<Lecture> lectureList) {...}

    }
After in *.java:
    public class CurriculumCourseSchedule ... implements Solution<...> {

        private List<Lecture> lectureList;

        ...

        @PlanningEntityCollectionProperty
        public List<Lecture> getLectureList() {...}
        public void setLectureList(List<Lecture> lectureList) {...}

    }
If you have a property that returns a single planning entity (instead of a collection), use @PlanningEntityProperty.

[MAJOR] The method getFacts() is renamed to getProblemFacts() and should no longer include planning entities.
Every planning entity is now automatically inserted into the working memory if and only if it is initialized.
When it's initialized later, it's also automatically inserted.
Remove the adding of the planning entities in the getFacts() method.
Before in *.java:
    public class ... implements Solution<...> {

        public Collection<? extends Object> getFacts() {
            List<Object> facts = new ArrayList<Object>();
            facts.addAll(teacherList);
            ...
            facts.addAll(calculateTopicConflictList());
            if (isInitialized()) {
                facts.addAll(lectureList);
            }
            return facts;
        }

    }
After in *.java:
    public class ... implements Solution<...> {

        public Collection<? extends Object> getProblemFacts() {
            List<Object> facts = new ArrayList<Object>();
            facts.addAll(teacherList);
            ...
            facts.addAll(calculateTopicConflictList());
            // Do not add the planning entity's (lectureList) because that will be done automatically
            return facts;
        }

    }

[README] A planning entity is considered uninitialized if one if at least on of its planning variables is null.
Therefor it's now possible to start planning from a partially initialized starting solution,
for example during real-time re-planning after facts change.

[MAJOR] The StartingSolutionInitializer no longer has a isSolutionInitialized(AbstractSolverScope) method.
The StartingSolutionInitializer should now be smart enough to do nothing if the solution is partially initialized
Before in *StartingSolutionInitializer.java:
    public class ...StartingSolutionInitializer extends AbstractStartingSolutionInitializer {

        @Override
        public boolean isSolutionInitialized(AbstractSolverScope abstractSolverScope) {
            ...
        }

        ...

    }
After in *StartingSolutionInitializer.java:
    public class ...StartingSolutionInitializer extends AbstractStartingSolutionInitializer {

        ...

    }
Note that you'll probably want to remove the StartingSolutionInitializer altogether
and replace it by a construction heuristic (see below).

[MAJOR] The planning entity collection in the Solution can never be null,
but some (or all) of its planning entity's can be uninitialized.
So create them before setting the starting solution, instead of in your StartingSolutionInitializer.
Before in *.java:
    public class ... {

        public void ...() {
            CurriculumCourseSchedule schedule = new CurriculumCourseSchedule();
            schedule.setTeacherList(teacherList);
            schedule.setCourseList(courseList);
            ...
            solver.setStartingSolution(schedule);
        }

    }
After in *.java:
    public class ... {

        public void ...() {
            CurriculumCourseSchedule schedule = new CurriculumCourseSchedule();
            schedule.setTeacherList(teacherList);
            schedule.setCourseList(courseList);
            ...
            createLectureList(schedule);
            solver.setStartingSolution(schedule);
        }

        private void createLectureList(CurriculumCourseSchedule schedule) {
            List<Course> courseList = schedule.getCourseList();
            List<Lecture> lectureList = new ArrayList<Lecture>(courseList.size());
            long id = 0L;
            for (Course course : courseList) {
                for (int i = 0; i < course.getLectureSize(); i++) {
                    Lecture lecture = new Lecture();
                    lecture.setId(id);
                    id++;
                    lecture.setCourse(course);
                    // Make sure to set all non PlanningVariable properties
                    lecture.setLectureIndexInCourse(i);
                    // Notice that we leave the PlanningVariable properties on null
                    lectureList.add(lecture);
                }
            }
            schedule.setLectureList(lectureList);
        }

    }

[RECOMMENDED] Remove the isInitialized() from Solution if you copied that from the examples.
Before in *.java:
    public class ... implements Solution<...> {

        public boolean isInitialized() {
            return (lectureList != null);
        }
        
        ...

    }
After in *.java:
    public class ... implements Solution<...> {

        ...

    }

[README] Phasing: a Solver can now have multiple phases.
Each phase runs an algorithm, such as local search (tabu search, simulated annealing, ...),
construction heuristic (first fit, first fit decreasing, best fit decreasing, ...), ...
The phasing algorithms are executed sequentially.
For example, it's now easy to do 5 minutes of simulated annealing, followed by 5 minutes of tabu search.

[MAJOR] The local search solver is now a local search solver phase.
Before in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <localSearchSolver>
        ...
      <termination>
        ...
      </termination>
      <selector>
        ...
      </selector>
      <acceptor>
        ...
      </acceptor>
      <forager>
        ...
      </forager>
    </localSearchSolver>
After in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <solver>
        ...
      <termination>
        ...
      </termination>
      <localSearch>
        <selector>
          ...
        </selector>
        <acceptor>
          ...
        </acceptor>
        <forager>
          ...
        </forager>
      </localSearch>
    </solver>
Note: it's also possible to set a termination per phase.
Warning: some terminations are not supported on the solver level, only on the phase level. For example maximumStepCount:
    <termination>
      <maximumStepCount>100</maximumStepCount><!-- ERROR -->
    </termination>
    <localSearch>
      <termination>
        <maximumStepCount>100</maximumStepCount><!-- OK -->
      </termination>
      ...
    </localSearch>
Warning for *SolverBenchmarkConfig.xml:
  If the <inheritedSolverBenchmark> contains a <selector>, <acceptor> or <forager>,
  that can no longer be inherited individually. Copy the <selector>, <acceptor> or <forager> to every <solverBenchmark>.
  Because a benchmark specific <localSearch> will not overwrite the inheriting <localSearch>,
  but instead add an extra localSearch phase, which will result in 2 separate, sequential localSearch phases.

[README] The StartingSolutionInitializer interface has been removed.
Instead, there's now out-of-the-box support for several construction heuristics.
These implementations are fast, scalable and configurable. They require little or no domain specific code.
They also support features like terminateEarly, logging, partially initialized starting solutions, ...
Alternatively, you can also refactor it to a CustomSolverPhaseCommand,
which has the same freedom (to write lots of custom code) as a StartingSolutionInitializer had.

[MAJOR] Replacing the StartingSolutionInitializer by a construction heuristics (recommended)
Before in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <startingSolutionInitializerClass>org.drools.planner.examples.examination.solver.solution.initializer.ExaminationStartingSolutionInitializer</startingSolutionInitializerClass>
    <termination>...</termination>
After in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <termination>...</termination>
    <constructionHeuristic>
      <constructionHeuristicType>FIRST_FIT</constructionHeuristicType>
      <!-- Speedup that can be applied to most, but not all use cases (see manual): -->
      <!-- <constructionHeuristicPickEarlyType>FIRST_LAST_STEP_SCORE_EQUAL_OR_IMPROVING</constructionHeuristicPickEarlyType> -->
    </constructionHeuristic>
But it's better to use the constructionHeuristicType FIRST_FIT_DECREASING instead,
however you'll need to implement create a difficultyComparatorClass or difficultyWeightFactoryClass
and configure that on your planning entity class:
    @PlanningEntity(difficultyComparatorClass = CloudAssignmentDifficultyComparator.class)
    public class CloudAssignment ...
    @PlanningEntity(difficultyWeightFactoryClass = LectureDifficultyWeightFactory.class)
    public class Lecture ...

[MINOR] Replacing the StartingSolutionInitializer by a CustomSolverPhaseCommand (not recommended)
Before in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <startingSolutionInitializerClass>org.drools.planner.examples.examination.solver.solution.initializer.ExaminationStartingSolutionInitializer</startingSolutionInitializerClass>
    <termination>...</termination>
After in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <termination>...</termination>
    <customSolverPhase>
      <customSolverPhaseCommandClass>org.drools.planner.examples.examination.solver.solution.initializer.ExaminationStartingSolutionInitializer</customSolverPhaseCommandClass>
    </customSolverPhase>
Before in *StartingSolutionInitializer.java:
    public class ...StartingSolutionInitializer extends AbstractStartingSolutionInitializer {

        public void initializeSolution(DefaultSolverScope solverScope) {
            // Initialize the solution
            ... solverScope.getWorkingMemory() ...
            ... solverScope.calculateScoreFromWorkingMemory() ...
        }

        ...
    }
After in *StartingSolutionInitializer.java:
    public class ...StartingSolutionInitializer implements CustomSolverPhaseCommand {

        protected final transient Logger logger = LoggerFactory.getLogger(getClass());

        public void changeWorkingSolution(SolutionDirector solutionDirector) {
            // Initialize the solution
            ... solutionDirector.getWorkingMemory() ...
            ... solutionDirector.calculateScoreFromWorkingMemory() ...
        }

        ...
    }
Warning: A CustomSolverPhaseCommand can be called with a (partially or complete) initialized solution,
in which case it probably doesn't want to reset the already initialized planning entities.

[MINOR] The AbstractMoveFactory lifecycle methods have changed signature.
If you overwrote them (which is unlikely as most implements use CachedMoveFactory), you'll need to adjust them.
Before in *MoveFactory.java:
    public class ...MoveFactory extends AbstractMoveFactory {

        @Override
        public void solvingStarted(LocalSearchSolverScope localSearchSolverScope) {
            ...
        }

        ...
    }
After in *MoveFactory.java:
    public class ... extends AbstractMoveFactory {

        @Override
        public void phaseStarted(LocalSearchSolverPhaseScope localSearchSolverPhaseScope) {
            ...
        }

        ...
    }
Similar for solvingEnded(LocalSearchSolverScope), which is now phaseEnded(LocalSearchSolverPhaseScope)

[MINOR] The Selector, Acceptor and Forager method have changed signature.
If you implemented a custom Selector, Acceptor or Forager, you 'll need to adjust them.
Before in *Selector.java, *Acceptor.java or *Forager.java:
    public class ...Selector extends AbstractSelector {

        @Override
        public void solvingStarted(LocalSearchSolverScope localSearchSolverScope) {
            ...
        }

        ...
    }
After in *Selector.java, *Acceptor.java or *Forager.java:
    public class ...Selector extends AbstractSelector {

        @Override
        public void phaseStarted(LocalSearchSolverPhaseScope localSearchSolverPhaseScope) {
            ...
        }

        ...
    }
Similar for solvingEnded(LocalSearchSolverScope), which is now phaseEnded(LocalSearchSolverPhaseScope)

[MINOR] TerminationConfig and Termination moved to another package.
Before in  *.java:
    import org.drools.planner.config.localsearch.termination.TerminationConfig;
    import org.drools.planner.core.localsearch.termination.Termination;
After in  *.java:
    import org.drools.planner.config.termination.TerminationConfig;
    import org.drools.planner.core.termination.Termination;
If you implemented a custom Termination: the interface has been changed to separate solver and phase termination.

[MINOR] SolverConfig has been moved to another package.
Before in *.java:
    import org.drools.planner.config.SolverConfig;
After in *.java:
    import org.drools.planner.config.solver.SolverConfig;

[MINOR] Solver.isTerminatedEarly() has been renamed to Solver.isTerminateEarly()
Before in  *.java:
    ... solver.isTerminatedEarly() ...
After in  *.java:
    ... solver.isTerminateEarly() ...

[MINOR] HardPenaltyDeciderScoreComparator has been replaced by FlatteningHardAndSoftScoreComparator
Before in  *.java:
    ... HardPenaltyDeciderScoreComparator ...
After in  *.java:
    ... FlatteningHardAndSoftScoreComparator ...


From 5.3.0.Beta1 to 5.3.0.CR1
-----------------------------

[MAJOR] PlanningFactChange has been renamed to ProblemFactChange (to be in sync with Solution.getProblemFacts())
Similarly, Solver.addPlanningFactChange has been renamed to Solver.addProblemFactChange.
Before in  *.java:
    solver.addPlanningFactChange(new PlanningFactChange() {
        public void doChange(SolutionDirector solutionDirector) {
            ...
    });
After in  *.java:
    solver.addProblemFactChange(new ProblemFactChange() {
        public void doChange(SolutionDirector solutionDirector) {
            ...
        }
    });

[MAJOR] The XmlSolverConfigurer method getConfig() has been renamed to getSolverConfig()
Before in  *.java:
    ... configurer.getConfig() ...
After in  *.java:
    ... configurer.getSolverConfig() ...

[MAJOR] The Solver method setStartingSolution(Solution) has been renamed to setPlanningProblem(Solution)
because using it to set an uninitialized Solution is more likely than to set an initialized starting Solution.
Before in  *.java:
    ... solver.setStartingSolution(...) ...
After in  *.java:
    ... solver.setPlanningProblem(...) ...

[MAJOR] Logging level changes: most debug statements have been changed to trace, most info statements have been changed to debug.
If you were using info logging, you probably want to use debug now.
Before in log4j*.xml:
  <category name="org.drools.planner">
    <priority value="info" />
  </category>
After in log4j*.xml:
  <category name="org.drools.planner">
    <priority value="debug" />
  </category>


From 5.3.0.Final to 5.4.0.Beta1
-------------------------------

[MAJOR] Local search configuration: the complete*TabuSize configuration properties have been renamed to *TabuSize.
Before in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <acceptor>
      <completeSolutionTabuSize>...</completeSolutionTabuSize>
    </acceptor>
After in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <acceptor>
      <solutionTabuSize>...</solutionTabuSize>
    </acceptor>
Before in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <acceptor>
      <completeMoveTabuSize>...</completeMoveTabuSize>
    </acceptor>
After in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <acceptor>
      <moveTabuSize>...</moveTabuSize>
    </acceptor>
Before in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <acceptor>
      <completeUndoMoveTabuSize>...</completeUndoMoveTabuSize>
    </acceptor>
After in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <acceptor>
      <undoMoveTabuSize>...</undoMoveTabuSize>
    </acceptor>
Before in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <acceptor>
      <completePropertyTabuSize>...</completePropertyTabuSize>
    </acceptor>
After in *SolverConfig.xml and *SolverBenchmarkConfig.xml:
    <acceptor>
      <propertyTabuSize>...</propertyTabuSize>
    </acceptor>

[MAJOR] HardAndSoftConstraintScoreCalculator has been renamed to HardAndSoftScoreCalculator.
Before in *ScoreRules.drl:
    import org.drools.planner.core.score.calculator.HardAndSoftConstraintScoreCalculator;
    global HardAndSoftConstraintScoreCalculator scoreCalculator;
After in *ScoreRules.drl:
    import org.drools.planner.core.score.calculator.HardAndSoftScoreCalculator;
    global HardAndSoftScoreCalculator scoreCalculator;

[MAJOR] The build-in Score implementations (including their ScoreCalculator and ScoreDefinition)
have been moved into a package per implementation functionality.
Before in *.java:
    import org.drools.planner.core.score.SimpleScore;
    import org.drools.planner.core.score.DefaultSimpleScore;
    import org.drools.planner.core.score.HardAndSoftScore;
    import org.drools.planner.core.score.DefaultHardAndSoftScore;
After in *.java:
    import org.drools.planner.core.score.buildin.simple.SimpleScore;
    import org.drools.planner.core.score.buildin.simple.DefaultSimpleScore;
    import org.drools.planner.core.score.buildin.hardandsoft.HardAndSoftScore;
    import org.drools.planner.core.score.buildin.hardandsoft.DefaultHardAndSoftScore;
Before in *ScoreRules.drl:
    import org.drools.planner.core.score.calculator.SimpleScoreCalculator;
    import org.drools.planner.core.score.calculator.HardAndSoftScoreCalculator;
After in *ScoreRules.drl:
    import org.drools.planner.core.score.buildin.simple.SimpleScoreCalculator;
    import org.drools.planner.core.score.buildin.hardandsoft.HardAndSoftScoreCalculator;
Before in xstreamed solution files:
    <score class="org.drools.planner.core.score.DefaultSimpleScore" ...>
    <score class="org.drools.planner.core.score.DefaultHardAndSoftScoreScore" ...>
After in xstreamed solution files:
    <score class="org.drools.planner.core.score.buildin.simple.DefaultSimpleScore" ...>
    <score class="org.drools.planner.core.score.buildin.hardandsoft.DefaultHardAndSoftScoreScore" ...>

[MINOR] If you implemented a custom score definition:
DefaultHardAndSoftScoreCalculator has been replaced by HardAndSoftScoreCalculator
Before in *ScoreDefinition.java:
    public ScoreCalculator buildScoreCalculator() {
        return new DefaultHardAndSoftScoreCalculator();
    }
After in *ScoreDefinition.java:
    public ScoreCalculator buildScoreCalculator() {
        return new HardAndSoftScoreCalculator();
    }

[MINOR] If you implemented a custom Acceptor or Forager:
double acceptanceChance has been replaced by boolean accepted.

[MINOR] The examples switched from log4j to logback. This does not affect you.
Drools Planner still uses slf4j, so log4j is  still supported too.

[MAJOR] If you use the Benchmarker: JFreeChart has been upgraded and it's GAV changed.
Upgrade the JFreeChart's groupId in your poms.
After in pom.xml:
    <dependency>
      <groupId>jfree</groupId>
      <artifactId>jfreechart</artifactId>
      ...
    </dependency>
After in pom.xml:
    <dependency>
      <groupId>org.jfree</groupId>
      <artifactId>jfreechart</artifactId>
      ...
    </dependency>


From 5.4.0.Beta1 to 5.4.0.Beta2
-------------------------------

[MAJOR] The class XmlSolverConfigurer has been renamed to XmlSolverFactory
Before in *.java:
    import org.drools.planner.config.XmlSolverConfigurer;
    ...
    protected Solver createSolver() {
        XmlSolverConfigurer configurer = new XmlSolverConfigurer();
        configurer.configure(SOLVER_CONFIG);
        return configurer.buildSolver();
    }
After in *.java:
    import org.drools.planner.config.XmlSolverFactory;
    ...
    protected Solver createSolver() {
        XmlSolverFactory solverFactory = new XmlSolverFactory();
        solverFactory.configure(SOLVER_CONFIG);
        return solverFactory.buildSolver();
    }

[MINOR] XmlSolverFactory.addXstreamAlias() has been renamed to addXstreamAnnotations()
Before in *.java:
    solverFactory.addXstreamAlias(...);
After in *.java:
    solverFactory.addXstreamAnnotations(...);

[MAJOR] The class XmlSolverBenchmarker has moved and been renamed to XmlPlannerBenchmarkFactory.
Before in *.java:
    import org.drools.planner.benchmark.XmlSolverBenchmarker;
    ...
    XmlSolverBenchmarker solverBenchmarker = new XmlSolverBenchmarker().configure(benchmarkConfig);
After in *.java:
    import org.drools.planner.benchmark.config.XmlPlannerBenchmarkFactory;
    ...
    XmlPlannerBenchmarkFactory plannerBenchmarkFactory = new XmlPlannerBenchmarkFactory().configure(benchmarkConfig);

[MAJOR] Benchmarker: the XmlPlannerBenchmarkFactory can now only build a PlannerBenchmark, not run it.
To run a benchmark, call benchmark() on that PlannerBenchmark.
Before in *.java:
    plannerBenchmarkFactory.benchmark();
After in *.java:
    PlannerBenchmark plannerBenchmark = plannerBenchmarkFactory.buildPlannerBenchmark();
    plannerBenchmark.benchmark();

[MINOR] All the classes in the benchmark package have been split-up into a config and a core package.
Look for "org.drools.planner.benchmark" in all your files. Normally you won't have any besides the XmlSolverBenchmarker.
One rare exception is the use of a build-in solverBenchmarkComparator:
Before in *BenchmarkConfig.xml:
    <solverBenchmarkComparator>org.drools.planner.benchmark.WorstScoreSolverBenchmarkComparator</solverBenchmarkComparator>
After in *BenchmarkConfig.xml:
    <solverBenchmarkComparator>org.drools.planner.benchmark.core.comparator.WorstScoreSolverBenchmarkComparator</solverBenchmarkComparator>
Before in *BenchmarkConfig.xml:
    <solverBenchmarkComparator>org.drools.planner.benchmark.TotalScoreSolverBenchmarkComparator</solverBenchmarkComparator>
After in *BenchmarkConfig.xml:
    <solverBenchmarkComparator>org.drools.planner.benchmark.core.comparator.TotalScoreSolverBenchmarkComparator</solverBenchmarkComparator>

[MAJOR] SolverBenchmarkSuite has been renamed to PlannerBenchmark.
Before in *BenchmarkConfig.xml:
    <solverBenchmarkSuite>
      ...
    </solverBenchmarkSuite>
After in *BenchmarkConfig.xml:
    <plannerBenchmark>
      ...
    </plannerBenchmark>

[MAJOR] Benchmarker: <unsolvedSolutionFile> has been renamed to <inputSolutionFile> and moved under <problemBenchmarks>
Before in *BenchmarkConfig.xml:
    <inheritedSolverBenchmark><!-- or <solverBenchmark> -->
      <unsolvedSolutionFile>data/nqueens/unsolved/unsolvedNQueens32.xml</unsolvedSolutionFile>
      <unsolvedSolutionFile>data/nqueens/unsolved/unsolvedNQueens64.xml</unsolvedSolutionFile>
      <solver>
        ...
      </solver>
    </inheritedSolverBenchmark>
After in *BenchmarkConfig.xml:
    <inheritedSolverBenchmark><!-- or <solverBenchmark> -->
      <problemBenchmarks>
        <inputSolutionFile>data/nqueens/unsolved/unsolvedNQueens32.xml</inputSolutionFile>
        <inputSolutionFile>data/nqueens/unsolved/unsolvedNQueens64.xml</inputSolutionFile>
      </problemBenchmarks>
      <solver>
        ...
      </solver>
    </inheritedSolverBenchmark>

[MAJOR] Benchmarker: The XStream to parse the benchmark configuration is now separate from the one to parse the solution files.
The xstreamAnnotatedClass is now set in the problemBenchmarks.
Note: if you prefer to use a different solution file format, you can now easily hook in one with <problemIOClass> (see manual).
Before in *BenchmarkApp.java:
    ...
    plannerBenchmarkFactory.addXstreamAnnotations(NQueens.class);
    ...
After in *BenchmarkApp.java:
    ...
Before in *BenchmarkConfig.xml:
    <problemBenchmarks>
      <inputSolutionFile>data/nqueens/unsolved/unsolvedNQueens32.xml</inputSolutionFile>
      ...
    </problemBenchmarks>
</plannerBenchmark>
After in *BenchmarkConfig.xml:
    <problemBenchmarks>
      <xstreamAnnotatedClass>org.drools.planner.examples.nqueens.domain.NQueens</xstreamAnnotatedClass>
      <inputSolutionFile>data/nqueens/unsolved/unsolvedNQueens32.xml</inputSolutionFile>
      ...
    </problemBenchmarks>

[MAJOR] Benchmarker: <solverStatisticType> has been renamed to <problemStatisticType> and moved under <problemBenchmarks> (in <inheritedSolverBenchmark> or <solverBenchmark>)
Before in *BenchmarkConfig.xml:
    <plannerBenchmark>
      ...
      <solverStatisticType>BEST_SOLUTION_CHANGED</solverStatisticType>
      ...
      <inheritedSolverBenchmark>
        <problemBenchmarks>
          ...
          <inputSolutionFile>data/nqueens/unsolved/unsolvedNQueens64.xml</inputSolutionFile>
          <problemStatisticType>BEST_SOLUTION_CHANGED</problemStatisticType>
        </problemBenchmarks>
        ...
      </inheritedSolverBenchmark>
      ...
    </plannerBenchmark>
After in *BenchmarkConfig.xml:
    <plannerBenchmark>
      ...
      <inheritedSolverBenchmark>
        <problemBenchmarks>
          ...
          <inputSolutionFile>data/nqueens/unsolved/unsolvedNQueens64.xml</inputSolutionFile>
          <problemStatisticType>BEST_SOLUTION_CHANGED</problemStatisticType>
        </problemBenchmarks>
        ...
      </inheritedSolverBenchmark>
      ...
    </plannerBenchmark>

[MINOR] Benchmarker: the solved solution files no longer contain the score the time spend in their filename.
See the statistic/index.html file for those numbers.

[MINOR] Benchmarker: <solverStatisticFilesDirectory> has been renamed to <statisticDirectory>
But it's better not to specify it at all and use the default.
Before in *BenchmarkConfig.xml:
    <plannerBenchmark>
        ...
        <solverStatisticFilesDirectory>local/data/nurserostering/statistic</solverStatisticFilesDirectory>
        ...
After in *BenchmarkConfig.xml:
    <plannerBenchmark>
        ...
        <statisticDirectory>local/data/nurserostering/statistic</statisticDirectory>
        ...

[RECOMMENDED] Rename *SolverBenchmarkConfig.xml to *BenchmarkConfig.xml.
This is to avoid confusion with the more fine-grained SolverBenchmark and SolverBenchmarkConfig classes.
The examples wrongly named their Benchmark configs for example nqueensSolverBenchmarkConfig.xml instead of nqueensBenchmarkConfig.xml.
Before in *BenchmarkApp.java:
    public static final String DEFAULT_SOLVER_BENCHMARK_CONFIG
            = "/org/drools/planner/examples/nqueens/benchmark/nqueensSolverBenchmarkConfig.xml";
After in *BenchmarkApp.java:
    public static final String DEFAULT_BENCHMARK_CONFIG
            = "/org/drools/planner/examples/nqueens/benchmark/nqueensBenchmarkConfig.xml";

[MINOR] The DeciderScoreComparatorFactory has been moved into the Forager
Before in *SolverConfig.xml:
      <localSearch>
        <deciderScoreComparatorFactory>
          <deciderScoreComparatorFactoryType>NATURAL</deciderScoreComparatorFactoryType>
        </deciderScoreComparatorFactory>
        ...
        <forager>
          ...
        </forager>
      </localSearch>
After in *SolverConfig.xml:
      <localSearch>
        ...
        <forager>
          <deciderScoreComparatorFactory>
            <deciderScoreComparatorFactoryType>NATURAL</deciderScoreComparatorFactoryType>
          </deciderScoreComparatorFactory>
          ...
        </forager>
      </localSearch>


From 5.4.0.Beta2 to 5.4.0.CR1
-----------------------------

[MAJOR] An uninitialized planning entity should be allowed to be put into the working memory
without causing a NullPointerException because a planning variable is still null.
Before in *.java:
    @PlanningEntity(...)
    public class Lecture ... {

        @PlanningVariable(...)
        public Period getPeriod() {
            return period;
        }
        ...

        public Day getDay() {
            return period.getDay();
        }

        public int getTimeslotIndex() {
            return period.getTimeslot().getTimeslotIndex();
        }

        ...
    }
After in *.java:
    @PlanningEntity(...)
    public class Lecture ... {

        @PlanningVariable(...)
        public Period getPeriod() {
            return period;
        }
        ...

        public Day getDay() {
            if (period == null) {
                return null;
            }
            return period.getDay();
        }

        public int getTimeslotIndex() {
            if (period == null) {
                return Integer.MIN_VALUE;
            }
            return period.getTimeslot().getTimeslotIndex();
        }

        ...
    }

[MINOR] AcceptorConfig and ForagerConfig no longer support directly assigning an Acceptor or Forager instance.
This breaks using the SolverFactory to build multiple Solver instances
and it also breaks XML file serialization of a Solver configuration.
Before in *.java:
    acceptorConfig.setAcceptor(myAcceptor);
Before in *.java:
    foragerConfig.setForager(myForager);
After in *.java:
    Follow the instructions in the manual section "Using a custom Selector, Acceptor, Forager or Termination".
    You will need to extend the *Config class and the Abtract* class as stipulated in the manual.

[MINOR] AcceptorConfig now accepts multiple acceptorClass instances.
Solver configuration XML is unchanged.
Before in *.java:
    acceptorConfig.setAcceptorClass(myAcceptorClass);
After in *.java:
    acceptorConfig.setAcceptorClassList(Collections.singletonList(myAcceptorClass));

[MAJOR] All @ValueRange* annotations have been folded into a single @ValueRange annotation.
Also, propertyName has been renamed to solutionProperty or planningEntityProperty accordingly.
This was needed to support @ValueRanges, a plural annotation of @ValueRange and get around Java's annotation limits.
Before in *.java:
    @PlanningVariable(...)
    @ValueRangeFromSolutionProperty(propertyName = "roomList")
    public Room getRoom() {...}
After in *.java:
    @PlanningVariable(...)
    @ValueRange(type = ValueRangeType.FROM_SOLUTION_PROPERTY, solutionProperty = "roomList")
    public Room getRoom() {...}
Before in *.java:
    @PlanningVariable(...)
    @ValueRangeFromPlanningEntityProperty(propertyName = "roomList")
    public Room getRoom() {...}
After in *.java:
    @PlanningVariable(...)
    @ValueRange(type = ValueRangeType.FROM_PLANNING_ENTITY_PROPERTY, planningEntityProperty = "roomList")
    public Room getRoom() {...}
Before in *.java:
    @PlanningVariable(...)
    @ValueRangeUndefined()
    public Room getRoom() {...}
After in *.java:
    @PlanningVariable(...)
    @ValueRange(type = ValueRangeType.UNDEFINED)
    public Room getRoom() {...}

[MAJOR] If you copied the examples GUI's HACKs with DefaultSolverScope,
transform them to use the less worse SolutionDirector HACK. But it's still a hack: avoid if you can.
An important change is that the GUI and the Solver should never share the same workingSolution instance any more.
Also, the Solver implementation has been adjusted so that the workingSolution is a clone of setPlanningProblem(),
instead of the bestSolution being the clone of it.
Before in *.java:
    public void setSolver(Solver solver) {
        this.solver = solver;
        // TODO HACK Planner internal API: don't do this
        this.solverScope = ((DefaultSolver) solver).getSolverScope();
    }
    ...
    public void openSolution(File file) {
        Solution solution = solutionDao.readSolution(file);
        solver.setPlanningProblem(solution);
    }
    ...
    public void solve() {
        solver.solve();
    }
After in *.java:
    public void setSolver(Solver solver) {
        this.solver = solver;
        // TODO HACK Planner internal API: don't do this
        this.guiSolutionDirector = ((DefaultSolver) solver).getSolverScope()
                .getSolutionDirector().cloneWithoutWorkingSolution();
    }
    ...
    public void openSolution(File file) {
        Solution solution = solutionDao.readSolution(file);
        guiSolutionDirector.setWorkingSolution(solution);
    }
    ...
    public void solve() {
        solver.setPlanningProblem(guiSolutionDirector.getWorkingSolution());
        solver.solve();
        Solution bestSolution = solver.getBestSolution();
        guiSolutionDirector.setWorkingSolution(bestSolution);
    }
Important note: scroll below, this has been further improved during the ScoreDirector refactor.

[MAJOR] The interface Move has gotten 2 new methods: getPlanningEntities() and getPlanningValues()
The TabuPropertyEnabled interface has been removed:
Normally, the method getTabuProperties() is renamed to getPlanningEntities().
Before in *.java:
    public class CloudComputerChangeMove implements Move, TabuPropertyEnabled {

        public Collection<? extends Object> getTabuProperties() {
            return Collections.singletonList(cloudProcess);
        }

    }
After in *.java:
    public class CloudComputerChangeMove implements Move {

        public Collection<? extends Object> getPlanningEntities() {
            return Collections.singletonList(cloudProcess);
        }

        public Collection<? extends Object> getPlanningValues() {
            return Collections.singletonList(toCloudComputer);
        }
    }
Before in *.java:
    public class CloudProcessSwapMove implements Move, TabuPropertyEnabled {

        public Collection<? extends Object> getTabuProperties() {
            return Arrays.<CloudProcess>asList(leftCloudProcess, rightCloudProcess);
        }

    }
After in *.java:
    public class CloudProcessSwapMove implements Move {

        public Collection<? extends Object> getPlanningEntities() {
            return Arrays.asList(leftCloudProcess, rightCloudProcess);
        }

        public Collection<? extends Object> getPlanningValues() {
            return Arrays.asList(leftCloudProcess.getComputer(), rightCloudProcess.getComputer());
        }
    }

[MAJOR] propertyTabu has been renamed to planningEntityTabu (or in some cases planningValueTabu)
Before in *SolverConfig.xml:
    <acceptor>
      <propertyTabuSize>7</propertyTabuSize>
    </acceptor>
After in *SolverConfig.xml:
    <acceptor>
      <planningEntityTabuSize>7</planningEntityTabuSize>
    </acceptor>

[MINOR] If you use planningEntityTabuSize and in the method getPlanningEntities() return a collection with a size >= 2,
then you might need to retweak your planningEntityTabuSize to a lower number.
More info in https://issues.jboss.org/browse/JBRULES-3007
Before in *SolverConfig.xml:
    <acceptor>
      <planningEntityTabuSize>9</planningEntityTabuSize>
    </acceptor>
After in *SolverConfig.xml:
    <acceptor>
      <planningEntityTabuSize>7</planningEntityTabuSize><!-- Check with the Benchmarker if 7 isn't better than 9 now -->
    </acceptor>

[MINOR] The interface HardAndSoftScore and HardAndSoftLongScore have a new method isFeasible().
If you use a custom score implementation that implements either interface, implement it:
After in *HardAndSoftScore.java:
    public boolean isFeasible() {
        return getHardScore() >= 0;
    }

[MINOR] SolverPhaseLifecycleListener.stepDecided() has been completely removed. Use stepTaken(...) instead.
Before in *.java:
    public void stepDecided(...) {
        ...
    }

[MINOR] If you have a custom ScoreCalculator: the clone() method has been removed
Before in *ScoreCalculator.java:
    public ... clone() {
        ...
    }

[MAJOR] ScoreCalculator has been renamed to ScoreHolder
and the DRL global variable scoreCalculator has been renamed to scoreHolder.
Before in *.drl:
    import org.drools.planner.core.score.buildin.hardandsoft.HardAndSoftScoreCalculator;
    ...
    global HardAndSoftScoreCalculator scoreCalculator;

    rule "hardConstraintsBroken" ...
        when ...
        then
            scoreCalculator.setHardConstraintsBroken($hardTotal.intValue());
    end

    rule "softConstraintsBroken" ...
        when ...
        then
            scoreCalculator.setSoftConstraintsBroken($softTotal.intValue());
    end
After in *.drl:
    import org.drools.planner.core.score.buildin.hardandsoft.HardAndSoftScoreHolder;
    ...
    global HardAndSoftScoreHolder scoreHolder;

    rule "hardConstraintsBroken" ...
        when ...
        then
            scoreHolder.setHardConstraintsBroken($hardTotal.intValue());
    end

    rule "softConstraintsBroken" ...
        when ...
        then
            scoreHolder.setSoftConstraintsBroken($softTotal.intValue());
    end
Similarly for SimpleScoreHolder, SimpleDoubleScoreHolder and HardAndSoftLongScoreHolder.

[MINOR] If you have a custom ScoreDefinition:
The method ScoreDefinition.buildScoreCalculator() has been renamed to buildScoreHolder().
The package org.drools.planner.core.score.calculator has been renamed to org.drools.planner.core.score.holder
The method ScoreHolder.calculateScore() has been renamed to extractScore().
Before in *ScoreDefinition.java:
    import org.drools.planner.core.score.calculator...
    ...
    public ScoreHolder buildScoreCalculator() {
        ...
    }
After in *ScoreDefinition.java:
    import org.drools.planner.core.score.holder...
    ...
    public ScoreHolder buildScoreHolder() {
        ...
    }
Before in *ScoreHolder.java:
    public Score calculateScore() {...}
After in *ScoreHolder.java:
    public Score extractScore() {...}

[MINOR] SolutionDirector has been renamed to ScoreDirector.

[MINOR] ScoreDirectorFactory has been extracted from ScoreDirector.

[README] Planner now supports score calculation with plain Java code, as an alternative to using Drools Expert.
As a result of this, the Drools Expert specific code has been centralized around the class DroolsScoreDirector
and does no longer leak into the rest of Planner's code or into your code.
If at any point, you still want to have direct access to WorkingMemory, simply do:
    ((DroolsScoreDirector) scoreDirector).getWorkingMemory()

[MAJOR] Instead of notifying the WorkingMemory directly, changes must notified the ScoreDirector,
before and after the entity or problem fact has been added, changed or removed.
Migration table:
    workingMemory.insert(entity)                -> beforeEntityAdded(entity) + afterEntityAdded(entity)
    workingMemory.update(entityHandle, entity)  -> beforeVariableChanged(entity, "variableName") + afterVariableChanged(entity, "variableName")
                                                or beforeAllVariablesChanged(entity) + afterAllVariablesChanged(entity)
    workingMemory.retract(entityHandle)         -> beforeEntityRemoved(entity) + afterEntityRemoved(entity)
    workingMemory.insert(problemFact)                     -> beforeProblemFactAdded(problemFact) + afterProblemFactAdded(problemFact)
    workingMemory.update(problemFactHandle, problemFact)  -> beforeProblemFactChanged(problemFact) + afterProblemFactChanged(problemFact)
    workingMemory.retract(problemFactHandle)              -> beforeProblemFactRemoved(problemFact) + afterProblemFactRemoved(problemFact)
Hint: Look for all usages of org.drools.WorkingMemory in your planner related code
to find all pieces of code that might be affected by these changes, which are described in detail below.

[MAJOR] If you're using custom Move implementations (and don't use the generic move implementations):
The class Move's methods with parameter WorkingMemory has been replaced by a parameter ScoreDirector.
Before in *Move.java or *MoveHelper.java:
    public class PeriodChangeMove implements Move {

        public boolean isMoveDoable(WorkingMemory workingMemory) {...}

        public Move createUndoMove(WorkingMemory workingMemory) {...}

        public void doMove(WorkingMemory workingMemory) {
            FactHandle factHandle = workingMemory.getFactHandle(exam);
            exam.setPeriod(toPeriod);
            workingMemory.update(factHandle, exam);
        }

    }
After in *Move.java or *MoveHelper.java:
    public class PeriodChangeMove implements Move {

        public boolean isMoveDoable(ScoreDirector scoreDirector) {...}

        public Move createUndoMove(ScoreDirector scoreDirector) {...}

        public void doMove(ScoreDirector scoreDirector) {
            scoreDirector.beforeVariableChanged(exam, "period");
            exam.setPeriod(toPeriod);
            scoreDirector.afterVariableChanged(exam, "period");
        }

    }
Note: if multiple variables are changed at the same time, you might want to use before/afterAllVariablesChanged():
    public void doMove(ScoreDirector scoreDirector) {
        scoreDirector.beforeAllVariablesChanged(exam);
        exam.setPeriod(toPeriod);
        exam.setRoom(toRoom);
        scoreDirector.afterAllVariablesChanged(exam);
    }

[MAJOR] If you use a CustomSolverPhaseCommand
or still have a custom SolutionInitializer (and haven't switched to the construction heuristics yet):
Before in *SolutionInitializer.java or *.java:
    public class MrOriginalMachineSolutionInitializer implements CustomSolverPhaseCommand {
        public void changeWorkingSolution(SolutionDirector solutionDirector) {
            ...
            processAssignment.setMachine(processAssignment.getOriginalMachine());
            workingMemory.insert(processAssignment);
            ...
        }
    }
After in *SolutionInitializer.java or *.java:
    public class MrOriginalMachineSolutionInitializer implements CustomSolverPhaseCommand {
        public void changeWorkingSolution(ScoreDirector scoreDirector) {
            ...
            scoreDirector.beforeEntityAdded(processAssignment);
            processAssignment.setMachine(processAssignment.getOriginalMachine());
            scoreDirector.afterEntityAdded(processAssignment);
            ...
        }
    }

[MAJOR] If you're using real-time planning with ProblemFactChange, the method doProblemFactChange's parameter changed
from SolutionDirector to ScoreDirector.
Before in *.java:
        solutionBusiness.doProblemFactChange(new ProblemFactChange() {
            public void doChange(SolutionDirector solutionDirector) {
                WorkingMemory workingMemory = solutionDirector.getWorkingMemory();
                ...
                        FactHandle computerHandle = workingMemory.getFactHandle(workingComputer);
                        workingMemory.retract(computerHandle);
                        it.remove(); // remove from list
                ...
            }
        });
After in *.java:
        solutionBusiness.doProblemFactChange(new ProblemFactChange() {
            public void doChange(ScoreDirector scoreDirector) {
                ...
                        scoreDirector.beforeProblemFactRemoved(workingComputer);
                        it.remove(); // remove from list
                        scoreDirector.beforeProblemFactRemoved(workingComputer);
                ...
            }
        });

[MAJOR] If you copied the examples GUI's HACKs with DefaultSolverScope,
the SolutionDirector.cloneWithoutWorkingSolution() has been removed already,
use the ScoreDirectorFactory.buildScoreDirector() method instead.
Before in *.java:
    guiSolutionDirector = ((DefaultSolver) solver).getSolverScope()
            .getSolutionDirector().cloneWithoutWorkingSolution();
After in *.java:
    ScoreDirectorFactory scoreDirectorFactory = solver.getScoreDirectorFactory();
    guiScoreDirector = scoreDirectorFactory.buildScoreDirector();
    // if (guiScoreDirector instanceof DroolsScoreDirector) {
    //     ... = ((DroolsScoreDirector) guiScoreDirector).getWorkingMemory();
    // }

[MINOR] The method Solver.getScoreDirectorFactory() has been removed.
Before in *.java:
    ... = solver.getScoreDefinition();
After in *.java:
    ... = solver.getScoreDirectorFactory().getScoreDefinition();

[MAJOR] <scoreDefinition> has been replaced by <scoreDirectorFactory> and <scoreDrl> has been moved under it.
Before in *SolverConfig.xml and *BenchmarkConfig.xml:
    <solver>
      ...
      <scoreDrl>/org/drools/planner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>
      <scoreDefinition>
        <scoreDefinitionType>HARD_AND_SOFT</scoreDefinitionType>
      </scoreDefinition>
      ...
    </solver>
After in *SolverConfig.xml and *BenchmarkConfig.xml:
    <solver>
      ...
      <scoreDirectorFactory>
        <scoreDefinitionType>HARD_AND_SOFT</scoreDefinitionType>
        <scoreDrl>/org/drools/planner/examples/cloudbalancing/solver/cloudBalancingScoreRules.drl</scoreDrl>
      </scoreDirectorFactory>
      ...
    </solver>
If instead, you use API configuration (less likely):
Before in *.java:
        solverConfig.setScoreDrlList(
                Arrays.asList("/org/drools/planner/examples/nqueens/solver/nQueensScoreRules.drl"));
        ScoreDefinitionConfig scoreDefinitionConfig = solverConfig.getScoreDefinitionConfig();
        scoreDefinitionConfig.setScoreDefinitionType(
                ScoreDefinitionConfig.ScoreDefinitionType.SIMPLE);
After in *.java:
        ScoreDirectorFactoryConfig scoreDirectorFactoryConfig = solverConfig.getScoreDirectorFactoryConfig();
        scoreDirectorFactoryConfig.setScoreDefinitionType(ScoreDirectorFactoryConfig.ScoreDefinitionType.SIMPLE);
        scoreDirectorFactoryConfig.setScoreDrlList(
                Arrays.asList("/org/drools/planner/examples/nqueens/solver/nQueensScoreRules.drl"));
