A potential customer is interested in seeing how BRMS Business Central can help him build an Optaplanner (also known as Business Resource Planner) application using the GUI alone after I demonstrated to him the Optometrist rostering app based on the Nurse Rostering sample application.
I wanted to create a simple Optaplanner app so I picked cloud balancing. The problem statement for cloud balancing can be found here:
A sample implementation can be downloaded here:
However, the rules in the sample implementation are in native .DRL syntax. The customer wants to see everything created using Business Central GUI tools, if possible. This is the reason why I wanted to re-create this example using Business Central.
Please note that you have to add the “plannermgmt” and “kie-server” roles to you user login to Business Central in order to see the Optaplaner-specific GUI and manage the execution server.
2 When Experience Fails
There is not much documentation on how to use the Optaplanner GUI tools on Business Central (BC). There are bits and pieces here and there but not a complete description on how to build an Optaplanner app from scratch. Without proper documentation, you may encounter issues when building your rules using the Guided Rule Editor. The more so if you are familiar with BC tools. This may sound counter intuitive but is is true. Let me tell you why.
Here is how one of the .drl rules looks like:
rule "requiredMemoryTotal" when $computer : CloudComputer($memory : memory) $requiredMemoryTotal : Number(intValue > $memory) from accumulate( CloudProcess( computer == $computer, $requiredMemory : requiredMemory), sum($requiredMemory) ) then scoreHolder.addHardConstraintMatch(kcontext, $memory - $requiredMemoryTotal.intValue()); end
The thing to note is scoreHolder which is an Optaplanner org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder object. For anyone who has worked with BC Guided Rule Editor before, you know that the first thing to do is to add the data object from the “Data Objects” tab.
However, the HardSoftScoreHolder class is nowhere to be found when you click on the “+New Item” button. I tried hard to make that class appear in the drop down list. Things I did include:
1) Using Authoring→Artifact repository to upload optaplanner-core-6.5.0-Final-readhat-2.jar as that is the jar that contains the class I need. It displayed an error message but the jar was uploaded and a pom created.
2) Adding the entry: “Optaplanner org.optaplanner.core.api.score.buildin.hardsoft.*” in the page-names-white-list file so that the class imported appear in the dropdown list.
After doing these, the class did appear and I can create the rules but came build time, I ran into lots of problems:
Caused by: org.eclipse.aether.resolution.ArtifactResolutionException: Failure to transfer org.javassist:javassist:pom:3.19.0.GA-redhat-1 from http://localhost:8080/business-central/maven2/ was cached in the local repository, resolution will not be reattempted until the update interval of guvnor-m2-repo has elapsed or updates are forced. Original error: Could not transfer artifact org.javassist:javassist:pom:3.19.0.GA-redhat-1 from/to guvnor-m2-repo (http://localhost:8080/business-central/maven2/): Unauthorized (401) ... ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/business-central].[M2Servlet]] (http-localhost/127.0.0.1:8080-3) JBWEB000236: Servlet.service() for servlet M2Servlet threw exception: java.lang.RuntimeException: org.eclipse.aether.deployment.DeploymentException: Failed to deploy artifacts: Could not transfer artifact org.optaplanner:optaplanner-core:jar:6.5.0.Final-redhat-2 from/to jboss-releases-repository (https://origin-repository.jboss.org/nexus/service/local/staging/deploy/maven2/): Unauthorized (401)
It turns out that you do not have to do any of the things I did. How I wished someone had told me before I went down this path. Then I cloned the sample implementation onto BC and see how it works. And I am going to document what is needed to create such an application from scratch so that you don’t have to waste time like I did.
3 The Missing Guide
3.1 Building the App
I am not going to tell you how to create a project on BC. I assume you all know how to do it. You need to do the following (some of the steps need not be in strict order) after creating the project:
3.1.1 Create Data Models
I created 3 classes (the data models for cloud balancing) using the Data Modeler: Computer, Process and Solution.
3.1.2 Annotate Your Data Models
We have to tell Optaplanner regarding the planning entity, planning variable, valueRangeProviderRef, planning solution, etc. using annotations. All these are achieved using the BC GUI tool as can be seen in the following diagrams.
3.1.3 Define Rules using Guided Rules Editor without DSL
Then I defined the costRule and the cpuRule by using the Guided Rule Editor without using DSL to get a feel of the complexity involved. Note that in both cases, we have to use the ugly “Add free form DRL” action to define the THEN part of the rule. The BU says enhancement is being developed to alleviate the need to drop down to Java code in the Guided Rule Editor. The cpuRule, although not complex in .drl terms, is tedious to construct using the Guided Rule editor due to the use of “from accumulate” Conditional Element. The rules (in Editor as well as in source Views) are shown below:
3.3.4 Define a DSL
One way to make the rules easier to understand and construct is to create a DSL as shown:
3.1.5 Define Rules Using Guided Rules Editor with DSL
Now that we have defined a DSL, the construction of the memoryRule is a lot simpler.
3.1.6 Define Solver Configuration
Use Authoring→Solver Config to create a solver configuration. Pick Hard_Soft and enter the termination criterion.
3.1.7 Define External Data Object
If you try to build the app now, it will fail because it still require 2 more things to be done. Click on the “Open Project Editor” and then select “External Data Objects” from the dropdown listbox on the Project editor pane. Add an external data object (Optaplanner org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder ) as shown:
3.1.8 Define Global Definition
Doing 3.1.7 alone is not sufficient, we also need to define a global variable (scoreHolder) to be used in the THEN part of the rules. To do this click on “New Item” and select Global Definition.
The alternative to doing Steps 3.1.7 and 3.1.8, as suggested by Matej Cimbora (email@example.com) in the sme-brms forum, is to create a .drl file in your project with content:
package opta.curriculumcourse; import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScoreHolder; global HardSoftScoreHolder scoreHolder;
This works but as our goal is not to use native .drl files, I am sticking with my approach ie, doing steps 3.1.7 and 3.1.8.
3.1.9 What about Testing the Rules?
I defined a test scenario called memoryTest. When I execute the test, it always results in error.
I’ve tried modifying the kie-deployment-descriptor.xml by adding a global element inside of the globals element hoping that this will instantiate the global variable making the test work. It did not work.
Matej Cimbora (firstname.lastname@example.org) explained why such tests won’t work:
...From what I see, the rule got indeed fired (see the exception - Exception executing consequence for rule "memoryRule" in ...). The problem is that the scoreHolder variable gets initialized internally by the OptaPlanner engine. Scenario runner has no awareness of the OptaPlanner-specific functionality, therefore it leaves the scoreHolder reference null, which causes the exception. I created  to resolve the issue…  https://issues.jboss.org/browse/PLANNER-720
Thanks Matej for logging the issue. You are indeed a Mate like your namesake
So, don’t waste your time trying to get your test scenarios to work. Test Scenarios are not working for Optaplanner apps yet.
3.1.10 Build and Deploy
There is nothing special in creating a kie-container to run our app. My kie-container’s name is ‘myplanner’.
4 Testing using SoapUI
Since I already have SopaUI on my machine, I am going to use it for testing. You create a REST project and give it the url:
You will be using the Optaplanner REST API to interact with the Optaplanner app you deployed earlier.
Please note that soapui (at lease the version I use V5.2.1) has the nasty habit of changing the URL (resource) for all you request once you changed one. In this case, different request should have different URLs. It also changed the operation (eg, PUT) for all requests once you changed one.
You need to set the header for the following requests with:
X-KIE-ContentType: xstream Content-Type: application/xml
4.1 Create a New Solver
You need to issue a PUT to http://localhost:8080/kie-server/services/rest/server/containers/myplanner/solvers/myplanner
<solver-instance> <solver-config-file>demo/myplanner/CloudBalance.solver.xml</solver-config-file> </solver-instance>
The first myplanner is the name of the kie-container I created on the server
the second myplanner is the name of the solver instance I want to create
4.2 Start Solving
Issue a POST to http://localhost:8080/kie-server/services/rest/server/containers/myplanner/solvers/myplanner
<solver-instance> <status>SOLVING</status> <planning-problem class="demo.myplanner.Solution"> <computerList> <demo.myplanner.Computer> <memory>4</memory><cost>2000</cost> </demo.myplanner.Computer> <demo.myplanner.Computer> <memory>8</memory><cost>3000</cost> </demo.myplanner.Computer> <demo.myplanner.Computer> <memory>16</memory><cost>4000</cost> </demo.myplanner.Computer> </computerList> <processList> <demo.myplanner.Process> <requiredMemory>1</requiredMemory> </demo.myplanner.Process> <demo.myplanner.Process> <requiredMemory>7</requiredMemory> </demo.myplanner.Process> </processList> </planning-problem> </solver-instance>
4.3 Get Best Result
Issue a GET to http://localhost:8080/kie-server/services/rest/server/containers/myplanner/solvers/myplanner/bestsolution to retrieve the best solution.
You will notice that the solution says computer 2 should be used to run both processes. Note that xpath array index start at 1 and not 0, computer 2 is the second computer.
In my humble opinion, the official BRMS documentation on using the Business Central GUI to build an Optaplanner application requires improvement. By documenting my experience in using the Business Central GUI tools to create an Optaplanner project, deploy and interact with it, I am hoping that you don’t have to go through all the hurdles that I had to go through. You are welcome to use it as the Missing Guide to help you create Optaplanner applications using the Business Central GUI.