Hi Guys,
First of all, congrats for the 5.3 release!
I was having a look at the recent improvements done to rules compilation,
mentioned
here<http://docs.jboss.org/drools/release/5.3.0.Final/droolsjbpm-intro...;,
and I unfortunately couldn't really realize a 3 times faster compilation :(
After some profiling, my problem seems to come from
some unsuccessful attempts to getResourceAsStream done
at org.drools.commons.jci.compilers.EclipseJavaCompiler. Basically on line
218, to be able to know if something is a type or not, it will get
a supposedly class name and try to load it, if it cannot be loaded then it
will infer that what it thought was a class was actually a package.
Here goes a call stack, to give some context. In this particular case, the
string parameter was "com.sample.org", thus not a type.
EclipseJavaCompiler$2.findType(String) line: 220
EclipseJavaCompiler$2.findType(char[], char[][]) line: 215
LookupEnvironment.askForType(PackageBinding, char[]) line: 127
PackageBinding.getTypeOrPackage(char[]) line: 183
MethodScope(Scope).getTypeOrPackage(char[], int, boolean) line: 2592
MethodScope(Scope).getPackage(char[][]) line: 2266
QualifiedTypeReference.getTypeBinding(Scope) line: 69
QualifiedTypeReference(TypeReference).internalResolveType(Scope) line: 130
QualifiedTypeReference(TypeReference).resolveType(BlockScope, boolean)
line: 197
SourceTypeBinding.resolveTypesFor(MethodBinding) line: 1370
SourceTypeBinding.methods() line: 1090
SourceTypeBinding.faultInTypesForFieldsAndMethods() line: 593
CompilationUnitScope.faultInTypes() line: 447
Compiler.process(CompilationUnitDeclaration, int) line: 752
Compiler.compile(ICompilationUnit[]) line: 464
EclipseJavaCompiler.compile(String[], ResourceReader, ResourceStore,
ClassLoader, JavaCompilerSettings) line: 358
EclipseJavaCompiler(AbstractJavaCompiler).compile(String[],
ResourceReader, ResourceStore, ClassLoader) line: 49
JavaDialect.compileAll() line: 369
DialectCompiletimeRegistry.compileAll() line: 53
PackageRegistry.compileAll() line: 71
PackageBuilder.compileAll() line: 869
PackageBuilder.addPackage(PackageDescr) line: 826
PackageBuilder.addPackageFromDrl(Resource) line: 404
PackageBuilder.addKnowledgeResource(Resource, ResourceType,
ResourceConfiguration) line: 586
KnowledgeBuilderImpl.add(Resource, ResourceType) line: 37
DroolsTest.readKnowledgeBase() line: 52
DroolsTest.main(String[]) line: 25
On the same lines, method isPackage on line 285, will try to load a "class
name" and if it can't be found it will assume it was actually a package
name and return true.
Again, an illustrative call stack:
CompositeClassLoader.getResourceAsStream(String) line: 128
EclipseJavaCompiler$2.isPackage(String) line: 288
EclipseJavaCompiler$2.isPackage(char[][], char[]) line: 318
LookupEnvironment.isPackage(char[][], char[]) line: 1262
PackageBinding.findPackage(char[]) line: 77
PackageBinding.getTypeOrPackage(char[]) line: 196
MethodScope(Scope).getTypeOrPackage(char[], int, boolean) line: 2592
MethodScope(Scope).getPackage(char[][]) line: 2266
QualifiedTypeReference.getTypeBinding(Scope) line: 69
QualifiedTypeReference(TypeReference).internalResolveType(Scope) line: 130
QualifiedTypeReference(TypeReference).resolveType(BlockScope, boolean)
line: 197
SourceTypeBinding.resolveTypesFor(MethodBinding) line: 1370
SourceTypeBinding.methods() line: 1090
SourceTypeBinding.faultInTypesForFieldsAndMethods() line: 593
CompilationUnitScope.faultInTypes() line: 447
Compiler.process(CompilationUnitDeclaration, int) line: 752
Turns out that getting a resource when it does not exist can be pretty
expensive if you're compiling rules inside a big application with a lot of
stuff on your classpath, and this approach ends up tying the compilation
time of rules to the classloaders' search space.
I was wondering if we could have a better way to distinguish types and
packages or at least a configurable way. The first things that come to my
mind would be caching, in the lines of what is done for class loading in
the org.drools.util.CompositeClassLoader. Or have two different
strategies/implementations for the findType and isPackage methods, one that
would assume that you respect java conventions and parse the string to say
if it's a package or a type and another that wouldn't assume anything and
use the getResourceAsStream as it's done today. Then, we could choose via
configuration which strategy to use.
Any other ideas? Any work already being done in this area?
Cheers,
Leo.