[jboss-svn-commits] JBL Code SVN: r30563 - in labs/jbossrules/trunk: drools-core/src/main/java/org/drools/agent/impl and 1 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Wed Dec 9 08:29:17 EST 2009


Author: eaa
Date: 2009-12-09 08:29:15 -0500 (Wed, 09 Dec 2009)
New Revision: 30563

Added:
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentIncrementalChangeSetTest.java
Modified:
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentTest.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/ResourceChangeScannerImpl.java
Log:
JBRULES-2152: KnowledgeAgentConfiguration - allow for property "drools.agent.newInstance" to be set to false
	-KnowledgeAgentImpl: Added support for drools.agent.newInstance=false. This will apply the change sets in an incremental way.
	-Moved Incremental change sets unit tests to a new class KnowledgeAgentIncrementalChangeSetTest.
	-Created new unit test for incremental change sets.

Added: 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	                        (rev 0)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentIncrementalChangeSetTest.java	2009-12-09 13:29:15 UTC (rev 30563)
@@ -0,0 +1,889 @@
+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.List;
+
+import junit.framework.TestCase;
+
+import org.drools.KnowledgeBase;
+import org.drools.KnowledgeBaseFactory;
+import org.drools.builder.KnowledgeBuilder;
+import org.drools.builder.KnowledgeBuilderFactory;
+import org.drools.builder.ResourceType;
+import org.drools.definition.KnowledgePackage;
+import org.drools.io.ResourceChangeScannerConfiguration;
+import org.drools.io.ResourceFactory;
+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 KnowledgeAgentIncrementalChangeSetTest 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 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";
+        File f1 = fileManager.newFile("rule1.drl");
+        Writer output = new BufferedWriter(new FileWriter(f1));
+        output.write(rule1);
+        output.close();
+
+        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";
+        File f2 = fileManager.newFile("rule2.drl");
+        output = new BufferedWriter(new FileWriter(f2));
+        output.write(rule2);
+        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();
+
+        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());
+
+        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(2, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule2"));
+
+        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);
+
+        rule1 = "";
+        rule1 += "package org.drools.test\n";
+        rule1 += "global java.util.List list\n";
+        rule1 += "rule rule3\n";
+        rule1 += "when\n";
+        rule1 += "then\n";
+        rule1 += "list.add( drools.getRule().getName() );\n";
+        rule1 += "end\n";
+        output = new BufferedWriter(new FileWriter(f1));
+        output.write(rule1);
+        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(2, list.size());
+
+        assertTrue(list.contains("rule3"));
+        assertTrue(list.contains("rule2"));
+        kagent.monitorResourceChangeEvents(false);
+    }
+
+    public void testRemoveFileUrlIncremental() 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";
+        File f1 = fileManager.newFile("rule1.drl");
+        Writer output = new BufferedWriter(new FileWriter(f1));
+        output.write(rule1);
+        output.close();
+
+        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";
+        File f2 = fileManager.newFile("rule2.drl");
+        output = new BufferedWriter(new FileWriter(f2));
+        output.write(rule2);
+        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();
+
+        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());
+
+        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(2, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule2"));
+
+        list.clear();
+
+        // Delete the file so only rule 2 fires
+        f1.delete();
+        Thread.sleep(3000);
+
+        // Use the same session for incremental build test
+        ksession = kbase.newStatefulKnowledgeSession();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(1, list.size());
+        assertTrue(list.contains("rule2"));
+
+        //Delete f2 now, no rules should fire
+        list.clear();
+        f2.delete();
+        Thread.sleep(3000);
+
+        ksession = kbase.newStatefulKnowledgeSession();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(0, list.size());
+
+        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";
+        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";
+        File f1 = fileManager.newFile("rule1.drl");
+        Writer output = new BufferedWriter(new FileWriter(f1));
+        output.write(rule1);
+        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";
+        File f2 = fileManager.newFile("rule2.drl");
+        output = new BufferedWriter(new FileWriter(f2));
+        output.write(rule2);
+        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();
+
+        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());
+
+        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(1, list.size());
+        assertTrue(list.contains("rule1_v2"));
+
+        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);
+
+        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);
+        output.close();
+        Thread.sleep(3000);
+
+        // Use the same session for incremental build test
+        ksession = kbase.newStatefulKnowledgeSession();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(1, list.size());
+        assertTrue(list.contains("rule1_v3"));
+
+        //Delete f2 now, rule1 should still fire if the indexing worked properly
+        list.clear();
+        f2.delete();
+        Thread.sleep(3000);
+
+        ksession = kbase.newStatefulKnowledgeSession();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(1, list.size());
+        assertTrue(list.contains("rule1_v3"));
+
+        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";
+        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\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("rules.drl");
+        Writer output = new BufferedWriter(new FileWriter(f1));
+        output.write(rule1);
+        output.write(rule2);
+        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/rules.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();
+
+        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());
+
+        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(2, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule2"));
+
+        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);
+
+        String rule3 = "";
+        rule3 += "rule rule3\n";
+        rule3 += "when\n";
+        rule3 += "then\n";
+        rule3 += "list.add( drools.getRule().getName());\n";
+        rule3 += "end\n";
+        output = new BufferedWriter(new FileWriter(f1));
+        output.write(rule1);
+        output.write(rule3);
+        output.close();
+        Thread.sleep(3000);
+
+        // Use the same session for incremental build test
+        ksession = kbase.newStatefulKnowledgeSession();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(2, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule3"));
+
+        kagent.monitorResourceChangeEvents(false);
+    }
+    
+    
+    public void testMultipleRulesOnFilesUrlIncremental() throws Exception {
+        String header = "";
+        header += "package org.drools.test\n";
+        header += "global java.util.List list\n\n";
+
+        String rule1 = "";
+        rule1 += "rule rule1\n";
+        rule1 += "when\n";
+        rule1 += "then\n";
+        rule1 += "list.add( drools.getRule().getName() );\n";
+        rule1 += "end\n\n";
+       
+
+        String rule2 = "";
+        rule2 += "rule rule2\n";
+        rule2 += "when\n";
+        rule2 += "then\n";
+        rule2 += "list.add( drools.getRule().getName());\n";
+        rule2 += "end\n";
+
+        String rule3 = "";
+        rule3 += "rule rule3\n";
+        rule3 += "when\n";
+        rule3 += "then\n";
+        rule3 += "list.add( drools.getRule().getName());\n";
+        rule3 += "end\n";
+
+        String rule4 = "";
+        rule4 += "rule rule4\n";
+        rule4 += "when\n";
+        rule4 += "then\n";
+        rule4 += "list.add( drools.getRule().getName());\n";
+        rule4 += "end\n";
+
+        String rule5 = "";
+        rule5 += "rule rule5\n";
+        rule5 += "when\n";
+        rule5 += "then\n";
+        rule5 += "list.add( drools.getRule().getName());\n";
+        rule5 += "end\n";
+
+        File f1 = fileManager.newFile("rules1.drl");
+        Writer output = new BufferedWriter(new FileWriter(f1));
+        output.write(header);
+        output.write(rule1);
+        output.write(rule2);
+        output.close();
+
+        File f2 = fileManager.newFile("rules2.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/rules1.drl' type='DRL' />";
+        xml += "        <resource source='http://localhost:9000/rules2.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();
+
+        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());
+
+        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(f2));
+        output.write(header);
+        output.write(rule4);
+        output.close();
+        Thread.sleep(3000);
+
+        // Use the same session for incremental build test
+        ksession = kbase.newStatefulKnowledgeSession();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(3, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule2"));
+        assertTrue(list.contains("rule4"));
+
+        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(rule1);
+        output.write(rule5);
+        output.close();
+        Thread.sleep(3000);
+
+
+        // Use the same session for incremental build test
+        ksession = kbase.newStatefulKnowledgeSession();
+        ksession.setGlobal("list", list);
+        ksession.fireAllRules();
+        ksession.dispose();
+
+        assertEquals(3, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule5"));
+        assertTrue(list.contains("rule4"));
+
+        list.clear();
+
+        kagent.monitorResourceChangeEvents(false);
+    }
+
+    
+    public void testModifyPackageUrlIncremental() 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 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";
+
+        // Do only Rule1 in the first package
+        File pkg1 = fileManager.newFile("pkg1.pkg");
+        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+        kbuilder.add(ResourceFactory.newByteArrayResource(rule1.getBytes()),
+                ResourceType.DRL);
+        if (kbuilder.hasErrors()) {
+            fail(kbuilder.getErrors().toString());
+        }
+        KnowledgePackage pkg = (KnowledgePackage) kbuilder.getKnowledgePackages().iterator().next();
+        writePackage(pkg, pkg1);
+
+        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 += "    </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(1, list.size());
+        assertTrue(list.contains("rule1"));
+
+        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);
+
+        rule1 = "";
+        rule1 += "package org.drools.test\n";
+        rule1 += "global java.util.List list\n";
+        rule1 += "rule rule3\n";
+        rule1 += "when\n";
+        rule1 += "then\n";
+        rule1 += "list.add( drools.getRule().getName() );\n";
+        rule1 += "end\n";
+
+        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());
+        }
+        pkg = (KnowledgePackage) kbuilder.getKnowledgePackages().iterator().next();
+        writePackage(pkg, pkg1);
+
+        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("rule3"));
+        assertTrue(list.contains("rule2"));
+        kagent.monitorResourceChangeEvents(false);
+    }
+
+    public void testUpdatePackageUrlIncremental() 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 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";
+
+        // Add Rule1 and Rule2 in the first package
+        File pkg1 = 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 pkg = (KnowledgePackage) kbuilder.getKnowledgePackages().iterator().next();
+        writePackage(pkg, pkg1);
+
+        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 += "    </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(2, list.size());
+        assertTrue(list.contains("rule1"));
+        assertTrue(list.contains("rule2"));
+
+        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);
+
+        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";
+
+        kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+        kbuilder.add(ResourceFactory.newByteArrayResource(rule2.getBytes()),
+                ResourceType.DRL);
+        kbuilder.add(ResourceFactory.newByteArrayResource(rule3.getBytes()),
+                ResourceType.DRL);
+        if (kbuilder.hasErrors()) {
+            fail(kbuilder.getErrors().toString());
+        }
+        pkg = (KnowledgePackage) kbuilder.getKnowledgePackages().iterator().next();
+        writePackage(pkg, pkg1);
+
+        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("rule2"));
+        assertTrue(list.contains("rule3"));
+        kagent.monitorResourceChangeEvents(false);
+    }
+
+     
+
+    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-compiler/src/test/java/org/drools/agent/KnowledgeAgentTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentTest.java	2009-12-09 06:02:19 UTC (rev 30562)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/agent/KnowledgeAgentTest.java	2009-12-09 13:29:15 UTC (rev 30563)
@@ -7,22 +7,15 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.Writer;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 
 import junit.framework.TestCase;
 
 import org.drools.KnowledgeBase;
 import org.drools.KnowledgeBaseFactory;
-import org.drools.agent.KnowledgeAgent;
-import org.drools.agent.KnowledgeAgentConfiguration;
-import org.drools.agent.KnowledgeAgentFactory;
 import org.drools.agent.KnowledgeAgentTest.ResultHandlerImpl;
 import org.drools.builder.KnowledgeBuilder;
 import org.drools.builder.KnowledgeBuilderFactory;
@@ -33,7 +26,6 @@
 import org.drools.io.ResourceFactory;
 import org.drools.io.impl.ResourceChangeNotifierImpl;
 import org.drools.io.impl.ResourceChangeScannerImpl;
-import org.drools.io.impl.UrlResource;
 import org.drools.runtime.StatefulKnowledgeSession;
 import org.drools.runtime.StatelessKnowledgeSession;
 import org.drools.runtime.pipeline.Action;
@@ -47,911 +39,1117 @@
 import org.mortbay.jetty.handler.ResourceHandler;
 
 public class KnowledgeAgentTest extends TestCase {
-    FileManager    fileManager;
+	FileManager fileManager;
 
-    private Server server;
-    private String returnUrl;
+	private Server server;
 
-    protected void setUp() throws Exception {
-        fileManager = new FileManager();
-        fileManager.setUp();
-        ((ResourceChangeScannerImpl) ResourceFactory.getResourceChangeScannerService()).reset();
-        ResourceFactory.getResourceChangeNotifierService().start();
-        ResourceFactory.getResourceChangeScannerService().start();
+	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() );
+		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.setHandler(resourceHandler);
 
-        server.start();
-    }
-    
+		server.start();
+	}
 
-    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  testModifyFileUrl() throws Exception {
+	protected void tearDown() throws Exception {
+		fileManager.tearDown();
+		ResourceFactory.getResourceChangeNotifierService().stop();
+		ResourceFactory.getResourceChangeScannerService().stop();
+		((ResourceChangeNotifierImpl) ResourceFactory
+				.getResourceChangeNotifierService()).reset();
+		((ResourceChangeScannerImpl) ResourceFactory
+				.getResourceChangeScannerService()).reset();
 
+		server.stop();
+	}
 
-        UrlResource.CACHE_DIR = new File(".");
+	public void testModifyFileUrl() 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";
+		File f1 = fileManager.newFile("rule1.drl");
+		Writer output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
 
-        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";
-        File f1 = fileManager.newFile( "rule1.drl" );
-        Writer output = new BufferedWriter( new FileWriter( f1 ) );
-        output.write( rule1 );
-        output.close();
+		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";
+		File f2 = fileManager.newFile("rule2.drl");
+		output = new BufferedWriter(new FileWriter(f2));
+		output.write(rule2);
+		output.close();
 
-        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";
-        File f2 = fileManager.newFile( "rule2.drl" );
-        output = new BufferedWriter( new FileWriter( f2 ) );
-        output.write( rule2 );
-        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();
 
-        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();
 
-        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+		ResourceChangeScannerConfiguration sconf = ResourceFactory
+				.getResourceChangeScannerService()
+				.newResourceChangeScannerConfiguration();
+		sconf.setProperty("drools.resource.scanner.interval", "2");
+		ResourceFactory.getResourceChangeScannerService().configure(sconf);
 
-        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", "true");
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
 
-        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
-        aconf.setProperty( "drools.agent.scanDirectories",
-                           "true" );
-        aconf.setProperty( "drools.agent.scanResources",
-                           "true" );
-        aconf.setProperty( "drools.agent.newInstance",
-                           "true" );
-        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                                                                         kbase,
-                                                                         aconf );
+		assertEquals("test agent", kagent.getName());
 
-        assertEquals("test agent", kagent.getName());
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI()
+				.toURL()));
 
-        kagent.applyChangeSet( ResourceFactory.newUrlResource( fxml.toURI().toURL() ) );
+		StatefulKnowledgeSession ksession = kagent.getKnowledgeBase()
+				.newStatefulKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        StatefulKnowledgeSession ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        List list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
 
-        assertEquals( 2,
-                      list.size() );
-        assertTrue( list.contains( "rule1" ) );
-        assertTrue( list.contains( "rule2" ) );
+		list.clear();
 
-        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);
 
-        // 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 );
+		rule1 = "";
+		rule1 += "package org.drools.test\n";
+		rule1 += "global java.util.List list\n";
+		rule1 += "rule rule3\n";
+		rule1 += "when\n";
+		rule1 += "then\n";
+		rule1 += "list.add( drools.getRule().getName() );\n";
+		rule1 += "end\n";
+		output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
+		Thread.sleep(3000);
 
-        rule1 = "";
-        rule1 += "package org.drools.test\n";
-        rule1 += "global java.util.List list\n";
-        rule1 += "rule rule3\n";
-        rule1 += "when\n";
-        rule1 += "then\n";
-        rule1 += "list.add( drools.getRule().getName() );\n";
-        rule1 += "end\n";
-        output = new BufferedWriter( new FileWriter( f1 ) );
-        output.write( rule1 );
-        output.close();
-        Thread.sleep( 3000 );
+		ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
+		list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		assertEquals(2, list.size());
 
-        assertEquals( 2,
-                      list.size() );
+		assertTrue(list.contains("rule3"));
+		assertTrue(list.contains("rule2"));
+		kagent.monitorResourceChangeEvents(false);
+	}
 
-        assertTrue( list.contains( "rule3" ) );
-        assertTrue( list.contains( "rule2" ) );
-        kagent.monitorResourceChangeEvents( false );
+	/**
+	 * Tests that if we change a ChangeSet that is referenced by another change
+	 * set or added by another ChangeSet, that the changes are picked up.
+	 *
+	 * @throws Exception
+	 *             If an unexpected exception occurs.
+	 */
+	public void testChangeSetInChangeSet() 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";
+		File f1 = fileManager.newFile("rule1.drl");
+		Writer output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
 
-        server.stop();
+		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";
+		File f2 = fileManager.newFile("rule2.drl");
+		output = new BufferedWriter(new FileWriter(f2));
+		output.write(rule2);
+		output.close();
 
+		String xml1 = "";
+		xml1 += "<change-set xmlns='http://drools.org/drools-5.0/change-set'";
+		xml1 += "    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'";
+		xml1 += "    xs:schemaLocation='http://drools.org/drools-5.0/change-set drools-change-set-5.0.xsd' >";
+		xml1 += "    <add> ";
+		xml1 += "        <resource source='http://localhost:9000/rule1.drl' type='DRL' />";
+		xml1 += "        <resource source='http://localhost:9000/rule2.drl' type='DRL' />";
+		xml1 += "    </add> ";
+		xml1 += "</change-set>";
+		File fxml1 = fileManager.newFile("changeset2.xml");
+		output = new BufferedWriter(new FileWriter(fxml1));
+		output.write(xml1);
+		output.close();
 
-        //now try it with the server stopped, so cache has to be used...
-        kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                                                                         kbase,
-                                                                         aconf );
-        kagent.monitorResourceChangeEvents(true);
-        assertEquals("test agent", kagent.getName());
+		String xml2 = "";
+		xml2 += "<change-set xmlns='http://drools.org/drools-5.0/change-set'";
+		xml2 += "    xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'";
+		xml2 += "    xs:schemaLocation='http://drools.org/drools-5.0/change-set drools-change-set-5.0.xsd' >";
+		xml2 += "    <add> ";
+		xml2 += "        <resource source='http://localhost:9000/changeset2.xml' type='CHANGE_SET' />";
+		xml2 += "    </add> ";
+		xml2 += "</change-set>";
+		File fxml2 = fileManager.newFile("changeset.xml");
+		output = new BufferedWriter(new FileWriter(fxml2));
+		output.write(xml2);
+		output.close();
 
+		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
 
-        //hmmm...
-        kagent.applyChangeSet( ResourceFactory.newFileResource(fxml)  );
+		ResourceChangeScannerConfiguration sconf = ResourceFactory
+				.getResourceChangeScannerService()
+				.newResourceChangeScannerConfiguration();
+		sconf.setProperty("drools.resource.scanner.interval", "2");
+		ResourceFactory.getResourceChangeScannerService().configure(sconf);
 
-        ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        assertNotNull(ksession);
-    }
-    
-    public void  testModifyFileUrlWithStateless() 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";
-        File f1 = fileManager.newFile( "rule1.drl" );
-        Writer output = new BufferedWriter( new FileWriter( f1 ) );
-        output.write( rule1 );
-        output.close();
+		KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory
+				.newKnowledgeAgentConfiguration();
+		aconf.setProperty("drools.agent.scanDirectories", "true");
+		aconf.setProperty("drools.agent.scanResources", "true");
+		aconf.setProperty("drools.agent.newInstance", "true");
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
 
-        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";
-        File f2 = fileManager.newFile( "rule2.drl" );
-        output = new BufferedWriter( new FileWriter( f2 ) );
-        output.write( rule2 );
-        output.close();
+		assertEquals("test agent", kagent.getName());
 
-        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();
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml2.toURI()
+				.toURL()));
 
-        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+		StatefulKnowledgeSession ksession = kagent.getKnowledgeBase()
+				.newStatefulKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
-        sconf.setProperty( "drools.resource.scanner.interval",
-                           "2" );
-        ResourceFactory.getResourceChangeScannerService().configure( sconf );
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
 
-        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
-        aconf.setProperty( "drools.agent.scanDirectories",
-                           "true" );
-        aconf.setProperty( "drools.agent.scanResources",
-                           "true" );
-        aconf.setProperty( "drools.agent.newInstance",
-                           "true" );
-        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                                                                         kbase,
-                                                                         aconf );
+		list.clear();
 
-        kagent.applyChangeSet( ResourceFactory.newUrlResource( fxml.toURI().toURL() ) );
+		// 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);
 
-        StatelessKnowledgeSession ksession = kagent.newStatelessKnowledgeSession();
-        List list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.execute( "hello" );
+		rule1 = "";
+		rule1 += "package org.drools.test\n";
+		rule1 += "global java.util.List list\n";
+		rule1 += "rule rule3\n";
+		rule1 += "when\n";
+		rule1 += "then\n";
+		rule1 += "list.add( drools.getRule().getName() );\n";
+		rule1 += "end\n";
+		output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
+		Thread.sleep(3000);
 
-        assertEquals( 2,
-                      list.size() );
-        assertTrue( list.contains( "rule1" ) );
-        assertTrue( list.contains( "rule2" ) );
+		ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
+		list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        list.clear();
+		assertEquals(2, list.size());
 
-        // 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 );
+		assertTrue(list.contains("rule3"));
+		assertTrue(list.contains("rule2"));
+		kagent.monitorResourceChangeEvents(false);
+	}
 
-        rule1 = "";
-        rule1 += "package org.drools.test\n";
-        rule1 += "global java.util.List list\n";
-        rule1 += "rule rule3\n";
-        rule1 += "when\n";
-        rule1 += "then\n";
-        rule1 += "list.add( drools.getRule().getName() );\n";
-        rule1 += "end\n";
-        System.out.println("root : " + f1.getPath() );
-        output = new BufferedWriter( new FileWriter( f1 ) );
-        output.write( rule1 );
-        output.close();
-        Thread.sleep( 3000 );
+	public void testModifyFileUrlWithStateless() 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";
+		File f1 = fileManager.newFile("rule1.drl");
+		Writer output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
 
+		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";
+		File f2 = fileManager.newFile("rule2.drl");
+		output = new BufferedWriter(new FileWriter(f2));
+		output.write(rule2);
+		output.close();
 
-        ksession.execute( "hello" );
+		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();
 
-        assertEquals( 2,
-                      list.size() );
-        
-        assertTrue( list.contains( "rule3" ) );
-        assertTrue( list.contains( "rule2" ) );
+		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
 
+		ResourceChangeScannerConfiguration sconf = ResourceFactory
+				.getResourceChangeScannerService()
+				.newResourceChangeScannerConfiguration();
+		sconf.setProperty("drools.resource.scanner.interval", "2");
+		ResourceFactory.getResourceChangeScannerService().configure(sconf);
 
-        kagent.monitorResourceChangeEvents( false );
+		KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory
+				.newKnowledgeAgentConfiguration();
+		aconf.setProperty("drools.agent.scanDirectories", "true");
+		aconf.setProperty("drools.agent.scanResources", "true");
+		aconf.setProperty("drools.agent.newInstance", "true");
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
 
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI()
+				.toURL()));
 
+		StatelessKnowledgeSession ksession = kagent
+				.newStatelessKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.execute("hello");
 
-    }    
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
 
-    public void  testModifyPackageUrl() 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 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";
-        
-        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 pkg = ( KnowledgePackage ) kbuilder.getKnowledgePackages().iterator().next();
-        writePackage( pkg, fileManager.newFile( "pkg1.pkg" ) );
-        
-    
-        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 += "    </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",
-                           "true" );
-        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                                                                         kbase,
-                                                                         aconf );
-    
-        kagent.applyChangeSet( ResourceFactory.newUrlResource( fxml.toURI().toURL() ) );
-    
-        StatefulKnowledgeSession ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        List list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
-    
-        assertEquals( 2,
-                      list.size() );
-        assertTrue( list.contains( "rule1" ) );
-        assertTrue( list.contains( "rule2" ) );
-    
-        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 );
-    
-        rule1 = "";
-        rule1 += "package org.drools.test\n";
-        rule1 += "global java.util.List list\n";
-        rule1 += "rule rule3\n";
-        rule1 += "when\n";
-        rule1 += "then\n";
-        rule1 += "list.add( drools.getRule().getName() );\n";
-        rule1 += "end\n";
-    
-        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() );
-        }
-        pkg = ( KnowledgePackage ) kbuilder.getKnowledgePackages().iterator().next();
-        writePackage( pkg, fileManager.newFile( "pkg1.pkg" ) );  
-        
-        //KnowledgePackage pkg2 = ( KnowledgePackage ) DroolsStreamUtils.streamIn( new FileInputStream( fileManager.newFile( "pkg1.pkg" ) ) );
-        
-        
-        Thread.sleep( 3000 );
-        
-        ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
-    
-        assertEquals( 2,
-                      list.size() );
-    
-        assertTrue( list.contains( "rule3" ) );
-        assertTrue( list.contains( "rule2" ) );
-        kagent.monitorResourceChangeEvents( false );
-    }
+		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);
 
-    public void testDeletePackageUrl() throws Exception {
-        String rule1 = "";
-        rule1 += "package org.drools.test1\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";
+		rule1 = "";
+		rule1 += "package org.drools.test\n";
+		rule1 += "global java.util.List list\n";
+		rule1 += "rule rule3\n";
+		rule1 += "when\n";
+		rule1 += "then\n";
+		rule1 += "list.add( drools.getRule().getName() );\n";
+		rule1 += "end\n";
+		System.out.println("root : " + f1.getPath());
+		output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
+		Thread.sleep(3000);
 
-        String rule2 = "";
-        rule2 += "package org.drools.test2\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";
+		ksession.execute("hello");
 
-        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() );
-        }
+		assertEquals(2, list.size());
 
-        Map map = new HashMap();
-        for ( KnowledgePackage pkg : kbuilder.getKnowledgePackages() ) {
-            map.put(  pkg.getName(), pkg );
-        }
-        writePackage( (KnowledgePackage) map.get( "org.drools.test1" ), fileManager.newFile( "pkg1.pkg" ) );
-        writePackage( (KnowledgePackage) map.get( "org.drools.test2" ), fileManager.newFile( "pkg2.pkg" ) );
+		assertTrue(list.contains("rule3"));
+		assertTrue(list.contains("rule2"));
+		kagent.monitorResourceChangeEvents(false);
+	}
 
+	public void testModifyPackageUrl() 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 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>";
+		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";
 
-        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+		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 pkg = (KnowledgePackage) kbuilder
+				.getKnowledgePackages().iterator().next();
+		writePackage(pkg, fileManager.newFile("pkg1.pkg"));
 
-        ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
-        sconf.setProperty( "drools.resource.scanner.interval",
-                           "2" );
-        ResourceFactory.getResourceChangeScannerService().configure( sconf );
+		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 += "    </add> ";
+		xml += "</change-set>";
+		File fxml = fileManager.newFile("changeset.xml");
+		Writer output = new BufferedWriter(new FileWriter(fxml));
+		output.write(xml);
+		output.close();
 
-        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
-        aconf.setProperty( "drools.agent.scanDirectories",
-                           "true" );
-        aconf.setProperty( "drools.agent.scanResources",
-                           "true" );
-        aconf.setProperty( "drools.agent.newInstance",
-                           "true" );
-        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                                                                         kbase,
-                                                                         aconf );
+		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
 
-        kagent.applyChangeSet( ResourceFactory.newByteArrayResource( xml.getBytes() ) );
+		ResourceChangeScannerConfiguration sconf = ResourceFactory
+				.getResourceChangeScannerService()
+				.newResourceChangeScannerConfiguration();
+		sconf.setProperty("drools.resource.scanner.interval", "2");
+		ResourceFactory.getResourceChangeScannerService().configure(sconf);
 
-        StatefulKnowledgeSession ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        List list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory
+				.newKnowledgeAgentConfiguration();
+		aconf.setProperty("drools.agent.scanDirectories", "true");
+		aconf.setProperty("drools.agent.scanResources", "true");
+		aconf.setProperty("drools.agent.newInstance", "true");
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
 
-        assertEquals( 2,
-                      list.size() );
-        assertTrue( list.contains( "rule1" ) );
-        assertTrue( list.contains( "rule2" ) );
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI()
+				.toURL()));
 
-        list.clear();
+		StatefulKnowledgeSession ksession = kagent.getKnowledgeBase()
+				.newStatefulKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        // 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 );
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
 
-        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 += "    <remove> ";
-        xml += "        <resource source='http://localhost:9000/pkg2.pkg' type='PKG' />";
-        xml += "    </remove> ";
-        xml += "</change-set>";
+		list.clear();
 
-        kagent.applyChangeSet( ResourceFactory.newByteArrayResource( xml.getBytes() ) );
+		// 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);
 
-        Thread.sleep( 3000 );
+		rule1 = "";
+		rule1 += "package org.drools.test\n";
+		rule1 += "global java.util.List list\n";
+		rule1 += "rule rule3\n";
+		rule1 += "when\n";
+		rule1 += "then\n";
+		rule1 += "list.add( drools.getRule().getName() );\n";
+		rule1 += "end\n";
 
-        ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		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());
+		}
+		pkg = (KnowledgePackage) kbuilder.getKnowledgePackages().iterator()
+				.next();
+		writePackage(pkg, fileManager.newFile("pkg1.pkg"));
 
-        assertEquals( 1,
-                      list.size() );
+		// KnowledgePackage pkg2 = ( KnowledgePackage )
+		// DroolsStreamUtils.streamIn( new FileInputStream( fileManager.newFile(
+		// "pkg1.pkg" ) ) );
 
-        assertTrue( list.contains( "rule1" ) );
-        kagent.monitorResourceChangeEvents( false );
-    }
+		Thread.sleep(3000);
 
-    public void  testOldSchoolPackageUrl() 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";
+		ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
+		list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        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";
+		assertEquals(2, list.size());
 
+		assertTrue(list.contains("rule3"));
+		assertTrue(list.contains("rule2"));
+		kagent.monitorResourceChangeEvents(false);
+	}
 
+	public void testDeletePackageUrl() throws Exception {
+		String rule1 = "";
+		rule1 += "package org.drools.test1\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 rule2 = "";
+		rule2 += "package org.drools.test2\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";
 
-        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() );
-        }
+		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());
+		}
 
-        KnowledgeBuilderImpl kbi = (KnowledgeBuilderImpl) kbuilder;
+		Map<String, KnowledgePackage> map = new HashMap<String, KnowledgePackage>();
+		for (KnowledgePackage pkg : kbuilder.getKnowledgePackages()) {
+			map.put(pkg.getName(), pkg);
+		}
+		writePackage((KnowledgePackage) map.get("org.drools.test1"),
+				fileManager.newFile("pkg1.pkg"));
+		writePackage((KnowledgePackage) map.get("org.drools.test2"),
+				fileManager.newFile("pkg2.pkg"));
 
-        //KnowledgePackage pkg = ( KnowledgePackage ) kbuilder.getKnowledgePackages().iterator().next();
-        writePackage( kbi.getPackageBuilder().getPackage(), fileManager.newFile( "pkgold.pkg" ) );
+		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>";
 
+		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
 
-        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/pkgold.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();
+		ResourceChangeScannerConfiguration sconf = ResourceFactory
+				.getResourceChangeScannerService()
+				.newResourceChangeScannerConfiguration();
+		sconf.setProperty("drools.resource.scanner.interval", "2");
+		ResourceFactory.getResourceChangeScannerService().configure(sconf);
 
-        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+		KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory
+				.newKnowledgeAgentConfiguration();
+		aconf.setProperty("drools.agent.scanDirectories", "true");
+		aconf.setProperty("drools.agent.scanResources", "true");
+		aconf.setProperty("drools.agent.newInstance", "true");
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
 
-        ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
-        sconf.setProperty( "drools.resource.scanner.interval",
-                "2" );
-        ResourceFactory.getResourceChangeScannerService().configure( sconf );
+		kagent.applyChangeSet(ResourceFactory.newByteArrayResource(xml
+				.getBytes()));
 
-        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
-        aconf.setProperty( "drools.agent.scanDirectories",
-                "true" );
-        aconf.setProperty( "drools.agent.scanResources",
-                "true" );
-        aconf.setProperty( "drools.agent.newInstance",
-                "true" );
-        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                kbase,
-                aconf );
+		StatefulKnowledgeSession ksession = kagent.getKnowledgeBase()
+				.newStatefulKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        kagent.applyChangeSet( ResourceFactory.newUrlResource( fxml.toURI().toURL() ) );
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
 
-        StatefulKnowledgeSession ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        List list = new ArrayList();
-        ksession.setGlobal( "list",
-                list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		list.clear();
 
-        assertEquals( 2,
-                list.size() );
-        assertTrue( list.contains( "rule1" ) );
-        assertTrue( list.contains( "rule2" ) );
+		// 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);
 
+		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 += "    <remove> ";
+		xml += "        <resource source='http://localhost:9000/pkg2.pkg' type='PKG' />";
+		xml += "    </remove> ";
+		xml += "</change-set>";
 
-    }
+		kagent.applyChangeSet(ResourceFactory.newByteArrayResource(xml
+				.getBytes()));
 
-    public void  testModifyFile() throws IOException,
-                                InterruptedException {
-        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";
-        File f1 = fileManager.newFile( "rule1.drl" );
-        Writer output = new BufferedWriter( new FileWriter( f1 ) );
-        output.write( rule1 );
-        output.close();
+		Thread.sleep(3000);
 
-        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";
-        File f2 = fileManager.newFile( "rule2.drl" );
-        output = new BufferedWriter( new FileWriter( f2 ) );
-        output.write( rule2 );
-        output.close();
+		ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
+		list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        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='" + f1.toURI().toURL() + "' type='DRL' />";
-        xml += "        <resource source='" + f2.toURI().toURL() + "' type='DRL' />";
-        xml += "    </add> ";
-        xml += "</change-set>";
-        File fxml = fileManager.newFile( "changeset.xml" );
-        output = new BufferedWriter( new FileWriter( fxml ) );
-        output.write( xml );
-        output.close();
+		assertEquals(1, list.size());
 
-        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+		assertTrue(list.contains("rule1"));
+		kagent.monitorResourceChangeEvents(false);
+	}
 
-        ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
-        sconf.setProperty( "drools.resource.scanner.interval",
-                           "2" );
-        ResourceFactory.getResourceChangeScannerService().configure( sconf );
+	public void testOldSchoolPackageUrl() 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";
 
-        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
-        aconf.setProperty( "drools.agent.scanDirectories",
-                           "true" );
-        aconf.setProperty( "drools.agent.scanResources",
-                           "true" );
-        aconf.setProperty( "drools.agent.newInstance",
-                           "true" );
-        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                                                                         kbase,
-                                                                         aconf );
+		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";
 
-        kagent.applyChangeSet( ResourceFactory.newUrlResource( fxml.toURI().toURL() ) );
+		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());
+		}
 
-        StatefulKnowledgeSession ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        List list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		KnowledgeBuilderImpl kbi = (KnowledgeBuilderImpl) kbuilder;
 
-        assertEquals( 2,
-                      list.size() );
-        assertTrue( list.contains( "rule1" ) );
-        assertTrue( list.contains( "rule2" ) );
+		// KnowledgePackage pkg = ( KnowledgePackage )
+		// kbuilder.getKnowledgePackages().iterator().next();
+		writePackage(kbi.getPackageBuilder().getPackage(), fileManager
+				.newFile("pkgold.pkg"));
 
-        list.clear();
+		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/pkgold.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();
 
-        // 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 );
+		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
 
-        rule1 = "";
-        rule1 += "package org.drools.test\n";
-        rule1 += "global java.util.List list\n";
-        rule1 += "rule rule3\n";
-        rule1 += "when\n";
-        rule1 += "then\n";
-        rule1 += "list.add( drools.getRule().getName() );\n";
-        rule1 += "end\n";
-        output = new BufferedWriter( new FileWriter( f1 ) );
-        output.write( rule1 );
-        output.close();
-        Thread.sleep( 3000 );
+		ResourceChangeScannerConfiguration sconf = ResourceFactory
+				.getResourceChangeScannerService()
+				.newResourceChangeScannerConfiguration();
+		sconf.setProperty("drools.resource.scanner.interval", "2");
+		ResourceFactory.getResourceChangeScannerService().configure(sconf);
 
-        ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory
+				.newKnowledgeAgentConfiguration();
+		aconf.setProperty("drools.agent.scanDirectories", "true");
+		aconf.setProperty("drools.agent.scanResources", "true");
+		aconf.setProperty("drools.agent.newInstance", "true");
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
 
-        assertEquals( 2,
-                      list.size() );
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI()
+				.toURL()));
 
-        assertTrue( list.contains( "rule3" ) );
-        assertTrue( list.contains( "rule2" ) );
-        kagent.monitorResourceChangeEvents( false );
-    }
-    
-    public void  testModifyDirectory() throws IOException,
-                                     InterruptedException {
-        // adds 2 files to a dir and executes then adds one and removes one and detects changes
-        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";
-        File f1 = fileManager.newFile( "rule1.drl" );
+		StatefulKnowledgeSession ksession = kagent.getKnowledgeBase()
+				.newStatefulKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        Writer output = new BufferedWriter( new FileWriter( f1 ) );
-        output.write( rule1 );
-        output.close();
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
 
-        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";
-        File f2 = fileManager.newFile( "rule2.drl" );
-        output = new BufferedWriter( new FileWriter( f2 ) );
-        output.write( rule2 );
-        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='" + f1.getParentFile().toURI().toURL() + "' type='DRL' />";
-        xml += "    </add> ";
-        xml += "</change-set>";
-        File newDir = fileManager.newFile( "changeset" );
-        newDir.mkdir();
-        File fxml = fileManager.newFile( newDir,
-                                         "changeset.xml" );
-        output = new BufferedWriter( new FileWriter( fxml ) );
-        output.write( xml );
-        output.close();
+	public void testModifyFile() throws IOException, InterruptedException {
+		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";
+		File f1 = fileManager.newFile("rule1.drl");
+		Writer output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
 
-        //        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
-        //        kbuilder.add( ResourceFactory.newUrlResource( fxml.toURI().toURL() ),
-        //                      ResourceType.ChangeSet );
-        //        assertFalse( kbuilder.hasErrors() );
+		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";
+		File f2 = fileManager.newFile("rule2.drl");
+		output = new BufferedWriter(new FileWriter(f2));
+		output.write(rule2);
+		output.close();
 
-        KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
-        //kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
+		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='" + f1.toURI().toURL()
+				+ "' type='DRL' />";
+		xml += "        <resource source='" + f2.toURI().toURL()
+				+ "' type='DRL' />";
+		xml += "    </add> ";
+		xml += "</change-set>";
+		File fxml = fileManager.newFile("changeset.xml");
+		output = new BufferedWriter(new FileWriter(fxml));
+		output.write(xml);
+		output.close();
 
-        ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
-        sconf.setProperty( "drools.resource.scanner.interval",
-                           "2" );
-        ResourceFactory.getResourceChangeScannerService().configure( sconf );
+		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
 
-        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
-        aconf.setProperty( "drools.agent.scanDirectories",
-                           "true" );
-        aconf.setProperty( "drools.agent.newInstance",
-                           "true" );
+		ResourceChangeScannerConfiguration sconf = ResourceFactory
+				.getResourceChangeScannerService()
+				.newResourceChangeScannerConfiguration();
+		sconf.setProperty("drools.resource.scanner.interval", "2");
+		ResourceFactory.getResourceChangeScannerService().configure(sconf);
 
-        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                                                                         kbase,
-                                                                         aconf );
-        kagent.applyChangeSet( ResourceFactory.newUrlResource( fxml.toURI().toURL() ) );
+		KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory
+				.newKnowledgeAgentConfiguration();
+		aconf.setProperty("drools.agent.scanDirectories", "true");
+		aconf.setProperty("drools.agent.scanResources", "true");
+		aconf.setProperty("drools.agent.newInstance", "true");
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
 
-        Thread.sleep( 3000 ); // give it 2 seconds to detect and build the changes
-        StatefulKnowledgeSession ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        List list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI()
+				.toURL()));
 
-        assertEquals( 2,
-                      list.size() );
-        assertTrue( list.contains( "rule1" ) );
-        assertTrue( list.contains( "rule2" ) );
+		StatefulKnowledgeSession ksession = kagent.getKnowledgeBase()
+				.newStatefulKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        list.clear();
-        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";
-        File f3 = fileManager.newFile( "rule3.drl" );
-        output = new BufferedWriter( new FileWriter( f3 ) );
-        output.write( rule3 );
-        output.close();
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
 
-        assertTrue( f1.delete() );
+		list.clear();
 
-        Thread.sleep( 3000 );
+		// 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);
 
-        ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
-        list = new ArrayList();
-        ksession.setGlobal( "list",
-                            list );
-        ksession.fireAllRules();
-        ksession.dispose();
+		rule1 = "";
+		rule1 += "package org.drools.test\n";
+		rule1 += "global java.util.List list\n";
+		rule1 += "rule rule3\n";
+		rule1 += "when\n";
+		rule1 += "then\n";
+		rule1 += "list.add( drools.getRule().getName() );\n";
+		rule1 += "end\n";
+		output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
+		Thread.sleep(3000);
 
-        assertEquals( 2,
-                      list.size() );
-        assertTrue( list.contains( "rule2" ) );
-        assertTrue( list.contains( "rule3" ) );
+		ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
+		list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-        kagent.monitorResourceChangeEvents( false );
-    }
+		assertEquals(2, list.size());
 
-    public void testStatelessWithPipeline() 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";
-        File f1 = fileManager.newFile( "rule1.drl" );
+		assertTrue(list.contains("rule3"));
+		assertTrue(list.contains("rule2"));
+		kagent.monitorResourceChangeEvents(false);
+	}
 
-        Writer output = new BufferedWriter( new FileWriter( f1 ) );
-        output.write( rule1 );
-        output.close();
+	public void testModifyDirectory() throws IOException, InterruptedException {
+		// adds 2 files to a dir and executes then adds one and removes one and
+		// detects changes
+		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";
+		File f1 = fileManager.newFile("rule1.drl");
 
-        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";
-        File f2 = fileManager.newFile( "rule2.drl" );
-        output = new BufferedWriter( new FileWriter( f2 ) );
-        output.write( rule2 );
-        output.close();
+		Writer output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		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='" + f1.getParentFile().toURI().toURL() + "' type='DRL' />";
-        xml += "    </add> ";
-        xml += "</change-set>";
-        File newDir = fileManager.newFile( "changeset" );
-        newDir.mkdir();
-        File fxml = fileManager.newFile( newDir,
-                                         "changeset.xml" );
-        output = new BufferedWriter( new FileWriter( fxml ) );
-        output.write( xml );
-        output.close();
-        
-        KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
-        aconf.setProperty( "drools.agent.scanDirectories",
-                           "true" );
-        aconf.setProperty( "drools.agent.newInstance",
-                           "true" );
+		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";
+		File f2 = fileManager.newFile("rule2.drl");
+		output = new BufferedWriter(new FileWriter(f2));
+		output.write(rule2);
+		output.close();
 
-        KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent",
-                                                                         aconf );
-        kagent.applyChangeSet( ResourceFactory.newUrlResource( fxml.toURI().toURL() ) );
+		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='"
+				+ f1.getParentFile().toURI().toURL() + "' type='DRL' />";
+		xml += "    </add> ";
+		xml += "</change-set>";
+		File newDir = fileManager.newFile("changeset");
+		newDir.mkdir();
+		File fxml = fileManager.newFile(newDir, "changeset.xml");
+		output = new BufferedWriter(new FileWriter(fxml));
+		output.write(xml);
+		output.close();
 
-        Thread.sleep( 3000 ); // give it 2 seconds to detect and build the changes
-        StatelessKnowledgeSession ksession = kagent.newStatelessKnowledgeSession();
-        
-         List list = new ArrayList();
-         ksession.setGlobal( "list",
-                             list );
+		// KnowledgeBuilder kbuilder =
+		// KnowledgeBuilderFactory.newKnowledgeBuilder();
+		// kbuilder.add( ResourceFactory.newUrlResource( fxml.toURI().toURL() ),
+		// ResourceType.ChangeSet );
+		// assertFalse( kbuilder.hasErrors() );
 
-         Action executeResultHandler = PipelineFactory.newExecuteResultHandler();
+		KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
+		// kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
 
-         Action assignResult = PipelineFactory.newAssignObjectAsResult();
-         assignResult.setReceiver( executeResultHandler );
+		ResourceChangeScannerConfiguration sconf = ResourceFactory
+				.getResourceChangeScannerService()
+				.newResourceChangeScannerConfiguration();
+		sconf.setProperty("drools.resource.scanner.interval", "2");
+		ResourceFactory.getResourceChangeScannerService().configure(sconf);
 
-         KnowledgeRuntimeCommand batchExecution = PipelineFactory.newCommandExecutor();
-         batchExecution.setReceiver( assignResult );
+		KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory
+				.newKnowledgeAgentConfiguration();
+		aconf.setProperty("drools.agent.scanDirectories", "true");
+		aconf.setProperty("drools.agent.newInstance", "true");
 
-         KnowledgeRuntimeCommand insertStage = PipelineFactory.newInsertObjectCommand();
-         insertStage.setReceiver( batchExecution );
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI()
+				.toURL()));
 
-         Pipeline pipeline = PipelineFactory.newStatelessKnowledgeSessionPipeline( ksession );
-         pipeline.setReceiver( insertStage );
+		Thread.sleep(3000); // give it 2 seconds to detect and build the changes
+		StatefulKnowledgeSession ksession = kagent.getKnowledgeBase()
+				.newStatefulKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
 
-         ResultHandlerImpl resultHandler = new ResultHandlerImpl();
-         pipeline.insert( "hello", resultHandler );
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
 
-         assertEquals( 2, list.size() );
-         assertTrue( list.contains( "rule1" ) );
-         assertTrue( list.contains( "rule2" ) );
-    }
-    
-    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;
-	    }
-    }
-}
+		list.clear();
+		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";
+		File f3 = fileManager.newFile("rule3.drl");
+		output = new BufferedWriter(new FileWriter(f3));
+		output.write(rule3);
+		output.close();
+
+		assertTrue(f1.delete());
+
+		Thread.sleep(3000);
+
+		ksession = kagent.getKnowledgeBase().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"));
+
+		kagent.monitorResourceChangeEvents(false);
+	}
+
+	public void testModifyFileInDirectory() throws Exception {
+		// Create the test directory
+		File testDirectory = fileManager.newFile("test");
+		testDirectory.mkdir();
+
+		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";
+		File f1 = fileManager.newFile(testDirectory, "rule1.drl");
+		Writer output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
+
+		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";
+		File f2 = fileManager.newFile(testDirectory, "rule2.drl");
+		output = new BufferedWriter(new FileWriter(f2));
+		output.write(rule2);
+		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='file:"
+				+ fileManager.getRootDirectory().getAbsolutePath()
+				+ "/test' 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();
+
+		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", "true");
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", kbase, aconf);
+
+		assertEquals("test agent", kagent.getName());
+
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI()
+				.toURL()));
+
+		StatefulKnowledgeSession ksession = kagent.getKnowledgeBase()
+				.newStatefulKnowledgeSession();
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
+
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
+
+		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);
+
+		rule1 = "";
+		rule1 += "package org.drools.test\n";
+		rule1 += "global java.util.List list\n";
+		rule1 += "rule rule3\n";
+		rule1 += "when\n";
+		rule1 += "then\n";
+		rule1 += "list.add( drools.getRule().getName() );\n";
+		rule1 += "end\n";
+		output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
+		Thread.sleep(3000);
+
+		ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
+		list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+		ksession.fireAllRules();
+		ksession.dispose();
+
+		assertEquals(2, list.size());
+
+		assertTrue(list.contains("rule3"));
+		assertTrue(list.contains("rule2"));
+		kagent.monitorResourceChangeEvents(false);
+	}
+
+	public void testStatelessWithPipeline() 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";
+		File f1 = fileManager.newFile("rule1.drl");
+
+		Writer output = new BufferedWriter(new FileWriter(f1));
+		output.write(rule1);
+		output.close();
+
+		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";
+		File f2 = fileManager.newFile("rule2.drl");
+		output = new BufferedWriter(new FileWriter(f2));
+		output.write(rule2);
+		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='"
+				+ f1.getParentFile().toURI().toURL() + "' type='DRL' />";
+		xml += "    </add> ";
+		xml += "</change-set>";
+		File newDir = fileManager.newFile("changeset");
+		newDir.mkdir();
+		File fxml = fileManager.newFile(newDir, "changeset.xml");
+		output = new BufferedWriter(new FileWriter(fxml));
+		output.write(xml);
+		output.close();
+
+		KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory
+				.newKnowledgeAgentConfiguration();
+		aconf.setProperty("drools.agent.scanDirectories", "true");
+		aconf.setProperty("drools.agent.newInstance", "true");
+
+		KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent(
+				"test agent", aconf);
+		kagent.applyChangeSet(ResourceFactory.newUrlResource(fxml.toURI()
+				.toURL()));
+
+		Thread.sleep(3000); // give it 2 seconds to detect and build the changes
+		StatelessKnowledgeSession ksession = kagent
+				.newStatelessKnowledgeSession();
+
+		List<String> list = new ArrayList<String>();
+		ksession.setGlobal("list", list);
+
+		Action executeResultHandler = PipelineFactory.newExecuteResultHandler();
+
+		Action assignResult = PipelineFactory.newAssignObjectAsResult();
+		assignResult.setReceiver(executeResultHandler);
+
+		KnowledgeRuntimeCommand batchExecution = PipelineFactory
+				.newCommandExecutor();
+		batchExecution.setReceiver(assignResult);
+
+		KnowledgeRuntimeCommand insertStage = PipelineFactory
+				.newInsertObjectCommand();
+		insertStage.setReceiver(batchExecution);
+
+		Pipeline pipeline = PipelineFactory
+				.newStatelessKnowledgeSessionPipeline(ksession);
+		pipeline.setReceiver(insertStage);
+
+		ResultHandlerImpl resultHandler = new ResultHandlerImpl();
+		pipeline.insert("hello", resultHandler);
+
+		assertEquals(2, list.size());
+		assertTrue(list.contains("rule1"));
+		assertTrue(list.contains("rule2"));
+	}
+
+	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;
+		}
+	}
+}
\ No newline at end of file

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-09 06:02:19 UTC (rev 30562)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/agent/impl/KnowledgeAgentImpl.java	2009-12-09 13:29:15 UTC (rev 30563)
@@ -3,6 +3,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -13,8 +14,8 @@
 import org.drools.ChangeSet;
 import org.drools.KnowledgeBase;
 import org.drools.KnowledgeBaseFactory;
+import org.drools.RuleBase;
 import org.drools.SystemEventListener;
-import org.drools.RuleBase;
 import org.drools.SystemEventListenerFactory;
 import org.drools.agent.KnowledgeAgent;
 import org.drools.agent.KnowledgeAgentConfiguration;
@@ -46,541 +47,907 @@
 import org.drools.xml.SemanticModules;
 import org.drools.xml.XmlChangeSetReader;
 
-public class KnowledgeAgentImpl
-    implements
-    KnowledgeAgent,
-    ResourceChangeListener {
-    private String                         name;
-    private Map<Resource, ResourceMapping> resources;
-    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;
+/**
+ * Drools Implementation of the KnowledgeAgent interface. Implements itself as a
+ * ResourceChangeListener as well so it can act as an agent service to provide
+ * incremental of the KnowledgeBase which connects to this or entirely new
+ * rebuilds for new KnowledgeBases.
+ *
+ * @author Mark Proctor, Sam Romano
+ */
+public class KnowledgeAgentImpl implements KnowledgeAgent,
+		ResourceChangeListener {
 
-    public KnowledgeAgentImpl(String name,
-                              KnowledgeBase kbase,
-                              KnowledgeAgentConfiguration configuration) {
-        this.name = name;
-        this.kbase = kbase;
-        this.resources = new HashMap<Resource, ResourceMapping>();
-        this.resourceDirectories = new HashSet<Resource>();
-        //this.listener = listener;
-        this.listener = SystemEventListenerFactory.getSystemEventListener();
-        this.newInstance = true; // we hard code this for now as incremental kbase changes don't work.
-        this.queue = new LinkedBlockingQueue<ChangeSet>();
-        boolean scanResources = false;
-        boolean monitor = false;
-        if ( configuration != null ) {
-            //this.newInstance = ((KnowledgeAgentConfigurationImpl) configuration).isNewInstance();
-            this.notifier = (ResourceChangeNotifierImpl) ResourceFactory.getResourceChangeNotifierService();
-            if ( ((KnowledgeAgentConfigurationImpl) configuration).isMonitorChangeSetEvents() ) {
-                monitor = true;
-            }
+	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;
 
-            if ( ((KnowledgeAgentConfigurationImpl) configuration).isScanDirectories() ) {
-                this.scanDirectories = 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;
+			}
 
-            scanResources = ((KnowledgeAgentConfigurationImpl) configuration).isScanResources();
-            if ( scanResources ) {
-                this.notifier.addResourceChangeMonitor( ResourceFactory.getResourceChangeScannerService() );
-                monitor = true; // if scanning, monitor must be true;
-            }
-        }
+			if (((KnowledgeAgentConfigurationImpl) configuration)
+					.isScanDirectories()) {
+				this.scanDirectories = true;
+			}
 
-        monitorResourceChangeEvents( monitor );
+			scanResources = ((KnowledgeAgentConfigurationImpl) configuration)
+					.isScanResources();
+			if (scanResources) {
+				this.notifier.addResourceChangeMonitor(ResourceFactory
+						.getResourceChangeScannerService());
+				monitor = true; // if scanning, monitor must be true;
+			}
+		}
 
-        //buildResourceMapping( kbase );
+		monitorResourceChangeEvents(monitor);
 
-        this.listener.info( "KnowledgAgent created, with configuration:\nmonitorChangeSetEvents=" + monitor + " scanResources=" + scanResources + " scanDirectories=" + this.scanDirectories );
-    }
+		buildResourceMapping();
 
-    public void setSystemEventListener(SystemEventListener listener) {
-        this.listener = listener;
-    }
+		this.listener
+				.info("KnowledgeAgent created, with configuration:\nmonitorChangeSetEvents="
+						+ monitor
+						+ " scanResources="
+						+ scanResources
+						+ " scanDirectories="
+						+ this.scanDirectories
+						+ " newInstance=" + this.newInstance);
+	}
 
-    public void applyChangeSet(Resource resource) {
-        applyChangeSet( getChangeSet( resource ) );
-    }
+	public void setSystemEventListener(SystemEventListener listener) {
+		this.listener = listener;
+	}
 
-    public void applyChangeSet(ChangeSet changeSet) {
-        synchronized ( this.resources ) {
-            this.listener.info( "KnowledgAgent applying ChangeSet" );
-            ChangeSetState changeSetState = new ChangeSetState();
-            changeSetState.scanDirectories = this.scanDirectories;
-            processChangeSet( changeSet,
-                              changeSetState );
-    
-            rebuildResources( changeSetState );
-        }
-        //buildResourceMapping( this.kbase );
-    }
+	public void applyChangeSet(Resource resource) {
+		applyChangeSet(getChangeSet(resource));
+	}
 
-    public void processChangeSet(Resource resource,
-                                 ChangeSetState changeSetState) {
-        processChangeSet( getChangeSet( resource ),
-                          changeSetState );
-    }
+	public void applyChangeSet(ChangeSet changeSet) {
+		synchronized (this.resourcesMap) {
+			this.listener.info("KnowledgeAgent applying ChangeSet");
 
-    public void processChangeSet(ChangeSet changeSet,
-                                 ChangeSetState changeSetState) {
-        synchronized ( this.resources ) {
-            
-            for ( Resource resource : changeSet.getResourcesAdded() ) {
-                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() ) {
-                        if ( ((InternalResource) child).isDirectory() ) {
-                            continue; // ignore sub directories
-                        }
-                        ((InternalResource) child).setResourceType( ((InternalResource) resource).getResourceType() );
-                        ResourceMapping mapping = this.resources.get( child );
-                        if ( mapping == null ) {
-                            this.listener.debug( "KnowledgeAgent subscribing to directory content resource=" + child );
-                            this.notifier.subscribeResourceChangeListener( this,
-                                                                           child );
-                            mapping = new ResourceMapping( child );
-                            this.resources.put( child,
-                                                mapping );
-                        }
-                    }
-                } else {
-                    if ( ((InternalResource) resource).getResourceType() == ResourceType.PKG ) {
-                        changeSetState.pkgs.add( resource );
-                    } else if ( ((InternalResource) resource).getResourceType() == ResourceType.CHANGE_SET ) {
-                        // @TODO
-                        continue;
-                    }
-    
-                    ResourceMapping mapping = this.resources.get( resource );
-                    if ( mapping == null ) {
-                        this.listener.debug( "KnowledgeAgent subscribing to resource=" + resource );
-                        this.notifier.subscribeResourceChangeListener( this,
-                                                                       resource );
-                        mapping = new ResourceMapping( resource );
-                        this.resources.put( resource,
-                                            mapping );
-                    }
-                }
-            }
-    
-            for ( Resource resource : changeSet.getResourcesRemoved() ) {
-                if ( ((InternalResource) resource).getResourceType() == ResourceType.CHANGE_SET ) {
-                    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 {
-                    this.listener.debug( "KnowledgeAgent unsubscribing from resource=" + resource );
-                    this.resources.remove( resource );
-                    this.notifier.unsubscribeResourceChangeListener( this,
-                                                                     resource );
-                }
-            }
-    
-            // are we going to need kbuilder to build these resources?
-            for ( Resource resource : this.resources.keySet() ) {
-                this.listener.debug( "KnowledgeAgent ChangeSet requires KnowledgeBuilder" );
-                if ( ((InternalResource) resource).getResourceType() != ResourceType.CHANGE_SET && ((InternalResource) resource).getResourceType() != ResourceType.PKG ) {
-                    changeSetState.needsKnowledgeBuilder = true;
-                    break;
-                }
-            }
-        }
+			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();
+		}
+	}
 
-    public ChangeSet getChangeSet(Resource resource) {
-        if ( this.semanticModules == null ) {
-            this.semanticModules = new SemanticModules();
-            this.semanticModules.addSemanticModule( new ChangeSetSemanticModule() );
-        }
+	public void processChangeSet(Resource resource,
+			ChangeSetState changeSetState) {
+		processChangeSet(getChangeSet(resource), changeSetState);
+	}
 
-        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 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()) {
 
-        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;
-    }
+						// ignore sub directories
+						if (((InternalResource) child).isDirectory()) {
+							continue;
+						}
 
-    public static class ChangeSetState {
-        List<Resource> pkgs = new ArrayList<Resource>();
-        boolean        scanDirectories;
-        boolean        needsKnowledgeBuilder;
-    }
+						((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);
+					}
+				}
+			}
 
-    /**
-     * This indexes the rules and flows against their respective urls, to allow more fine grained removal and not just removing of an entire package
-     * @param kbase
-     */
-    public void buildResourceMapping(KnowledgeBase kbase) {
-        RuleBase rbase = ((KnowledgeBaseImpl) kbase).ruleBase;
-        this.listener.debug( "KnowledgeAgent building resource map" );
-        synchronized ( this.resources ) {
+			/*
+			 * 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);
 
-            for ( Package pkg : rbase.getPackages() ) {
-                for ( Rule rule : pkg.getRules() ) {
-                    Resource resource = rule.getResource();
-                    if ( resource == null || !((InternalResource) resource).hasURL() ) {
-                        continue;
-                    }
-                    ResourceMapping mapping = this.resources.get( resource );
-                    if ( mapping == null ) {
-                        this.notifier.subscribeResourceChangeListener( this,
-                                                                       resource );
-                        mapping = new ResourceMapping( resource );
-                        this.resources.put( resource,
-                                            mapping );
-                    }
-                    this.listener.debug( "KnowledgeAgent mapping resource=" + resource + " to rule=" + rule );
-                    mapping.getKnowledgeDefinitions().add( rule );
-                }
+					if (removedEntry != null && changeSetState.incrementalBuild) {
+						changeSetState.removedResourceMappings
+								.add(removedEntry);
+					}
+				}
+			}
 
-                for ( Process process : pkg.getRuleFlows().values() ) {
-                    Resource resource = ((org.drools.process.core.Process) process).getResource();
-                    if ( resource == null || !((InternalResource) resource).hasURL() ) {
-                        continue;
-                    }
-                    ResourceMapping mapping = this.resources.get( resource );
-                    if ( mapping == null ) {
-                        this.notifier.subscribeResourceChangeListener( this,
-                                                                       resource );
-                        mapping = new ResourceMapping( resource );
-                        this.resources.put( resource,
-                                            mapping );
-                    }
-                    this.listener.debug( "KnowledgeAgent mapping resource=" + resource + " to process=" + process );
-                    mapping.getKnowledgeDefinitions().add( process );
-                }
+			/*
+			 * 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 ( TypeDeclaration typeDeclaration : pkg.getTypeDeclarations().values() ) {
-                    Resource resource = typeDeclaration.getResource();
-                    if ( resource == null || !((InternalResource) resource).hasURL() ) {
-                        continue;
-                    }
-                    ResourceMapping mapping = this.resources.get( resource );
-                    if ( mapping == null ) {
-                        this.notifier.subscribeResourceChangeListener( this,
-                                                                       resource );
-                        mapping = new ResourceMapping( resource );
-                        this.resources.put( resource,
-                                            mapping );
-                    }
-                    this.listener.debug( "KnowledgeAgent mapping resource=" + resource + " to TypeDeclaration=" + typeDeclaration );
-                    mapping.getKnowledgeDefinitions().add( typeDeclaration );
-                }
+						// ignore sub directories
+						if (((InternalResource) child).isDirectory()) {
+							continue;
+						}
 
-                for ( Function function : pkg.getFunctions().values() ) {
-                    Resource resource = function.getResource();
-                    if ( resource == null || !((InternalResource) resource).hasURL() ) {
-                        continue;
-                    }
-                    ResourceMapping mapping = this.resources.get( resource );
-                    if ( mapping == null ) {
-                        this.notifier.subscribeResourceChangeListener( this,
-                                                                       resource );
-                        mapping = new ResourceMapping( resource );
-                        this.resources.put( resource,
-                                            mapping );
-                    }
-                    this.listener.debug( "KnowledgeAgent mapping resource=" + resource + " to function=" + function );
-                    mapping.getKnowledgeDefinitions().add( function );
-                }
-            }
-        }
-    }
+						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);
+						}
+					}
+				}
+			}
+		}
+	}
 
-    public KnowledgeBase getKnowledgeBase() {
-        synchronized ( this.resources ) {
-            return this.kbase;
-        }
-    }
+	/**
+	 * 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 StatelessKnowledgeSession newStatelessKnowledgeSession() {
-        return new StatelessKnowledgeSessionImpl( null, this, null );
-    }
+		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(KnowledgeSessionConfiguration conf) {
-        return new StatelessKnowledgeSessionImpl( null, this, conf );
-    }
-    
-    //    public void resourceModified(ResourceModifiedEvent event) {
-    //        ResourceMapping mapping = this.resources.get( event.getResource() );
-    //        System.out.println( "modified : " + event.getResource() );
-    //        KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
-    //        synchronized ( this.resources ) {
-    //            for ( Resource resource : this.resources.keySet() ) {
-    //                System.out.println( "building : " + resource );
-    //                kbuilder.add( resource,
-    //                              KnowledgeType.DRL );
-    //            }
-    //
-    //            this.kbase = KnowledgeBaseFactory.newKnowledgeBase();
-    //            this.kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
-    //        }
-    //    }
+		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 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 ) );
-        }
-    }
+	/**
+	 * 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;
+	}
 
-    private void rebuildResources(ChangeSetState changeSetState) {
-        this.listener.debug( "KnowledgeAgent rebuilding KnowledgeBase using ChangeSet" );
-        synchronized ( this.resources ) {
-            // modified we already know is in the map, so no need to process those
+	/**
+	 * 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);
+				}
 
-            //            // now make a copy of the resource keys, as we are about to reset it, but need the keys to rebuild the kbase
-            //            Resource[] resourcesClone = this.resources.keySet().toArray( new Resource[this.resources.size()] );
-            //
-            //            // reset the resources map, so it can now be rebuilt
-            //            this.resources.clear();
+				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 ( this.kbase != null ) {
-                // re-use the KnowledgeBaseConfiguration if possible
-                this.kbase = KnowledgeBaseFactory.newKnowledgeBase( ((InternalRuleBase) ((KnowledgeBaseImpl) this.kbase).ruleBase).getConfiguration() );
-            } else {
-                this.kbase = KnowledgeBaseFactory.newKnowledgeBase();
-            }
+				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);
+				}
 
-            if ( changeSetState.needsKnowledgeBuilder ) {
+				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);
+				}
+			}
+		}
+	}
 
-                // rebuild the kbase
-                KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
+	public KnowledgeBase getKnowledgeBase() {
+		synchronized (this.resourcesMap) {
+			return this.kbase;
+		}
+	}
 
-                for ( Resource resource : this.resources.keySet() ) {
-                    if ( ((InternalResource) resource).getResourceType() != ResourceType.PKG ) {
-                        // .pks are handled as a special case.                        
-                        if ( ((InternalResource) resource).getConfiguration() == null ) {
-                            kbuilder.add( resource,
-                                          ((InternalResource) resource).getResourceType() );                            
-                        } else {
-                            kbuilder.add( resource,
-                                          ((InternalResource) resource).getResourceType(),
-                                          ((InternalResource) resource).getConfiguration() );                             
-                        }
-                        this.listener.debug( "KnowledgeAgent building resource=" + resource );
-                    }
-                }
+	public StatelessKnowledgeSession newStatelessKnowledgeSession() {
+		return new StatelessKnowledgeSessionImpl(null, this, null);
+	}
 
-                if ( kbuilder.hasErrors() ) {
-                    this.listener.warning( "KnowledgeAgent has KnowledgeBuilder errors ",
-                                           kbuilder.getErrors() );
-                }
+	public StatelessKnowledgeSession newStatelessKnowledgeSession(
+			KnowledgeSessionConfiguration conf) {
+		return new StatelessKnowledgeSessionImpl(null, this, conf);
+	}
 
-                this.kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
-            }
+	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));
+		}
+	}
 
-            for ( Resource resource : this.resources.keySet() ) {
+	/**
+	 * 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) {
 
-                if ( ((InternalResource) resource).getResourceType() == ResourceType.PKG ) {
-                    this.listener.debug( "KnowledgeAgent building resource=" + resource );
+			/*
+			 * 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);
+			}
 
-                    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;
-                        } else {
-                            pkg = (Package) object;
-                        }
-                        this.listener.debug( "KnowledgeAgent adding KnowledgeDefinitionsPackage " + pkg.getName() );
-                        ((KnowledgeBaseImpl) this.kbase).ruleBase.addPackage( pkg );
-                    } catch ( Exception e ) {
-                        this.listener.exception( new RuntimeException( "KnowledgeAgent exception while trying to deserialize KnowledgeDefinitionsPackage  ", e ) );
-                    } finally {
-                        try {
-                            is.close();
-                        } catch ( IOException e ) {
-                            this.listener.exception( new RuntimeException( "KnowledgeAgent exception while trying to close KnowledgeDefinitionsPackage  ", e ) );
-                        }
-                    }
-                }
-            }
-            
-            InternalRuleBase ruleBase = ( InternalRuleBase ) ((KnowledgeBaseImpl)this.kbase).ruleBase;
-            synchronized ( ruleBase.getPackagesMap() ) {
-                if ( ruleBase.getConfiguration().isSequential() ) {
-                    ruleBase.getReteooBuilder().order();
-                }
-            } 
+			/*
+			 * 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 ( Resource child : changeSetState.pkgs ) {
-            //                try {
-            //                    this.listener.debug( "child : " + ((InternalResource) child).getLastRead() + " : " + ((InternalResource) child).getLastModified() );
-            //                    InputStream is = child.getInputStream();
-            //                    Object object = DroolsStreamUtils.streamIn( is );
-            //                    Package pkg = null;
-            //                    if ( object instanceof KnowledgePackage ) {
-            //                        pkg = ((KnowledgePackageImp)object).pkg;
-            //                    } else {
-            //                        pkg = ( Package ) pkg;
-            //                    }
-            //                    this.listener.debug( "KnowledgeAgent adding KnowledgeDefinitionsPackage " + pkg.getName() );
-            //                    ((KnowledgeBaseImpl) this.kbase).ruleBase.addPackage( pkg );
-            //                    is.close();
-            //                } catch ( Exception e ) {
-            //                    this.listener.exception( new RuntimeException( "KnowledgeAgent exception while trying to serialize and KnowledgeDefinitionsPackage  " ) );
-            //                }
-            //            }        
+	/**
+	 * 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) {
 
-            this.listener.info( "KnowledgeAgent new KnowledgeBase now built and in use" );
-        }
+		if (!this.newInstance) {
+			listener
+					.warning("KnowledgeAgent rebuilding KnowledgeBase when newInstance is false");
+		}
 
-        // code commented out to try and do incremental kbase changes
-        // @TODO get this working for incremental changes
-        //        synchronized ( this.resources ) {
-        //            // first deal with removals
-        //            for ( Resource resource : changeSet.getResourcesRemoved() ) {
-        //                ResourceMapping mapping = this.resources.remove(resource );
-        //                if ( !this.newInstance  ) {
-        //                    // we are keeping the current instance, so we need remove the individual knowledge definitions           
-        //                    for ( KnowledgeDefinition kd : mapping.getKnowledgeDefinitions() ) {
-        //                        if ( kd instanceof Rule ) {
-        //                            Rule rule = ( Rule ) kd;
-        //                            this.kbase.removeRule( rule.getPackageName(), rule.getName() );
-        //                        } else if ( kd instanceof Process ) {
-        //                            Process process = ( Process ) kd;
-        //                            this.kbase.removeProcess( process.getId() );
-        //                        }
-        //                        // @TODO functions and type declarations
-        //                    }
-        //                }
-        //            }
-        //            
-        //            // now deal with additions
-        //            for ( Resource resource : changeSet.getResourcesAdded() ) {
-        //                
-        //            }
-        //            
-        //            // final deal with modifies
-        //        }        
-    }
+		/*
+		 * 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 String getName() {
-        return this.name;
-    }
+		addResourcesToKnowledgeBase(resourcesMap.getAllResources());
 
-    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();
-        }
+		this.listener
+				.info("KnowledgeAgent new KnowledgeBase now built and in use");
+	}
 
-    }
+	/**
+	 * 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");
 
-    public static class ChangeSetNotificationDetector
-        implements
-        Runnable {
-        private LinkedBlockingQueue<ChangeSet> queue;
-        private volatile boolean                monitor;
-        private KnowledgeAgentImpl             kagent;
-        private SystemEventListener            listener;
+			// Create the knowledge base if one does not exist
+			if (this.kbase == null) {
+				this.kbase = KnowledgeBaseFactory.newKnowledgeBase();
+			}
 
-        public ChangeSetNotificationDetector(KnowledgeAgentImpl kagent,
-                                             LinkedBlockingQueue<ChangeSet> queue,
-                                             SystemEventListener listener) {
-            this.queue = queue;
-            this.kagent = kagent;
-            this.listener = listener;
-            this.monitor = true;
-        }
-        
-        public void stop() {
-            this.monitor = false;
-        }
+			// Remove all rules from the resources removed and also those
+			// modified
+			for (ResourceMapEntry resourceMapEntry : changeSetState.removedResourceMappings) {
+				for (KnowledgeDefinition kd : resourceMapEntry
+						.getKnowledgeDefinitions()) {
+					removeKnowledgeDefinitionFromBase(kd);
+				}
+			}
 
-        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 ) );
-                }
-            }
+			for (ResourceMapEntry resourceMapEntry : changeSetState.modifiedResourceMappings) {
+				for (KnowledgeDefinition kd : resourceMapEntry
+						.getKnowledgeDefinitions()) {
+					removeKnowledgeDefinitionFromBase(kd);
+				}
+				changeSetState.addedResources.add(resourceMapEntry
+						.getResource());
+			}
 
-            this.listener.info( "KnowledegAgent has stopped listening for ChangeSet notifications" );
-        }
-    }
+			/*
+			 * 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");
+	}
 
-    public static class ResourceMapping {
-        private Resource                 resource;
-        private Set<KnowledgeDefinition> knowledgeDefinitions;
+	/**
+	 *
+	 * @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
+		}
+	}
 
-        public ResourceMapping(Resource resource) {
-            this.knowledgeDefinitions = new HashSet<KnowledgeDefinition>();
-        }
+	/**
+	 * 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 Resource getResource() {
-            return resource;
-        }
+		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);
 
-        public Set<KnowledgeDefinition> getKnowledgeDefinitions() {
-            return knowledgeDefinitions;
-        }
+				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;
 
-    }
+					} else {
+						pkg = (Package) object;
+					}
+					for (Rule rule : pkg.getRules()) {
+						rule.setResource(resource);
+					}
 
-    @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;
-        }
-    }
+					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));
+					}
+				}
+			}
+		}
 
+		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);
+		}
+	}
 
-}
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see org.drools.agent.KnowledgeAgent#getName()
+	 */
+	public String getName() {
+		return this.name;
+	}
+
+	/**
+	 * 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;
+
+		public ChangeSetNotificationDetector(KnowledgeAgentImpl kagent,
+				LinkedBlockingQueue<ChangeSet> queue,
+				SystemEventListener listener) {
+			this.queue = queue;
+			this.kagent = kagent;
+			this.listener = listener;
+			this.monitor = true;
+		}
+
+		public void stop() {
+			this.monitor = false;
+		}
+
+		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));
+				}
+			}
+
+			this.listener
+					.info("KnowledegAgent has stopped listening for ChangeSet notifications");
+		}
+	}
+
+	/**
+	 * 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;
+
+		public ResourceMapEntry(Resource resource) {
+			this.resource = resource;
+			this.knowledgeDefinitions = new HashSet<KnowledgeDefinition>();
+		}
+
+		public Resource getResource() {
+			return resource;
+		}
+
+		public Set<KnowledgeDefinition> getKnowledgeDefinitions() {
+			return knowledgeDefinitions;
+		}
+	}
+
+	/**
+	 * 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;
+		}
+	}
+
+	/*
+	 * (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;
+		}
+	}
+
+}
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ResourceChangeScannerImpl.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ResourceChangeScannerImpl.java	2009-12-09 06:02:19 UTC (rev 30562)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/io/impl/ResourceChangeScannerImpl.java	2009-12-09 13:29:15 UTC (rev 30563)
@@ -18,278 +18,314 @@
 import org.drools.io.ResourceChangeScanner;
 import org.drools.io.ResourceChangeScannerConfiguration;
 
-public class ResourceChangeScannerImpl
-    implements
-    ResourceChangeScanner {
+public class ResourceChangeScannerImpl implements ResourceChangeScanner {
 
-    private Map<Resource, Set<ResourceChangeNotifier>> resources;
-    private Set<Resource>                              directories;
-    private SystemEventListener                        listener;
-    private int                                        interval;
+	private Map<Resource, Set<ResourceChangeNotifier>> resources;
+	private Set<Resource> directories;
+	private SystemEventListener listener;
+	private int interval;
 
-    public ResourceChangeScannerImpl() {
-        this.listener = SystemEventListenerFactory.getSystemEventListener();
-        this.resources = new HashMap<Resource, Set<ResourceChangeNotifier>>();
-        this.directories = new HashSet<Resource>();
-        this.interval = 60;
+	public ResourceChangeScannerImpl() {
+		this.listener = SystemEventListenerFactory.getSystemEventListener();
+		this.resources = new HashMap<Resource, Set<ResourceChangeNotifier>>();
+		this.directories = new HashSet<Resource>();
+		this.interval = 60;
         this.listener.info( "ResourceChangeScanner created with default interval=60" );
-    }
+	}
 
-    public void setSystemEventListener(SystemEventListener listener) {
-        this.listener = listener;
-    }
+	public void setSystemEventListener(SystemEventListener listener) {
+		this.listener = listener;
+	}
 
-    public void configure(ResourceChangeScannerConfiguration configuration) {
+	public void configure(ResourceChangeScannerConfiguration configuration) {
         this.interval = ((ResourceChangeScannerConfigurationImpl) configuration).getInterval();
         this.listener.info( "ResourceChangeScanner reconfigured with interval=" + getInterval() );
 
-        // restart it if it's already running.
-        if ( this.scannerScheduler != null && this.scannerScheduler.isRunning() ) {
-            stop();
-            start();
-        }
-    }
+		// restart it if it's already running.
+		if (this.scannerScheduler != null && this.scannerScheduler.isRunning()) {
+			stop();
+			start();
+		}
+	}
 
-    public ResourceChangeScannerConfiguration newResourceChangeScannerConfiguration() {
-        return new ResourceChangeScannerConfigurationImpl();
-    }
+	public ResourceChangeScannerConfiguration newResourceChangeScannerConfiguration() {
+		return new ResourceChangeScannerConfigurationImpl();
+	}
 
-    public ResourceChangeScannerConfiguration newResourceChangeScannerConfiguration(Properties properties) {
-        return new ResourceChangeScannerConfigurationImpl( properties );
-    }
+	public ResourceChangeScannerConfiguration newResourceChangeScannerConfiguration(
+			Properties properties) {
+		return new ResourceChangeScannerConfigurationImpl(properties);
+	}
 
-    public void subscribeNotifier(ResourceChangeNotifier notifier,
-                                  Resource resource) {
-        synchronized ( this.resources ) {
-            if ( ((InternalResource) resource).isDirectory() ) {
-                this.directories.add( resource );
-            }
-            Set<ResourceChangeNotifier> notifiers = this.resources.get( resource );
-            if ( notifiers == null ) {
-                notifiers = new HashSet<ResourceChangeNotifier>();
-                this.resources.put( resource,
-                                    notifiers );
-            }
-            this.listener.debug( "ResourceChangeScanner subcribing notifier=" + notifier + " to resource=" + resource );
-            notifiers.add( notifier );
-        }
-    }
+	public void subscribeNotifier(ResourceChangeNotifier notifier,
+			Resource resource) {
+		synchronized (this.resources) {
+			if (((InternalResource) resource).isDirectory()) {
+				this.directories.add(resource);
+			}
+			Set<ResourceChangeNotifier> notifiers = this.resources
+					.get(resource);
+			if (notifiers == null) {
+				notifiers = new HashSet<ResourceChangeNotifier>();
+				this.resources.put(resource, notifiers);
+			}
+			this.listener.debug("ResourceChangeScanner subcribing notifier="
+					+ notifier + " to resource=" + resource);
+			notifiers.add(notifier);
+		}
+	}
 
-    public void unsubscribeNotifier(ResourceChangeNotifier notifier,
-                                    Resource resource) {
-        synchronized ( this.resources ) {
-            Set<ResourceChangeNotifier> notifiers = this.resources.get( resource );
-            if ( notifiers == null ) {
-                return;
-            }
-            this.listener.debug( "ResourceChangeScanner unsubcribing notifier=" + notifier + " to resource=" + resource );
-            notifiers.remove( notifier );
-            if ( notifiers.isEmpty() ) {
-                this.listener.debug( "ResourceChangeScanner resource=" + resource + " now has no subscribers" );
-                this.resources.remove( resource );
-                this.directories.remove( resource ); // don't bother with isDirectory check, as doing a remove is harmless if it doesn't exist
-            }
-        }
-    }
+	public void unsubscribeNotifier(ResourceChangeNotifier notifier,
+			Resource resource) {
+		synchronized (this.resources) {
+			Set<ResourceChangeNotifier> notifiers = this.resources
+					.get(resource);
+			if (notifiers == null) {
+				return;
+			}
+			this.listener.debug("ResourceChangeScanner unsubcribing notifier="
+					+ notifier + " to resource=" + resource);
+			notifiers.remove(notifier);
+			if (notifiers.isEmpty()) {
+				this.listener.debug("ResourceChangeScanner resource="
+						+ resource + " now has no subscribers");
+				this.resources.remove(resource);
+				this.directories.remove(resource); // don't bother with
+				// isDirectory check, as
+				// doing a remove is
+				// harmless if it doesn't
+				// exist
+			}
+		}
+	}
 
-    public void scan() {
-        this.listener.debug( "ResourceChangeScanner attempt to scan " + this.resources.size() + " resources" );
+	public void scan() {
+		this.listener.debug("ResourceChangeScanner attempt to scan "
+				+ this.resources.size() + " resources");
 
-        synchronized ( this.resources ) {
-            Map<ResourceChangeNotifier, ChangeSet> notifications = new HashMap<ResourceChangeNotifier, ChangeSet>();
+		synchronized (this.resources) {
+			Map<ResourceChangeNotifier, ChangeSet> notifications = new HashMap<ResourceChangeNotifier, ChangeSet>();
 
-            List<Resource> removed = new ArrayList<Resource>();
+			List<Resource> removed = new ArrayList<Resource>();
 
-            // detect modified and added
-            for ( Resource resource : this.directories ) {
-                this.listener.debug( "ResourceChangeScanner scanning directory=" + resource );
-                for ( Resource child : ((InternalResource) resource).listResources() ) {
-                    if ( ((InternalResource) child).isDirectory() ) {
-                        continue; // ignore sub directories
-                    }
-                    if ( !this.resources.containsKey( child ) ) {
+			// detect modified and added
+			for (Resource resource : this.directories) {
+				this.listener.debug("ResourceChangeScanner scanning directory="
+						+ resource);
+				for (Resource child : ((InternalResource) resource)
+						.listResources()) {
+					if (((InternalResource) child).isDirectory()) {
+						continue; // ignore sub directories
+					}
+					if (!this.resources.containsKey(child)) {
 
-                        this.listener.debug( "ResourceChangeScanner new resource=" + child );
-                        // child is new
-                        ((InternalResource) child).setResourceType( ((InternalResource) resource).getResourceType() );
-                        Set<ResourceChangeNotifier> notifiers = this.resources.get( resource ); // get notifiers for this directory
-                        for ( ResourceChangeNotifier notifier : notifiers ) {
-                            ChangeSetImpl changeSet = (ChangeSetImpl) notifications.get( notifier );
-                            if ( changeSet == null ) {
-                                // lazy initialise changeSet
-                                changeSet = new ChangeSetImpl();
-                                notifications.put( notifier,
-                                                   changeSet );
-                            }
-                            if ( changeSet.getResourcesAdded().isEmpty() ) {
-                                changeSet.setResourcesAdded( new ArrayList<Resource>() );
-                            }
-                            changeSet.getResourcesAdded().add( child );
-                            notifier.subscribeChildResource( resource,
-                                                             child );
-                        }
-                    }
-                }
-            }
+						this.listener
+								.debug("ResourceChangeScanner new resource="
+										+ child);
+						// child is new
+						((InternalResource) child)
+								.setResourceType(((InternalResource) resource)
+										.getResourceType());
+						Set<ResourceChangeNotifier> notifiers = this.resources
+								.get(resource); // get notifiers for this
+						// directory
+						for (ResourceChangeNotifier notifier : notifiers) {
+							ChangeSetImpl changeSet = (ChangeSetImpl) notifications
+									.get(notifier);
+							if (changeSet == null) {
+								// lazy initialise changeSet
+								changeSet = new ChangeSetImpl();
+								notifications.put(notifier, changeSet);
+							}
+							if (changeSet.getResourcesAdded().isEmpty()) {
+								changeSet
+										.setResourcesAdded(new ArrayList<Resource>());
+							}
+							changeSet.getResourcesAdded().add(child);
+							notifier.subscribeChildResource(resource, child);
+						}
+					}
+				}
+			}
 
-            for ( Entry<Resource, Set<ResourceChangeNotifier>> entry : this.resources.entrySet() ) {
-                Resource resource = entry.getKey();
-                Set<ResourceChangeNotifier> notifiers = entry.getValue();
+			for (Entry<Resource, Set<ResourceChangeNotifier>> entry : this.resources
+					.entrySet()) {
+				Resource resource = entry.getKey();
+				Set<ResourceChangeNotifier> notifiers = entry.getValue();
 
-                if ( !((InternalResource) resource).isDirectory() ) {
-                    // detect if Resource has been removed
-                    long lastModified = ((InternalResource) resource).getLastModified();
-                    if ( lastModified == 0 ) {
-                        this.listener.debug( "ResourceChangeScanner removed resource=" + resource );
-                        removed.add( resource );
-                        // resource is no longer present
-                        // iterate notifiers for this resource and add to each removed
-                        for ( ResourceChangeNotifier notifier : notifiers ) {
-                            ChangeSetImpl changeSet = (ChangeSetImpl) notifications.get( notifier );
-                            if ( changeSet == null ) {
-                                // lazy initialise changeSet
-                                changeSet = new ChangeSetImpl();
-                                notifications.put( notifier,
-                                                   changeSet );
-                            }
-                            if ( changeSet.getResourcesRemoved().isEmpty() ) {
-                                changeSet.setResourcesRemoved( new ArrayList<Resource>() );
-                            }
-                            changeSet.getResourcesRemoved().add( resource );
-                        }
-                    } else if ( ((InternalResource) resource).getLastRead() < lastModified ) {
-                        this.listener.debug( "ResourceChangeScanner modified resource=" + resource + " : " + ((InternalResource) resource).getLastRead() + " : " + lastModified );
-                        // it's modified
-                        // iterate notifiers for this resource and add to each modified
-                        for ( ResourceChangeNotifier notifier : notifiers ) {
-                            ChangeSetImpl changeSet = (ChangeSetImpl) notifications.get( notifier );
-                            if ( changeSet == null ) {
-                                // lazy initialise changeSet
-                                changeSet = new ChangeSetImpl();
-                                notifications.put( notifier,
-                                                   changeSet );
-                            }
-                            if ( changeSet.getResourcesModified().isEmpty() ) {
-                                changeSet.setResourcesModified( new ArrayList<Resource>() );
-                            }
-                            changeSet.getResourcesModified().add( resource );
-                        }
-                    }
-                }
-            }
+				if (!((InternalResource) resource).isDirectory()) {
+					// detect if Resource has been removed
+					long lastModified = ((InternalResource) resource)
+							.getLastModified();
+					long lastRead = ((InternalResource) resource).getLastRead();
+					if (lastModified == 0) {
+						this.listener
+								.debug("ResourceChangeScanner removed resource="
+										+ resource);
+						removed.add(resource);
+						// resource is no longer present
+						// iterate notifiers for this resource and add to each
+						// removed
+						for (ResourceChangeNotifier notifier : notifiers) {
+							ChangeSetImpl changeSet = (ChangeSetImpl) notifications
+									.get(notifier);
+							if (changeSet == null) {
+								// lazy initialise changeSet
+								changeSet = new ChangeSetImpl();
+								notifications.put(notifier, changeSet);
+							}
+							if (changeSet.getResourcesRemoved().isEmpty()) {
+								changeSet
+										.setResourcesRemoved(new ArrayList<Resource>());
+							}
+							changeSet.getResourcesRemoved().add(resource);
+						}
+					} else if (lastRead < lastModified && lastRead >= 0) {
+						this.listener
+								.debug("ResourceChangeScanner modified resource="
+										+ resource
+										+ " : "
+										+ lastRead
+										+ " : "
+										+ lastModified);
+						// it's modified
+						// iterate notifiers for this resource and add to each
+						// modified
+						for (ResourceChangeNotifier notifier : notifiers) {
+							ChangeSetImpl changeSet = (ChangeSetImpl) notifications
+									.get(notifier);
+							if (changeSet == null) {
+								// lazy initialise changeSet
+								changeSet = new ChangeSetImpl();
+								notifications.put(notifier, changeSet);
+							}
+							if (changeSet.getResourcesModified().isEmpty()) {
+								changeSet
+										.setResourcesModified(new ArrayList<Resource>());
+							}
+							changeSet.getResourcesModified().add(resource);
+						}
+					}
+				}
+			}
 
-            // now iterate and removed the removed resources, we do this so as not to mutate the foreach loop while iterating
-            for ( Resource resource : removed ) {
-                this.resources.remove( resource );
-            }
+			// now iterate and removed the removed resources, we do this so as
+			// not to mutate the foreach loop while iterating
+			for (Resource resource : removed) {
+				this.resources.remove(resource);
+			}
 
-            for ( Entry<ResourceChangeNotifier, ChangeSet> entry : notifications.entrySet() ) {
-                ResourceChangeNotifier notifier = entry.getKey();
-                ChangeSet changeSet = entry.getValue();
-                notifier.publishChangeSet( changeSet );
-            }
-        }
-    }
+			for (Entry<ResourceChangeNotifier, ChangeSet> entry : notifications
+					.entrySet()) {
+				ResourceChangeNotifier notifier = entry.getKey();
+				ChangeSet changeSet = entry.getValue();
+				notifier.publishChangeSet(changeSet);
+			}
+		}
+	}
 
-    public void setInterval(int interval) {
-        this.interval = interval;
-        this.listener.info( "ResourceChangeScanner reconfigured with interval=" + getInterval() );
+	public void setInterval(int interval) {
+		this.interval = interval;
+		this.listener.info("ResourceChangeScanner reconfigured with interval="
+				+ getInterval());
 
-        if ( this.scannerScheduler != null && this.scannerScheduler.isRunning() ) {
-            stop();
-            start();
-        }
-    }
+		if (this.scannerScheduler != null && this.scannerScheduler.isRunning()) {
+			stop();
+			start();
+		}
+	}
 
-    public int getInterval() {
-        return this.interval;
-    }
+	public int getInterval() {
+		return this.interval;
+	}
 
-    public void start() {
-        this.scannerScheduler = new ProcessChangeSet( this.resources,
-                                                      this,
-                                                      this.listener,
-                                                      this.interval );
-        thread = new Thread( this.scannerScheduler );
-        thread.start();
-    }
+	public void start() {
+		this.scannerScheduler = new ProcessChangeSet(this.resources, this,
+				this.listener, this.interval);
+		thread = new Thread(this.scannerScheduler);
+		thread.start();
+	}
 
-    public void stop() {
-        if ( this.scannerScheduler != null && this.scannerScheduler.isRunning() ) {
-            this.scannerScheduler.stop();
-            this.thread.interrupt();
-            this.scannerScheduler = null;
-        }
-    }
+	public void stop() {
+		if (this.scannerScheduler != null && this.scannerScheduler.isRunning()) {
+			this.scannerScheduler.stop();
+			this.thread.interrupt();
+			this.scannerScheduler = null;
+		}
+	}
 
-    public void reset() {
-        this.resources.clear();
-        this.directories.clear();
-    }
+	public void reset() {
+		this.resources.clear();
+		this.directories.clear();
+	}
 
-    private Thread           thread;
-    private ProcessChangeSet scannerScheduler;
+	private Thread thread;
+	private ProcessChangeSet scannerScheduler;
 
-    public static class ProcessChangeSet
-        implements
-        Runnable {
-        private volatile boolean                           scan;
-        private ResourceChangeScannerImpl                  scanner;
-        private long                                       interval;
-        private Map<Resource, Set<ResourceChangeNotifier>> resources;
-        private SystemEventListener                        listener;
+	public static class ProcessChangeSet implements Runnable {
+		private volatile boolean scan;
+		private ResourceChangeScannerImpl scanner;
+		private long interval;
+		private Map<Resource, Set<ResourceChangeNotifier>> resources;
+		private SystemEventListener listener;
 
-        ProcessChangeSet(Map<Resource, Set<ResourceChangeNotifier>> resources,
-                         ResourceChangeScannerImpl scanner,
-                         SystemEventListener listener,
-                         int interval) {
-            this.resources = resources;
-            this.scanner = scanner;
-            this.listener = listener;
-            this.interval = interval;
-            this.scan = true;
-        }
+		ProcessChangeSet(Map<Resource, Set<ResourceChangeNotifier>> resources,
+				ResourceChangeScannerImpl scanner,
+				SystemEventListener listener, int interval) {
+			this.resources = resources;
+			this.scanner = scanner;
+			this.listener = listener;
+			this.interval = interval;
+			this.scan = true;
+		}
 
-        public int getInterval() {
-            return (int) this.interval;
-        }
+		public int getInterval() {
+			return (int) this.interval;
+		}
 
-        public void stop() {
-            this.scan = false;
-        }
+		public void stop() {
+			this.scan = false;
+		}
 
-        public boolean isRunning() {
-            return this.scan;
-        }
+		public boolean isRunning() {
+			return this.scan;
+		}
 
-        public void run() {
-            synchronized ( this ) {
-                if ( this.scan ) {
-                    this.listener.info( "ResourceChangeNotification scanner has started" );
-                }
-                while ( this.scan ) {
-                    Exception exception = null;
-                    //System.out.println( "BEFORE : sync this.resources" );
-                    synchronized ( this.resources ) {
-                        //System.out.println( "DURING : sync this.resources" );
-                        // lock the resources, as we don't want this modified while processing
-                        this.scanner.scan();
-                    }
-                    //System.out.println( "AFTER : SCAN" );
-                    try {
-                        this.listener.debug( "ResourceChangeScanner thread is waiting for " + this.interval );
-                        wait( this.interval * 1000 );
-                    } catch ( InterruptedException e ) {
-                        exception = e;
-                    }
+		public void run() {
+			synchronized (this) {
+				if (this.scan) {
+					this.listener
+							.info("ResourceChangeNotification scanner has started");
+				}
+				while (this.scan) {
+					Exception exception = null;
+					// System.out.println( "BEFORE : sync this.resources" );
+					synchronized (this.resources) {
+						// System.out.println( "DURING : sync this.resources" );
+						// lock the resources, as we don't want this modified
+						// while processing
+						this.scanner.scan();
+					}
+					// System.out.println( "AFTER : SCAN" );
+					try {
+						this.listener
+								.debug("ResourceChangeScanner thread is waiting for "
+										+ this.interval + " seconds.");
+						wait(this.interval * 1000);
+					} catch (InterruptedException e) {
+						exception = e;
+					}
 
-                    if ( this.scan && exception != null ) {
-                        this.listener.exception( new RuntimeException( "ResourceChangeNotification ChangeSet scanning thread was interrupted, but shutdown was not requested",
-                                                                       exception ) );
-                    }
-                }
-                this.listener.info( "ResourceChangeNotification scanner has stopped" );
-            }
-        }
-    }
-}
+					if (this.scan && exception != null) {
+						this.listener
+								.exception(new RuntimeException(
+										"ResourceChangeNotification ChangeSet scanning thread was interrupted, but shutdown was not requested",
+										exception));
+					}
+				}
+				this.listener
+						.info("ResourceChangeNotification scanner has stopped");
+			}
+		}
+	}
+}
\ No newline at end of file



More information about the jboss-svn-commits mailing list