[jboss-svn-commits] JBL Code SVN: r30648 - in labs/jbossrules/trunk: drools-api/src/main/java/org/drools/agent and 3 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Dec 14 15:13:29 EST 2009


Author: eaa
Date: 2009-12-14 15:13:28 -0500 (Mon, 14 Dec 2009)
New Revision: 30648

Added:
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentRemoveRuleChangeSetTest.java
Modified:
   labs/jbossrules/trunk/drools-api/src/main/java/org/drools/ChangeSet.java
   labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgent.java
   labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgentConfiguration.java
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentIncrementalChangeSetTest.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/agent/impl/KnowledgeAgentImpl.java
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ChangeSetImpl.java
Log:
JBRULES-2082: support for delete/modify in changesets
	- ChangeSet: added new property "knowledgeDefinitionsRemoved" to store the rules to be removed from kbase.	
	- KnowledgeAgent: Added support for individual rules deletion using ChangeSet's property.    
	- Created new unit test for individual rules deletion using Change Sets: KnowledgeAgentRemoveRuleChangeSetTest

Modified: labs/jbossrules/trunk/drools-api/src/main/java/org/drools/ChangeSet.java
===================================================================
--- labs/jbossrules/trunk/drools-api/src/main/java/org/drools/ChangeSet.java	2009-12-14 19:17:11 UTC (rev 30647)
+++ labs/jbossrules/trunk/drools-api/src/main/java/org/drools/ChangeSet.java	2009-12-14 20:13:28 UTC (rev 30648)
@@ -1,6 +1,7 @@
 package org.drools;
 
 import java.util.Collection;
+import java.util.Map;
 
 import org.drools.io.Resource;
 
@@ -81,4 +82,8 @@
      */
     public Collection<Resource> getResourcesModified();
 
+    Map<Resource, String> getKnowledgeDefinitionsRemoved();
+
+    void setKnowledgeDefinitionsRemoved(Map<Resource, String> knowledgeDefinitionsRemoved);
+
 }

Modified: labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgent.java
===================================================================
--- labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgent.java	2009-12-14 19:17:11 UTC (rev 30647)
+++ labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgent.java	2009-12-14 20:13:28 UTC (rev 30648)
@@ -1,5 +1,6 @@
 package org.drools.agent;
 
+import org.drools.ChangeSet;
 import org.drools.KnowledgeBase;
 import org.drools.SystemEventListener;
 import org.drools.io.Resource;
@@ -45,5 +46,7 @@
 
     void applyChangeSet(Resource resource);
 
+    void applyChangeSet(ChangeSet changeSet);
+
     void setSystemEventListener(SystemEventListener listener);
 }

Modified: labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgentConfiguration.java
===================================================================
--- labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgentConfiguration.java	2009-12-14 19:17:11 UTC (rev 30647)
+++ labs/jbossrules/trunk/drools-api/src/main/java/org/drools/agent/KnowledgeAgentConfiguration.java	2009-12-14 20:13:28 UTC (rev 30648)
@@ -16,4 +16,13 @@
     extends
     PropertiesConfiguration {
 
+    public boolean isScanResources();
+
+    public boolean isScanDirectories();
+
+    public boolean isMonitorChangeSetEvents();
+
+    public boolean isNewInstance();
+
+
 }

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentIncrementalChangeSetTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentIncrementalChangeSetTest.java	2009-12-14 19:17:11 UTC (rev 30647)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentIncrementalChangeSetTest.java	2009-12-14 20:13:28 UTC (rev 30648)
@@ -265,15 +265,15 @@
         kagent.monitorResourceChangeEvents(false);
     }
 
-     
 
+
     /**
      * Tests that if we have two DRL files, where one file overwrites a rule in
      * a prior file, that if we modify the first file that was overwritten, that
      * it will gain precedence and overwrite the other.
      *
      * @throws Exception
-     */    
+     */
     public void testModifyFileUrlOverwriteIncremental() throws Exception {
         String rule1 = "";
         rule1 += "package org.drools.test\n";
@@ -283,22 +283,31 @@
         rule1 += "then\n";
         rule1 += "list.add( drools.getRule().getName() );\n";
         rule1 += "end\n";
+
+        String rule2 = "";
+        rule2 += "rule rule2\n";
+        rule2 += "when\n";
+        rule2 += "then\n";
+        rule2 += "list.add( drools.getRule().getName() );\n";
+        rule2 += "end\n";
+
         File f1 = fileManager.newFile("rule1.drl");
         Writer output = new BufferedWriter(new FileWriter(f1));
         output.write(rule1);
+        output.write(rule2);
         output.close();
 
-        String rule2 = "";
-        rule2 += "package org.drools.test\n";
-        rule2 += "global java.util.List list\n";
-        rule2 += "rule rule1\n";
-        rule2 += "when\n";
-        rule2 += "then\n";
-        rule2 += "list.add( drools.getRule().getName() + \"_v2\");\n";
-        rule2 += "end\n";
+        String rule1v2 = "";
+        rule1v2 += "package org.drools.test\n";
+        rule1v2 += "global java.util.List list\n";
+        rule1v2 += "rule rule1\n";
+        rule1v2 += "when\n";
+        rule1v2 += "then\n";
+        rule1v2 += "list.add( drools.getRule().getName() + \"_v2\");\n";
+        rule1v2 += "end\n";
         File f2 = fileManager.newFile("rule2.drl");
         output = new BufferedWriter(new FileWriter(f2));
-        output.write(rule2);
+        output.write(rule1v2);
         output.close();
 
         String xml = "";
@@ -339,8 +348,9 @@
         ksession.fireAllRules();
         ksession.dispose();
 
-        assertEquals(1, list.size());
+        assertEquals(2, list.size());
         assertTrue(list.contains("rule1_v2"));
+        assertTrue(list.contains("rule2"));
 
         list.clear();
 
@@ -348,16 +358,16 @@
         // http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=1&t=019789
         Thread.sleep(2000);
 
-        rule1 = "";
-        rule1 += "package org.drools.test\n";
-        rule1 += "global java.util.List list\n";
-        rule1 += "rule rule1\n";
-        rule1 += "when\n";
-        rule1 += "then\n";
-        rule1 += "list.add( drools.getRule().getName() + \"_v3\" );\n";
-        rule1 += "end\n";
-        output = new BufferedWriter(new FileWriter(f1));
-        output.write(rule1);
+        String rule1v3 = "";
+        rule1v3 += "package org.drools.test\n";
+        rule1v3 += "global java.util.List list\n";
+        rule1v3 += "rule rule1\n";
+        rule1v3 += "when\n";
+        rule1v3 += "then\n";
+        rule1v3 += "list.add( drools.getRule().getName() + \"_v3\" );\n";
+        rule1v3 += "end\n";
+        output = new BufferedWriter(new FileWriter(f2));
+        output.write(rule1v3);
         output.close();
         Thread.sleep(3000);
 
@@ -367,8 +377,9 @@
         ksession.fireAllRules();
         ksession.dispose();
 
-        assertEquals(1, list.size());
+        assertEquals(2, list.size());
         assertTrue(list.contains("rule1_v3"));
+        assertTrue(list.contains("rule2"));
 
         //Delete f2 now, rule1 should still fire if the indexing worked properly
         list.clear();
@@ -381,18 +392,18 @@
         ksession.dispose();
 
         assertEquals(1, list.size());
-        assertTrue(list.contains("rule1_v3"));
+        assertTrue(list.contains("rule2"));
 
         kagent.monitorResourceChangeEvents(false);
     }
-    
 
 
+
     /**
      * Creates two rules (rule1 and rule2) in a drl file. Then it modifies the
      * drl file to change rule2 with rule3.
      * @throws Exception
-     */    
+     */
     public void testMultipleRulesOnFileUrlIncremental() throws Exception {
         String rule1 = "";
         rule1 += "package org.drools.test\n";
@@ -402,8 +413,8 @@
         rule1 += "then\n";
         rule1 += "list.add( drools.getRule().getName() );\n";
         rule1 += "end\n\n";
-       
 
+
         String rule2 = "";
         rule2 += "rule rule2\n";
         rule2 += "when\n";
@@ -488,8 +499,8 @@
 
         kagent.monitorResourceChangeEvents(false);
     }
-    
-    
+
+
     public void testMultipleRulesOnFilesUrlIncremental() throws Exception {
         String header = "";
         header += "package org.drools.test\n";
@@ -501,8 +512,8 @@
         rule1 += "then\n";
         rule1 += "list.add( drools.getRule().getName() );\n";
         rule1 += "end\n\n";
-       
 
+
         String rule2 = "";
         rule2 += "rule rule2\n";
         rule2 += "when\n";
@@ -593,7 +604,7 @@
         // http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=1&t=019789
         Thread.sleep(2000);
 
-        
+
         output = new BufferedWriter(new FileWriter(f2));
         output.write(header);
         output.write(rule4);
@@ -642,7 +653,7 @@
         kagent.monitorResourceChangeEvents(false);
     }
 
-    
+
     public void testModifyPackageUrlIncremental() throws Exception {
         String rule1 = "";
         rule1 += "package org.drools.test\n";
@@ -862,6 +873,138 @@
         kagent.monitorResourceChangeEvents(false);
     }
 
+
+    public void testUpdatePackageUrlOverwriteIncremental() throws Exception {
+        String rule1 = "";
+        rule1 += "package org.drools.test\n";
+        rule1 += "global java.util.List list\n";
+        rule1 += "rule rule1\n";
+        rule1 += "when\n";
+        rule1 += "then\n";
+        rule1 += "list.add( drools.getRule().getName() );\n";
+        rule1 += "end\n";
+
+        String rule1v2 = "";
+        rule1v2 += "package org.drools.test\n";
+        rule1v2 += "global java.util.List list\n";
+        rule1v2 += "rule rule1\n";
+        rule1v2 += "when\n";
+        rule1v2 += "then\n";
+        rule1v2 += "list.add( drools.getRule().getName()+\"_V2\");\n";
+        rule1v2 += "end\n";
+
+        String rule2 = "";
+        rule2 += "package org.drools.test\n";
+        rule2 += "global java.util.List list\n";
+        rule2 += "rule rule2\n";
+        rule2 += "when\n";
+        rule2 += "then\n";
+        rule2 += "list.add( drools.getRule().getName() );\n";
+        rule2 += "end\n";
+
+        String rule3 = "";
+        rule3 += "package org.drools.test\n";
+        rule3 += "global java.util.List list\n";
+        rule3 += "rule rule3\n";
+        rule3 += "when\n";
+        rule3 += "then\n";
+        rule3 += "list.add( drools.getRule().getName() );\n";
+        rule3 += "end\n";
+
+        // Add Rule1 and Rule2 in the first package
+        File pkgF1 = fileManager.newFile("pkg1.pkg");
+        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+        kbuilder.add(ResourceFactory.newByteArrayResource(rule1.getBytes()),
+                ResourceType.DRL);
+        kbuilder.add(ResourceFactory.newByteArrayResource(rule2.getBytes()),
+                ResourceType.DRL);
+        if (kbuilder.hasErrors()) {
+            fail(kbuilder.getErrors().toString());
+        }
+        KnowledgePackage pkg1 = (KnowledgePackage) kbuilder.getKnowledgePackages().iterator().next();
+        writePackage(pkg1, pkgF1);
+
+        // Add Rule3 in the second package
+        File pkgF2 = fileManager.newFile("pkg2.pkg");
+        kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+        kbuilder.add(ResourceFactory.newByteArrayResource(rule3.getBytes()),
+                ResourceType.DRL);
+        if (kbuilder.hasErrors()) {
+            fail(kbuilder.getErrors().toString());
+        }
+        KnowledgePackage pkg2 = (KnowledgePackage) kbuilder.getKnowledgePackages().iterator().next();
+        writePackage(pkg2, pkgF2);
+
+        String xml = "";
+        xml += "<change-set xmlns='http://drools.org/drools-5.0/change-set'";
+        xml += "    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'";
+        xml += "    xs:schemaLocation='http://drools.org/drools-5.0/change-set drools-change-set-5.0.xsd' >";
+        xml += "    <add> ";
+        xml += "        <resource source='http://localhost:9000/pkg1.pkg' type='PKG' />";
+        xml += "        <resource source='http://localhost:9000/pkg2.pkg' type='PKG' />";
+        xml += "    </add> ";
+        xml += "</change-set>";
+        File fxml = fileManager.newFile("changeset.xml");
+        Writer output = new BufferedWriter(new FileWriter(fxml));
+        output.write(xml);
+        output.close();
+
+        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+
+        ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
+        sconf.setProperty("drools.resource.scanner.interval", "2");
+        ResourceFactory.getResourceChangeScannerService().configure(sconf);
+
+        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
+        aconf.setProperty("drools.agent.scanDirectories", "true");
+        aconf.setProperty("drools.agent.scanResources", "true");
+        aconf.setProperty("drools.agent.newInstance", "false");
+        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+                "test agent", kbase, aconf);
+
+        kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI().toURL()));
+
+        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
+        List<String> list = new ArrayList<String>();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(3, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule2"));
+        assertTrue(list.contains("rule3"));
+
+        list.clear();
+
+        // have to sleep here as linux lastModified does not do milliseconds
+        // http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=1&t=019789
+        Thread.sleep(2000);
+
+        kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+        kbuilder.add(ResourceFactory.newByteArrayResource(rule1v2.getBytes()),
+                ResourceType.DRL);
+        if (kbuilder.hasErrors()) {
+            fail(kbuilder.getErrors().toString());
+        }
+        pkg2 = (KnowledgePackage) kbuilder.getKnowledgePackages().iterator().next();
+        writePackage(pkg2, pkgF2);
+
+        Thread.sleep(3000);
+
+        ksession = kbase.newStatefulKnowledgeSession();
+        list = new ArrayList<String>();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(2, list.size());
+
+        assertTrue(list.contains("rule1_V2"));
+        assertTrue(list.contains("rule2"));
+        kagent.monitorResourceChangeEvents(false);
+    }
+
      
 
     private static void writePackage(Object pkg, File p1file)

Added: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentRemoveRuleChangeSetTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentRemoveRuleChangeSetTest.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentRemoveRuleChangeSetTest.java	2009-12-14 20:13:28 UTC (rev 30648)
@@ -0,0 +1,365 @@
+package org.drools.agent;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.drools.KnowledgeBase;
+import org.drools.KnowledgeBaseFactory;
+import org.drools.io.Resource;
+import org.drools.io.ResourceChangeScannerConfiguration;
+import org.drools.io.ResourceFactory;
+import org.drools.io.impl.ChangeSetImpl;
+import org.drools.io.impl.ResourceChangeNotifierImpl;
+import org.drools.io.impl.ResourceChangeScannerImpl;
+import org.drools.runtime.StatefulKnowledgeSession;
+import org.drools.runtime.pipeline.ResultHandler;
+import org.drools.util.DroolsStreamUtils;
+import org.drools.util.FileManager;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.handler.ResourceHandler;
+
+public class KnowledgeAgentRemoveRuleChangeSetTest extends TestCase {
+
+    FileManager fileManager;
+    private Server server;
+
+    @Override
+    protected void setUp() throws Exception {
+        fileManager = new FileManager();
+        fileManager.setUp();
+        ((ResourceChangeScannerImpl) ResourceFactory.getResourceChangeScannerService()).reset();
+        ResourceFactory.getResourceChangeNotifierService().start();
+        ResourceFactory.getResourceChangeScannerService().start();
+
+        this.server = new Server(9000);
+        ResourceHandler resourceHandler = new ResourceHandler();
+        resourceHandler.setResourceBase(fileManager.getRootDirectory().getPath());
+        System.out.println("root : " + fileManager.getRootDirectory().getPath());
+
+        server.setHandler(resourceHandler);
+
+        server.start();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        fileManager.tearDown();
+        ResourceFactory.getResourceChangeNotifierService().stop();
+        ResourceFactory.getResourceChangeScannerService().stop();
+        ((ResourceChangeNotifierImpl) ResourceFactory.getResourceChangeNotifierService()).reset();
+        ((ResourceChangeScannerImpl) ResourceFactory.getResourceChangeScannerService()).reset();
+
+        server.stop();
+    }
+
+    public void testModifyFileUrlIncremental() throws Exception {
+
+        String header = "";
+        header += "package org.drools.test\n";
+        header += "global java.util.List list\n\n";
+
+        String rule1 = this.createCommonRule("rule1");
+        String rule2 = this.createCommonRule("rule2");
+        String rule3 = this.createCommonRule("rule3");
+        String rule4 = this.createCommonRule("rule4");
+
+        String function1 = this.createDummyFunction("function1");
+
+        String query1 = "";
+        query1 += "query \"all the Strings\"\n";
+        //query1 += "query \"rule1\"\n";
+        query1 += "     str : String()\n";
+        query1 += "end\n";
+
+        String type1 = "";
+        type1 += "declare Address\n";
+        type1 += "  number : int\n";
+        type1 += "  streetName : String\n";
+        type1 += "  city : String\n";
+        type1 += "end\n";
+
+
+        File f1 = fileManager.newFile("rule1.drl");
+        Writer output = new BufferedWriter(new FileWriter(f1));
+        output.write(header);
+        output.write(type1);
+        output.write(query1);
+        output.write(function1);
+        output.write(rule1);
+        output.write(rule2);
+        output.close();
+
+        File f2 = fileManager.newFile("rule2.drl");
+        output = new BufferedWriter(new FileWriter(f2));
+        output.write(header);
+        output.write(rule3);
+        output.close();
+
+        String xml = "";
+        xml += "<change-set xmlns='http://drools.org/drools-5.0/change-set'";
+        xml += "    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'";
+        xml += "    xs:schemaLocation='http://drools.org/drools-5.0/change-set drools-change-set-5.0.xsd' >";
+        xml += "    <add> ";
+        xml += "        <resource source='http://localhost:9000/rule1.drl' type='DRL' />";
+        xml += "        <resource source='http://localhost:9000/rule2.drl' type='DRL' />";
+        xml += "    </add> ";
+        xml += "</change-set>";
+        File fxml = fileManager.newFile("changeset.xml");
+        output = new BufferedWriter(new FileWriter(fxml));
+        output.write(xml);
+        output.close();
+
+        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+        KnowledgeAgent kagent = this.createKAgent(kbase);
+        kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI().toURL()));
+
+        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
+        List<String> list = new ArrayList<String>();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(3, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule2"));
+        assertTrue(list.contains("rule3"));
+
+        list.clear();
+
+        // have to sleep here as linux lastModified does not do milliseconds
+        // http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=1&t=019789
+        Thread.sleep(2000);
+
+
+        output = new BufferedWriter(new FileWriter(f1));
+        output.write(header);
+        output.write(rule2);
+        output.write(rule4);
+        output.close();
+        Thread.sleep(3000);
+
+        // Use the same session for incremental build test
+        ksession = kbase.newStatefulKnowledgeSession();
+        list = new ArrayList<String>();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(3, list.size());
+
+        assertTrue(list.contains("rule3"));
+        assertTrue(list.contains("rule2"));
+        assertTrue(list.contains("rule4"));
+        kagent.monitorResourceChangeEvents(false);
+    }
+
+    public void testRemoveRuleChangeSet() throws Exception {
+
+        String header = "";
+        header += "package org.drools.test\n";
+        header += "global java.util.List list\n\n";
+
+        String rule1 = this.createCommonRule("rule1");
+        String rule2 = this.createCommonRule("rule2");
+        String rule3 = this.createCommonRule("rule3");
+
+        String function1 = this.createDummyFunction("function1");
+
+        File f1 = fileManager.newFile("rule1.drl");
+        Writer output = new BufferedWriter(new FileWriter(f1));
+        output.write(header);
+        output.write(function1);
+        output.write(rule1);
+        output.write(rule2);
+        output.close();
+
+        File f2 = fileManager.newFile("rule2.drl");
+        output = new BufferedWriter(new FileWriter(f2));
+        output.write(header);
+        output.write(rule3);
+        output.close();
+
+        String xml = "";
+        xml += "<change-set xmlns='http://drools.org/drools-5.0/change-set'";
+        xml += "    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'";
+        xml += "    xs:schemaLocation='http://drools.org/drools-5.0/change-set drools-change-set-5.0.xsd' >";
+        xml += "    <add> ";
+        xml += "        <resource source='http://localhost:9000/rule1.drl' type='DRL' />";
+        xml += "        <resource source='http://localhost:9000/rule2.drl' type='DRL' />";
+        xml += "    </add> ";
+        xml += "</change-set>";
+        final File fxml = fileManager.newFile("changeset.xml");
+        output = new BufferedWriter(new FileWriter(fxml));
+        output.write(xml);
+        output.close();
+
+        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+        KnowledgeAgent kagent = this.createKAgent(kbase);
+        kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI().toURL()));
+
+        StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
+        List<String> list = new ArrayList<String>();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(3, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule2"));
+        assertTrue(list.contains("rule3"));
+
+        list.clear();
+
+        //Creates a new changeSet that will delete Rule1 from kbase
+        ChangeSetImpl cs = new ChangeSetImpl();
+        cs.setKnowledgeDefinitionsRemoved(new HashMap<Resource, String>() {
+
+            {
+                Resource r = ResourceFactory.newUrlResource("http://localhost:9000/rule1.drl");
+                this.put(r, "rule1");
+            }
+        });
+
+        kagent.applyChangeSet(cs);
+
+
+        ksession = kbase.newStatefulKnowledgeSession();
+        list = new ArrayList<String>();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(2, list.size());
+
+        assertTrue(list.contains("rule2"));
+        assertTrue(list.contains("rule3"));
+
+
+
+        //Creates a new changeSet that will try to delete Rule3 from rule1.drl.
+        //Because Rule3 is defined in rule2.drl, this shouldn't remove any rule.
+        cs = new ChangeSetImpl();
+        cs.setKnowledgeDefinitionsRemoved(new HashMap<Resource, String>() {
+
+            {
+                Resource r = ResourceFactory.newUrlResource("http://localhost:9000/rule1.drl");
+                this.put(r, "rule3");
+            }
+        });
+
+        kagent.applyChangeSet(cs);
+
+
+        ksession = kbase.newStatefulKnowledgeSession();
+        list = new ArrayList<String>();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(2, list.size());
+
+        assertTrue(list.contains("rule2"));
+        assertTrue(list.contains("rule3"));
+
+
+        //Finally, remove Rule3
+        cs = new ChangeSetImpl();
+        cs.setKnowledgeDefinitionsRemoved(new HashMap<Resource, String>() {
+
+            {
+                Resource r = ResourceFactory.newUrlResource("http://localhost:9000/rule2.drl");
+                this.put(r, "rule3");
+            }
+        });
+
+        kagent.applyChangeSet(cs);
+
+
+        ksession = kbase.newStatefulKnowledgeSession();
+        list = new ArrayList<String>();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(1, list.size());
+
+        assertTrue(list.contains("rule2"));
+
+    }
+    
+
+    private KnowledgeAgent createKAgent(KnowledgeBase kbase){
+        ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
+        sconf.setProperty("drools.resource.scanner.interval", "2");
+        ResourceFactory.getResourceChangeScannerService().configure(sconf);
+
+        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
+        aconf.setProperty("drools.agent.scanDirectories", "true");
+        aconf.setProperty("drools.agent.scanResources", "true");
+        // Testing incremental build here
+        aconf.setProperty("drools.agent.newInstance", "false");
+        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+                "test agent", kbase, aconf);
+
+        assertEquals("test agent", kagent.getName());
+
+        return kagent;
+    }
+
+    private String createCommonRule(String ruleName) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("rule ");
+        sb.append(ruleName);
+        sb.append("\n");
+        sb.append("when\n");
+        sb.append("then\n");
+        sb.append("list.add( drools.getRule().getName() );\n");
+        sb.append("end\n");
+
+        return sb.toString();
+    }
+
+    private String createDummyFunction(String functionName) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("function void  ");
+        sb.append(functionName);
+        sb.append("(){\n");
+        sb.append(" System.out.println(\"Function executed\");\n");
+        sb.append("}\n");
+
+        return sb.toString();
+    }
+
+    private static void writePackage(Object pkg, File p1file)
+            throws IOException, FileNotFoundException {
+        FileOutputStream out = new FileOutputStream(p1file);
+        try {
+            DroolsStreamUtils.streamOut(out, pkg);
+        } finally {
+            out.close();
+        }
+    }
+
+    public static class ResultHandlerImpl implements ResultHandler {
+
+        Object object;
+
+        public void handleResult(Object object) {
+            this.object = object;
+        }
+
+        public Object getObject() {
+            return this.object;
+        }
+    }
+}

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/agent/impl/KnowledgeAgentImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/agent/impl/KnowledgeAgentImpl.java	2009-12-14 19:17:11 UTC (rev 30647)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/agent/impl/KnowledgeAgentImpl.java	2009-12-14 20:13:28 UTC (rev 30648)
@@ -38,6 +38,7 @@
 import org.drools.io.impl.ResourceChangeNotifierImpl;
 import org.drools.rule.Function;
 import org.drools.rule.Package;
+import org.drools.rule.Query;
 import org.drools.rule.Rule;
 import org.drools.rule.TypeDeclaration;
 import org.drools.runtime.KnowledgeSessionConfiguration;
@@ -56,898 +57,953 @@
  * @author Mark Proctor, Sam Romano
  */
 public class KnowledgeAgentImpl implements KnowledgeAgent,
-		ResourceChangeListener {
+        ResourceChangeListener {
 
-	private String name;
-	private ResourceMap resourcesMap;
-	private Set<Resource> resourceDirectories;
-	private KnowledgeBase kbase;
-	private ResourceChangeNotifierImpl notifier;
-	private boolean newInstance;
-	private SystemEventListener listener;
-	private boolean scanDirectories;
-	private LinkedBlockingQueue<ChangeSet> queue;
-	private Thread thread;
-	private ChangeSetNotificationDetector changeSetNotificationDetector;
-	private SemanticModules semanticModules;
+    private String name;
+    private ResourceMap resourcesMap;
+    private Set<Resource> resourceDirectories;
+    private KnowledgeBase kbase;
+    private ResourceChangeNotifierImpl notifier;
+    private boolean newInstance;
+    private SystemEventListener listener;
+    private boolean scanDirectories;
+    private LinkedBlockingQueue<ChangeSet> queue;
+    private Thread thread;
+    private ChangeSetNotificationDetector changeSetNotificationDetector;
+    private SemanticModules semanticModules;
 
-	/**
-	 * Default constructor for KnowledgeAgentImpl
-	 *
-	 * @param name
-	 * @param kbase
-	 * @param configuration
-	 */
-	public KnowledgeAgentImpl(String name, KnowledgeBase kbase,
-			KnowledgeAgentConfiguration configuration) {
-		this.name = name;
-		this.kbase = kbase;
-		this.resourcesMap = new ResourceMap(this);
-		this.resourceDirectories = new HashSet<Resource>();
-		// this.listener = listener;
-		this.listener = SystemEventListenerFactory.getSystemEventListener();
-		this.queue = new LinkedBlockingQueue<ChangeSet>();
-		boolean scanResources = false;
-		boolean monitor = false;
-		if (configuration != null) {
-			// New Instance describes if we do incremental builds or not
-			this.newInstance = ((KnowledgeAgentConfigurationImpl) configuration)
-					.isNewInstance();
-			this.notifier = (ResourceChangeNotifierImpl) ResourceFactory
-					.getResourceChangeNotifierService();
-			if (((KnowledgeAgentConfigurationImpl) configuration)
-					.isMonitorChangeSetEvents()) {
-				monitor = true;
-			}
+    /**
+     * Default constructor for KnowledgeAgentImpl
+     *
+     * @param name
+     * @param kbase
+     * @param configuration
+     */
+    public KnowledgeAgentImpl(String name, KnowledgeBase kbase,
+            KnowledgeAgentConfiguration configuration) {
+        this.name = name;
+        this.kbase = kbase;
+        this.resourcesMap = new ResourceMap(this);
+        this.resourceDirectories = new HashSet<Resource>();
+        // this.listener = listener;
+        this.listener = SystemEventListenerFactory.getSystemEventListener();
+        this.queue = new LinkedBlockingQueue<ChangeSet>();
+        boolean scanResources = false;
+        boolean monitor = false;
+        if (configuration != null) {
+            // New Instance describes if we do incremental builds or not
+            this.newInstance = ((KnowledgeAgentConfigurationImpl) configuration).isNewInstance();
+            this.notifier = (ResourceChangeNotifierImpl) ResourceFactory.getResourceChangeNotifierService();
+            if (((KnowledgeAgentConfigurationImpl) configuration).isMonitorChangeSetEvents()) {
+                monitor = true;
+            }
 
-			if (((KnowledgeAgentConfigurationImpl) configuration)
-					.isScanDirectories()) {
-				this.scanDirectories = true;
-			}
+            if (((KnowledgeAgentConfigurationImpl) configuration).isScanDirectories()) {
+                this.scanDirectories = true;
+            }
 
-			scanResources = ((KnowledgeAgentConfigurationImpl) configuration)
-					.isScanResources();
-			if (scanResources) {
-				this.notifier.addResourceChangeMonitor(ResourceFactory
-						.getResourceChangeScannerService());
-				monitor = true; // if scanning, monitor must be true;
-			}
-		}
+            scanResources = ((KnowledgeAgentConfigurationImpl) configuration).isScanResources();
+            if (scanResources) {
+                this.notifier.addResourceChangeMonitor(ResourceFactory.getResourceChangeScannerService());
+                monitor = true; // if scanning, monitor must be true;
+            }
+        }
 
-		monitorResourceChangeEvents(monitor);
+        monitorResourceChangeEvents(monitor);
 
-		buildResourceMapping();
+        buildResourceMapping();
 
-		this.listener
-				.info("KnowledgeAgent created, with configuration:\nmonitorChangeSetEvents="
-						+ monitor
-						+ " scanResources="
-						+ scanResources
-						+ " scanDirectories="
-						+ this.scanDirectories
-						+ " newInstance=" + this.newInstance);
-	}
+        this.listener.info("KnowledgeAgent created, with configuration:\nmonitorChangeSetEvents="
+                + monitor
+                + " scanResources="
+                + scanResources
+                + " scanDirectories="
+                + this.scanDirectories
+                + " newInstance=" + this.newInstance);
+    }
 
-	public void setSystemEventListener(SystemEventListener listener) {
-		this.listener = listener;
-	}
+    public void setSystemEventListener(SystemEventListener listener) {
+        this.listener = listener;
+    }
 
-	public void applyChangeSet(Resource resource) {
-		applyChangeSet(getChangeSet(resource));
-	}
+    public void applyChangeSet(Resource resource) {
+        applyChangeSet(getChangeSet(resource));
+    }
 
-	public void applyChangeSet(ChangeSet changeSet) {
-		synchronized (this.resourcesMap) {
-			this.listener.info("KnowledgeAgent applying ChangeSet");
+    public void applyChangeSet(ChangeSet changeSet) {
+        synchronized (this.resourcesMap) {
+            this.listener.info("KnowledgeAgent applying ChangeSet");
 
-			ChangeSetState changeSetState = new ChangeSetState();
-			changeSetState.scanDirectories = this.scanDirectories;
-			// incremental build is inverse of newInstance
-			changeSetState.incrementalBuild = !(this.newInstance);
+            ChangeSetState changeSetState = new ChangeSetState();
+            changeSetState.scanDirectories = this.scanDirectories;
+            // incremental build is inverse of newInstance
+            changeSetState.incrementalBuild = !(this.newInstance);
 
-			// Process the new ChangeSet
-			processChangeSet(changeSet, changeSetState);
-			// Rebuild or do an update to the KnowledgeBase
-			buildKnowledgeBase(changeSetState);
-			// Rebuild the resource mapping
-			buildResourceMapping();
-		}
-	}
+            // Process the new ChangeSet
+            processChangeSet(changeSet, changeSetState);
+            // Rebuild or do an update to the KnowledgeBase
+            buildKnowledgeBase(changeSetState);
+            // Rebuild the resource mapping
+            buildResourceMapping();
+        }
+    }
 
-	public void processChangeSet(Resource resource,
-			ChangeSetState changeSetState) {
-		processChangeSet(getChangeSet(resource), changeSetState);
-	}
+    public void processChangeSet(Resource resource,
+            ChangeSetState changeSetState) {
+        processChangeSet(getChangeSet(resource), changeSetState);
+    }
 
-	public void processChangeSet(ChangeSet changeSet,
-			ChangeSetState changeSetState) {
-		synchronized (this.resourcesMap) {
-			/*
-			 * Process the added resources from a ChangeSet by subscribing to
-			 * the notifier and inserting a new ResourceMapping.
-			 */
-			for (Resource resource : changeSet.getResourcesAdded()) {
-				if (((InternalResource) resource).getResourceType() == ResourceType.CHANGE_SET) {
-					// @TODO We should not ignore an added change set
-					this.listener
-							.debug("KnowledgeAgent processing sub ChangeSet="
-									+ resource);
-					processChangeSet(resource, changeSetState);
-				} else if (((InternalResource) resource).isDirectory()) {
-					this.resourceDirectories.add(resource);
-					this.listener
-							.debug("KnowledgeAgent subscribing to directory="
-									+ resource);
-					this.notifier.subscribeResourceChangeListener(this,
-							resource);
-					// if it's a dir, subscribe it's children first
-					for (Resource child : ((InternalResource) resource)
-							.listResources()) {
+    public void processChangeSet(ChangeSet changeSet,
+            ChangeSetState changeSetState) {
+        synchronized (this.resourcesMap) {
+            /*
+             * Process the added resources from a ChangeSet by subscribing to
+             * the notifier and inserting a new ResourceMapping.
+             */
+            for (Resource resource : changeSet.getResourcesAdded()) {
+                if (((InternalResource) resource).getResourceType() == ResourceType.CHANGE_SET) {
+                    // @TODO We should not ignore an added change set
+                    this.listener.debug("KnowledgeAgent processing sub ChangeSet="
+                            + resource);
+                    processChangeSet(resource, changeSetState);
+                } else if (((InternalResource) resource).isDirectory()) {
+                    this.resourceDirectories.add(resource);
+                    this.listener.debug("KnowledgeAgent subscribing to directory="
+                            + resource);
+                    this.notifier.subscribeResourceChangeListener(this,
+                            resource);
+                    // if it's a dir, subscribe it's children first
+                    for (Resource child : ((InternalResource) resource).listResources()) {
 
-						// ignore sub directories
-						if (((InternalResource) child).isDirectory()) {
-							continue;
-						}
+                        // ignore sub directories
+                        if (((InternalResource) child).isDirectory()) {
+                            continue;
+                        }
 
-						((InternalResource) child)
-								.setResourceType(((InternalResource) resource)
-										.getResourceType());
-						if (this.resourcesMap.addResourceMapping(child, true)
-								&& changeSetState.incrementalBuild) {
-							changeSetState.addedResources.add(child);
-						}
-					}
-				} else {
-					if (this.resourcesMap.addResourceMapping(resource, true)
-							&& changeSetState.incrementalBuild) {
-						changeSetState.addedResources.add(resource);
-					}
-				}
-			}
+                        ((InternalResource) child).setResourceType(((InternalResource) resource).getResourceType());
+                        if (this.resourcesMap.addResourceMapping(child, true)
+                                && changeSetState.incrementalBuild) {
+                            changeSetState.addedResources.add(child);
+                        }
+                    }
+                } else {
+                    if (this.resourcesMap.addResourceMapping(resource, true)
+                            && changeSetState.incrementalBuild) {
+                        // parse the reource using DlrParser. save the packageDescr into a Map<Resource,PackageDescr
+                        changeSetState.addedResources.add(resource);
 
-			/*
-			 * For those marked as removed by the ChangeSet, remove their
-			 * mappings, index them if we are doing incremental builds so the
-			 * incremental building process knows what to remove.
-			 */
-			for (Resource resource : changeSet.getResourcesRemoved()) {
-				if (((InternalResource) resource).getResourceType() == ResourceType.CHANGE_SET) {
-					// @TODO Is this true? Shouldn't we just ignore it in
-					// removed?
-					processChangeSet(resource, changeSetState);
-				} else if (changeSetState.scanDirectories
-						&& ((InternalResource) resource).isDirectory()) {
-					this.listener
-							.debug("KnowledgeAgent unsubscribing from directory resource="
-									+ resource);
-					this.resourceDirectories.remove(resource);
-					this.notifier.unsubscribeResourceChangeListener(this,
-							resource);
-				} else {
-					ResourceMapEntry removedEntry = this.resourcesMap
-							.removeResourceMapping(resource, true);
 
-					if (removedEntry != null && changeSetState.incrementalBuild) {
-						changeSetState.removedResourceMappings
-								.add(removedEntry);
-					}
-				}
-			}
+                    }
+                }
+            }
 
-			/*
-			 * For those marked as modified, remove their ResourceMapping,
-			 * attach it to the ChangeSetState, and add a new one - it will be
-			 * repopulated with the KnowledgeDefinitions later after rebuilding.
-			 * Process any modified ChangeSets - treat them as if they were new.
-			 */
-			for (Resource resource : changeSet.getResourcesModified()) {
-				if (((InternalResource) resource).getResourceType() == ResourceType.CHANGE_SET) {
-					// processChangeSet(resource, changeSetState);
-					continue;
-				} else if (((InternalResource) resource).isDirectory()) {
-					if (this.resourceDirectories.add(resource)) {
-						this.listener
-								.warning("KnowledgeAgent is subscribing to a modified directory="
-										+ resource
-										+ " when it should have already been subscribed");
-						this.notifier.subscribeResourceChangeListener(this,
-								resource);
-					}
-					// if it's a dir, subscribe it's children first
-					for (Resource child : ((InternalResource) resource)
-							.listResources()) {
+            /*
+             * For those marked as removed by the ChangeSet, remove their
+             * mappings, index them if we are doing incremental builds so the
+             * incremental building process knows what to remove.
+             */
+            for (Resource resource : changeSet.getResourcesRemoved()) {
+                if (((InternalResource) resource).getResourceType() == ResourceType.CHANGE_SET) {
+                    // @TODO Is this true? Shouldn't we just ignore it in
+                    // removed?
+                    processChangeSet(resource, changeSetState);
+                } else if (changeSetState.scanDirectories
+                        && ((InternalResource) resource).isDirectory()) {
+                    this.listener.debug("KnowledgeAgent unsubscribing from directory resource="
+                            + resource);
+                    this.resourceDirectories.remove(resource);
+                    this.notifier.unsubscribeResourceChangeListener(this,
+                            resource);
+                } else {
+                    ResourceMapEntry removedEntry = this.resourcesMap.removeResourceMapping(resource, true);
 
-						// ignore sub directories
-						if (((InternalResource) child).isDirectory()) {
-							continue;
-						}
+                    if (removedEntry != null && changeSetState.incrementalBuild) {
+                        changeSetState.removedResourceMappings.add(removedEntry);
+                    }
+                }
+            }
 
-						if (this.resourcesMap.addResourceMapping(child, true)) {
-							((InternalResource) child)
-									.setResourceType(((InternalResource) resource)
-											.getResourceType());
-							if (changeSetState.incrementalBuild) {
-								changeSetState.addedResources.add(child);
-							}
-						}
-					}
-				} else {
-					ResourceMapEntry modifiedMapping = this.resourcesMap
-							.removeResourceMapping(resource, false);
-					if (modifiedMapping == null) {
-						this.listener
-								.warning("KnowledgeAgent subscribing to new resource="
-										+ resource
-										+ ", though it was marked as modified.");
-						this.resourcesMap.addResourceMapping(resource, true);
-						if (changeSetState.incrementalBuild) {
-							changeSetState.addedResources.add(resource);
-						}
-					} else {
-						/*
-						 * Put a new one, but no need to subscribe or update
-						 * since this will be done in the buildResourceMapping
-						 * later
-						 */
-						this.resourcesMap.addResourceMapping(resource, false);
-						if (changeSetState.incrementalBuild) {
-							changeSetState.modifiedResourceMappings
-									.add(modifiedMapping);
-						}
-					}
-				}
-			}
-		}
-	}
+            /*
+             * For those marked as modified, remove their ResourceMapping,
+             * attach it to the ChangeSetState, and add a new one - it will be
+             * repopulated with the KnowledgeDefinitions later after rebuilding.
+             * Process any modified ChangeSets - treat them as if they were new.
+             */
+            for (Resource resource : changeSet.getResourcesModified()) {
+                if (((InternalResource) resource).getResourceType() == ResourceType.CHANGE_SET) {
+                    // processChangeSet(resource, changeSetState);
+                    continue;
+                } else if (((InternalResource) resource).isDirectory()) {
+                    if (this.resourceDirectories.add(resource)) {
+                        this.listener.warning("KnowledgeAgent is subscribing to a modified directory="
+                                + resource
+                                + " when it should have already been subscribed");
+                        this.notifier.subscribeResourceChangeListener(this,
+                                resource);
+                    }
+                    // if it's a dir, subscribe it's children first
+                    for (Resource child : ((InternalResource) resource).listResources()) {
 
-	/**
-	 * Returns a ChangeSet based on a resource with a resource type of
-	 * ChangeSet.
-	 *
-	 * @param resource
-	 *            A resource with the type set to ChangeSet
-	 * @return A ChangeSet that can be processed by this Agent.
-	 */
-	public ChangeSet getChangeSet(Resource resource) {
-		if (this.semanticModules == null) {
-			this.semanticModules = new SemanticModules();
-			this.semanticModules
-					.addSemanticModule(new ChangeSetSemanticModule());
-		}
+                        // ignore sub directories
+                        if (((InternalResource) child).isDirectory()) {
+                            continue;
+                        }
 
-		XmlChangeSetReader reader = new XmlChangeSetReader(this.semanticModules);
-		if (resource instanceof ClassPathResource) {
-			reader.setClassLoader(((ClassPathResource) resource)
-					.getClassLoader());
-		} else {
-			reader
-					.setClassLoader(((AbstractRuleBase) (((KnowledgeBaseImpl) this.kbase).ruleBase))
-							.getConfiguration().getClassLoader());
-		}
+                        if (this.resourcesMap.addResourceMapping(child, true)) {
+                            ((InternalResource) child).setResourceType(((InternalResource) resource).getResourceType());
+                            if (changeSetState.incrementalBuild) {
+                                changeSetState.addedResources.add(child);
+                            }
+                        }
+                    }
+                } else {
+                    ResourceMapEntry modifiedMapping = this.resourcesMap.removeResourceMapping(resource, false);
+                    if (modifiedMapping == null) {
+                        this.listener.warning("KnowledgeAgent subscribing to new resource="
+                                + resource
+                                + ", though it was marked as modified.");
+                        this.resourcesMap.addResourceMapping(resource, true);
+                        if (changeSetState.incrementalBuild) {
+                            changeSetState.addedResources.add(resource);
+                        }
+                    } else {
+                        /*
+                         * Put a new one, but no need to subscribe or update
+                         * since this will be done in the buildResourceMapping
+                         * later
+                         */
+                        this.resourcesMap.addResourceMapping(resource, false);
+                        if (changeSetState.incrementalBuild) {
+                            changeSetState.modifiedResourceMappings.add(modifiedMapping);
+                        }
+                    }
+                }
+            }
 
-		ChangeSet changeSet = null;
-		try {
-			changeSet = reader.read(resource.getReader());
-		} catch (Exception e) {
-			this.listener.exception(new RuntimeException(
-					"Unable to parse ChangeSet", e));
-		}
-		if (changeSet == null) {
-			this.listener.exception(new RuntimeException(
-					"Unable to parse ChangeSet"));
-		}
-		return changeSet;
-	}
 
-	/**
-	 * Keeps state information during the 'state' of a ChangeSet alteration so
-	 * past information can be kept along the way.
-	 *
-	 * @author Mark Proctor
-	 */
-	public static class ChangeSetState {
-		List<Resource> addedResources = new ArrayList<Resource>();
-		List<ResourceMapEntry> removedResourceMappings = new ArrayList<ResourceMapEntry>();
-		List<ResourceMapEntry> modifiedResourceMappings = new ArrayList<ResourceMapEntry>();
-		boolean scanDirectories;
-		boolean incrementalBuild;
-	}
+            //Removes each knowledgeDefinition marked as deleted from resourceMap.
+            //The deletion from kbase will be performed after by buildKnowledgeBase()
+            for (Resource resource : changeSet.getKnowledgeDefinitionsRemoved().keySet()) {
 
-	/**
-	 * This indexes the rules, flows, type declarations, etc against their
-	 * respective URLs if they have any, to allow more fine grained removal and
-	 * not just removing of an entire package
-	 */
-	public void buildResourceMapping() {
-		this.listener.debug("KnowledgeAgent building resource map");
-		synchronized (this.resourcesMap) {
-			RuleBase rbase = ((KnowledgeBaseImpl) this.kbase).ruleBase;
-			/*
-			 * Iterate each package for the different types of
-			 * KnowledgeDefinitions we want to track
-			 */
-			for (Package pkg : rbase.getPackages()) {
-				for (Rule rule : pkg.getRules()) {
-					Resource resource = rule.getResource();
-					if (resource == null
-							|| !((InternalResource) resource).hasURL()) {
-						this.listener
-								.debug("KnowledgeAgent no resource mapped for rule="
-										+ rule);
-						continue;
-					}
-					this.resourcesMap.putResourceMappingEntry(resource, rule);
-				}
+                KnowledgeDefinition removedDefinition = this.resourcesMap.removeResourceMappingEntry(resource, changeSet.getKnowledgeDefinitionsRemoved().get(resource));
 
-				for (Process process : pkg.getRuleFlows().values()) {
-					Resource resource = ((org.drools.process.core.Process) process)
-							.getResource();
-					if (resource == null
-							|| !((InternalResource) resource).hasURL()) {
-						this.listener
-								.debug("KnowledgeAgent no resource mapped for process="
-										+ process);
-						continue;
-					}
-					this.resourcesMap
-							.putResourceMappingEntry(resource, process);
-				}
+                if (removedDefinition == null) {
+                    this.listener.warning("Knowledge definition "
+                            + changeSet.getKnowledgeDefinitionsRemoved().get(resource)
+                            + " couldn't be removed from "
+                            + resource);
+                } else{
+                    //set the removedDefinition into the changeSetState so it
+                    //can be removed from kbase by buildKnowledgeBase().
+                    changeSetState.removedKnowledgeDefinitions.put(resource, removedDefinition);
+                }
+            }
 
-				for (TypeDeclaration typeDeclaration : pkg
-						.getTypeDeclarations().values()) {
-					Resource resource = typeDeclaration.getResource();
-					if (resource == null
-							|| !((InternalResource) resource).hasURL()) {
-						this.listener
-								.debug("KnowledgeAgent no resource mapped for typeDeclaration="
-										+ typeDeclaration);
-						continue;
-					}
-					this.resourcesMap.putResourceMappingEntry(resource,
-							typeDeclaration);
-				}
+        }
+    }
 
-				for (Function function : pkg.getFunctions().values()) {
-					Resource resource = function.getResource();
-					if (resource == null
-							|| !((InternalResource) resource).hasURL()) {
-						this.listener
-								.debug("KnowledgeAgent no resource mapped for function="
-										+ function);
-						continue;
-					}
-					this.resourcesMap.putResourceMappingEntry(resource,
-							function);
-				}
-			}
-		}
-	}
+    /**
+     * Returns a ChangeSet based on a resource with a resource type of
+     * ChangeSet.
+     *
+     * @param resource
+     *            A resource with the type set to ChangeSet
+     * @return A ChangeSet that can be processed by this Agent.
+     */
+    public ChangeSet getChangeSet(Resource resource) {
+        if (this.semanticModules == null) {
+            this.semanticModules = new SemanticModules();
+            this.semanticModules.addSemanticModule(new ChangeSetSemanticModule());
+        }
 
-	public KnowledgeBase getKnowledgeBase() {
-		synchronized (this.resourcesMap) {
-			return this.kbase;
-		}
-	}
+        XmlChangeSetReader reader = new XmlChangeSetReader(this.semanticModules);
+        if (resource instanceof ClassPathResource) {
+            reader.setClassLoader(((ClassPathResource) resource).getClassLoader());
+        } else {
+            reader.setClassLoader(((AbstractRuleBase) (((KnowledgeBaseImpl) this.kbase).ruleBase)).getConfiguration().getClassLoader());
+        }
 
-	public StatelessKnowledgeSession newStatelessKnowledgeSession() {
-		return new StatelessKnowledgeSessionImpl(null, this, null);
-	}
+        ChangeSet changeSet = null;
+        try {
+            changeSet = reader.read(resource.getReader());
+        } catch (Exception e) {
+            this.listener.exception(new RuntimeException(
+                    "Unable to parse ChangeSet", e));
+        }
+        if (changeSet == null) {
+            this.listener.exception(new RuntimeException(
+                    "Unable to parse ChangeSet"));
+        }
+        return changeSet;
+    }
 
-	public StatelessKnowledgeSession newStatelessKnowledgeSession(
-			KnowledgeSessionConfiguration conf) {
-		return new StatelessKnowledgeSessionImpl(null, this, conf);
-	}
+    /**
+     * Keeps state information during the 'state' of a ChangeSet alteration so
+     * past information can be kept along the way.
+     *
+     * @author Mark Proctor
+     */
+    public static class ChangeSetState {
 
-	public void resourcesChanged(ChangeSet changeSet) {
-		try {
-			this.listener
-					.debug("KnowledgeAgent received ChangeSet changed notification");
-			this.queue.put(changeSet);
-		} catch (InterruptedException e) {
-			this.listener
-					.exception(new RuntimeException(
-							"KnowledgeAgent error while adding ChangeSet notification to queue",
-							e));
-		}
-	}
+        List<Resource> addedResources = new ArrayList<Resource>();
+        List<ResourceMapEntry> removedResourceMappings = new ArrayList<ResourceMapEntry>();
+        List<ResourceMapEntry> modifiedResourceMappings = new ArrayList<ResourceMapEntry>();
+        Map<Resource, KnowledgeDefinition> removedKnowledgeDefinitions = new HashMap<Resource, KnowledgeDefinition>();
+        boolean scanDirectories;
+        boolean incrementalBuild;
+    }
 
-	/**
-	 * Rebuilds and creates a new KnowledgeBase for this KnowledgeAgent when
-	 * called based on the ChangeSet that comes in and if newInstance is set to
-	 * true. If incremental building or KnowledgeBase updates is on, then this
-	 * will attempt to update the KnowledgeBase instead.
-	 *
-	 * @param changeSetState
-	 *            The state that the ChangeSet performed
-	 */
-	public void buildKnowledgeBase(ChangeSetState changeSetState) {
-		this.listener
-				.debug("KnowledgeAgent rebuilding KnowledgeBase using ChangeSet");
-		synchronized (this.resourcesMap) {
+    /**
+     * This indexes the rules, flows, type declarations, etc against their
+     * respective URLs if they have any, to allow more fine grained removal and
+     * not just removing of an entire package
+     */
+    public void buildResourceMapping() {
+        this.listener.debug("KnowledgeAgent building resource map");
+        synchronized (this.resourcesMap) {
+            RuleBase rbase = ((KnowledgeBaseImpl) this.kbase).ruleBase;
+            /*
+             * Iterate each package for the different types of
+             * KnowledgeDefinitions we want to track
+             */
+            for (Package pkg : rbase.getPackages()) {
+                for (Rule rule : pkg.getRules()) {
+                    Resource resource = rule.getResource();
+                    if (resource == null
+                            || !((InternalResource) resource).hasURL()) {
+                        this.listener.debug("KnowledgeAgent no resource mapped for rule="
+                                + rule);
+                        continue;
+                    }
+                    this.resourcesMap.putResourceMappingEntry(resource, rule);
+                }
 
-			/*
-			 * Do the following only if we are building a new instance,
-			 * otherwise, do an incremental build/update
-			 */
-			if (this.newInstance) {
-				rebuildResources(changeSetState);
-			} else {
-				incrementalBuildResources(changeSetState);
-			}
+                for (Process process : pkg.getRuleFlows().values()) {
+                    Resource resource = ((org.drools.process.core.Process) process).getResource();
+                    if (resource == null
+                            || !((InternalResource) resource).hasURL()) {
+                        this.listener.debug("KnowledgeAgent no resource mapped for process="
+                                + process);
+                        continue;
+                    }
+                    this.resourcesMap.putResourceMappingEntry(resource, process);
+                }
 
-			/*
-			 * If the ruleBase is sequential, after rebuilding or incremental
-			 * update, do an ordering of the ReteooBuilder
-			 */
-			InternalRuleBase ruleBase = (InternalRuleBase) ((KnowledgeBaseImpl) this.kbase).ruleBase;
-			synchronized (ruleBase.getPackagesMap()) {
-				if (ruleBase.getConfiguration().isSequential()) {
-					ruleBase.getReteooBuilder().order();
-				}
-			}
-		}
-		this.listener
-				.debug("KnowledgeAgent finished rebuilding KnowledgeBase using ChangeSet");
-	}
+                for (TypeDeclaration typeDeclaration : pkg.getTypeDeclarations().values()) {
+                    Resource resource = typeDeclaration.getResource();
+                    if (resource == null
+                            || !((InternalResource) resource).hasURL()) {
+                        this.listener.debug("KnowledgeAgent no resource mapped for typeDeclaration="
+                                + typeDeclaration);
+                        continue;
+                    }
+                    this.resourcesMap.putResourceMappingEntry(resource,
+                            typeDeclaration);
+                }
 
-	/**
-	 * This method is meant to rebuild the entire KnowledgeBase. Cached
-	 * references outside of this Agent will no longer be valid to the current
-	 * KnowledgeBase
-	 *
-	 * @param changeSetState
-	 *            The ChangeSetState
-	 */
-	private void rebuildResources(ChangeSetState changeSetState) {
+                for (Function function : pkg.getFunctions().values()) {
+                    Resource resource = function.getResource();
+                    if (resource == null
+                            || !((InternalResource) resource).hasURL()) {
+                        this.listener.debug("KnowledgeAgent no resource mapped for function="
+                                + function);
+                        continue;
+                    }
+                    this.resourcesMap.putResourceMappingEntry(resource,
+                            function);
+                }
+            }
+        }
+    }
 
-		if (!this.newInstance) {
-			listener
-					.warning("KnowledgeAgent rebuilding KnowledgeBase when newInstance is false");
-		}
+    public KnowledgeBase getKnowledgeBase() {
+        synchronized (this.resourcesMap) {
+            return this.kbase;
+        }
+    }
 
-		/*
-		 * Rebuild a new knowledge base. Try to use the old configuration if
-		 * possible
-		 */
-		if (this.kbase != null) {
-			this.kbase = KnowledgeBaseFactory
-					.newKnowledgeBase(((InternalRuleBase) ((KnowledgeBaseImpl) this.kbase).ruleBase)
-							.getConfiguration());
-		} else {
-			this.kbase = KnowledgeBaseFactory.newKnowledgeBase();
-		}
+    public StatelessKnowledgeSession newStatelessKnowledgeSession() {
+        return new StatelessKnowledgeSessionImpl(null, this, null);
+    }
 
-		addResourcesToKnowledgeBase(resourcesMap.getAllResources());
+    public StatelessKnowledgeSession newStatelessKnowledgeSession(
+            KnowledgeSessionConfiguration conf) {
+        return new StatelessKnowledgeSessionImpl(null, this, conf);
+    }
 
-		this.listener
-				.info("KnowledgeAgent new KnowledgeBase now built and in use");
-	}
+    public void resourcesChanged(ChangeSet changeSet) {
+        try {
+            this.listener.debug("KnowledgeAgent received ChangeSet changed notification");
+            this.queue.put(changeSet);
+        } catch (InterruptedException e) {
+            this.listener.exception(new RuntimeException(
+                    "KnowledgeAgent error while adding ChangeSet notification to queue",
+                    e));
+        }
+    }
 
-	/**
-	 * This method is meant to incrementally build or update the current
-	 * KnowledgeBase.
-	 *
-	 * @param changeSet
-	 * @param changeSetState
-	 */
-	private void incrementalBuildResources(ChangeSetState changeSetState) {
-		if (this.newInstance) {
-			this.listener
-					.warning("KnowledgeAgent incremental build of KnowledgeBase when newInstance is true");
-		}
-		// Incrementally rebuild the resources
-		synchronized (this.resourcesMap) {
-			this.listener
-					.info("KnowledgeAgent performing an incremental build of the ChangeSet");
+    /**
+     * Rebuilds and creates a new KnowledgeBase for this KnowledgeAgent when
+     * called based on the ChangeSet that comes in and if newInstance is set to
+     * true. If incremental building or KnowledgeBase updates is on, then this
+     * will attempt to update the KnowledgeBase instead.
+     *
+     * @param changeSetState
+     *            The state that the ChangeSet performed
+     */
+    public void buildKnowledgeBase(ChangeSetState changeSetState) {
+        this.listener.debug("KnowledgeAgent rebuilding KnowledgeBase using ChangeSet");
+        synchronized (this.resourcesMap) {
 
-			// Create the knowledge base if one does not exist
-			if (this.kbase == null) {
-				this.kbase = KnowledgeBaseFactory.newKnowledgeBase();
-			}
+            /*
+             * Do the following only if we are building a new instance,
+             * otherwise, do an incremental build/update
+             */
+            if (this.newInstance) {
+                rebuildResources(changeSetState);
+            } else {
+                incrementalBuildResources(changeSetState);
+            }
 
-			// Remove all rules from the resources removed and also those
-			// modified
-			for (ResourceMapEntry resourceMapEntry : changeSetState.removedResourceMappings) {
-				for (KnowledgeDefinition kd : resourceMapEntry
-						.getKnowledgeDefinitions()) {
-					removeKnowledgeDefinitionFromBase(kd);
-				}
-			}
+            /*
+             * If the ruleBase is sequential, after rebuilding or incremental
+             * update, do an ordering of the ReteooBuilder
+             */
+            InternalRuleBase ruleBase = (InternalRuleBase) ((KnowledgeBaseImpl) this.kbase).ruleBase;
+            synchronized (ruleBase.getPackagesMap()) {
+                if (ruleBase.getConfiguration().isSequential()) {
+                    ruleBase.getReteooBuilder().order();
+                }
+            }
+        }
+        this.listener.debug("KnowledgeAgent finished rebuilding KnowledgeBase using ChangeSet");
+    }
 
-			for (ResourceMapEntry resourceMapEntry : changeSetState.modifiedResourceMappings) {
-				for (KnowledgeDefinition kd : resourceMapEntry
-						.getKnowledgeDefinitions()) {
-					removeKnowledgeDefinitionFromBase(kd);
-				}
-				changeSetState.addedResources.add(resourceMapEntry
-						.getResource());
-			}
+    /**
+     * This method is meant to rebuild the entire KnowledgeBase. Cached
+     * references outside of this Agent will no longer be valid to the current
+     * KnowledgeBase
+     *
+     * @param changeSetState
+     *            The ChangeSetState
+     */
+    private void rebuildResources(ChangeSetState changeSetState) {
 
-			/*
-			 * Adds both the newly added resources and the modified resources
-			 */
-			addResourcesToKnowledgeBase(changeSetState.addedResources);
-		}
-		this.listener
-				.info("KnowledgeAgent incremental build of KnowledgeBase finished and in use");
-	}
+        if (!this.newInstance) {
+            listener.warning("KnowledgeAgent rebuilding KnowledgeBase when newInstance is false");
+        }
 
-	/**
-	 *
-	 * @param kd
-	 */
-	private void removeKnowledgeDefinitionFromBase(KnowledgeDefinition kd) {
-		if (kd instanceof Rule) {
-			Rule rule = (Rule) kd;
-			this.listener.debug("KnowledgeAgent removing Rule=" + rule
-					+ " from package=" + rule.getPackageName());
-			this.kbase.removeRule(rule.getPackageName(), rule.getName());
-		} else if (kd instanceof Process) {
-			Process process = (Process) kd;
-			this.listener.debug("KnowledgeAgent removing Process=" + process);
-			this.kbase.removeProcess(process.getId());
-		} else if (kd instanceof TypeDeclaration) {
-			// @TODO Handle Type Declarations... is there a way to remove this?
-		} else if (kd instanceof Function) {
-			// @TODO functions and type declarations
-		}
-	}
+        /*
+         * Rebuild a new knowledge base. Try to use the old configuration if
+         * possible
+         */
+        if (this.kbase != null) {
+            this.kbase = KnowledgeBaseFactory.newKnowledgeBase(((InternalRuleBase) ((KnowledgeBaseImpl) this.kbase).ruleBase).getConfiguration());
+        } else {
+            this.kbase = KnowledgeBaseFactory.newKnowledgeBase();
+        }
 
-	/**
-	 * Adds the resources to the current KnowledgeBase on this KnowledgeAgent.
-	 * Only uses the KnowledgeBuilder when necessary.
-	 *
-	 * @param resources
-	 */
-	private void addResourcesToKnowledgeBase(Collection<Resource> resources) {
+        addResourcesToKnowledgeBase(resourcesMap.getAllResources());
 
-		KnowledgeBuilder kbuilder = null;
-		List<Package> packages = new ArrayList<Package>();
-		for (Resource resource : resources) {
-			/*
-			 * If it's not a PKG, clearly we need the knowledge builder, so
-			 * build it
-			 */
-			if (((InternalResource) resource).getResourceType() != ResourceType.PKG) {
-				this.listener.debug("KnowledgeAgent building resource="
-						+ resource);
-				if (kbuilder == null) {
-					kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
-				}
-				kbuilder.add(resource, ((InternalResource) resource)
-						.getResourceType());
-			} else {
-				// For PKG (.pks) just add them
-				this.listener.debug("KnowledgeAgent obtaining pkg resource="
-						+ resource);
+        this.listener.info("KnowledgeAgent new KnowledgeBase now built and in use");
+    }
 
-				InputStream is = null;
-				try {
-					// .pks are handled as a special case.
-					is = resource.getInputStream();
-					Object object = DroolsStreamUtils.streamIn(is);
-					Package pkg = null;
-					if (object instanceof KnowledgePackage) {
-						pkg = ((KnowledgePackageImp) object).pkg;
+    /**
+     * This method is meant to incrementally build or update the current
+     * KnowledgeBase.
+     *
+     * @param changeSet
+     * @param changeSetState
+     */
+    private void incrementalBuildResources(ChangeSetState changeSetState) {
+        if (this.newInstance) {
+            this.listener.warning("KnowledgeAgent incremental build of KnowledgeBase when newInstance is true");
+        }
+        // Incrementally rebuild the resources
+        synchronized (this.resourcesMap) {
+            this.listener.info("KnowledgeAgent performing an incremental build of the ChangeSet");
 
-					} else {
-						pkg = (Package) object;
-					}
-					for (Rule rule : pkg.getRules()) {
-						rule.setResource(resource);
-					}
+            // Create the knowledge base if one does not exist
+            if (this.kbase == null) {
+                this.kbase = KnowledgeBaseFactory.newKnowledgeBase();
+            }
 
-					packages.add(pkg);
-				} catch (Exception e) {
-					this.listener
-							.exception(new RuntimeException(
-									"KnowledgeAgent exception while trying to deserialize KnowledgeDefinitionsPackage  ",
-									e));
-				} finally {
-					try {
-						if (is != null) {
-							is.close();
-						}
-					} catch (IOException e) {
-						this.listener
-								.exception(new RuntimeException(
-										"KnowledgeAgent exception while trying to close KnowledgeDefinitionsPackage  ",
-										e));
-					}
-				}
-			}
-		}
+            // Remove all rules from the resources removed and also those
+            // modified
+            for (ResourceMapEntry resourceMapEntry : changeSetState.removedResourceMappings) {
+                for (KnowledgeDefinition kd : resourceMapEntry.getKnowledgeDefinitions()) {
+                    removeKnowledgeDefinitionFromBase(kd);
+                }
+            }
 
-		if (kbuilder != null) {
-			// Log any errors we come across
-			if (kbuilder.hasErrors()) {
-				this.listener.warning(
-						"KnowledgeAgent has KnowledgeBuilder errors ", kbuilder
-								.getErrors());
-			}
-			this.listener
-					.debug("KnowledgeAgent adding KnowledgePackages from KnowledgeBuilder");
-			this.kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
-		}
-		/*
-		 * Add all the packages we found, but did not build, from the resources
-		 * now
-		 */
-		for (Package pkg : packages) {
-			this.listener
-					.debug("KnowledgeAgent adding KnowledgeDefinitionsPackage "
-							+ pkg.getName());
-			((KnowledgeBaseImpl) this.kbase).ruleBase.addPackage(pkg);
-		}
-	}
+            for (ResourceMapEntry resourceMapEntry : changeSetState.modifiedResourceMappings) {
+                for (KnowledgeDefinition kd : resourceMapEntry.getKnowledgeDefinitions()) {
+                    removeKnowledgeDefinitionFromBase(kd);
+                }
+                changeSetState.addedResources.add(resourceMapEntry.getResource());
+            }
 
-	/*
-	 * (non-Javadoc)
-	 *
-	 * @see org.drools.agent.KnowledgeAgent#getName()
-	 */
-	public String getName() {
-		return this.name;
-	}
+            /*
+             * Adds both the newly added resources and the modified resources
+             */
+            addResourcesToKnowledgeBase(changeSetState.addedResources);
 
-	/**
-	 * Kicks off the monitoring service for handling ResourceChangeEvents on a
-	 * separate process.
-	 *
-	 * @boolean monitor True if monitoring should take place, false otherwise
-	 */
-	public void monitorResourceChangeEvents(boolean monitor) {
-		if (!monitor && this.changeSetNotificationDetector != null) {
-			// we are running, but it wants to stop
-			// this will stop the thread
-			this.changeSetNotificationDetector.stop();
-			this.thread.interrupt();
-			this.changeSetNotificationDetector = null;
-		} else if (monitor && this.changeSetNotificationDetector == null) {
-			this.changeSetNotificationDetector = new ChangeSetNotificationDetector(
-					this, this.queue, this.listener);
-			this.thread = new Thread(this.changeSetNotificationDetector);
-			this.thread.start();
-		}
-	}
 
-	/**
-	 * A class to monitor and handle ChangeSets fired by the
-	 * ResourceChangeNotifier on a separate service (or process).
-	 *
-	 * @author Mark Proctor
-	 */
-	public static class ChangeSetNotificationDetector implements Runnable {
-		private LinkedBlockingQueue<ChangeSet> queue;
-		private volatile boolean monitor;
-		private KnowledgeAgentImpl kagent;
-		private SystemEventListener listener;
+            //Remove the individual knowledgeDefinitions marked as deleted by the
+            //changeset
+            for (Resource resource : changeSetState.removedKnowledgeDefinitions.keySet()) {
+                removeKnowledgeDefinitionFromBase(changeSetState.removedKnowledgeDefinitions.get(resource));
+            }
+        }
+        this.listener.info("KnowledgeAgent incremental build of KnowledgeBase finished and in use");
+    }
 
-		public ChangeSetNotificationDetector(KnowledgeAgentImpl kagent,
-				LinkedBlockingQueue<ChangeSet> queue,
-				SystemEventListener listener) {
-			this.queue = queue;
-			this.kagent = kagent;
-			this.listener = listener;
-			this.monitor = true;
-		}
+    /**
+     *
+     * @param kd
+     */
+    private void removeKnowledgeDefinitionFromBase(KnowledgeDefinition kd) {
+        if (kd instanceof Query) {
+            // @TODO Queries. The way JavaDialectRuntimeData removes rules
+            // doesn't apply to Queries (Even when Query is a subclass of Rule).
+        } else if (kd instanceof Rule) {
+            Rule rule = (Rule) kd;
+            this.listener.debug("KnowledgeAgent removing Rule=" + rule
+                    + " from package=" + rule.getPackageName());
+            this.kbase.removeRule(rule.getPackageName(), rule.getName());
+        } else if (kd instanceof Process) {
+            Process process = (Process) kd;
+            this.listener.debug("KnowledgeAgent removing Process=" + process);
+            this.kbase.removeProcess(process.getId());
+        } else if (kd instanceof TypeDeclaration) {
+            // @TODO Handle Type Declarations... is there a way to remove this?
+        } else if (kd instanceof Function) {
+            // @TODO functions and type declarations
+        }
+    }
 
-		public void stop() {
-			this.monitor = false;
-		}
+    /**
+     * Adds the resources to the current KnowledgeBase on this KnowledgeAgent.
+     * Only uses the KnowledgeBuilder when necessary.
+     *
+     * @param resources
+     */
+    private void addResourcesToKnowledgeBase(Collection<Resource> resources) {
 
-		public void run() {
-			if (this.monitor) {
-				this.listener
-						.info("KnowledegAgent has started listening for ChangeSet notifications");
-			}
-			while (this.monitor) {
-				Exception exception = null;
-				try {
-					kagent.applyChangeSet(this.queue.take());
-				} catch (InterruptedException e) {
-					exception = e;
-				}
-				Thread.yield();
-				if (this.monitor && exception != null) {
-					this.listener
-							.exception(new RuntimeException(
-									"KnowledgeAgent ChangeSet notification thread has been interrupted, but shutdown was not scheduled",
-									exception));
-				}
-			}
+        KnowledgeBuilder kbuilder = null;
+        List<Package> packages = new ArrayList<Package>();
+        for (Resource resource : resources) {
+            /*
+             * If it's not a PKG, clearly we need the knowledge builder, so
+             * build it
+             */
+            if (((InternalResource) resource).getResourceType() != ResourceType.PKG) {
+                this.listener.debug("KnowledgeAgent building resource="
+                        + resource);
+                if (kbuilder == null) {
+                    kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+                }
+                kbuilder.add(resource, ((InternalResource) resource).getResourceType());
+            } else {
+                // For PKG (.pks) just add them
+                this.listener.debug("KnowledgeAgent obtaining pkg resource="
+                        + resource);
 
-			this.listener
-					.info("KnowledegAgent has stopped listening for ChangeSet notifications");
-		}
-	}
+                InputStream is = null;
+                try {
+                    // .pks are handled as a special case.
+                    is = resource.getInputStream();
+                    Object object = DroolsStreamUtils.streamIn(is);
+                    Package pkg = null;
+                    if (object instanceof KnowledgePackage) {
+                        pkg = ((KnowledgePackageImp) object).pkg;
 
-	/**
-	 * Maps a set of KnowledgeDefinitions to the resource that created them so
-	 * we can perform incremental building of a KnowledgeBase.
-	 *
-	 * @author Mark Proctor
-	 */
-	public static class ResourceMapEntry {
-		private final Resource resource;
-		private Set<KnowledgeDefinition> knowledgeDefinitions;
+                    } else {
+                        pkg = (Package) object;
+                    }
+                    for (Rule rule : pkg.getRules()) {
+                        rule.setResource(resource);
+                    }
 
-		public ResourceMapEntry(Resource resource) {
-			this.resource = resource;
-			this.knowledgeDefinitions = new HashSet<KnowledgeDefinition>();
-		}
+                    packages.add(pkg);
+                } catch (Exception e) {
+                    this.listener.exception(new RuntimeException(
+                            "KnowledgeAgent exception while trying to deserialize KnowledgeDefinitionsPackage  ",
+                            e));
+                } finally {
+                    try {
+                        if (is != null) {
+                            is.close();
+                        }
+                    } catch (IOException e) {
+                        this.listener.exception(new RuntimeException(
+                                "KnowledgeAgent exception while trying to close KnowledgeDefinitionsPackage  ",
+                                e));
+                    }
+                }
+            }
+        }
 
-		public Resource getResource() {
-			return resource;
-		}
+        if (kbuilder != null) {
+            // Log any errors we come across
+            if (kbuilder.hasErrors()) {
+                this.listener.warning(
+                        "KnowledgeAgent has KnowledgeBuilder errors ", kbuilder.getErrors());
+            }
+            this.listener.debug("KnowledgeAgent adding KnowledgePackages from KnowledgeBuilder");
+            this.kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
+        }
+        /*
+         * Add all the packages we found, but did not build, from the resources
+         * now
+         */
+        for (Package pkg : packages) {
+            this.listener.debug("KnowledgeAgent adding KnowledgeDefinitionsPackage "
+                    + pkg.getName());
+            ((KnowledgeBaseImpl) this.kbase).ruleBase.addPackage(pkg);
+        }
+    }
 
-		public Set<KnowledgeDefinition> getKnowledgeDefinitions() {
-			return knowledgeDefinitions;
-		}
-	}
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.drools.agent.KnowledgeAgent#getName()
+     */
+    public String getName() {
+        return this.name;
+    }
 
-	/**
-	 * A Bidirectional map of Resources to KnowledgeDefinitions.This allows you
-	 * to go both ways due to a KnowledgeDefinition being able to be overwritten
-	 * by multiple resources, and we only want to track the Resource responsible
-	 * as tagged by the KnowledgeBase for creating that resource.
-	 *
-	 * @author Sam Romano
-	 */
-	public static class ResourceMap {
-		private final KnowledgeAgentImpl agent;
-		private Map<Resource, ResourceMapEntry> resourceMappings;
-		private Map<KnowledgeDefinition, Resource> knowledgeDefinitionMappings;
+    /**
+     * Kicks off the monitoring service for handling ResourceChangeEvents on a
+     * separate process.
+     *
+     * @boolean monitor True if monitoring should take place, false otherwise
+     */
+    public void monitorResourceChangeEvents(boolean monitor) {
+        if (!monitor && this.changeSetNotificationDetector != null) {
+            // we are running, but it wants to stop
+            // this will stop the thread
+            this.changeSetNotificationDetector.stop();
+            this.thread.interrupt();
+            this.changeSetNotificationDetector = null;
+        } else if (monitor && this.changeSetNotificationDetector == null) {
+            this.changeSetNotificationDetector = new ChangeSetNotificationDetector(
+                    this, this.queue, this.listener);
+            this.thread = new Thread(this.changeSetNotificationDetector);
+            this.thread.start();
+        }
+    }
 
-		public ResourceMap(KnowledgeAgentImpl agent) {
-			this.agent = agent;
-			this.resourceMappings = new HashMap<Resource, ResourceMapEntry>();
-			this.knowledgeDefinitionMappings = new HashMap<KnowledgeDefinition, Resource>();
-		}
+    /**
+     * A class to monitor and handle ChangeSets fired by the
+     * ResourceChangeNotifier on a separate service (or process).
+     *
+     * @author Mark Proctor
+     */
+    public static class ChangeSetNotificationDetector implements Runnable {
 
-		/**
-		 * @param resource
-		 *            The resource to add to the Map
-		 * @param notify
-		 *            True if you want to notify the listener, false otherwise.
-		 * @return True if it was added, false otherwise.
-		 */
-		public boolean addResourceMapping(Resource resource, boolean notify) {
-			ResourceMapEntry rsrcMapping = this.resourceMappings.get(resource);
-			if (rsrcMapping == null) {
-				rsrcMapping = new ResourceMapEntry(resource);
-				this.resourceMappings.put(resource, rsrcMapping);
-				if (notify) {
-					this.agent.listener
-							.debug("KnowledgeAgent notifier subscribing to resource="
-									+ resource);
+        private LinkedBlockingQueue<ChangeSet> queue;
+        private volatile boolean monitor;
+        private KnowledgeAgentImpl kagent;
+        private SystemEventListener listener;
 
-					this.agent.notifier.subscribeResourceChangeListener(agent,
-							resource);
-				}
-				return true;
-			}
-			return false;
-		}
+        public ChangeSetNotificationDetector(KnowledgeAgentImpl kagent,
+                LinkedBlockingQueue<ChangeSet> queue,
+                SystemEventListener listener) {
+            this.queue = queue;
+            this.kagent = kagent;
+            this.listener = listener;
+            this.monitor = true;
+        }
 
-		/**
-		 * Returns the old ResourceMapping mapped to the Resource. If it finds a
-		 * resource mapping, it will unsubscribe from the
-		 * ResourceChangeListener.
-		 *
-		 * @param resource
-		 * @param unsubscribe
-		 *            True if you want to unsubscribe on a successful removal,
-		 *            false otherwise... normally false on attempting to remove
-		 *            entries for Modifications
-		 * @return The old resourceMapping with the KnowledgeDefinitions that it
-		 *         use to have
-		 */
-		public ResourceMapEntry removeResourceMapping(Resource resource,
-				boolean unsubscribe) {
-			this.agent.listener
-					.debug("KnowledgeAgent removing mappings for resource="
-							+ resource + " with unsubscribe=" + unsubscribe);
-			ResourceMapEntry rsrcMapping = this.resourceMappings
-					.remove(resource);
-			if (rsrcMapping != null) {
-				if (unsubscribe) {
-					this.agent.listener
-							.debug("KnowledgeAgent notifier unsubscribing to resource="
-									+ resource);
-					this.agent.notifier.unsubscribeResourceChangeListener(
-							agent, resource);
-				}
+        public void stop() {
+            this.monitor = false;
+        }
 
-				for (KnowledgeDefinition kd : rsrcMapping.knowledgeDefinitions) {
-					this.knowledgeDefinitionMappings.remove(kd);
-				}
-			}
-			return rsrcMapping;
-		}
+        public void run() {
+            if (this.monitor) {
+                this.listener.info("KnowledegAgent has started listening for ChangeSet notifications");
+            }
+            while (this.monitor) {
+                Exception exception = null;
+                try {
+                    kagent.applyChangeSet(this.queue.take());
+                } catch (InterruptedException e) {
+                    exception = e;
+                }
+                Thread.yield();
+                if (this.monitor && exception != null) {
+                    this.listener.exception(new RuntimeException(
+                            "KnowledgeAgent ChangeSet notification thread has been interrupted, but shutdown was not scheduled",
+                            exception));
+                }
+            }
 
-		public Set<Resource> getAllResources() {
-			return this.resourceMappings.keySet();
-		}
+            this.listener.info("KnowledegAgent has stopped listening for ChangeSet notifications");
+        }
+    }
 
-		/**
-		 * Maps a resource to the knowledge Definition, and vice versa for
-		 * bidirectional mapping and integrity. If the resource is not mapped at
-		 * all, this will subscribe the agent specified to this ResourceMap to
-		 * listen for those changes.
-		 *
-		 * @param resource
-		 * @param kd
-		 * @return The old resource the KnowledgeDefinition use to be mapped to
-		 *         if it was
-		 */
-		public Resource putResourceMappingEntry(Resource resource,
-				KnowledgeDefinition kd) {
-			ResourceMapEntry rsrcMapping = this.resourceMappings.get(resource);
-			if (rsrcMapping == null) {
-				addResourceMapping(resource, true);
-				rsrcMapping = this.resourceMappings.get(resource);
-			}
-			/*
-			 * If adding this returns true, then we need to map it the other
-			 * way, otherwise don't bother with the bidirectional logic and
-			 * waste time - essentially we know we mapped it before.
-			 */
-			if (rsrcMapping.knowledgeDefinitions.add(kd)) {
-				this.agent.listener.debug("KnowledgeAgent mapping resource="
-						+ resource + " to KnowledgeDefinition=" + kd);
+    /**
+     * Maps a set of KnowledgeDefinitions to the resource that created them so
+     * we can perform incremental building of a KnowledgeBase.
+     *
+     * @author Mark Proctor
+     */
+    public static class ResourceMapEntry {
 
-				Resource oldRsrc = this.knowledgeDefinitionMappings.put(kd,
-						resource);
-				/*
-				 * If an oldRsrc exists, make sure we remove the kd from that
-				 * mapping - but dont unsubscribe from it as the resource is
-				 * still being compiled in the KnowledgeBase, we need to know of
-				 * its updates
-				 */
-				ResourceMapEntry oldRsrcMapping = this.resourceMappings
-						.get(oldRsrc);
-				if (oldRsrcMapping != null) {
-					this.agent.listener
-							.debug("KnowledgeAgent removing reference from resource="
-									+ oldRsrc + " to KnowledgeDefinition=" + kd);
-					oldRsrcMapping.getKnowledgeDefinitions().remove(kd);
-				}
+        private final Resource resource;
+        private Set<KnowledgeDefinition> knowledgeDefinitions;
 
-				return oldRsrc;
-			}
-			return null;
-		}
+        public ResourceMapEntry(Resource resource) {
+            this.resource = resource;
+            this.knowledgeDefinitions = new HashSet<KnowledgeDefinition>();
+        }
 
-		public boolean removeResourceMappingEntry(Resource resource,
-				KnowledgeDefinition kd) {
-			ResourceMapEntry rsrcMapping = this.resourceMappings.get(resource);
-			if (rsrcMapping != null) {
-				/*
-				 * If the above didn't remove the kd, then we don't do the
-				 * bidirectional removal
-				 */
-				if (rsrcMapping.getKnowledgeDefinitions().remove(kd)) {
-					this.knowledgeDefinitionMappings.remove(kd);
-					return true;
-				}
-			}
-			return false;
-		}
-	}
+        public Resource getResource() {
+            return resource;
+        }
 
-	/*
-	 * (non-Javadoc)
-	 *
-	 * @see java.lang.Object#finalize()
-	 */
-	@Override
-	protected void finalize() throws Throwable {
-		// users should turn off monitoring, but just in case when this class is
-		// GC'd we turn off the thread
-		if (this.changeSetNotificationDetector != null) {
-			this.changeSetNotificationDetector.monitor = false;
-		}
-	}
+        public Set<KnowledgeDefinition> getKnowledgeDefinitions() {
+            return knowledgeDefinitions;
+        }
+    }
 
-}
\ No newline at end of file
+    /**
+     * A Bidirectional map of Resources to KnowledgeDefinitions.This allows you
+     * to go both ways due to a KnowledgeDefinition being able to be overwritten
+     * by multiple resources, and we only want to track the Resource responsible
+     * as tagged by the KnowledgeBase for creating that resource.
+     *
+     * @author Sam Romano
+     */
+    public static class ResourceMap {
+
+        private final KnowledgeAgentImpl agent;
+        private Map<Resource, ResourceMapEntry> resourceMappings;
+        private Map<KnowledgeDefinition, Resource> knowledgeDefinitionMappings;
+
+        public ResourceMap(KnowledgeAgentImpl agent) {
+            this.agent = agent;
+            this.resourceMappings = new HashMap<Resource, ResourceMapEntry>();
+            this.knowledgeDefinitionMappings = new HashMap<KnowledgeDefinition, Resource>();
+        }
+
+        /**
+         * @param resource
+         *            The resource to add to the Map
+         * @param notify
+         *            True if you want to notify the listener, false otherwise.
+         * @return True if it was added, false otherwise.
+         */
+        public boolean addResourceMapping(Resource resource, boolean notify) {
+            ResourceMapEntry rsrcMapping = this.resourceMappings.get(resource);
+            if (rsrcMapping == null) {
+                rsrcMapping = new ResourceMapEntry(resource);
+                this.resourceMappings.put(resource, rsrcMapping);
+                if (notify) {
+                    this.agent.listener.debug("KnowledgeAgent notifier subscribing to resource="
+                            + resource);
+
+                    this.agent.notifier.subscribeResourceChangeListener(agent,
+                            resource);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Returns the old ResourceMapping mapped to the Resource. If it finds a
+         * resource mapping, it will unsubscribe from the
+         * ResourceChangeListener.
+         *
+         * @param resource
+         * @param unsubscribe
+         *            True if you want to unsubscribe on a successful removal,
+         *            false otherwise... normally false on attempting to remove
+         *            entries for Modifications
+         * @return The old resourceMapping with the KnowledgeDefinitions that it
+         *         use to have
+         */
+        public ResourceMapEntry removeResourceMapping(Resource resource,
+                boolean unsubscribe) {
+            this.agent.listener.debug("KnowledgeAgent removing mappings for resource="
+                    + resource + " with unsubscribe=" + unsubscribe);
+            ResourceMapEntry rsrcMapping = this.resourceMappings.remove(resource);
+            if (rsrcMapping != null) {
+                if (unsubscribe) {
+                    this.agent.listener.debug("KnowledgeAgent notifier unsubscribing to resource="
+                            + resource);
+                    this.agent.notifier.unsubscribeResourceChangeListener(
+                            agent, resource);
+                }
+
+                for (KnowledgeDefinition kd : rsrcMapping.knowledgeDefinitions) {
+                    this.knowledgeDefinitionMappings.remove(kd);
+                }
+            }
+            return rsrcMapping;
+        }
+
+        public Set<Resource> getAllResources() {
+            return this.resourceMappings.keySet();
+        }
+
+        /**
+         * Maps a resource to the knowledge Definition, and vice versa for
+         * bidirectional mapping and integrity. If the resource is not mapped at
+         * all, this will subscribe the agent specified to this ResourceMap to
+         * listen for those changes.
+         *
+         * @param resource
+         * @param kd
+         * @return The old resource the KnowledgeDefinition use to be mapped to
+         *         if it was
+         */
+        public Resource putResourceMappingEntry(Resource resource,
+                KnowledgeDefinition kd) {
+            ResourceMapEntry rsrcMapping = this.resourceMappings.get(resource);
+            if (rsrcMapping == null) {
+                addResourceMapping(resource, true);
+                rsrcMapping = this.resourceMappings.get(resource);
+            }
+            /*
+             * If adding this returns true, then we need to map it the other
+             * way, otherwise don't bother with the bidirectional logic and
+             * waste time - essentially we know we mapped it before.
+             */
+            if (rsrcMapping.knowledgeDefinitions.add(kd)) {
+                this.agent.listener.debug("KnowledgeAgent mapping resource="
+                        + resource + " to KnowledgeDefinition=" + kd);
+
+                Resource oldRsrc = this.knowledgeDefinitionMappings.put(kd,
+                        resource);
+                /*
+                 * If an oldRsrc exists, make sure we remove the kd from that
+                 * mapping - but dont unsubscribe from it as the resource is
+                 * still being compiled in the KnowledgeBase, we need to know of
+                 * its updates
+                 */
+                ResourceMapEntry oldRsrcMapping = this.resourceMappings.get(oldRsrc);
+                if (oldRsrcMapping != null) {
+                    this.agent.listener.debug("KnowledgeAgent removing reference from resource="
+                            + oldRsrc + " to KnowledgeDefinition=" + kd);
+                    oldRsrcMapping.getKnowledgeDefinitions().remove(kd);
+                }
+
+                return oldRsrc;
+            }
+            return null;
+        }
+
+        public boolean removeResourceMappingEntry(Resource resource,
+                KnowledgeDefinition kd) {
+            ResourceMapEntry rsrcMapping = this.resourceMappings.get(resource);
+            if (rsrcMapping != null) {
+                /*
+                 * If the above didn't remove the kd, then we don't do the
+                 * bidirectional removal
+                 */
+                if (rsrcMapping.getKnowledgeDefinitions().remove(kd)) {
+                    this.knowledgeDefinitionMappings.remove(kd);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Removes a resource's knowledge definition from the maps given its name.
+         * To find the right knowledge definition, this method uses
+         * {@link #getKnowledgeDefinitionByName(org.drools.io.Resource, java.lang.String).
+         *
+         * <b>Author:<b> Esteban Aliverti.
+         *
+         * @param resource the resource where the kdefinition will be seached.
+         * @param knowledgeDefinitionName the name of the kdefinition.
+         * @return The removed kdefinition if it was found and succesfully
+         * removed. Oterwise, null.
+         */
+        public KnowledgeDefinition removeResourceMappingEntry(Resource resource,
+                String knowledgeDefinitionName) {
+
+            ResourceMapEntry rsrcMapping = this.resourceMappings.get(resource);
+
+
+            if (rsrcMapping != null) {
+                KnowledgeDefinition foundDefinition = this.getKnowledgeDefinitionByName(resource, knowledgeDefinitionName);
+                if (rsrcMapping.getKnowledgeDefinitions().remove(foundDefinition)) {
+                    this.knowledgeDefinitionMappings.remove(foundDefinition);
+                    return foundDefinition;
+                }
+            }
+
+
+            return null;
+        }
+
+        /**
+         * Return a knowledgeDeinition of a resource fiven its name. If
+         * the resource doesn't have a kdefinition with he specified name, null
+         * is returned.
+         * If the resouce has more than one kdefinition with the given name
+         * (according to some tests I made, functions and queries could have
+         * the same name), the first kdefinition found is returned. The search
+         * order is Rule/Query, Function, TypeDeclaration.
+         *
+         * <b>Author:<b> Esteban Aliverti.
+         *
+         * @param resource the resource where the kdefinition will be seached.
+         * @param knowledgeDefinitionName the name of the kdefinition.
+         * @return the kdefinition with the given name, or null if it doesn't exist.
+         *
+         */
+        private KnowledgeDefinition getKnowledgeDefinitionByName(Resource resource, String knowledgeDefinitionName) {
+
+            KnowledgeDefinition foundDefinition = null;
+
+            ResourceMapEntry rsrcMapping = this.resourceMappings.get(resource);
+            if (rsrcMapping != null) {
+
+
+                for (KnowledgeDefinition kd : rsrcMapping.knowledgeDefinitions) {
+
+                    String currentKDefinitionName = "";
+
+                    if (kd instanceof Rule) {
+                        //rules and queries
+                        currentKDefinitionName = ((Rule) kd).getName();
+                    } else if (kd instanceof Function) {
+                        currentKDefinitionName = ((Function) kd).getName();
+                    } else if (kd instanceof TypeDeclaration) {
+                        currentKDefinitionName = ((TypeDeclaration) kd).getTypeName();
+                    }
+
+                    if (currentKDefinitionName.equals(knowledgeDefinitionName)) {
+                        foundDefinition = kd;
+                        break;
+                    }
+
+                }
+
+            }
+
+            return foundDefinition;
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see java.lang.Object#finalize()
+     */
+    @Override
+    protected void finalize() throws Throwable {
+        // users should turn off monitoring, but just in case when this class is
+        // GC'd we turn off the thread
+        if (this.changeSetNotificationDetector != null) {
+            this.changeSetNotificationDetector.monitor = false;
+
+        }
+    }
+}

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ChangeSetImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ChangeSetImpl.java	2009-12-14 19:17:11 UTC (rev 30647)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ChangeSetImpl.java	2009-12-14 20:13:28 UTC (rev 30648)
@@ -2,6 +2,8 @@
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.drools.ChangeSet;
 import org.drools.definition.KnowledgeDefinition;
@@ -11,7 +13,10 @@
     private Collection<Resource> resourcesRemoved = Collections.<Resource>emptyList();
     private Collection<Resource> resourcesAdded = Collections.<Resource>emptyList();
     private Collection<Resource> resourcesModified = Collections.<Resource>emptyList();    
-    private Collection<KnowledgeDefinition> knowledgeDefinitionsRemoved = Collections.<KnowledgeDefinition>emptyList();
+
+    //Map of removed kdefinitions. The key is the resource and the string is
+    //the knowledgeDefinition's name.
+    private Map<Resource,String>  knowledgeDefinitionsRemoved = new HashMap<Resource, String>();
     
     public ChangeSetImpl() {
         
@@ -41,12 +46,13 @@
         this.resourcesModified = resourcesModified;
     }
 
-    public void setKnowledgeDefinitionsRemoved(Collection<KnowledgeDefinition> knowledgeDefinitionsRemoved) {
+    public Map<Resource, String> getKnowledgeDefinitionsRemoved() {
+        return knowledgeDefinitionsRemoved;
+    }
+
+    public void setKnowledgeDefinitionsRemoved(Map<Resource, String> knowledgeDefinitionsRemoved) {
         this.knowledgeDefinitionsRemoved = knowledgeDefinitionsRemoved;
     }
+
     
-    public Collection<KnowledgeDefinition> getKnowledgeDefinitionsRemoved() {
-        return knowledgeDefinitionsRemoved;
-    }
-        
 }



More information about the jboss-svn-commits mailing list