I don't know how to switch the compiler, but lLooking at the source, I
see that janino uses ClassLoaderIClassLoader,
http://fisheye.codehaus.org/browse/~raw,r=1.6/janino/janino/src/org/codehaus/janino/ClassLoaderIClassLoader.java
which in fact uses a reflection-based loader.
I believe I had already pointed out the problem with using reflection
to resolve external references: it can lead to unexpected first active
uses (in other words, using a class as a reference in compilation
could trigger the class's static {} initializer.) which may or may not
be tolerable (if the class is already loaded or has no static
initializer, it's not a problem - otherwise, it's a nightmare.)
In any event, this is all besides the point (at least the point I was
trying to make). I argue that a sound design should separate runtime
and compilation classpath (or at least provide the option of doing
so), but I acknowledge that the current approach is pragmatic and
probably works for a large number of cases.
To return to the original point of discussion, I'm wondering how to
make it easy for different .drl files to refer to each other. You had
brought up the Rule Agent, though it wasn't clear to me whether you
meant that the rule agent implementation as it currently exists
already has a way of specifying such dependencies, and if so, how - or
whether you are consider this a future addition.
>From my (admittedly brief) examination of the the rule agent, it
appears to be a tool that monitors filesystem or network-based sources
of rules in pre-compiled packages, then loads them. What I am seeking
is a simple way for one rulebase to refer to a set of classes and
rules on which it depends, similar to how, for instance, an XML file
can refer to an external DTD or Schema.
The rule agent allows you to specify one or more binary packages ro
DRLs, which it will
compile (as long as drools-compiler is in the classpath) and build a
rulebase for on the fly. We will try and add JARs to this for the next
major release, so it can load the model on the fly too. I don't want
one drl having to be hard coded to another drl or other remote
resources, I would rather it was specified at the configuration level
for something like the rule agent.
- Godmar
On 10/2/07, Mark Proctor <mproctor@codehaus.org> wrote:
try using janino instead of eclipse jdt
Godmar Back wrote:
PS: it turns out that Drool's class loader in
org/drools/rule/PackageCompilationData.java falls back to
getResource
also (that's why I had to delete .class file in my first attempt at
RLoader.) Installing a class loader that fails getResource() for
.class files makes it even simpler to see that Drools's compilation
machinery relies on it. So, to convince yourselves, use this loader:
// RLoader.java, v2
import java.io.File;
import java.net.URL;
public class RLoader extends ClassLoader {
public RLoader() { }
public RLoader(ClassLoader parent) { super(parent); }
public Class loadClass(String name) throws ClassNotFoundException {
return getParent().loadClass(name);
}
public URL getResource(String name) {
if (name.endsWith(".class")) {
System.out.println("Classloader asked for .class file as
resource URL: " + name);
new Throwable().printStackTrace();
return null;
}
return getParent().getResource(name);
}
}
and you can observe the same failure - maybe this convinces you.
- Godmar
On 9/27/07, Godmar Back <godmar@gmail.com> wrote:
On 9/27/07, Mark Proctor <mproctor@codehaus.org> wrote:
Godmar Back wrote:
I agree that it may not belong into the .drl file, though loading
bytecode through the classloader via getResourceAsStream() also seems
a rather ad-hoc solution.
I've already told you, that you are mistaken here. You do not need to keep
bytecode hanging around, and available via getResourceAsStream() for any
compilation to work. I can generate a class at runtime, in memory, add it
to a classloader and have the engine compile against it without
getResourceAsStream() being able to search for and return the .class'
bytecode.
Ok - here's an experiment you can perform.
Write a class loader RLoader.java as follows:
// RLoader.java
import java.io.File;
import java.io.InputStream;
public class RLoader extends ClassLoader {
public RLoader() { }
public RLoader(ClassLoader parent) { super(parent); }
public Class loadClass(String name) throws ClassNotFoundException {
return getParent().loadClass(name);
}
public InputStream getResourceAsStream(String name) {
if (name.endsWith(".class")) {
System.out.println("Classloader asked for .class file as
resource: " + name);
new Throwable().printStackTrace();
// delete the .class file to ensure that no other part of
drools attempts to read it.
new File(name).delete();
return null;
}
return getParent().getResourceAsStream(name);
}
}
Now use this class as your system class loader. Specify:
-Djava.system.class.loader=RLoader
When you then run your application, you will see output such as:
Classloader asked for .class file as resource:
org/enhancementpatterns/castor/CastorEnhancements/AddVisitor.class
java.lang.Throwable
at RLoader.getResourceAsStream(RLoader.java:13)
at
org.drools.rule.PackageCompilationData$PackageClassLoader.getResourceAsStream(PackageCompilationData.java:386)
at
org.drools.commons.jci.compilers.EclipseJavaCompiler$2.isPackage(EclipseJavaCompiler.java:282)
at
org.drools.commons.jci.compilers.EclipseJavaCompiler$2.isPackage(EclipseJavaCompiler.java:313)
at
org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment.isPackage(LookupEnvironment.java:1157)
at
org.eclipse.jdt.internal.compiler.lookup.PackageBinding.findPackage(PackageBinding.java:75)
at
org.eclipse.jdt.internal.compiler.lookup.PackageBinding.getTypeOrPackage(PackageBinding.java:190)
at
org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope.findImport(CompilationUnitScope.java:438)
at
org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope.findSingleImport(CompilationUnitScope.java:492)
at
org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope.faultInImports(CompilationUnitScope.java:356)
at
org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope.faultInTypes(CompilationUnitScope.java:425)
at
org.eclipse.jdt.internal.compiler.Compiler.process(Compiler.java:589)
at
org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:411)
at
org.drools.commons.jci.compilers.EclipseJavaCompiler.compile(EclipseJavaCompiler.java:353)
at
org.drools.commons.jci.compilers.AbstractJavaCompiler.compile(AbstractJavaCompiler.java:51)
at
org.drools.rule.builder.dialect.java.JavaDialect.compileAll(JavaDialect.java:332)
at
org.drools.compiler.DialectRegistry.compileAll(DialectRegistry.java:60)
at
org.drools.compiler.PackageBuilder.addPackage(PackageBuilder.java:288)
at
org.drools.compiler.PackageBuilder.addPackageFromDrl(PackageBuilder.java:158)
Leading to failures such as:
Exception in thread "main"
org.drools.rule.InvalidRulePackage: Rule
Compilation error : [Rule name=Add Visitors, agendaGroup=MAIN,
salience=0, no-loop=false]
org/enhancementpatterns/castor/test/Rule_Add_Visitors_0.java
(3:127) : Only a type can be imported.
org.enhancementpatterns.castor.CastorEnhancements.AddVisitor
resolves
to a package
- Godmar
_______________________________________________
rules-users mailing list
rules-users@lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users
_______________________________________________
rules-users mailing list
rules-users@lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users
_______________________________________________
rules-users mailing list
rules-users@lists.jboss.org
https://lists.jboss.org/mailman/listinfo/rules-users