Question

i'm working at a little drools project and i have following problem:

- when i read the knowledgepackages from drools via the knowledgeAgent it takes a long time to load
((now i know that building the knowledgeBase in general and especially when loading packages from guvnor is very intense ))

  • so I'm trying to serialize the KnowledgeBase to a file which is located locally on the system
    - on the one hand because loading the kBase from a local file is much much faster
    - and for the other so that i can use the KnowledgeBase for other applications
    The Problem with this is, that while using the KnowledgeAgent to load the KnowledgeBase the first time, the base will be updated by the Agent automatically

    BUT: whilst the Base is updated, my local file will not be updated too
    So I'm wondering how to handle/get the changeNotification from my KnowledgeAgent so i can call a method to serialize my KnowledgeBase ?


    Is this somehow possible? basically i just want to update my local knowledgeBase file, everytime someone edits a rule in governor, so that my local file is always up to date.


    If it isn't possible, or a really bad solution to begin with, what is the recommended / best way to go about it?


    Please endure my english and the question itself, if you cant really make out what i want to accomplish or if my request is actually not a good solution or the question itself is redundant, im rather new to java and a total noob when it comes to drools.

Down below is the code:

public class DroolsConnection {

private static KnowledgeAgent kAgent;
private static KnowledgeBase  kAgentBase;

public DroolsConnection(){
     ResourceFactory.getResourceChangeNotifierService().start();
     ResourceFactory.getResourceChangeScannerService() .start();

} 

public KnowledgeBase readKnowledgeBase( ) throws Exception {

     kAgent     = KnowledgeAgentFactory.newKnowledgeAgent("guvnorAgent");
     kAgent      .applyChangeSet( ResourceFactory.newFileResource(CHANGESET_PATH));
     kAgent.monitorResourceChangeEvents(true);

     kAgentBase = kAgent.getKnowledgeBase();
     serializeKnowledgeBase(kAgentBase);
     return kAgentBase;

   }


 public List<EvaluationObject> runAgainstRules( List<EvaluationObject> objectsToEvaluate,
                                                KnowledgeBase kBase ) throws Exception{

    StatefulKnowledgeSession knowSession = kBase.newStatefulKnowledgeSession();
    KnowledgeRuntimeLogger knowLogger    = KnowledgeRuntimeLoggerFactory.newFileLogger(knowSession, "logger");

    for ( EvaluationObject o : objectsToEvaluate ){
        knowSession.insert( o );
    }

    knowSession.fireAllRules();
    knowLogger .close();
    knowSession.dispose();
    return objectsToEvaluate;
 }


 public KnowledgeBase serializeKnowledgeBase(KnowledgeBase kBase) throws IOException{

        OutputStream outStream = new FileOutputStream( SERIALIZE_BASE_PATH );
        ObjectOutputStream oos = new ObjectOutputStream( outStream );
        oos.writeObject        ( kBase );
        oos.close();
        return kBase;
 }


 public KnowledgeBase loadFromSerializedKnowledgeBase() throws Exception {

        KnowledgeBase kBase   = KnowledgeBaseFactory.newKnowledgeBase(); 
        InputStream is        = new FileInputStream( SERIALIZE_BASE_PATH );
        ObjectInputStream ois = new ObjectInputStream( is );
        kBase                 = (KnowledgeBase) ois.readObject();
        ois.close();
        return kBase;
 }

}


thanks for your help in advance!
best regards,
Marenko

Was it helpful?

Solution

In order to keep your local kbase updated you could use a KnowledgeAgentEventListener to know when its internal kbase gets updated:

    kagent.addEventListener( new KnowledgeAgentEventListener() {

        public void beforeChangeSetApplied(BeforeChangeSetAppliedEvent event) {
        }

        public synchronized void afterChangeSetApplied(AfterChangeSetAppliedEvent event) {
        }

        public void beforeChangeSetProcessed(BeforeChangeSetProcessedEvent event) {
        }

        public void afterChangeSetProcessed(AfterChangeSetProcessedEvent event) {
        }

        public void beforeResourceProcessed(BeforeResourceProcessedEvent event) {
        }

        public void afterResourceProcessed(AfterResourceProcessedEvent event) {
        }

        public void knowledgeBaseUpdated(KnowledgeBaseUpdatedEvent event) {
            //THIS IS THE EVENT YOU ARE INTERESTED IN 
        }

        public void resourceCompilationFailed(ResourceCompilationFailedEvent event) {               
        }
    } );

You still need to handle concurrently accesses on your local kbase though.

By the way, since you are not using 'newInstance' configuration option, the agent will create a new instance of a kbase each time a change-set is applied. So, make sure you serialize the kagent's internal kbase (kagent.getKnowledgeBase()) instead of the reference you have in your app.

Hope it helps,

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top