Red Hat Training

A Red Hat training course is available for JBoss Enterprise SOA Platform

Chapter 7. The Rule Language

7.1. The KnowledgeBuilder

The KnowledgeBuilder is responsible for taking source files, such as a DRL file or an Excel file, and turning them into a Knowledge Package of rule and process definitions which a Knowledge Base can consume. An object of the class ResourceType indicates the type of resource the builder is being asked to process.

7.2. The ResourceFactory

The ResourceFactory provides capabilities to load resources from a number of sources, such as a java.io.Reader, the classpath, a URL, a java.io.File, or a byte array. Binary files, such as decision tables (Excel's .xls files), should not be passed in with Reader, which is only suitable for text based resources.

7.3. Creating a new KnowledgeBuilder

Procedure 7.1. Task

  1. Open the KnowledgeBuilderFactory.
  2. Create a new default configuration.
  3. Enter this into the configuration:
    KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
    The first parameter is for properties and is optional. If left blank, the default options will be used. The options parameter can be used for things like changing the dialect or registering new accumulator functions.
  4. To add a KnowledgeBuilder with a custom ClassLoader, use this code:
    KnowledgeBuilderConfiguration kbuilderConf = KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(null, classLoader );
    KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(kbuilderConf);
    

7.4. Adding DRL Resources

Procedure 7.2. Task

  1. Resources of any type can be added iteratively. Below, a DRL file is added. The Knowledge Builder can handle multiple namespaces, so you can combine resources regardless of their namespace:
    kbuilder.add( ResourceFactory.newFileResource( "/project/myrules.drl" ),
                  ResourceType.DRL);
    
  2. Check the compilation results after each resource addition. The KnowledgeBuilder can report compilation results of 3 different severities: ERROR, WARNING and INFO.
    • An ERROR indicates that the compilation of the resource failed. You should not add more resources or retrieve the Knowledge Packages if there are errors. getKnowledgePackages() returns an empty list if there are errors.
    • WARNING and INFO results can be ignored, but are available for inspection nonetheless.

7.5. KnowledgeBuilder Result Inspection Methods

The KnowledgeBuilder API offers several methods to check and retrieve the build results for a list of severities:
    /**
     * Return the knowledge builder results for the listed severities.
     * @param severities
     * @return
     */
    KnowledgeBuilderResults getResults(ResultSeverity... severities);
    
    /**
     * Checks if the builder generated any results of the listed severities
     * @param severities
     * @return
     */
    boolean hasResults(ResultSeverity... severities ;
The KnowledgeBuilder API also has two helper methods to inspect for errors only: hasErrors() and getErrors():
if( kbuilder.hasErrors() ) {
    System.out.println( kbuilder.getErrors() );
    return;
}

7.6. Getting the KnowledgePackages

When all the resources have been added and there are no errors, the collection of Knowledge Packages can be retrieved. It is a java.util.Collection because there is one KnowledgePackage per package namespace. These Knowledge Packages are serializable and often used as a unit of deployment.
This is what it looks like:
Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();

7.7. Extended KnowledgeBuilder Example

This is what a complete KnowledgeBuilder package looks like:
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
if( kbuilder.hasErrors() ) {
    System.out.println( kbuilder.getErrors() );
    return;
}

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newFileResource( "/project/myrules1.drl" ),
              ResourceType.DRL);
kbuilder.add( ResourceFactory.newFileResource( "/project/myrules2.drl" ),
              ResourceType.DRL);

if( kbuilder.hasErrors() ) {
    System.out.println( kbuilder.getErrors() );
    return;
}

Collection<KnowledgePackage> kpkgs = kbuilder.getKnowledgePackages();

7.8. Using KnowledgeBuilder in Batch Mode

The KnowledgeBuilder has a batch mode with a fluent interface. It allows you to build multiple DRLs at once as in the following example:
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.batch()
        .add( ResourceFactory.newFileResource( "/project/myrules1.drl" ), ResourceType.DRL )
        .add( ResourceFactory.newFileResource( "/project/myrules2.drl" ), ResourceType.DRL )
        .add( ResourceFactory.newFileResource( "/project/mytypes1.drl" ), ResourceType.DRL )
        .build();

7.9. Discard the Build of the Last Added DRL

the KnowledgeBuilder (regardless if you are using the batch mode or not) also allows to discard what has been added with the last DRL(s) build. This can be useful to recover from having added an erroneous DRL to the KnowledgeBuilder, as shown below:
kbuilder.add( ResourceFactory.newFileResource( "/project/wrong.drl" ), ResourceType.DRL );
if ( kbuilder.hasErrors() ) {
    kbuilder.undo();
}

7.10. Building Using Configuration and the ChangeSet XML

You can create definitions using a configuration within the ChangeSet XML. The simple XML file supports three elements: add, remove, and modify. Each of these have a sequence of <resource> subelements defining a configuration entity.

7.11. XML Schema for ChangeSet XML (not normative)

This is the schema for a non-normative ChangeSet:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://drools.org/drools-5.0/change-set"
           targetNamespace="http://drools.org/drools-5.0/change-set">

  <xs:element name="change-set" type="ChangeSet"/>

  <xs:complexType name="ChangeSet">
    <xs:choice maxOccurs="unbounded">
      <xs:element name="add"    type="Operation"/>
      <xs:element name="remove" type="Operation"/>
      <xs:element name="modify" type="Operation"/>
    </xs:choice>
  </xs:complexType>

  <xs:complexType name="Operation">
    <xs:sequence>
      <xs:element name="resource" type="Resource"
                  maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Resource">
    <xs:sequence>
      <!-- To be used with <resource type="DTABLE"...> -->
      <xs:element name="decisiontable-conf" type="DecTabConf"
                  minOccurs="0"/>
    </xs:sequence>
    <!-- java.net.URL, plus "classpath" protocol -->
    <xs:attribute name="source" type="xs:string"/>
    <xs:attribute name="type"   type="ResourceType"/>
  </xs:complexType>

  <xs:complexType name="DecTabConf">
    <xs:attribute name="input-type"     type="DecTabInpType"/>
    <xs:attribute name="worksheet-name" type="xs:string"
                  use="optional"/>
  </xs:complexType>

  <!-- according to org.drools.builder.ResourceType -->
  <xs:simpleType name="ResourceType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="DRL"/>
      <xs:enumeration value="XDRL"/>
      <xs:enumeration value="DSL"/>
      <xs:enumeration value="DSLR"/>
      <xs:enumeration value="DRF"/>
      <xs:enumeration value="DTABLE"/>
      <xs:enumeration value="PKG"/>
      <xs:enumeration value="BRL"/>
      <xs:enumeration value="CHANGE_SET"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- according to org.drools.builder.DecisionTableInputType -->
  <xs:simpleType name="DecTabInpType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="XLS"/>
      <xs:enumeration value="CSV"/>
    </xs:restriction>
  </xs:simpleType>

</xs:schema>