JBoss.orgCommunity Documentation
Planner's input and output data (the planning problem and the best solution) are plain old JavaBeans (POJO's), so integration with other Java technologies is straightforward. For example:
To read a planning problem from the database (and store the best solution in it), annotate the domain POJO's with JPA annotations.
To read a planning problem from an XML file (and store the best solution in it), annotate the domain POJO's with XStream or JAXB annotations.
To expose the Solver as a REST Service that reads the planning problem and responds with the best
solution, annotate the domain POJO's with XStream or JAXB annotations and hook the Solver
in
Camel or RESTEasy.
Enrich the domain POJO's (solution, entities and problem facts) with JPA annotations to store them in a database.
Do not confuse JPA's @Entity
annotation with Planner's
@PlanningEntity
annotation. They can appear both on the same class.
Enrich the domain POJO's (solution, entities and problem facts) with XStream annotations to serialize them to/from XML.
Camel is an enterprise integration framework which includes support for Planner (starting from Camel 2.13). It can expose a use case as a REST service, a SOAP service, a JMS service, ...
Read the documentation for the camel-optaplanner component. That component works in Karaf too.
To deploy an Planner web application on WildFly, simply include the optaplanner dependency jars in the
war
file's WEB-INF/lib
directory (just like any other dependency) as shown
in the optaplanner-webexamples-*.war
. However, in this approach the war file can easily grow to
several MB in size, which is fine for a one-time deployment, but too heavyweight for frequent redeployments
(especially over a slow network connection).
The remedy is to use deliver the optaplanner jars in a JBoss module to WildFly and create a skinny war. Let's create an module called org.optaplanner:
Navigate to the directory ${WILDFLY_HOME}/modules/system/layers/base/
.
This directory contains the JBoss modules of WildFly. Create directory structure
org/optaplanner/main
for our new module.
Copy optaplanner-core-${version}.jar
and all its direct and transitive dependency
jars into that new directory. Use "mvn dependency:tree" on each optaplanner artifact to discover all
dependencies.
Create the file module.xml
in that new directory. Give it this content:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.3" name="org.optaplanner">
<resources>
...
<resource-root path="kie-api-${version}.jar"/>
...
<resource-root path="optaplanner-core-${version}.jar"/>
...
<resource-root path="."/>
</resources>
<dependencies>
<module name="javaee.api"/>
</dependencies>
</module>
Navigate to the deployed war
file.
Remove optaplanner-core-${version}.jar
and all its direct and transitive
dependency jars from the WEB-INF/lib
directory in the war
file.
Create the file jboss-deployment-structure.xml
in the
WEB-INF/lib
directory. Give it this content:
<?xml version="1.0" encoding="UTF-8" ?>
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.optaplanner" export="true"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
Because of WildFly's class loading, the method
SolverFactory.createFromXmlResource()
might not find the solver configuration and throw an
IllegalArgumentException
. Instead use:
SolverFactory solverFactory = SolverFactory.createFromXmlInputStream(
getClass().getClassLoader().getResourceAsStream(
"org/optaplanner/examples/nqueens/solver/nqueensSolverConfig.xml"));
The optaplanner-core
jar includes OSGi metadata to function properly in an OSGi
environment too.
Planner does not require OSGi. It works perfectly fine in a normal Java environment too.
Planner does not work out-of-the-box on Android yet, because it is not a complete JVM. For more information and workarounds, see this issue.
A good Planner implementation beats any good human planner for non-trivial datasets. Many human planners fail to accept this, often because they feel threatened by an automated system.
But despite that, Planner can benefit from a human planner as supervisor:
The human planner defines and validates the score function.
Some examples expose a *Parametrization
object, which defines the weight for each
score constraint. The human planner can then tweak those weights at runtime.
When the business changes, the score function often needs to change too. The human planner can notify the developers to add, change or remove score constraints.
The human planner is always in control of Planner.
As shown in the course scheduling example, the human planner can lock 1 or more planning variables to a specific planning value and make those immovable. Because they are immovable, Planner does not change them: it optimizes the planning around the enforcements made by the human. If the human planner locks all planning variables, he/she sidelines Planner completely.
In a prototype implementation, the human planner might use this occasionally. But as the implementation matures, it must become obsolete. But do keep the feature alive: as a reassurance for the humans. Or in case that one day the business changes dramatically before the score constraints can be adjusted.
Therefore, it's often a good idea to involve the human planner in your project.