Skip to end of metadata
Go to start of metadata

TODO Fix all mispellings of temperature (ie, tempurature) both in this text and the classes.


In this tutorial I will the build HVAC example from Jess In Action (JIA) using drools-spring. The HVAC application will consist of a main class that creates a spring ApplicationContext and asserts the initial facts, a set of domain abstractions (eg, Vent, HeatPump, Floor) that serve as facts, a simulator that models heat transfer between the floors of a building, and a set of rules that react to changes in temperature by adjusting the state of Vents and HeatPumps.

All the rules are implemented as simple POJOs with annotations and declared in the spring config file. Drools .drl files are not used by the spring integration. The rules and system components are created and initialized by spring. All dependencies between components are wired using spring's dependency injection mechanisms.

Because everything in drools-spring is a POJO, you get to use the full power your IDE as well test-first using junit. Most of the HVAC application was developed test-first with exception of the simulator and the GUI which I mainly copied directly from the JIA example. Otherwise test coverage is fairly complete.

While this tutorial uses and requires Java SE 5+, drools-spring does not depend on Java 5 at all. Drools-spring uses pluggable strategies for obtaining rule-metadata and provides a growing set of Java 1.4 compatible strategies. The drools-spring-jdk5 module extends drools-spring with Tiger assertions for declaring rules, conditions, and consequences, along with the related strategies. More on this later.

The tutorial is organized in two parts. In the Part 1, The HVAC Application, I describe and build the HVAC application using only those drools-spring features required for the HVAC application. Specifically, all rule metadata will be specified using Java 5 annotations, even though drools-spring has equivalent support for Java 1.4. In Part 2, Drools Spring Strategies, I will outline additional drools-spring implementation strategies. Part 2 will also provide links to other documentation and javadocs.

Part 1, The HVAC Application

Getting Started

Since I won't cover every detail of the application in this tutorial, if you want to run the application and browse the code, you will need to download the drools-spring-examples project from the drools cvs server. Drools projects are built with maven. If you plan on building and running the HVAC appliation, you will need to have maven installed.

... TODO describe how to download and build ...
... TODO describe the required dependencies ...

The Domain Model

The domain for the HVAC application consists of HeatPump, Vent, Thermometer, Floor, and TempuratureControl. We don't model the building that contains the floors directly since the rules do not depend on that abstraction. All of these abstractions are declared as interfaces, with implemenations provided by the sim package.

... TODO include a diagram like JIA figure 14.1 ...


Floor represents a single floor in the building. The Floor keeps track of its floor number, its Thermometer, HeatPump, and Vent.


Thermometer is sensor that detects the tempurature of its floor. Its getReading method provides the current tempurature. Thermometer implements the JavaBeans property-change protocol methods which allows drools to detect changes to the tempurature and automatically update WorkingMemory with the new value. The simulator implements this interface and updates the Thermometer based on its heat transfer model.


Vent controls the flow of heated or cooled onto the floor. A Vent can either be OPEN or CLOSED. Rules open and close the Vent according to the need to adjust the tempurature on a floor.


HeatPump exchanges heat between floors and the outside of the building. A HeatPump can be either HEATING, COOLING, or OFF. A single HeatPump can serve multiple floors. Rules change the HeatPump state according to the need to adjust the tempurature on a floor.


TempuratureControl sets the desired tempurature for the entire building, represented by the property setPoint. Rules use TempuratureControl to determine whether a floor is too hot or too cold. To keep the system from thrashing between cooling and heating, TempuratureControl uses the property guardAmount to define "guard lines" around the desired tempurature. The current tempurature must be above or below the setPoint by guardAmount before it will be considered too hold or too cold.

TempuratureControl exports two concepts: Whether a floor is cool or warm enough, and whether a floor is too cool or too hot. Cool enough or warm enough is when the tempurature has reached the setPoint but has not gone beyond the guardPoint. Too cool or tool hot is when the tempurature has gone beyond the setPoint by the guardAmount. As we will see in the next section, the rules use these two concepts decide how aggressive to be in attempting to adjust the tempurature on a floor.

... TODO should this next para be here or later when we describe the rules ...

In the current implementation, the values for setPoint and guardAmount are specified in and cannot be changed at runtime. TempuratureControl is not fact, but rather injected as a dependency into the rules. If we wanted to change setPoint or guardAmount at runtime, we would need to make TempuratureControl a fact so that rules fired upon the property change. But I have left it this way so I could demonstrate dependency injection into rules.

The HVAC Rules

(Note: The rule design was lifted directly out of JIA, so I won't make any attempt to explain the whys or alternatives. I recommend that you read JIA, its an excellent book.)

The rules are seperated into two groups, or rule-sets. One set for controlling the heat pumps, and another for controlling the vents.

Controlling the Heat Pumps

There are four rules that control the heat pumps. PumpOffWhenFloorsCoolEnough and PumpOffWhenFloorsWarnEnough ensure that the heat pump is turned off when a floor's tempurature reaches the desired level (ie, the setPoint defined by TempuratureControl). PumpCoolingWhenFloorTooHot, sets the pump state to COOLING when the floor becomes too hot. Remember that "too hot" means that the tempurature has passed the setPoint by guardAmount. In other words, we don't want to turn the pump on immediatly after desired tempurature has been reached to avoid hystersis and thus damaging the pump. Similary, PumpHeatingWhenFloorTooCold sets the pump state to HEATING when the floor becomes too cold.

Lets build PumpCoolingWhenFloorTooHot first. The first step is to create a POJO class annotated with @Rule.

The @Rule annotation declares the POJO to be a drools rule. @Rule allows for rule metadata to be declared in the annotation. For example:

As we will soon see, the conditions in this rule will need access to the buildings TemperatureControl. Recall from the domain model that TemperatureControl maintains the buildings desired tempurature, as well as exporting methods that determine if a given temperature is too cold, too hot, etc. We declare TemperatureControl as a java beans property on the rule. We'll see how this property get injected into the rule when we cover the spring configuration.

Next comes the condition methods. We only want this rule to fire (ie, turn the pump to COOLING) if the pump is currently in the OFF state.

The @Condition annotation declares a method to be a rule condition. The method must have the signature "boolean *(..)".

Condition methods are invoked by the drools rete engine, therefore the arguments passed to them must be known to the engine. Three types of condition parameters are supported: facts, application-data, and the special class KnowledgeHelper. When using annotations, facts are specified using the @Fact parameter annotation. Drools-spring can also infer condition argument types using various pluggable strageties. Throughout the HVAC application, all condition parameters will be facts, so we will omit @Fact and specify an appropriate strategy in the spring configuration (covered later on).

The next condition for this rule is that the Thermometer tempurature reading "is too hot". We check this by invoking the method TempuratureControl.isTooHot(double tempurature).

Recall from the domain model that a HeatPump serves three adjacent Floors. So we need to ensure that the HeatPump we determined to be OFF is serving the the Floor of the Thermometer instance checked by the isTooHot condition method.

You might be tempted to think that we are doing to much work by checking too many permutations. But because of the way Rete networks are built, a condition is tested for a given set of facts only once, and the calculated result stored until a fact is actually modified.

Finally, we need to specify the rule consequence. When our conditions have determined that the floor's temperature is too hot, and the floor's heat pump is off, then we set the heat pump cooling.

The @Consequence annotations marks the method as a rule consequence. And here again we see HeatPump specified as a parameter. Similar to conditions, the spring configuration will be setup such that the consequence parameters without annotations will be considered facts. Since HeatPump is a fact asserted into working-memory, the change in its state will propagate through the Rete network, causing conditions to fire, and possibly activating other rules.

Here is complete code for PumpOffWhenFloorsCoolEnough.


The other three heat-pump rules are simialar and should be self explainitory:

Controlling the Vents


Spring Configuration

The spring application context config file must define the drools beans and HVAC application beans. The main class will create a spring application using this config file an start the HVAC simulation running.

The first step is to define the rule-sets for the heat-pump rules and vent rules. A rule-set bean is created with RuleSetFactoryBean. The rules are specified with the rules property.

This will result in the creation a RuleSet composed of the four heat-pump rules. We'll cover the details of rule bean shortly. For each pojo rule, RuleSetFactoryBean will build a corresponding internal drools Rule. In order to do this, we need to tell RuleSetFactoryBean how to obtain the rule metadata, of which there are three kinds. 1) Rule metadata, such as the rule name and saliance; 2) Method metadata, which indicates which methods in the rule pojo are conditions and which are consequences; 3) Argument metatada, which indicates for each condition/consequence parameter whether its a fact or application-data.

  • No labels

1 Comment

  1. Barry,

    This looks very interesting, would this work with JDK 1.4?

    Cheers, Nicolas