package org.drools.agent;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseConfiguration;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilderConfiguration;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.io.ResourceFactory;
import org.drools.runtime.StatefulKnowledgeSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class KnowledgeAgentCustomClassLoaderTest extends BaseKnowledgeAgentTest {
@Test
public void testCustomKnowledgeBuilderConfigurationWithIncrementalProcessing() throws Exception{
this.testCustomKnowledgeBuilderConfiguration(false);
}
@Test
public void testCustomKnowledgeBuilderConfigurationWithoutIncrementalProcessing() throws Exception{
this.testCustomKnowledgeBuilderConfiguration(true);
}
@Test
public void testUseKBaseClassLoaderForCompilingPropertyWithIncrementalProcessing() throws Exception{
this.testUseKBaseClassLoaderForCompilingProperty(false);
}
@Test
public void testUseKBaseClassLoaderForCompilingPropertyWithoutIncrementalProcessing() throws Exception{
this.testUseKBaseClassLoaderForCompilingProperty(true);
}
private void testCustomKnowledgeBuilderConfiguration(boolean newInstance) throws Exception {
this.testKagentWithCustomClassLoader(newInstance, false);
}
private void testUseKBaseClassLoaderForCompilingProperty(boolean newInstance) throws Exception {
this.testKagentWithCustomClassLoader(newInstance, true);
}
/**
*
* @param newInstance
* @param useKBaseClassLoaderForCompiling if true, the kagent will use
* the kbase's class loader to compile the rules. If false, it will
* create a new KnowledgeBuilderConfiguration with the kbase's cl and pass
* it to the agent.
* @throws Exception
*/
private void testKagentWithCustomClassLoader(boolean newInstance, boolean useKBaseClassLoaderForCompiling) throws Exception {
//A simple rule using a class (org.drools.agent.test.KnowledgeAgentInstance)
//that is not present in the classloader.
String rule = this.createCustomRule(true, "org.drools.test", new String[]{"org.drools.agent.test.KnowledgeAgentInstance"}, new String[]{"rule1"}, null, " KnowledgeAgentInstance($id: instanceId)\n"," list.add(\"Instance number \"+$id);\n");
this.fileManager.write("rule1.drl", rule);
//The change set to process the created resource
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 http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' >";
xml += " <add> ";
xml += " <resource source='http://localhost:"+this.getPort()+"/rule1.drl' type='DRL' />";
xml += " </add> ";
xml += "</change-set>";
File fxml = fileManager.write( "changeset.xml",
xml );
//We are going to add KAModelTest.jar to the kbase classloader.
//This kbase will be the one used by the agent.
URL jarURL = this.getClass().getResource("/KAModelTest.jar");
URLClassLoader ucl = new URLClassLoader(new URL[]{jarURL}, this.getClass().getClassLoader());
//Add the classloader to the kbase
KnowledgeBaseConfiguration kbaseConfig = KnowledgeBaseFactory.newKnowledgeBaseConfiguration(null, ucl);
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(kbaseConfig);
//Create a kagent with the kbase
KnowledgeAgent kagent = this.createKAgent(kbase,newInstance,false);
//The agent processes the changeset (Because the compiler created internally
//by the agent doesn't have a definition for KnowledgeAgentInstance,
//the compilation will fail.
try{
applyChangeSet(kagent, ResourceFactory.newUrlResource(fxml.toURI().toURL()));
fail( "Knowledge should fail to compile" );
}catch (Exception e){
assertTrue(e.getMessage().contains("Unable to compile Knowledge"));
}
//Because the compilation failed, no package was created.
assertTrue(kagent.getKnowledgeBase().getKnowledgePackages().isEmpty());
//Stop monitoring resources
kagent.dispose();
if (useKBaseClassLoaderForCompiling){
//Create a kagent with the kbase and using useKBaseClassLoaderForCompiling.
//The kbase's classloader should be used for compilation too
kagent = this.createKAgent(kbase, newInstance, true);
}else{
//Now we create a new kagent, but passing a custom KnowledgeBuilderConfiguration
//having the correct classloader
KnowledgeBuilderConfiguration kbuilderConfig =
KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(null, ucl);
kagent = this.createKAgent(kbase, newInstance, false, kbuilderConfig);
}
//The agent processes the changeset. The rule should be compiled
//succesfully
this.applyChangeSet(kagent, ResourceFactory.newUrlResource(fxml.toURI().toURL()));
//One package should be created
assertEquals(1, kagent.getKnowledgeBase().getKnowledgePackages().size());
//We create a session to test if the rule runs ok
StatefulKnowledgeSession ksession = kagent.getKnowledgeBase().newStatefulKnowledgeSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);
//Create a new KnowledgeAgentInstance and set its instanceId = 2
Class<?> modelClass = ucl.loadClass("org.drools.agent.test.KnowledgeAgentInstance");
Object modelInstance = modelClass.newInstance();
modelClass.getMethod("setInstanceId", int.class).invoke(modelInstance, 2);
//insert the KnowledgeAgentInstance
ksession.insert(modelInstance);
//fire all rules
ksession.fireAllRules();
//The global list should contain 1 element
assertEquals(1, list.size());
assertTrue(list.contains("Instance number 2"));
ksession.dispose();
kagent.dispose();
}
}