[jboss-svn-commits] JBL Code SVN: r31039 - in labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src: test/java/org/jboss/internal/soa/esb/services/rules and 1 other directory.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Tue Jan 12 15:53:14 EST 2010


Author: kevin.conner at jboss.com
Date: 2010-01-12 15:53:14 -0500 (Tue, 12 Jan 2010)
New Revision: 31039

Added:
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleBaseState.java
Modified:
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleService.java
   labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/test/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleServiceUnitTest.java
Log:
Introduce a rules execution state and cache sessions: JBESB-3106

Added: labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleBaseState.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleBaseState.java	                        (rev 0)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleBaseState.java	2010-01-12 20:53:14 UTC (rev 31039)
@@ -0,0 +1,390 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.internal.soa.esb.services.rules;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.log4j.Logger;
+import org.drools.RuleBase;
+import org.drools.SessionConfiguration;
+import org.drools.StatefulSession;
+import org.drools.StatelessSession;
+import org.drools.WorkingMemoryEntryPoint;
+import org.drools.common.EventFactHandle;
+import org.drools.common.InternalFactHandle;
+import org.drools.impl.EnvironmentFactory;
+import org.drools.runtime.Environment;
+import org.drools.spi.GlobalResolver;
+import org.jboss.internal.soa.esb.services.rules.util.RulesContext;
+import org.jboss.soa.esb.message.Message;
+import org.jboss.soa.esb.services.rules.StatefulRuleInfo;
+
+/**
+ * Drools rule base state used to execute and cleanup rule bases.  Some parts have been extracted from the DroolsRuleService.
+ * 
+ * @author <a href='mailto:Kevin.Conner at jboss.com'>Kevin Conner</a>
+ * @author jdelong at redhat.com
+ * @author <a href="mailto:dbevenius at redhat.com">Daniel Bevenius</a>
+ */
+class DroolsRuleBaseState
+{
+    /**
+     * The logger for this state.
+     */
+    private static Logger LOGGER = Logger.getLogger(DroolsRuleBaseState.class);
+    
+    /**
+     * The rule base associated with this state.
+     */
+    private final RuleBase ruleBase ;
+    /**
+     * The disposed flag.  If set, stateful sessions are automatically disposed.
+     */
+    private transient boolean disposed ;
+    
+    /**
+     * The stateful session.
+     */
+    private StatefulSession statefulSession ;
+    /**
+     * Stateful session configuration.
+     */
+    private SessionConfiguration statefulSessionConfiguration ;
+    /**
+     * Stateful environment
+     */
+    private Environment statefulEnvironment ;
+    /**
+     * The stateful session lock.
+     */
+    private final Lock statefulSessionLock = new ReentrantLock() ;
+    /**
+     * The stateful session count lock.
+     */
+    private final Lock statefulSessionCountLock = new ReentrantLock() ;
+    /**
+     * The number of sessions queued for the stateful session.
+     */
+    private int statefulSessionCount ;
+    /**
+     * The stateless sessions.
+     */
+    private final ConcurrentLinkedQueue<StatelessSession> statelessSessions = new ConcurrentLinkedQueue<StatelessSession>() ;
+    
+    /**
+     * Construct the rule base state.
+     * @param ruleBase The associated rule base.
+     */
+    DroolsRuleBaseState(final RuleBase ruleBase)
+    {
+        this.ruleBase = ruleBase ;
+    }
+    
+    /**
+     * Get the rule base associated with this state.
+     * @return The rule base.
+     */
+    RuleBase getRuleBase()
+    {
+        return ruleBase ;
+    }
+    
+    /**
+     * Execute rules using using the Stateless API
+     *
+     * @param message -
+     *          Message that is updated with the results.
+     * @param objectList -
+     *          a list with additional objects (typically pulled from the message)
+     *          to be inserted into working memory
+     * @param globals -
+     *            Map of globals variables that should be set in the working memory
+     *
+     * @return Message -
+     *          with updated objects.
+     */
+    Message executeStatelessRules(
+            final Message message,
+            final Map<String,Object> globals,
+            final List<Object> objectList)
+    {
+        final StatelessSession head = statelessSessions.poll() ;
+        final StatelessSession statelessSession = (head != null ? head : ruleBase.newStatelessSession()) ;
+        RulesContext.clearContext() ;
+        try
+        {
+            final List<Object> facts = new ArrayList<Object>() ;
+            facts.add(message) ;
+            if (objectList != null)
+            {
+                facts.addAll(objectList) ;
+            }
+            statelessSession.setGlobalResolver(new StatelessGlobalResolver(globals)) ;
+            try
+            {
+                statelessSession.execute(facts);
+            }
+            finally
+            {
+                statelessSession.setGlobalResolver(null) ;
+            }
+        }
+        finally
+        {
+            RulesContext.clearContext() ;
+            statelessSessions.add(statelessSession) ;
+        }
+        return message;
+    }
+    
+    /**
+     * Execute rules using using the Stateful API
+     *
+     * @param dispose -
+     *          if true the working memory will be dereferenced.
+     * @param message -
+     *          Message that is updated with the results.
+     * @param globals -
+     *          Map of globals variables that should be set in the working memory
+     * @param entryPointMap -
+     *          a map with additional objects to be inserted into working memory or
+     *          into the named WorkingMemoryEntryPoint. Any objects included in the
+     *          {@link #DEFAULT_ENTRY_POINT} name will be inserted into the normal
+     *          working memory. The rest will lookup the entry point working memory
+     *          and insert the objects into the those working memories.
+     * @return Message -
+     *          a possibly updated Message object. The message object is available
+     *          to Rules and my be updated by them.
+     * @throws RuleServiceException
+     */
+    Message executeStatefulRules(
+            final StatefulRuleInfo ruleInfo,
+            final Message message) throws RuleServiceException
+    {
+        final boolean debugEnabled = LOGGER.isDebugEnabled() ;
+        
+        RulesContext.clearContext() ;
+        statefulSessionCountLock.lock() ;
+        statefulSessionCount++ ;
+        statefulSessionCountLock.unlock() ;
+        
+        try
+        {
+            statefulSessionLock.lock() ;
+            try
+            {
+                if ((statefulSession != null) && !ruleInfo.continueState())
+                {
+                    if (debugEnabled)
+                    {
+                        LOGGER.debug("Disposing current stateful session, no continue set") ;
+                    }
+                    final StatefulSession disposedStatefulSession = statefulSession ;
+                    statefulSession = null ;
+                    disposedStatefulSession.dispose() ;
+                }
+                
+                if (statefulSession == null)
+                {
+                    if (debugEnabled)
+                    {
+                        LOGGER.debug("Creating stateful session") ;
+                    }
+                    if (statefulSessionConfiguration == null)
+                    {
+                        statefulSessionConfiguration = new SessionConfiguration() ;
+                    }
+                    if (statefulEnvironment == null)
+                    {
+                        statefulEnvironment = EnvironmentFactory.newEnvironment() ;
+                    }
+                    statefulSession = ruleBase.newStatefulSession(statefulSessionConfiguration, statefulEnvironment) ;
+                }
+                
+                try
+                {
+                    final Map<String, Object> globals = ruleInfo.getGlobals() ;
+                    if (globals != null)
+                    {
+                        if (debugEnabled)
+                        {
+                            LOGGER.debug("Inserting globals") ;
+                        }
+                        final Set<Entry<String, Object>> entrySet = globals.entrySet() ;
+                        for(Entry<String, Object> entry : entrySet)
+                        {
+                            statefulSession.setGlobal( entry.getKey(), entry.getValue() );
+                        }
+                    }
+
+                    // Always insert the ESB Message object.
+                    InternalFactHandle handle = (InternalFactHandle) statefulSession.insert(message);
+                    if (debugEnabled && handle.isEvent())
+                    {
+                        EventFactHandle ef = (EventFactHandle) handle;
+                        LOGGER.debug("Event :" +  ef.getObject().getClass().getName() + ", startTimeStamp: " + ef.getStartTimestamp());
+                    }
+                    
+                    // Always insert the Default facts
+                    final List<Object> defaultFacts = ruleInfo.getDefaultFacts();
+                    if (defaultFacts != null)
+                    {
+                        if (debugEnabled)
+                        {
+                            LOGGER.debug("Inserting default facts") ;
+                        }
+                        for(Object object : defaultFacts)
+                        {
+                            statefulSession.insert(object);
+                        }
+                    }
+
+                    // Insert any object that that did not specify an entry-point into the main working memory.
+                    if (ruleInfo.getFacts() != null)
+                    {
+                        if (debugEnabled)
+                        {
+                            LOGGER.debug("Inserting facts") ;
+                        }
+                        for(Entry<String, List<Object>> entry : ruleInfo.getFacts().entrySet())
+                        {
+                            String entryPointName = entry.getKey();
+                            // Insert object that have explicitly specified an entry-point.
+                            WorkingMemoryEntryPoint wmep = statefulSession.getWorkingMemoryEntryPoint(entryPointName);
+                            if (wmep == null)
+                            {
+                                throw new RuleServiceException("The entry-point '" + entryPointName + "' was not found in the current stateful session. Please double check your rules source");
+                            }
+                            for(Object object : entry.getValue())
+                            {
+                                wmep.insert(object);
+                            }
+                        }
+                    }
+                    
+                    if (debugEnabled)
+                    {
+                        LOGGER.debug("Firing rules") ;
+                    }
+                    // Fire rules.
+                    statefulSession.fireAllRules();
+                }
+                finally
+                {
+                    if ( ruleInfo.dispose() )
+                    {
+                        if (debugEnabled)
+                        {
+                            LOGGER.debug("Disposing current stateful session, dispose set") ;
+                        }
+                        final StatefulSession disposedStatefulSession = statefulSession ;
+                        statefulSession = null ;
+                        disposedStatefulSession.dispose() ;
+                    }
+                }
+            }
+            finally
+            {
+                statefulSessionLock.unlock() ;
+            }
+        }
+        finally
+        {
+            RulesContext.clearContext() ;
+            statefulSessionCountLock.lock() ;
+            statefulSessionCount-- ;
+            if (disposed && (statefulSessionCount == 0))
+            {
+                dispose() ;
+            }
+            statefulSessionCountLock.unlock() ;
+        }
+        return message ;
+    }
+    
+    void dispose()
+    {
+        statefulSessionCountLock.lock() ;
+        try
+        {
+            disposed = true ;
+            if ((statefulSessionCount == 0) && (statefulSession != null))
+            {
+                LOGGER.debug("Disposing stateful session") ;
+                final StatefulSession disposedStatefulSession = statefulSession ;
+                statefulSession = null ;
+                disposedStatefulSession.dispose() ;
+            }
+            statelessSessions.clear() ;
+        }
+        finally
+        {
+            statefulSessionCountLock.unlock() ;
+        }
+    }
+    
+    /**
+     * Global resolver for stateless execution
+     * @author <a href='kevin.conner at jboss.com'>Kevin Conner</a>
+     */
+    public class StatelessGlobalResolver implements GlobalResolver
+    {
+        /**
+         * The map of globals.
+         */
+        private final Map<String, Object> globals ;
+        
+        public StatelessGlobalResolver(Map<String, Object> globals)
+        {
+            this.globals = new HashMap<String, Object>(globals) ;
+        }
+
+        /**
+         * Resolve the global identifier.
+         * @param identifier The identifier.
+         * @return the value or null.
+         */
+        public Object resolveGlobal(final String identifier)
+        {
+            return globals.get(identifier) ;
+        }
+
+        /**
+         * Set the global identifier.
+         * @param identifier The identifier.
+         * @parma value the value.
+         */
+        public void setGlobal(final String identifier, final Object value)
+        {
+            globals.put(identifier, value) ;
+        }
+    }
+}


Property changes on: labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleBaseState.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleService.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleService.java	2010-01-12 20:40:46 UTC (rev 31038)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/main/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleService.java	2010-01-12 20:53:14 UTC (rev 31039)
@@ -22,31 +22,22 @@
 package org.jboss.internal.soa.esb.services.rules;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.log4j.Logger;
 import org.drools.RuleBase;
 import org.drools.StatefulSession;
-import org.drools.StatelessSession;
-import org.drools.WorkingMemoryEntryPoint;
 import org.drools.agent.RuleAgent;
-import org.drools.common.EventFactHandle;
-import org.drools.common.InternalFactHandle;
 import org.drools.compiler.DroolsParserException;
 import org.jboss.internal.soa.esb.assertion.AssertArgument;
-import org.jboss.internal.soa.esb.services.rules.util.RulesContext;
 import org.jboss.soa.esb.helpers.ConfigTree;
 import org.jboss.soa.esb.lifecycle.LifecyclePriorities;
 import org.jboss.soa.esb.lifecycle.LifecycleResource;
 import org.jboss.soa.esb.lifecycle.LifecycleResourceException;
 import org.jboss.soa.esb.lifecycle.LifecycleResourceFactory;
-import org.jboss.soa.esb.lifecycle.LifecycleResourceManager;
 import org.jboss.soa.esb.message.Message;
 import org.jboss.soa.esb.services.rules.RuleInfo;
 import org.jboss.soa.esb.services.rules.RuleService;
@@ -65,9 +56,9 @@
     private static Logger log = Logger.getLogger(DroolsRuleService.class);
 
     /**
-	 * The lifecycle resource factory for RuleBases.
+	 * The lifecycle resource state factory for RuleBases.
 	 */
-	private static final LifecycleResourceFactory<Map<String, RuleBase>> lifecycleRuleBaseFactory = new LifecycleRuleBaseFactory();
+	private static final LifecycleResourceFactory<Map<String, DroolsRuleBaseState>> lifecycleRuleBaseStateFactory = new LifecycleRuleBaseStateFactory();
 
     /**
 	 * The lifecycle resource factory for RuleAgents.
@@ -77,13 +68,13 @@
 	/**
 	 * The lifecycle resource factory rule sets.
 	 */
-	private static final LifecycleResourceFactory<Map<String, String>> lifecycleRuleSetFactory = new LifecycleRuleSetFactory();
+	private static final LifecycleResourceFactory<ConcurrentHashMap<String, String>> lifecycleRuleSetFactory = new LifecycleRuleSetFactory();
 
 	/**
-	 * The lifecycle resource rule bases.
+	 * The lifecycle resource rule base states.
 	 */
-	private static final LifecycleResource<Map<String, RuleBase>> lifecycleRuleBases = new LifecycleResource<Map<String, RuleBase>>(
-			lifecycleRuleBaseFactory, LifecyclePriorities.RULE_BASE_PRIORITY);
+	private static final LifecycleResource<Map<String, DroolsRuleBaseState>> lifecycleRuleBaseStates = new LifecycleResource<Map<String, DroolsRuleBaseState>>(
+			lifecycleRuleBaseStateFactory, LifecyclePriorities.RULE_BASE_PRIORITY);
 
 	/**
 	 * RuleAgents cache
@@ -94,7 +85,7 @@
 	/**
 	 * The lifecycle resource for ruleset.
 	 */
-	private static final LifecycleResource<Map<String, String>> lifecycleRuleSets = new LifecycleResource<Map<String, String>>(
+	private static final LifecycleResource<ConcurrentHashMap<String, String>> lifecycleRuleSets = new LifecycleResource<ConcurrentHashMap<String, String>>(
 			lifecycleRuleSetFactory, LifecyclePriorities.RULE_BASE_PRIORITY);
 
 	/**
@@ -131,8 +122,8 @@
 	{
 		AssertArgument.isNotNullAndNotEmpty( ruleSet, "ruleSet" );
 
-		RuleBase ruleBase = getRuleBaseForFileBasedRules(ruleSet, dsl, ruleReload);
-		return executeStatelessRules(ruleBase, message, globals, objectList);
+		DroolsRuleBaseState ruleBaseState = getRuleBaseStateForFileBasedRules(ruleSet, dsl, ruleReload);
+		return ruleBaseState.executeStatelessRules(message, globals, objectList);
 	}
 
 	/**
@@ -145,8 +136,8 @@
 	public Message executeStatelessRules(final RuleInfo ruleInfo, final Message message) throws RuleServiceException
 	{
 		AssertArgument.isNotNull(ruleInfo, "ruleInfo" );
-		final RuleBase ruleBase = getRuleBaseForFileBasedRules(ruleInfo.getRuleSource(), ruleInfo.getDslSource(), ruleInfo.getReload());
-		return executeStatelessRules(ruleBase, message, ruleInfo.getGlobals(), ruleInfo.getDefaultFacts());
+		final DroolsRuleBaseState ruleBaseState = getRuleBaseStateForFileBasedRules(ruleInfo.getRuleSource(), ruleInfo.getDslSource(), ruleInfo.getReload());
+		return ruleBaseState.executeStatelessRules(message, ruleInfo.getGlobals(), ruleInfo.getDefaultFacts());
 	}
 
 
@@ -178,15 +169,15 @@
 	{
 		AssertArgument.isNotNullAndNotEmpty( decisionTable, "decisionTable" );
 
-		RuleBase ruleBase = getRuleBaseForDecisionTable( decisionTable, ruleReload );
-		return executeStatelessRules( ruleBase, message, globals, objectList );
+		DroolsRuleBaseState ruleBaseState = getRuleBaseStateForDecisionTable( decisionTable, ruleReload );
+		return ruleBaseState.executeStatelessRules( message, globals, objectList );
 	}
 
 	public Message executeStatelessRulesFromDecisionTable(final RuleInfo ruleInfo, final Message message) throws RuleServiceException
 	{
 		AssertArgument.isNotNull(ruleInfo, "ruleInfo" );
-		RuleBase ruleBase = getRuleBaseForDecisionTable(ruleInfo.getRuleSource(), ruleInfo.getReload());
-		return executeStatelessRules(ruleBase, message, ruleInfo.getGlobals(), ruleInfo.getDefaultFacts());
+		DroolsRuleBaseState ruleBaseState = getRuleBaseStateForDecisionTable(ruleInfo.getRuleSource(), ruleInfo.getReload());
+		return ruleBaseState.executeStatelessRules(message, ruleInfo.getGlobals(), ruleInfo.getDefaultFacts());
 
 	}
 
@@ -217,8 +208,8 @@
 
 		try
 		{
-    		final RuleBase ruleBase = getRuleBaseForRuleAgent( ruleAgentProperties ) ;
-			return executeStatelessRules(ruleBase, message, globals, objectList);
+    		final DroolsRuleBaseState ruleBaseState = getRuleBaseStateForRuleAgent( ruleAgentProperties ) ;
+			return ruleBaseState.executeStatelessRules(message, globals, objectList);
 		}
 		catch ( final IOException e)
 		{
@@ -235,8 +226,8 @@
 		AssertArgument.isNotNull(ruleInfo, "ruleInfo" );
 		try
         {
-            final RuleBase ruleBase = getRuleBaseForRuleAgent(ruleInfo.getRuleSource());
-            return executeStatelessRules(ruleBase, message, ruleInfo.getGlobals(), ruleInfo.getDefaultFacts());
+            final DroolsRuleBaseState ruleBaseState = getRuleBaseStateForRuleAgent(ruleInfo.getRuleSource());
+            return ruleBaseState.executeStatelessRules(message, ruleInfo.getGlobals(), ruleInfo.getDefaultFacts());
         }
         catch ( final IOException e)
         {
@@ -288,8 +279,8 @@
 		builder.defaultFacts(objectList);
 		StatefulRuleInfoImpl ruleInfo = new StatefulRuleInfoImpl(builder.build(), false, false);
 
-		RuleBase ruleBase = getRuleBaseForFileBasedRules( ruleInfo.getRuleSource(), ruleInfo.getDslSource(), ruleInfo.getReload());
-		return executeStatefulRules(ruleBase, ruleInfo, message);
+		DroolsRuleBaseState ruleBaseState = getRuleBaseStateForFileBasedRules( ruleInfo.getRuleSource(), ruleInfo.getDslSource(), ruleInfo.getReload());
+		return ruleBaseState.executeStatefulRules(ruleInfo, message);
 	}
 
 	/**
@@ -305,8 +296,8 @@
 	public Message executeStatefulRules(final StatefulRuleInfo info, final Message msg) throws RuleServiceException
     {
 		AssertArgument.isNotNull(info, "ruleInfo" );
-		final RuleBase ruleBase = getRuleBaseForFileBasedRules(info.getRuleSource(), info.getDslSource(), info.getReload());
-		return executeStatefulRules(ruleBase, info, msg);
+		final DroolsRuleBaseState ruleBaseState = getRuleBaseStateForFileBasedRules(info.getRuleSource(), info.getDslSource(), info.getReload());
+		return ruleBaseState.executeStatefulRules(info, msg);
     }
 
     /**
@@ -343,9 +334,9 @@
 		builder.defaultFacts(objectList);
 		StatefulRuleInfoImpl ruleInfo = new StatefulRuleInfoImpl(builder.build(), false, false);
 
-		final RuleBase ruleBase = getRuleBaseForDecisionTable(ruleInfo.getRuleSource(), ruleInfo.getReload());
+		final DroolsRuleBaseState ruleBaseState = getRuleBaseStateForDecisionTable(ruleInfo.getRuleSource(), ruleInfo.getReload());
 
-		return executeStatefulRules(ruleBase, ruleInfo, message);
+		return ruleBaseState.executeStatefulRules(ruleInfo, message);
 	}
 
 	/**
@@ -361,8 +352,8 @@
 	@Deprecated
     public Message executeStatefulRulesFromDecisionTable(StatefulRuleInfo ruleInfo, Message msg) throws RuleServiceException
     {
-		final RuleBase ruleBase = getRuleBaseForDecisionTable(ruleInfo.getRuleSource(), ruleInfo.getReload());
-		return executeStatefulRules(ruleBase, ruleInfo, msg);
+		final DroolsRuleBaseState ruleBaseState = getRuleBaseStateForDecisionTable(ruleInfo.getRuleSource(), ruleInfo.getReload());
+		return ruleBaseState.executeStatefulRules(ruleInfo, msg);
     }
 
     /**
@@ -395,9 +386,9 @@
     		builder.defaultFacts(objectList);
     		StatefulRuleInfoImpl ruleInfo = new StatefulRuleInfoImpl(builder.build(), false, false);
 
-    		final RuleBase ruleBase = getRuleBaseForRuleAgent(ruleInfo.getRuleSource()) ;
+    		final DroolsRuleBaseState ruleBaseState = getRuleBaseStateForRuleAgent(ruleInfo.getRuleSource()) ;
 
-			return executeStatefulRules(ruleBase, ruleInfo, message);
+			return ruleBaseState.executeStatefulRules(ruleInfo, message);
 		}
 		catch (IOException e)
 		{
@@ -417,9 +408,9 @@
     {
 	    try
         {
-            final RuleBase ruleBase = getRuleBaseForRuleAgent(ruleInfo.getRuleSource()) ;
+            final DroolsRuleBaseState ruleBaseState = getRuleBaseStateForRuleAgent(ruleInfo.getRuleSource()) ;
 
-            return executeStatefulRules(ruleBase, ruleInfo, msg);
+            return ruleBaseState.executeStatefulRules(ruleInfo, msg);
         }
         catch (IOException e)
         {
@@ -465,15 +456,15 @@
 
 		try
 		{
-			final Map<String, RuleBase> ruleBases = lifecycleRuleBases.getLifecycleResource();
+			final Map<String, DroolsRuleBaseState> ruleBaseStates = getCachedRuleBaseStates();
     		final RuleInfoBuilder builder = new RuleInfoBuilder(rules);
     		builder.globals(globals);
     		builder.defaultFacts(objectList);
     		StatefulRuleInfo ruleInfo = new StatefulRuleInfoImpl(builder.build(), dispose, true);
 
-			final RuleBase ruleBase = ruleBases.get( rules );
+			final DroolsRuleBaseState ruleBaseState = ruleBaseStates.get( rules );
 
-			return executeStatefulRules(ruleBase, ruleInfo, message);
+			return ruleBaseState.executeStatefulRules(ruleInfo, message);
 		}
 		catch (Exception e)
 		{
@@ -485,10 +476,10 @@
     {
 		try
 		{
-			final Map<String, RuleBase> ruleBases = lifecycleRuleBases.getLifecycleResource();
-			final RuleBase ruleBase = ruleBases.get(info.getRuleSource());
+			final Map<String, DroolsRuleBaseState> ruleBaseStates = getCachedRuleBaseStates();
+			final DroolsRuleBaseState ruleBaseState = ruleBaseStates.get(info.getRuleSource());
 
-			return executeStatefulRules(ruleBase, info, msg);
+			return ruleBaseState.executeStatefulRules(info, msg);
 		}
 		catch (Exception e)
 		{
@@ -503,7 +494,7 @@
 	//	package protected methods
 
 	/**
-	 * Determine if file based rules need reloading and return the rulebase
+	 * Determine if file based rules need reloading and return the rulebase state
 	 *
 	 * @param ruleSet -
 	 *            String reference to a file which contains a ruleSet.
@@ -516,7 +507,7 @@
 	 *
 	 * @return Message with updated objects.
 	 */
-	RuleBase getRuleBaseForFileBasedRules(
+	DroolsRuleBaseState getRuleBaseStateForFileBasedRules(
 			final String ruleSet,
 			final String dsl,
 			final boolean ruleReload) throws RuleServiceException
@@ -525,36 +516,41 @@
 		{
 			final DroolsRuleBaseHelper rbHelper = DroolsRuleBaseHelper.getInstance();
 
-			String newRuleSet = null;
-			boolean isRulesChanged = false;
 
-			final Map<String, String> ruleSets = lifecycleRuleSets.getLifecycleResource();
+			final ConcurrentHashMap<String, String> ruleSets = lifecycleRuleSets.getLifecycleResource();
 
-            synchronized (ruleSets) {
-                if ( ruleReload )
-                {
-                    String currentRuleSet = ruleSets.get( ruleSet );
-                    newRuleSet = rbHelper.getRulesAsString( ruleSet, dsl );
-                    if ( currentRuleSet == null || !currentRuleSet.equals(newRuleSet) )
-                    {
-                        isRulesChanged = true;
-                    }
-                }
-                final Map<String, RuleBase> ruleBases = lifecycleRuleBases.getLifecycleResource();
-                RuleBase ruleBase = ruleBases.get( ruleSet );
-                if ( ruleBase == null || isRulesChanged )
-                {
-                    ruleBase = rbHelper.createRuleBaseFromRuleFiles(ruleSet, dsl);
-                    if (ruleBase != null)
-                        ruleBases.put(ruleSet, ruleBase);
-                    if (newRuleSet == null)
-                        newRuleSet = rbHelper.getRulesAsString(ruleSet, dsl);
-                    if (ruleSet != null)
-                        ruleSets.put(ruleSet, newRuleSet);
-                }
+			synchronized(ruleSets)
+			{
+				String newRuleSet = null;
+				if ( ruleReload )
+				{
+					newRuleSet = rbHelper.getRulesAsString( ruleSet, dsl );
+					String oldRuleSet = ruleSets.put( ruleSet, newRuleSet );
+					if ((oldRuleSet != null) && !oldRuleSet.equals(newRuleSet) )
+					{
+						final DroolsRuleBaseState ruleBaseState = getCachedRuleBaseStates().remove(oldRuleSet);
+						if (ruleBaseState != null)
+						{
+							ruleBaseState.dispose() ;
+						}
+					}
+				}
 
-                return ruleBase;
-            }
+				
+				final Map<String, DroolsRuleBaseState> ruleBaseStates = getCachedRuleBaseStates();
+				DroolsRuleBaseState ruleBaseState = ruleBaseStates.get(ruleSet) ;
+				if (ruleBaseState == null)
+				{
+					final RuleBase ruleBase = rbHelper.createRuleBaseFromRuleFiles(ruleSet, dsl);
+					if (newRuleSet == null)
+						newRuleSet = rbHelper.getRulesAsString(ruleSet, dsl);
+					ruleSets.put(ruleSet, newRuleSet);
+					ruleBaseState = new DroolsRuleBaseState(ruleBase) ;
+					ruleBaseStates.put(ruleSet, ruleBaseState) ;
+				}
+
+				return ruleBaseState;
+			}
 		}
 		catch (final LifecycleResourceException e)
 		{
@@ -571,7 +567,7 @@
 	}
 
 	/**
-	 * Determine if decision table need reloading and return the rulebase
+	 * Determine if decision table need reloading and return the rulebase state
 	 *
 	 * @param decisionTable -
 	 *            String reference to a file which contains a decision table.
@@ -581,23 +577,37 @@
 	 *
 	 * @return Message with updated objects.
 	 */
-	RuleBase getRuleBaseForDecisionTable(
+	DroolsRuleBaseState getRuleBaseStateForDecisionTable(
 			final String decisionTable,
 			final boolean ruleReload ) throws RuleServiceException {
 
 		try
 		{
-            Map<String, RuleBase> ruleBases = getCachedRuleBases();
+            Map<String, DroolsRuleBaseState> ruleBaseStates = getCachedRuleBaseStates();
 
-            synchronized (ruleBases) {
-                RuleBase ruleBase = ruleBases.get( decisionTable );
-                if ( ruleReload || ruleBase == null )
+            DroolsRuleBaseState ruleBaseState = (!ruleReload ? ruleBaseStates.get( decisionTable ) : null) ;
+            if (ruleBaseState == null)
+            {
+                synchronized (ruleBaseStates)
                 {
-                    ruleBase = DroolsRuleBaseHelper.getInstance().createRuleBaseFromDecisionTable(decisionTable);
-                    ruleBases.put( decisionTable, ruleBase );
+                    if (!ruleReload)
+                    {
+                        ruleBaseState = ruleBaseStates.get( decisionTable );
+                    }
+                    
+                    if (ruleBaseState == null)
+                    {
+                        final RuleBase ruleBase = DroolsRuleBaseHelper.getInstance().createRuleBaseFromDecisionTable(decisionTable);
+                        ruleBaseState = new DroolsRuleBaseState(ruleBase) ;
+                        final DroolsRuleBaseState origRuleBasedState = ruleBaseStates.put( decisionTable, ruleBaseState );
+                        if (origRuleBasedState != null)
+                        {
+                            origRuleBasedState.dispose() ;
+                        }
+                    }
                 }
-                return ruleBase;
             }
+            return ruleBaseState;
         }
 		catch (final IOException e)
 		{
@@ -613,198 +623,8 @@
 		}
 	}
 
-	/**
-	 * Execute rules using using the Stateless API
-	 *
-	 * @param rulebase -
-	 *          the rulebase to use
-	 * @param message -
-	 *          Message that is updated with the results.
-	 * @param objectList -
-	 * 			a list with additional objects (typically pulled from the message)
-	 * 			to be inserted into working memory
-	 * @param globals -
-	 *            Map of globals variables that should be set in the working memory
-	 *
-	 * @return Message -
-	 * 			with updated objects.
-	 */
-	Message executeStatelessRules(
-			final RuleBase ruleBase,
-			final Message message,
-			final Map<String,Object> globals,
-			final List<Object> objectList)
+	DroolsRuleBaseState getRuleBaseStateForRuleAgent( final String ruleAgentProperties ) throws IOException, Exception
 	{
-
-		final StatelessSession statelessSession = ruleBase.newStatelessSession();
-		RulesContext.clearContext() ;
-		try
-		{
-			final List<Object> facts = getFacts( message, objectList );
-			addGlobalsVariables( statelessSession, globals );
-			statelessSession.execute(facts);
-		}
-		finally
-		{
-			RulesContext.clearContext() ;
-		}
-		return message;
-	}
-
-	/**
-	 * Execute rules using using the Stateful API
-	 *
-	 * @param   rulebase -
-     * 			the rulebase to use
-	 * @param dispose -
-	 * 			if true the working memory will be dereferenced.
-	 * @param message -
-	 * 			Message that is updated with the results.
-	 * @param globals -
-	 * 			Map of globals variables that should be set in the working memory
-	 * @param entryPointMap -
-	 * 			a map with additional objects to be inserted into working memory or
-	 *          into the named WorkingMemoryEntryPoint. Any objects included in the
-	 *          {@link #DEFAULT_ENTRY_POINT} name will be inserted into the normal
-	 *          working memory. The rest will lookup the entry point working memory
-	 *          and insert the objects into the those working memories.
-	 * @return Message -
-	 * 			a possibly updated Message object. The message object is available
-	 * 			to Rules and my be updated by them.
-	 * @throws RuleServiceException
-	 */
-	Message executeStatefulRules(
-			final RuleBase ruleBase,
-			final StatefulRuleInfo ruleInfo,
-			final Message message) throws RuleServiceException
-	{
-        synchronized (ruleBase)
-        {
-            RulesContext.clearContext() ;
-
-            final StatefulSession statefulSession = getStatefulSession( ruleBase, ruleInfo.continueState() );
-            try
-            {
-                addGlobalsVariables(statefulSession, ruleInfo.getGlobals());
-
-                // Always insert the ESB Message object.
-                InternalFactHandle handle = (InternalFactHandle) statefulSession.insert(message);
-                if (log.isDebugEnabled())
-                {
-                    if (handle.isEvent())
-                    {
-                        EventFactHandle ef = (EventFactHandle) handle;
-                        log.debug("Event :" +  ef.getObject().getClass().getName() + ", startTimeStamp: " + ef.getStartTimestamp());
-                    }
-                }
-
-                // Always insert the Default facts
-                final List<Object> defaultFacts = ruleInfo.getDefaultFacts();
-                for (Object object : defaultFacts)
-                {
-                    statefulSession.insert(object);
-                }
-
-                // Insert any object that that did not specify an entry-point into the main working memory.
-                if (ruleInfo.getFacts() != null)
-                {
-                    for (Entry<String, List<Object>> entry : ruleInfo.getFacts().entrySet())
-                    {
-                        String entryPointName = entry.getKey();
-                        // Insert object that have explicitely specifed an entry-point.
-                        WorkingMemoryEntryPoint wmep = statefulSession.getWorkingMemoryEntryPoint(entryPointName);
-                        if (wmep == null)
-                        {
-                            throw new RuleServiceException("The entry-point '" + entryPointName + "' was not found in the current stateful session. Please double check your rules source");
-                        }
-                        for (Object object : entry.getValue())
-                        {
-                            wmep.insert(object);
-                        }
-                    }
-                }
-                // Fire rules.
-                statefulSession.fireAllRules();
-            }
-            finally
-            {
-                RulesContext.clearContext() ;
-                if ( ruleInfo.dispose() )
-                {
-                    statefulSession.dispose();
-                }
-            }
-        }
-        return message;
-	}
-
-	private List<Object> getFacts(final Message message, final List<Object> objectList )
-	{
-		final List<Object> facts = new ArrayList<Object>();
-		facts.add( message );
-		if ( objectList != null )
-			facts.addAll( objectList );
-		return facts;
-	}
-
-	/*
-	 * Checks whether the ruleBase has an existing session, and returns
-	 * that session, otherwise a new session is created.
-	 */
-	private StatefulSession getStatefulSession( final RuleBase ruleBase, final boolean continueState )
-	{
-        synchronized (ruleBase) {
-            final StatefulSession[] statefulSessions = ruleBase.getStatefulSessions();
-            boolean existingSession = statefulSessions != null && statefulSessions.length > 0;
-            if (existingSession)
-            {
-                final StatefulSession session = statefulSessions[0];
-                if (continueState)
-                {
-                    return session ;
-                }
-                else
-                {
-                    session.dispose();
-                }
-            }
-            return ruleBase.newStatefulSession();
-        }
-    }
-
-	/*
-	 * Will set the passed-in elements in the globals Map as global
-	 * variables.
-	 */
-	private void addGlobalsVariables( final StatelessSession statelessSession, final Map<String,Object> globals )
-	{
-		if ( globals != null )
-		{
-			Set<Entry<String, Object>> entrySet = globals.entrySet();
-			for ( Entry<String, Object> entry : entrySet ) {
-				statelessSession.setGlobal( entry.getKey(), entry.getValue() );
-            }
-        }
-	}
-
-	/*
-	 * Will set the passed-in elements in the globals Map as global
-	 * variables.
-	 */
-	private void addGlobalsVariables( final StatefulSession statefulSession, final Map<String,Object> globals )
-	{
-		if ( globals != null )
-		{
-			Set<Entry<String, Object>> entrySet = globals.entrySet();
-			for ( Entry<String, Object> entry : entrySet )
-			{
-				statefulSession.setGlobal( entry.getKey(), entry.getValue() );
-			}
-		}
-	}
-
-	RuleBase getRuleBaseForRuleAgent( final String ruleAgentProperties ) throws IOException, Exception
-	{
 		Map<String, RuleAgent> ruleAgents = getCachedRuleAgents();
 		RuleAgent ruleAgent = ruleAgents.get( ruleAgentProperties );
 		if ( ruleAgent == null )
@@ -822,16 +642,26 @@
 
 		RuleBase currentRuleBase = ruleAgent.getRuleBase();
 		//	always update the cache as the rulebase might have been updated.
-		final RuleBase origRuleBase = getCachedRuleBases().put( ruleAgentProperties, currentRuleBase );
-		if ((origRuleBase != currentRuleBase) && (origRuleBase != null))
+		final Map<String, DroolsRuleBaseState> ruleBaseStates = getCachedRuleBaseStates() ;
+		DroolsRuleBaseState ruleBaseState = ruleBaseStates.get(ruleAgentProperties) ;
+		if ((ruleBaseState == null) || (ruleBaseState.getRuleBase() != currentRuleBase))
 		{
-			if (log.isInfoEnabled())
+			synchronized(ruleBaseStates)
 			{
-				log.info("destroying stateful session for " + LifecycleResourceManager.getSingleton().getIdentity());
+				ruleBaseState = ruleBaseStates.get(ruleAgentProperties) ;
+				currentRuleBase = ruleAgent.getRuleBase();
+				if ((ruleBaseState == null) || (ruleBaseState.getRuleBase() != currentRuleBase))
+				{
+					if (ruleBaseState != null)
+					{
+						ruleBaseState.dispose() ;
+					}
+					ruleBaseState = new DroolsRuleBaseState(currentRuleBase) ;
+					ruleBaseStates.put(ruleAgentProperties, ruleBaseState) ;
+				}
 			}
-			disposeStatefulSessions(origRuleBase.getStatefulSessions()) ;
 		}
-		return currentRuleBase;
+		return ruleBaseState;
 	}
 
 	Map<String, RuleAgent> getCachedRuleAgents() throws LifecycleResourceException
@@ -839,17 +669,17 @@
 		return lifecycleRuleAgents.getLifecycleResource();
 	}
 
-	Map<String, RuleBase> getCachedRuleBases() throws LifecycleResourceException
+	Map<String, DroolsRuleBaseState> getCachedRuleBaseStates() throws LifecycleResourceException
 	{
-		return lifecycleRuleBases.getLifecycleResource();
+		return lifecycleRuleBaseStates.getLifecycleResource();
 	}
 
 	/**
-	 * The lifecycle resource factory for rule sets.
+	 * The lifecycle resource factory for rule base state.
 	 *
 	 * @author kevin
 	 */
-	public static class LifecycleRuleBaseFactory implements LifecycleResourceFactory<Map<String, RuleBase>>
+	public static class LifecycleRuleBaseStateFactory implements LifecycleResourceFactory<Map<String, DroolsRuleBaseState>>
 	{
 		/**
 		 * Create a resource object which will be associated with the
@@ -861,9 +691,9 @@
 		 * @throws LifecycleResourceException
 		 *             for errors during construction.
 		 */
-		public Map<String, RuleBase> createLifecycleResource( final String lifecycleIdentity) throws LifecycleResourceException
+		public Map<String, DroolsRuleBaseState> createLifecycleResource( final String lifecycleIdentity) throws LifecycleResourceException
 		{
-			return new ConcurrentHashMap<String, RuleBase>();
+			return new ConcurrentHashMap<String, DroolsRuleBaseState>();
 		}
 
 		/**
@@ -877,35 +707,20 @@
 		 * @throws LifecycleResourceException
 		 *             for errors during destroy.
 		 */
-		public void destroyLifecycleResource( final Map<String, RuleBase> resource, final String lifecycleIdentity) throws LifecycleResourceException
+		public void destroyLifecycleResource( final Map<String, DroolsRuleBaseState> resource, final String lifecycleIdentity) throws LifecycleResourceException
 		{
 		    if (resource != null)
 		    {
-		        final Collection<RuleBase> values = resource.values();
-		        for (RuleBase ruleBase : values)
-                {
-                    if (log.isInfoEnabled())
-                    {
-                        log.info("destroying stateful session for " + lifecycleIdentity);
-                    }
-    		        disposeStatefulSessions(ruleBase.getStatefulSessions());
-                }
+		        final Collection<DroolsRuleBaseState> values = resource.values();
+		        for (DroolsRuleBaseState ruleBaseState : values)
+		        {
+		            ruleBaseState.dispose() ;
+		        }
 		        resource.clear();
 		    }
 		}
 	}
 
-	private static void disposeStatefulSessions(final StatefulSession[] sessions)
-	{
-	    if (sessions == null)
-	        return;
-
-        for (StatefulSession statefulSession : sessions)
-        {
-            statefulSession.dispose();
-        }
-	}
-
 	public static class LifecycleRuleAgentFactory implements LifecycleResourceFactory<Map<String, RuleAgent>>
 	{
         /**
@@ -944,10 +759,17 @@
                 {
                     if (log.isInfoEnabled())
                     {
-                        log.info("destroying stateful session for " + lifecycleIdentity);
+                        log.info("destroying rule agent for " + lifecycleIdentity);
                     }
-    		        disposeStatefulSessions(ruleAgent.getRuleBase().getStatefulSessions());
                     ruleAgent.stopPolling() ;
+                    final StatefulSession[] sessions = ruleAgent.getRuleBase().getStatefulSessions();
+                    if (sessions != null)
+                    {
+                        for (StatefulSession statefulSession : sessions)
+                        {
+                            statefulSession.dispose();
+                        }
+                    }
                 }
                 resource.clear();
             }
@@ -959,7 +781,7 @@
 	 *
 	 * @author kevin
 	 */
-	public static class LifecycleRuleSetFactory implements LifecycleResourceFactory<Map<String, String>>
+	public static class LifecycleRuleSetFactory implements LifecycleResourceFactory<ConcurrentHashMap<String, String>>
 	{
 		/**
 		 * Create a resource object which will be associated with the
@@ -971,7 +793,7 @@
 		 * @throws LifecycleResourceException
 		 *             for errors during construction.
 		 */
-		public Map<String, String> createLifecycleResource( final String lifecycleIdentity) throws LifecycleResourceException
+		public ConcurrentHashMap<String, String> createLifecycleResource( final String lifecycleIdentity) throws LifecycleResourceException
 		{
 			return new ConcurrentHashMap<String, String>();
 		}
@@ -988,7 +810,7 @@
 		 * @throws LifecycleResourceException
 		 *             for errors during destroy.
 		 */
-		public void destroyLifecycleResource( final Map<String, String> resource, final String lifecycleIdentity) throws LifecycleResourceException
+		public void destroyLifecycleResource( final ConcurrentHashMap<String, String> resource, final String lifecycleIdentity) throws LifecycleResourceException
 		{
 		    if (resource != null)
 		    {

Modified: labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/test/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleServiceUnitTest.java
===================================================================
--- labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/test/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleServiceUnitTest.java	2010-01-12 20:40:46 UTC (rev 31038)
+++ labs/jbossesb/branches/JBESB_4_7_CP/product/services/jbrules/src/test/java/org/jboss/internal/soa/esb/services/rules/DroolsRuleServiceUnitTest.java	2010-01-12 20:53:14 UTC (rev 31039)
@@ -63,7 +63,7 @@
 {
 	private DroolsRuleService ruleService = new DroolsRuleService();
 
-	private RuleBase ruleBase;
+	private DroolsRuleBaseState ruleBaseState;
 	private Message message;
 
 	private Order order;
@@ -74,7 +74,7 @@
 	public void executeStatelessRules()
 	{
 		Map<String,Object> globals = getGlobalsWithDestAndMessage();
-		message = ruleService.executeStatelessRules( ruleBase, message , globals, null );
+		message = ruleBaseState.executeStatelessRules( message , globals, null );
 		ArrayList<String> destinations = getDistinations( globals );
 		assertTrue( destinations.size() == 1 );
 	}
@@ -300,7 +300,7 @@
 	@Before
 	public void setup() throws RuleServiceException
 	{
-		ruleBase = ruleService.getRuleBaseForFileBasedRules( "JBossESBRules.drl", null, true );
+		ruleBaseState = ruleService.getRuleBaseStateForFileBasedRules( "JBossESBRules.drl", null, true );
 		message = MessageFactory.getInstance().getMessage();
 
 		order = new Order();



More information about the jboss-svn-commits mailing list