I was sort of wondering why these cleanups exist. It looks to me like
perhaps there's some premature optimization going on here, and some
poorly-allocated division of responsibility.
While closing the zipfiles is certainly important, that's a cache; it'll
reopen as necessary. But clearing out project & pathComponents? I'm guessing
that's the proximal cause of the "unusuable state" you find the loader in --
unnecessary "optimization" as far as I can tell.
And why isn't the creator of the AntClassLoader responsible for cleaning it
up? e.g., refactoring the code in Launcher.java:
protected AntClassLoader getClassLoader(ClassLoader systemClassLoader,
File antHome) {
// We now create the class loader with which we are going to launch
ant
AntClassLoader antLoader = new AntClassLoader(systemClassLoader,
false);
// need to find tools.jar
addToolsJar(antLoader);
// add everything in the lib directory to this classloader
File libDir = new File(antHome, "lib");
addDirJars(antLoader, libDir);
File optionalDir = new File(antHome, "lib/optional");
addDirJars(antLoader, optionalDir);
return antLoader;
}
protected File findAntHome(ClassLoader systemClassLoader) {
if (systemClassLoader == null) {
antHome = determineAntHome11();
}
else {
antHome = determineAntHome(systemClassLoader);
}
if (antHome == null) {
System.err.println("Unable to determine ANT_HOME");
System.exit(1);
}
System.out.println("ANT_HOME is " + antHome);
return antHome;
}
public static void main(String[] args) {
ClassLoader systemClassLoader = Launcher.class.getClassLoader();
File antHome = findAntHome(systemClassLoader);
Properties launchProperties = new Properties();
launchProperties.put("ant.home", antHome.getAbsolutePath());
AntClassLoader antLoader = getClassLoader(systemClassLoader,
antHome);
try {
Class mainClass =
antLoader.loadClass("org.apache.tools.ant.Main");
antLoader.initializeClass(mainClass);
final Class[] param = {Class.forName("[Ljava.lang.String;"),
Properties.class, ClassLoader.class};
final Method startMethod = mainClass.getMethod("start", param);
final Object[] argument = {args, launchProperties,
systemClassLoader};
startMethod.invoke(null, argument);
}
catch (Exception e) {
System.out.println("Exception running Ant: " +
e.getClass().getName() + ": " + e.getMessage());
e.printStackTrace();
}
finally {
antLoader.cleanup(); // I would call this 'close()'
}
}
I can find even less justification for the IntrospectionHelper's use of this
event. Wouldn't it be simpler to just move the
IntrospectionHelper.getHelper() method to Project as a non-static? And thus
have IntrospectionHelper.helpers be an instance field of Project, and thus
be GC'd when the Project is GC'd?
All this manual managing of resources makes me queasy -- and apparently
leads to bugs.
-----Original Message-----
From: Adam Murdoch [mailto:[EMAIL PROTECTED]
Sent: Saturday, December 29, 2001 4:02 PM
To: [EMAIL PROTECTED]
Subject: [PATCH] build listener class loading
Hi,
This patch fixes an odd class loading problem, where the classes used by a
BuildListener's buildFinished() method cannot be loaded. This is how the
problem happens:
- The task is loaded via an AntClassLoader (e.g. using <taskdef> with a
classpath specified).
- The AntClassLoader adds a BuildListener to the project, so that it can
clean up when the build finishes.
- When the task executes, it adds a BuildListener to its project.
- The build finishes, and a build finished event is fired.
- The AntClassLoader's buildFinished() method is called. The class loader
cleans itself up.
- The task's buildFinished() method is called. If this method uses classes
which have not been loaded, the AntClassLoader's findClass() method is
called.
- The AntClassLoader is in an unusable state, and a NPE is thrown.
This patch defers AntClassLoader (and IntrospectionHelper) cleanup until
after the build finished event has been handled by all build listeners.
Adam
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>