There is no need to update your kbase in the listener. The agent will apply all the changes to the provided kbase. If you already have a stateful ksession from that kbase, then the changes in the kbase should be reflected immediately. Could you please post the log output of the kagent?
Best Regards, XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Esteban Aliverti - Developer @ http://www.plugtree.com - Blog @ http://ilesteban.wordpress.com On Tue, Apr 19, 2011 at 4:24 AM, Mattias Avelin <[email protected]>wrote: > Hi! > > Yes, I have already implemented a KnowledgeAgentEventListener acts on > KnowledgeBaseUpdatedEvent and ResourceCompilationFailedEvent. I use this to > update my knowledgebase reference in my class that wraps the KnowledgeBase > and KnowledgeAgent. Below is the code for this class > ("DynamicDecisionService"). I suspect that I have missed something vital > since I'm actually not getting my knowledgebase to update itself either but > I "do it myself" in the listener when I receive a KnowledgeBaseUpdatedEvent. > > Here is the code that handles the KnowledgeAgent and KnowledgeBase (I have > stripped out some labels and comments since this belongs to the client). > > Best regards > > Mattias Avelin > > package com.x.service; > > import java.util.ArrayList; > import org.apache.log4j.Logger; > import org.drools.KnowledgeBase; > import org.drools.KnowledgeBaseConfiguration; > import org.drools.KnowledgeBaseFactory; > import org.drools.agent.KnowledgeAgent; > import org.drools.agent.KnowledgeAgentConfiguration; > import org.drools.agent.KnowledgeAgentFactory; > import org.drools.builder.KnowledgeBuilderError; > import org.drools.builder.KnowledgeBuilderErrors; > import org.drools.conf.EventProcessingOption; > import org.drools.event.knowledgeagent.KnowledgeBaseUpdatedEvent; > import org.drools.event.knowledgeagent.ResourceCompilationFailedEvent; > import org.drools.event.rule.DefaultKnowledgeAgentEventListener; > import org.drools.io.ResourceChangeScannerConfiguration; > import org.drools.io.ResourceFactory; > > /** > * {@inheritDoc} > * <p> > * This implementation of DecisionService updates the knowledgebase > dynamically > * when the underlying rules (drl-files) are updated. Therefore each call > to the > * createSession() method will return a session based on the most resent > version > * of the rules (allowing for some lag due to the intervals of the > * resource scanner). > * </p> > * <p> > * For statefull sessions the session needs to be updated "manually" when > the > * KnowledgeBase has been updated. > * </P> > * @author Mattias Avelin - [email protected] > */ > public class DynamicDecisionService implements DecisionService > { > private static Logger LOG = > Logger.getLogger(DynamicDecisionService.class); > > // Repository of all the application's knowledge definitions > private KnowledgeBase kBase; > // The agent that monitores the rule files (resources) for changes > private KnowledgeAgent kAgent; > // Decision service type > private DecisionSessionType type; > // When the current knowledgebase was created > private long kbaseLastUpdated; > > /** > * Create a DynamicDecisionService using a ChangeSet. > * > * @param changeSet - The ChangeSet referencing the rule-files to use > * for this service. Expects a classpath reference > * > * @throws IllegalArgumentException if changeSet is not a valid > ChangeSet. > */ > public DynamicDecisionService( > String changeSet, > DecisionSessionType type) > { > this.kBase = createKnowledgeBase(type); > // the method could reference kBase itself but I thought it > // more more "clear" if I actually supply it in the method > invocation > this.kAgent = createKnowledgeAgent(changeSet, this.kBase); > // This should not be neccesary according to all sources I've found > // but without re-assigning the reference it doesn't work!?!? > this.kBase = kAgent.getKnowledgeBase(); > this.kbaseLastUpdated = System.currentTimeMillis(); > } > > > /** > * {@inheritDoc} > */ > public DecisionSession createSession () > { > return new DecisionSession(kBase.newStatefulKnowledgeSession()); > } > > > /** > * {@inheritDoc} > */ > public DecisionSession updateSession (DecisionSession oldSession) > { > // Create a new session from the current KnowledgeBase > DecisionSession newSession = > new DecisionSession(kBase.newStatefulKnowledgeSession()); > > if(oldSession != null) > { > // "Clean" the old session of all stateless facts before update > oldSession.removeAllStatelessKnowledge(); > // Copy all remaining facts to the new session > newSession.uploadKnowledge(new > ArrayList(oldSession.getAllFacts())); > } > return newSession; > } > > > /** > * {@inheritDoc} > */ > public boolean isSessionStale(DecisionSession decisionSession) > { > if(decisionSession.getCreationTime() < this.kbaseLastUpdated) > { > return true; > } > else > { > return false; > } > } > > > /** > * Create a KnowledgeBuilder from a ChangeSet. > * > * @param changeSet - The ChangeSet > * @return A KnowledgeBuilder > * @throws IllegalArgumentException if changeSet is not a valid > ChangeSet. > */ > private KnowledgeAgent createKnowledgeAgent( > String changeSet, > KnowledgeBase kbase) > { > // Configure KnowledgeAgentFactory > configureAgentFactory(); > // Create the knowledge agent > KnowledgeAgent agent = KnowledgeAgentFactory.newKnowledgeAgent( > "classificationAgent", > kbase); > > agent.applyChangeSet(ResourceFactory.newClassPathResource(changeSet)); > // Add actionListener for detecting rule updates > agent.addEventListener(new xKnowledgeAgentEventListener()); > // Start the monitoring... > ResourceFactory.getResourceChangeNotifierService().start(); > ResourceFactory.getResourceChangeScannerService().start(); > return agent; > } > > > /** > * Configure the agentFactory. > */ > private void configureAgentFactory() > { > // Enable incremental knowledge base build - false means that the > // old knowledge base is "reused" and updated when there are > // updated rules. True means that the old base is discarded and a > new > // one is created > KnowledgeAgentConfiguration kagentConf = > KnowledgeAgentFactory.newKnowledgeAgentConfiguration(); > kagentConf.setProperty("drools.agent.newInstance", "false"); > > // Configure the scanning interval - default is 60 sec. > // (Scanning resources for changes...) > ResourceChangeScannerConfiguration sconf = > > > ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration(); > sconf.setProperty("drools.resource.scanner.interval", "30"); > ResourceFactory.getResourceChangeScannerService().configure(sconf); > } > > > /** > * Create a KnowledgeBase. For CEP (Drools Fusion) decision service > * use type = STATE_FULL otherwise use STATE_LESS. > * > * @param type - The type KnowledgeBase, state full or state less > * > * @return A KnowledgeBase > */ > private KnowledgeBase createKnowledgeBase(DecisionSessionType type) > { > KnowledgeBase kbase; > if(type.equals(DecisionSessionType.STATE_FULL)){ > KnowledgeBaseConfiguration config = > KnowledgeBaseFactory.newKnowledgeBaseConfiguration(); > config.setOption( EventProcessingOption.STREAM ); > kbase = KnowledgeBaseFactory.newKnowledgeBase( config ); > } > else > { > kbase = KnowledgeBaseFactory.newKnowledgeBase(); > } > return kbase; > } > > > /** > * Get the ServiceType of this Service. > * > * @return The ServiceType of this service (STATE_FULL or STATE_LESS) > */ > public DecisionSessionType getType () > { > return type; > } > > > /** > * When was the KnowledgeBase last updated. > * > * @return The timestamp (ms) for last update of KnowledgeBase > */ > public long getLastUpdated() > { > return this.kbaseLastUpdated; > } > > > /** > * Custom event listener for acting on events such as rule updates and > * rule loading errors. > */ > private class xKnowledgeAgentEventListener > extends DefaultKnowledgeAgentEventListener > { > > /** > * Update the working copy of the KnowledgeBase when detecting > * a updated one. > * > * @param event - The event signalling that the rule base has been > updated > */ > @Override > public void knowledgeBaseUpdated ( > KnowledgeBaseUpdatedEvent event) > { > LOG.info("Detected updated rules! Rebuilding knowledgeBase!"); > long startTime = System.currentTimeMillis(); > kBase = kAgent.getKnowledgeBase(); > long endTime = System.currentTimeMillis(); > // Update the timestamp for when the knowledgeBase was updated > kbaseLastUpdated = endTime; > LOG.info("Rebuilding knowledgebase took " + > (endTime - startTime) + "ms..."); > } > > > /** > * Log errors when problems updating the knowledge base. > * > * @param event - the Event signalling failure to load updated rules > */ > @Override > public void resourceCompilationFailed ( > ResourceCompilationFailedEvent event) > { > KnowledgeBuilderErrors errors = > event.getKnowledgeBuilder().getErrors(); > > if (errors.size() > 0) > { > LOG.error("Errors loading knowledge."); > for (KnowledgeBuilderError error : errors) > { > LOG.error(error); > } > } > } > } > } > > > > > > ________________________________________ > From: [email protected] [ > [email protected]] On Behalf Of Esteban Aliverti [ > [email protected]] > Sent: Monday, April 18, 2011 19:18 > To: Rules Users List > Subject: Re: [rules-users] Dynamic updates of stateful sessions > > Maybe the new rules fail to compile. You can add an > KnowledgeAgentEventListener to the agent to check for compilation errors. > Could you post some code snippet showing how are you creating the kagent, > the kbase, etc. > > You can take a look at some tests using newInstence=false here: > > https://github.com/droolsjbpm/drools/blob/master/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentIncrementalChangeSetTest.java > > Best Regards, > > XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX > > Esteban Aliverti > - Developer @ http://www.plugtree.com > - Blog @ http://ilesteban.wordpress.com > > > On Mon, Apr 18, 2011 at 1:31 PM, Mattias Avelin < > [email protected]<mailto:[email protected]>> wrote: > Thanks for the swift reply! > > I have configured my Knowledge Agent to reuse the same KnowledgeBase (set > drools.agent.newInstance property to "false" in my > KnowledgeAgentConfiguration) as described in the Expert documentation. But > my stateful session keeps using the old rules event though I can see from > the log output that the Knowledgebase has been updated. > > /Mattias > ________ > From: [email protected]<mailto: > [email protected]> [[email protected] > <mailto:[email protected]>] On Behalf Of Esteban > Aliverti [[email protected]<mailto:[email protected]>] > Sent: Monday, April 18, 2011 16:49 > To: Rules Users List > Subject: Re: [rules-users] Dynamic updates of stateful sessions > > By default, the Knowledge Agent creates a new kbase when changes in the > monitored resources are detected. So the stateful sessions you had are not > going to "see" the changes because they belong to a different kbase. > If you want the agent to apply the changes to the current kbase, you need > to set drools.agent.newInstance property to "false" in knowledge agent > configuration. > You can read about this here: > http://ilesteban.wordpress.com/2010/03/25/knowledge-agent-incremental-change-set-processing-and-binary-diff/ > > If you are defining the kagent using spring, you can use the "newInstence" > attribute of <kagent> bean. > > Best Regards, > > XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX > > Esteban Aliverti > - Developer @ http://www.plugtree.com > - Blog @ http://ilesteban.wordpress.com > > > On Mon, Apr 18, 2011 at 11:41 AM, Mattias Avelin < > [email protected]<mailto:[email protected]><mailto: > [email protected]<mailto:[email protected]>>> wrote: > We have a application in which we have both stateless & stateful sessions > running. We're using the KnowledgeAgent and ChangeSets to automatically > update our knowledge bases when the rules are changed. > This works fine for our stateless sessions for which we are creating a new > session for each request and if the rules have been updated this is > reflected in next session we create. > > But for stateful sessions I'm not quite as sure on how to get it working. I > can see in the logs that the KnowledgeBase is re-built when the > KnowledgeAgent detects the updated rule files. But my "long running" > session > is does not reflect these changes (which it shouldn't right?). But how do > we > apply these changes to the stateful session without loosing all the facts I > accumulated? > > The way I've solved it now is to keep a "last updated" timestamp for the > knowledgeBase and a "created" timestamp for the session and then compare > these before using the session. If the knowledgeBase's "update timestamp" > is > later that the sessions "creation timestamp" I create a new Session and > then > "manually" copy all facts from the former to the latter. > > Is this the way you would do this or is there a better way? > > Best Regards > > Mattias Avelin > > > _______________________________________________ > rules-users mailing list > [email protected]<mailto:[email protected]><mailto: > [email protected]<mailto:[email protected]>> > https://lists.jboss.org/mailman/listinfo/rules-users > > > ______________________________________________________________________ > This email has been scanned by the MessageLabs Email Security System. > For more information please visit http://www.messagelabs.com/email > ______________________________________________________________________ > > > > _______________________________________________ > rules-users mailing list > [email protected]<mailto:[email protected]> > https://lists.jboss.org/mailman/listinfo/rules-users > > > ______________________________________________________________________ > This email has been scanned by the MessageLabs Email Security System. > For more information please visit http://www.messagelabs.com/email > ______________________________________________________________________ > > > > _______________________________________________ > rules-users mailing list > [email protected] > https://lists.jboss.org/mailman/listinfo/rules-users >
_______________________________________________ rules-users mailing list [email protected] https://lists.jboss.org/mailman/listinfo/rules-users
