6.3. The Knowledge Agent

6.3.1. Knowledge Agent

The Knowledge Agent provides automatic loading, caching and re-loading of resources and is configured from a Knowledge Base properties files. The Knowledge Agent can update or rebuild a Knowledge Base as the resources it uses are changed. The strategy for this is determined by the configuration given to the factory, but it is typically pull-based using regular polling.
Below is a Knowledge Agent example:
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );
kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) );
KnowledgeBase kbase = kagent.getKnowledgeBase();
The code below is responsible for making a new KnowledgeAgent:
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );

6.3.2. KnowledgeAgent Objects

A KnowledgeAgent object will continuously scan all resources using a default polling interval of 60 seconds. When a modification date is updated, it will applied the changes into the cached Knowledge Base using the new resources. The previous KnowledgeBase reference will still exist and you'll have to call getKnowledgeBase() to access the newly built KnowledgeBase. If a directory is specified as part of the change set, the entire contents of that directory will be scanned for changes. The way modifications are applied depends on drools.agent.newInstance property present in the KnowledgeAgentConfiguration object passed to the agent.

6.3.3. Writing the KnowledgePackage to an OutputStream

This is how to write the KnowledgePackage to an OutputStream:
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent" );
kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) );
KnowledgeBase kbase = kagent.getKnowledgeBase();

6.3.4. ClassLoaders

6.3.4.1. Custom ClassLoaders for KnowledgeBuilder

The Knowledge Agent could end up failing during the compiling or executing process while using classes outside the agent's classloader. If this occurs, use a custom classloader for the Knowledge Agent's kbuilder or force the Knowledge Agent to use the same classloader that its kbase uses.

Procedure 6.4. Custom Classloaders for KnowledgeBuilder

  1. Open a KnowledgeBuilderConfiguration and specify a custom classloader.
  2. If you need to pass custom configuration to these compilers, sends a KnowledgeBuilderConfiguration object to KnowledgeAgentFactory.newKnowledgeAgent().
This object will be used in every builder the agent creates.

Procedure 6.5. Reusing the KnowledgeBase ClassLoader

  1. Determine if the classloader you want to use in the compilation process of remote resources is the same needed in the Knowledge Agent's kbase, so the rules can be executed.
  2. Set up the desired ClassLoader to the agent kbase and use the drools.agent.useKBaseClassLoaderForCompiling property of KnowledgeAgentConfiguration object.
  3. Modify the agent's kbuilder classloader in runtime by modifying the agent's kbase classloader.
The following is an example of the KnowledgeAgentConfiguration property:
KnowledgeBaseConfiguration kbaseConfig =
    KnowledgeBaseFactory.newKnowledgeBaseConfiguration(null, customClassLoader);
KnowledgeBase kbase =
    KnowledgeBaseFactory.newKnowledgeBase(kbaseConfig); //kbase with custom classloader
KnowledgeAgentConfiguration aconf =
    KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
aconf.setProperty("drools.agent.newInstance", "false"); //incremental change set processing enabled
aconf.setProperty("drools.agent.useKBaseClassLoaderForCompiling", "true");
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
                "test agent", kbase, aconf);

6.3.5. newInstance

6.3.5.1. The newInstance Property

The newInstance property assists in processing change sets.
A Knowledge Agent can process change sets in two different ways: recreating the knowledge base every time a new change set is processed or applying the change set in the cached knowledge base without destroying it. This behavior is controlled by the KnowledgeAgentConfiguration object's newInstance property when it is passed to the Agent's constructor.

6.3.6. Resource Scanning

6.3.6.1. Starting the Scanning and Notification Services

This is the code for starting scanning and notification services:
ResourceFactory.getResourceChangeNotifierService().start();
ResourceFactory.getResourceChangeScannerService().start();

Note

Resource scanning is not on by default. It must be started. This also applies to notification. Both can be done via the ResourceFactory.

6.3.6.2. The ResourceChangeScanner

The ResourceChangeScanner is used to scan for services. The default resource scanning period may be changed via the ResourceChangeScannerService. A suitably updated ResourceChangeScannerConfiguration object is passed to the service's configure() method, which allows for the service to be reconfigured on demand.

6.3.6.3. Changing the Scanning Intervals

This is the code to use to change scanning intervals:
ResourceChangeScannerConfiguration sconf =
    ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
// Set the disk scanning interval to 30s, default is 60s.
sconf.setProperty( "drools.resource.scanner.interval", "30" ); 
ResourceFactory.getResourceChangeScannerService().configure( sconf );

6.3.6.4. The KnowledgeAgentConfiguration Property

The KnowledgeAgentConfiguration can be used to modify a Knowledge Agent's default behavior. You can use this to load the resources from a directory while inhibiting the continuous scan for changes of that directory.

6.3.6.5. Change the Scanning Behavior

Use this code to change the scanning behavior:
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();

KnowledgeAgentConfiguration kaconf =
    KnowledgeAgentFactory.newKnowledgeAgentConfiguation();
// Do not scan directories, just files.
kaconf.setProperty( "drools.agent.scanDirectories", "false" );
KnowledgeAgent kagent =
    KnowledgeAgentFactory.newKnowledgeAgent( "test agent", kaconf );

6.3.7. Knowledge Bases and applyChangeSet()

6.3.7.1. Interactions Between Knowledge Agents and Knowledge Bases

Knowledge Agents can process both an empty Knowledge Base or a populated one. If a populated Knowledge Base is provided, the Knowledge Agent will run an iterator from Knowledge Base and subscribe to the resources that it finds. While it is possible for the Knowledge Builder to build all resources found in a directory, that information is lost by the Knowledge Builder so that those directories will not be continuously scanned. Only directories specified as part of the applyChangeSet(Resource) method are monitored.
One of the advantages of providing KnowledgeBase as the starting point is that you can provide it with a KnowledgeBaseConfiguration. When resource changes are detected and a new KnowledgeBase object is instantiated, it will use the KnowledgeBaseConfiguration of the previous KnowledgeBase object.

6.3.7.2. Using an Existing KnowledgeBase

This is the code for utilizing an existing KnowledgeBase:
KnowledgeBaseConfiguration kbaseConf =
    KnowledgeBaseFactory.createKnowledgeBaseConfiguration( null, cl );
KnowledgeBase kbase KnowledgeBaseFactory.newKnowledgeBase( kbaseConf );
// Populate kbase with resources here.

KnowledgeAgent kagent =
    KnowledgeAgentFactory.newKnowledgeAgent( "MyAgent", kbase );
KnowledgeBase kbase = kagent.getKnowledgeBase();
In the above example getKnowledgeBase() will return the same provided kbase instance until resource changes are detected and a new Knowledge Base is built. When the new Knowledge Base is built, it will be done with the KnowledgeBaseConfiguration that was provided to the previous KnowledgeBase.

6.3.7.3. The applyChangeSet() Method

If a ChangeSet XML is used with the applyChangeSet() method it will add any directories to the scanning process. When the directory scan detects an additional file, it will be added to the Knowledge Base. Any removed file is removed from the Knowledge Base, and modified files will be removed from the Knowledge Base.

6.3.7.4. ChangeSet XML to Add Directory Contents

Use this XML to add the contents of a directory to a ChangeSet:
<change-set xmlns='http://drools.org/drools-5.0/change-set'
            xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'
            xs:schemaLocation='http://drools.org/drools-5.0/change-set.xsd' >
   <add>
      <resource source='file:/projects/myproject/myrules' type='PKG' />
   </add>
</change-set>

Note

Note that for the resource type PKG, the drools-compiler dependency is not needed. The Knowledge Agent is able to handle those with just drools-core.

6.3.8. Resource Caching

6.3.8.1. Restoring Resource Caching After a Restart

If your knowledge agent is pulling resources from an http(s) URL, the resource from the remote web server may suddenly disappear.

Procedure 6.6. Resource Restart

  1. To survive a restart when a resource is no longer available remotely (for example, the remote server is being restarted), set a System Property: drools.resource.urlcache.
  2. Make sure that System Property is set to a directory that has write permissions for the application. The Knowledge Agent will cache copies of the remote resources in that directory.
  3. Using the java command line -Ddrools.resource.urlcache=/users/someone/KnowledgeCache - will keep local copies of the resources (rules, packages etc) in that directory for the agent to use should it be restarted. (When a remote resource becomes available, and is updated, it will automatically update the local cache copy.)