[[cloudBalancingDomainModel]]
= Using the domain model
:imagesdir: ../../..


[[cloudBalancingDomainModelDesign]]
== Domain model design

Using a <<domainModelingGuide,domain model>> helps determine which classes are planning entities and which of their properties are planning variables. It also helps to simplify constraints, improve performance, and increase flexibility for future needs.

To create a domain model, define all the objects that represent the input data for the problem. In this simple example, the objects are processes and computers.

A separate object in the domain model must represent a full data set of problem, which contains the input data as well as a solution. In this example, this object holds a list of computers and a list of processes. Each process is assigned to a computer; the distribution of processes between computers is the solution.

. Draw a class diagram of your domain model.
. Normalize it to remove duplicate data.
. Write down some sample instances for each class.

* ``Computer``: represents a computer with certain hardware and maintenance costs.
+
In this example, the sample instances for the `Computer` class are: `cpuPower`, `memory`, `networkBandwidth`, `cost`.
* ``Process``: represents a process with a demand. Needs to be assigned to a `Computer` by OptaPlanner.
+
Sample instances for ``Process`` are: `requiredCpuPower`, `requiredMemory`, and `requiredNetworkBandwidth`.
* ``CloudBalance``: represents a problem. Contains every `Computer` and `Process` for a certain data set.
+
For an object representing the full data set and solution, a sample instance holding the _score_ must be present. OptaPlanner can calculate and compare the scores for different solutions; the solution with the highest score is the optimal solution. Therefore, the sample instance for `CloudBalance` is `score`.

. Determine which relationships (or fields) change during planning.

* _Planning entity_: The class (or classes) that OptaPlanner can change during solving. In this example, it is the class ``Process``, because OptaPlanner can assign processes to computers.
* _Problem fact_: A class representing input data that OptaPlanner cannot change.
* _Planning variable_: The property (or properties) of a planning entity class that changes during solving. In this example, it is the property `computer` on the class ``Process``.
* _Planning solution_: The class that represents a solution to the problem. This class must represent the full data set and contain all planning entities. In this example that is the class ``CloudBalance``.

In the UML class diagram below, the OptaPlanner concepts are already annotated:

image::UseCasesAndExamples/CloudBalancing/DomainModel/cloudBalanceClassDiagram.png[align="center"]

[[cloudBalancingDomainModelImplementation]]
== Domain model implementation


[[cloudBalancingClassComputer]]
=== The `Computer` class

The `Computer` class is a POJO (Plain Old Java Object). Usually, you will have more of this kind of classes with input data.

.CloudComputer.java
====
[source,java,options="nowrap"]
----
public class CloudComputer ... {

    private int cpuPower;
    private int memory;
    private int networkBandwidth;
    private int cost;

    ... // getters
}
----
====


[[cloudBalancingClassProcess]]
=== The `Process` class

The `Process` class is particularly important. It is the class that is modified during solving.

We need to tell OptaPlanner that it can change the property ``computer``. To do this:
. Annotate the class with `@PlanningEntity`.
. Annotate the getter `getComputer()` with ``@PlanningVariable``.

Of course, the property `computer` needs a setter too, so OptaPlanner can change it during solving.

.CloudProcess.java
====
[source,java,options="nowrap"]
----
@PlanningEntity(...)
public class CloudProcess ... {

    private int requiredCpuPower;
    private int requiredMemory;
    private int requiredNetworkBandwidth;

    private CloudComputer computer;

    ... // getters

    @PlanningVariable(valueRangeProviderRefs = {"computerRange"})
    public CloudComputer getComputer() {
        return computer;
    }

    public void setComputer(CloudComputer computer) {
        computer = computer;
    }

    // ************************************************************************
    // Complex methods
    // ************************************************************************

    ...

}
----
====

* OptaPlanner needs to know which values it can choose from to assign to the property ``computer``. Those values are retrieved from the method `CloudBalance.getComputerList()` on the planning solution, which returns a list of all computers in the current data set.

* The ``@PlanningVariable``'s `valueRangeProviderRefs` parameter on `CloudProcess.getComputer()` needs to match with the ``@ValueRangeProvider``'s `id` on `CloudBalance.getComputerList()`.

[NOTE]
====
Instead of getter annotations, it is also possible to use <<annotationAlternatives,field annotations>>.
====


[[cloudBalancingClassCloudBalance]]
=== The `CloudBalance` class

The `CloudBalance` class has a [path]_@PlanningSolution_
 annotation.

* It holds a list of all computers and a list of all processes.
* It represents both the planning problem and (if it is initialized) the planning solution.
* To save a solution, OptaPlanner initializes a new instance of the class.

. The `processList` property holds a list of processes.
OptaPlanner can change the processes, allocating them to different computers.
Therefore, a process is a planning entity and the list of processes is a collection of planning entities.
We annotate the getter `getProcessList()` with ``@PlanningEntityCollectionProperty``.

. The `computerList` property holds a list of computers.
OptaPlanner cannot change the computers.
Therefore, a computer is a problem fact.
Especially for <<constraintStreams,Constraint Streams>> and <<droolsScoreCalculation,Drools score calculation>>,
the property `computerList` needs to be annotated with a `@ProblemFactCollectionProperty` so that OptaPlanner can retrieve the list of computers (problem facts) and make it available to the rule engine.

. The `CloudBalance` class also has a `@PlanningScore` annotated property ``score``, which is the `Score` of that solution in its current state.
OptaPlanner automatically updates it when it calculates a `Score` for a solution instance. Therefore, this property needs a setter.


.CloudBalance.java
====
[source,java,options="nowrap"]
----
@PlanningSolution
public class CloudBalance ... {

    private List<CloudComputer> computerList;

    private List<CloudProcess> processList;

    private HardSoftScore score;

    @ValueRangeProvider(id = "computerRange")
    @ProblemFactCollectionProperty
    public List<CloudComputer> getComputerList() {
        return computerList;
    }

    @PlanningEntityCollectionProperty
    public List<CloudProcess> getProcessList() {
        return processList;
    }

    @PlanningScore
    public HardSoftScore getScore() {
        return score;
    }

    public void setScore(HardSoftScore score) {
        this.score = score;
    }

    ...
}
----
====
