[rules-dev] Compiling drools-5 to .NET -- issue with ClassLoaders

Michael Neale michael.neale at gmail.com
Wed Sep 2 20:01:55 EDT 2009


Hi Krishna - I don't think the .Net version on the codehaus is kept
that up to date, so its probably a good thing you are doing what you
are doing with the latest.

Yes, those accessor classes are indeed lazily generated and loaded
"in-situ" - this is for fast access of fields in the alpha network
which can be hit hard and often... an inlined version of the ASM
library is used to do this.

I am pretty sure that even in drools 3 we did something like this
(also using ASM) and that was able to work with IKVM - so there must
be some small change that has made the IKVM classloader angry...

On a barely related note: is it worth thinking about a Source to
Source translator to C# - there are a few around (ILog even open
sourced one, although it didn't cope with Generics last I checked...)
?


Michael.

On Wed, Sep 2, 2009 at 11:56 PM, kpowerinfinity<kpowerinfinity at gmail.com> wrote:
> Hello,
>
> I've been trying to compile the latest version of drools to .NET for a
> few days now. However, due to the classloaders structure, the classes
> in the org.drools.base.extractors.* are not found by the classloader,
> and the execution stops with a NoClassDefFoundError for classes in
> that package.
>
> Here's some details about the setup:
> Drools version: 5.0.1
> IKVM Version: 0.40.0.1
>
> I have successfully compiled all the required libraries into a DLL
> using IKVM, and a simple rule (containing a null LHS) runs
> successfully, all the classes are found, and the rule engine produces
> the correct output. However, when I add a condition into the LHS, it
> fails because it can't find one of the classes in
> /org.drools.base.extractors..*Reader/
>
> A sample rule I am using is:
> """
> package package
> import rules.Customer
> import rules.VoucherSeries
>
> rule "everything free for Krishna"
>
>        when
>                $c : Customer( firstname == "Krishna" )
>        then
>                VoucherSeries fact0 = new VoucherSeries();
>                fact0.setSeriesCode( "FREE" );
>                insert(fact0 );
> end
> """
>
> I have verified that all the classes are present in the classloader I
> am passing to the KnowledgeBuilderConfiguration. In fact, I also tried
> creating a MapBasedClassLoader that contains all the missing classes
> so that they can be easily found using fastFindClass. In the code
> listing below, both klass and klass2 resolve to the correct class
> objects.
>
> """
>            java.util.Properties p = new java.util.Properties();
>            p.put("drools.dialect.java.compiler", "JANINO");
>            java.lang.ClassLoader cl =
> java.lang.Class.forName("org.drools.base.extractors.BaseLongClassFieldReader").getClassLoader();
>            org.drools.rule.CompositeClassLoader compositeClassLoader
> = new org.drools.rule.CompositeClassLoader(cl);
>
>            org.drools.rule.MapBackedClassLoader mbcl =
> getMapBackedClassLoader(cl);
>
>            compositeClassLoader.addClassLoader(mbcl);
>            java.lang.Class klass =
> compositeClassLoader.fastFindClass("rules.Customer");
>            java.lang.Class klass2 =
> compositeClassLoader.fastFindClass("org.drools.base.extractors.BaseObjectClassFieldReader");
>            java.lang.ClassLoader finalClassLoader = compositeClassLoader;
>
>            org.drools.builder.KnowledgeBuilderConfiguration kbc =
> org.drools.builder.KnowledgeBuilderFactory.newKnowledgeBuilderConfiguration(p,
> finalClassLoader);
> """
>
> However, adding the DRL / PKG file, it fails with the exception:
>
> java.lang.NoClassDefFoundError was caught
>  Message="org.drools.base.extractors.BaseObjectClassFieldReader"
>  Source="IKVM.Runtime"
>  StackTrace:
>       at IKVM.NativeCode.java.lang.ClassLoader.defineClass1(Object
> thisClassLoader, String name, Byte[] b, Int32 off, Int32 len, Object
> pd, String source)
>       at java.lang.ClassLoader.defineClass1(String , Byte[] , Int32 ,
> Int32 , ProtectionDomain , String )
>       at java.lang.ClassLoader.defineClass(String name, Byte[] b,
> Int32 off, Int32 len, ProtectionDomain protectionDomain)
>       at org.drools.base.ClassFieldAccessorCache.ByteArrayClassLoader.defineClass(String
> name, Byte[] bytes, ProtectionDomain domain)
>       at org.drools.base.ClassFieldAccessorFactory.getClassFieldReader(Class
> clazz, String fieldName, CacheEntry cache)
>       at org.drools.base.ClassFieldAccessorCache.CacheEntry.getReadAccessor(AccessorKey
> key, Class cls)
>       at org.drools.base.ClassFieldAccessorCache.getReadAcessor(ClassFieldReader
> reader)
>       at org.drools.base.ClassFieldAccessorStore.wire(ClassFieldReader reader)
>       at org.drools.base.ClassFieldAccessorStore.getReader(String
> className, String fieldName, AcceptsReadAccessor target, AccessorType
> accessorType)
>       at org.drools.base.ClassFieldAccessorStore.getReader(String
> className, String fieldName, AcceptsReadAccessor target)
>       at org.drools.rule.builder.PatternBuilder.getFieldReadAccessor(RuleBuildContext
> context, BaseDescr descr, ObjectType objectType, String fieldName,
> AcceptsReadAccessor target, Boolean reportError)
>       at org.drools.rule.builder.PatternBuilder.build(RuleBuildContext
> , Pattern , FieldConstraintDescr , AbstractCompositeConstraint )
>       at org.drools.rule.builder.PatternBuilder.buildConstraint(RuleBuildContext
> , Pattern , Object , AbstractCompositeConstraint )
>       at org.drools.rule.builder.PatternBuilder.build(RuleBuildContext
> context, BaseDescr descr, Pattern prefixPattern)
>       at org.drools.rule.builder.PatternBuilder.build(RuleBuildContext
> context, BaseDescr descr)
>       at org.drools.rule.builder.GroupElementBuilder.build(RuleBuildContext
> context, BaseDescr descr, Pattern prefixPattern)
>       at org.drools.rule.builder.RuleBuilder.build(RuleBuildContext context)
>       at org.drools.compiler.PackageBuilder.addRule(RuleDescr )
>       at org.drools.compiler.PackageBuilder.addPackage(PackageDescr
> packageDescr)
>       at org.drools.compiler.PackageBuilder.addPackageFromDrl(Resource
> resource)
>       at org.drools.compiler.PackageBuilder.addKnowledgeResource(Resource
> resource, ResourceType type, ResourceConfiguration configuration)
>       at org.drools.builder.impl.KnowledgeBuilderImpl.add(Resource
> resource, ResourceType type)
>       at Capillary.Client.RulesEngine.RuleManager.ReadRules(String
> filename) in D:\coderoot\module\DataEntryClient-DVS\SubProjects\RulesEngine\RuleManager.cs:line
> 116
>  InnerException:
>
> I saw the code at org/drools/base/ClassFieldAccessorCache.java, and it
> seems me that the Reader class for the particular type is being
> defined in situ using a byte[] array, but I am unable to understand
> why it can't load the class at that point.
>
> Can anybody with a better idea of the drools classloading structure
> guide me here?
>
> Also, is the drools.NET project active now? I would post all the steps
> I took for posterity.
>
> Thanks and Regards,
> Krishna.
>
> --
> http://kpowerinfinity.wordpress.com
> http://www.linkedin.com/in/kpowerinfinity
> _______________________________________________
> rules-dev mailing list
> rules-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/rules-dev
>



-- 
Michael D Neale
home: www.michaelneale.net
blog: michaelneale.blogspot.com



More information about the rules-dev mailing list