Hello conrads.<div><br></div><div>To explain what I need, the problem that I found and the solution that I planning to use, I will firstly describe my cenario.</div><div><br></div><div><b><font size="6">Cenario</font></b></div>
<div>In my cenario, I have a declarative model and rules of different groups. I need put each rules group in a different knowledge base and all of it will share the same declarative model.</div><div><br></div><div>In a time, I will create a fact using fact types defined in a knowledge base that I will call as <font face="courier new, monospace">kbaseModel</font>. This knowledge base will have only the declarative model and no rules.</div>
<div><br></div><div>All facts created will be used in other knowledge base, called <font face="courier new, monospace">kbaseRules</font>. All <font face="courier new, monospace">kbaseRules</font> have only rules and no declarative model, because model was defined in <font face="courier new, monospace">kbaseModel</font>.</div>
<div><br></div><div>I could have many <font face="courier new, monospace">kbaseRules</font> but exists only one <font face="courier new, monospace">kbaseModel</font>.</div><div><br></div><div>Using the Drools API, teoricaly, I could implement my cenario using the following code:</div>
<div><br></div><div><font face="courier new, monospace">//DRL for resourceModel</font></div><div><div><font face="courier new, monospace">declare MyEntity</font></div><div><font face="courier new, monospace"> name : String</font></div>
<div><font face="courier new, monospace">end</font></div></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">//DRL for resourceRules</font></div><div><div><font face="courier new, monospace">rule "Simple Rule"</font></div>
<div><font face="courier new, monospace"> when</font></div><div><font face="courier new, monospace"> $entity: MyEntity()</font></div><div><font face="courier new, monospace"> then</font></div><div><font face="courier new, monospace"> System.out.println($entity)</font></div>
<div><font face="courier new, monospace"> end</font></div></div><div><br></div><div><font face="courier new, monospace">Resource resourceModel = ... //Resource with only the declarative model and no rules</font></div><div>
<font face="courier new, monospace">Resource resourceRules = ... //Resource with only rules and no declarative model</font></div><div><font face="courier new, monospace"><br></font></div><div><div><font face="courier new, monospace">KnowledgeBuilder kbuilderModel = KnowledgeBuilderFactory.newKnowledgeBuilder();</font></div>
<div><font face="courier new, monospace">kbuilderModel add(resourceModel, ResourceType.DRL);</font></div><div><font face="courier new, monospace">KnowledgeBase kbaseModel = kbuilderModel.newKnowledgeBase();</font></div></div>
<div><font face="courier new, monospace"><br></font></div><div><div><font face="courier new, monospace">KnowledgeBuilder kbuilderRules = KnowledgeBuilderFactory.newKnowledgeBuilder(kbaseModel);</font></div><div><font face="courier new, monospace">kbuilderRules.add(resourceRules, ResourceType.DRL);</font></div>
</div><div><div><font face="courier new, monospace">KnowledgeBase kbaseRules = KnowledgeBaseFactory.newKnowledgeBase();</font></div><div><font face="courier new, monospace">kbaseRules.addKnowledgePackages(kbuilderRules.getKnowledgePackages());</font></div>
</div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">FactType factType = kbaseModel.getFactType("mymodel", "MyEntity");</font></div><div><div><font face="courier new, monospace">Object myEntity = factType.newInstance();</font></div>
<div><font face="courier new, monospace">factType.set(myEntity, "name", "Jackson Cunha Cassimiro");</font></div></div><div><font face="courier new, monospace"><br></font></div><div><div><font face="courier new, monospace">StatelessKnowledgeSession session = kbaseRules.newStatelessKnowledgeSession();</font></div>
<div><font face="courier new, monospace">session.execute(myEntity);</font></div></div><div><br></div><div>This code should work, but when I try to run I get this stacktrace:</div><div><span style="font-family:'Courier New';font-size:12px"><br>
</span></div><div><span style="font-family:'Courier New';font-size:12px">java.lang.ClassNotFoundException: Unable to load class: mymodel.MyEntity</span></div><div><span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at org.drools.util.CompositeClassLoader.loadClass(CompositeClassLoader.java:92)</span><br>
<span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at org.drools.common.AbstractRuleBase.registerAndLoadTypeDefinition(AbstractRuleBase.java:649)</span><br><span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at org.drools.common.AbstractRuleBase.addPackages(AbstractRuleBase.java:553)</span><br>
<span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at org.drools.reteoo.ReteooRuleBase.addPackages(ReteooRuleBase.java:472)</span><br><span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at org.drools.impl.KnowledgeBaseImpl.addKnowledgePackages(KnowledgeBaseImpl.java:150)</span><br>
<span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at app.UsingDeclares.main(UsingDeclares.java:79)</span><br><span style="font-size:12px;font-family:'Courier New';vertical-align:baseline">Exception in thread "main" org.drools.RuntimeDroolsException: unable to resolve Type Declaration class 'mymodel.MyEntity'</span><br>
<span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at org.drools.common.AbstractRuleBase.addPackages(AbstractRuleBase.java:582)</span><br><span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at org.drools.reteoo.ReteooRuleBase.addPackages(ReteooRuleBase.java:472)</span><br>
<span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at org.drools.impl.KnowledgeBaseImpl.addKnowledgePackages(KnowledgeBaseImpl.java:150)</span><br><span style="font-size:12px;font-family:'Courier New';vertical-align:baseline"> at app.UsingDeclares.main(UsingDeclares.java:79)</span><br>
</div><div><br></div><div>It happens because Drools can't find any reference of <span style="font-family:'Courier New';font-size:12px">mymodel.MyEntity </span><font face="arial, helvetica, sans-serif" style="font-size:12px">in </font><font face="courier new, monospace" style="font-size:12px">kbaseRules</font><font face="arial, helvetica, sans-serif" style="font-size:12px">, but this kbase was built from </font><font face="courier new, monospace" style="font-size:12px">kbaseModel</font><font face="arial, helvetica, sans-serif"><span style="font-size:12px"> that already have this class declared. </span><font size="4"><b style="background-color:rgb(255,255,0)">I think it can be a </b><b style="background-color:rgb(255,255,0)">bug</b></font><span style="font-size:12px">.</span></font></div>
<div><br></div><div><div><b><font size="6">Debuging</font></b></div><div>During creation of kbaseModel, a method called <font face="courier new, monospace">mergePackage(pkgRegistry, packageDescr)</font><span style="font-family:Arial"> from </span><font face="courier new, monospace">PackageBuilder</font><span style="font-family:Arial"> class is invoked. The </span><font face="courier new, monospace">pkgRegistry</font><span style="font-family:Arial"> not contains any reference to declarative model. The </span><font face="courier new, monospace">packageDescr</font><span style="font-family:Arial"> contains a list of type definitions from declarative model. Inside </span><font face="courier new, monospace">mergePackage</font><span style="font-family:Arial"> is invoked other method, called </span><font face="courier new, monospace">processTypeDeclarations(pkgRegistry, packageDescr)</font><span style="font-family:Arial"> that will iterate over all type definitions from </span><font face="courier new, monospace">packageDescr</font><font face="arial, helvetica, sans-serif"> and will fill a map called </font><font face="courier new, monospace">Map<String,byte[]> classLookups</font><font face="arial, helvetica, sans-serif"> from </font><font face="courier new, monospace">JavaDialectRuntimeData</font><font face="arial, helvetica, sans-serif"> class.</font></div>
<div><font face="arial, helvetica, sans-serif"><br></font></div><div><font face="arial, helvetica, sans-serif">During the creation of kbaseRules the method </font><font face="courier new, monospace">mergePackage(pkgRegistry, packageDescr)</font><span style="font-family:Arial"> from </span><font face="courier new, monospace">PackageBuilder</font><span style="font-family:Arial"> is invoked again, but at this time </span><font face="courier new, monospace">pkgRegistry</font><span style="font-family:Arial"> contains all type definitions defined previously in </span><font face="courier new, monospace">kbaseModel</font><span style="font-family:Arial"> and </span><font face="courier new, monospace">packageDescr</font><span style="font-family:Arial"> not contains any type definitions, only rules. When the method</span><font face="courier new, monospace"> processTypeDeclarations(pkgRegistry, packageDescr)</font><span style="font-family:Arial"> from </span><font face="courier new, monospace">PackageBuilder</font><span style="font-family:Arial"> is called and try iterate over type definitions of </span><font face="courier new, monospace">packageDescr</font><span style="font-family:Arial">, this is empty and nothing is done and the map </span><font face="courier new, monospace">Map<String,byte[]> classLookups</font><span style="font-family:Arial"> from </span><font face="courier new, monospace">JavaDialectRuntimeData</font><span style="font-family:Arial"> will be empty too</span><span style="font-family:Arial;font-size:15px">.</span></div>
<div><span style="font-family:Arial;font-size:15px"><br></span></div><div><b><font size="4" style="background-color:rgb(255,255,102)"><span style="font-family:Arial">The </span><font face="courier new, monospace">classLookups</font><span style="font-family:Arial"> empty</span><span style="font-family:Arial"> is the cause of </span><font face="courier new, monospace">ClassNotFoundException</font></font></b><span style="font-family:'Courier New';font-size:12px">.</span></div>
<div><span style="font-family:'Courier New';font-size:12px"><br></span></div><div><font face="arial, helvetica, sans-serif" size="6"><b>Solution</b></font></div><div>The solution that I found was apply reflection to fill <font face="courier new, monospace">Map<String,byte[]> classLookups</font><span style="font-family:Arial"> from </span><font face="courier new, monospace">JavaDialectRuntimeData </font><span style="font-family:Arial">correctly before add the packages into </span><font face="courier new, monospace">kbaseRules</font><span style="font-family:Arial">: </span></div>
<div><span style="font-family:Arial"><br></span></div><div><div><font face="courier new, monospace">Collection<KnowledgePackage> packages = kbuilderRules.getKnowledgePackages();</font></div><div><font face="courier new, monospace">Mirror mirror = new Mirror();//Reflection utilities</font></div>
<div><span class="Apple-tab-span" style="white-space:pre"><font face="courier new, monospace">                </font></span></div><div><font face="courier new, monospace">for (KnowledgePackage kPackage : packages) {</font></div><div><font face="courier new, monospace"> Package pkg = (Package) mirror.on(kPackage).get().field("pkg");</font></div>
<div><font face="courier new, monospace"> JavaDialectRuntimeData dialect = (JavaDialectRuntimeData) pkg.getDialectRuntimeRegistry().getDialectData( "java" );</font></div><div><span class="Apple-tab-span" style="white-space:pre"><font face="courier new, monospace">                        </font></span></div>
<div><font face="courier new, monospace"> for (FactType factType : kPackage.getFactTypes()) {</font></div><div><font face="courier new, monospace"> Class<?> c = factType.getFactClass();</font></div><div><font face="courier new, monospace"> String className = c.getName();</font></div>
<div><font face="courier new, monospace"> String classAsPath = className.replace('.', '/') + ".class";</font></div><div><font face="courier new, monospace"> InputStream stream = c.getClassLoader().getResourceAsStream(classAsPath);</font></div>
<div><font face="courier new, monospace"> byte[] bytes = IOUtils.toByteArray(stream);</font></div><div><font face="courier new, monospace"> dialect.putClassDefinition(classAsPath, bytes);</font></div><div><font face="courier new, monospace"> }</font></div>
<div><font face="courier new, monospace">}</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">KnowledgeBase kbaseRules = KnowledgeBaseFactory.newKnowledgeBase();</font></div>
<div><font face="courier new, monospace">kbaseRules.addKnowledgePackages(packages);</font></div></div><div><font face="arial, helvetica, sans-serif"><br></font></div><br>----------------------------------------------------------------------------------------------------------------<br>
Jackson Cunha Cassimiro (CereB)<br>Bacharel em Ciencia da Computação - UFPI<br>MSN: <a href="mailto:jackson.cereb@gmail.com" target="_blank">jackson.cereb@gmail.com</a><br>Telefone Móvel +55 86 9928 1251<br>Analista de Sistemas - Infoway - <a href="http://www.infoway-pi.com.br" target="_blank">http://www.infoway-pi.com.br</a><br>
Missão Infoway - "Influenciar a Gestão de Sistemas de Saúde através de e-health"<br><br>("A vida é um combate que os fracos abate, aos bravos, aos fortes só pode exaltar" - Canção do Tamoio, Gonçalves Dias)<br>
----------------------------------------------------------------------------------------------------------------<br>
</div>