提交 a3117648 编写于 作者: K kohsuke

Using AntClassLoader with Closeable so that we can predictably release jar...

Using AntClassLoader with Closeable so that we can predictably release jar files opened by URLClassLoader

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@19472 71c3de6d-444a-0410-be80-ed276b4c234a
上级 2dd66726
...@@ -33,15 +33,18 @@ import java.io.FileInputStream; ...@@ -33,15 +33,18 @@ import java.io.FileInputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.io.Closeable;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Arrays;
import java.util.Collection;
import java.util.jar.Manifest; import java.util.jar.Manifest;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.taskdefs.Expand; import org.apache.tools.ant.taskdefs.Expand;
import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.FileSet;
...@@ -115,7 +118,7 @@ public class ClassicPluginStrategy implements PluginStrategy { ...@@ -115,7 +118,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
// TODO: define a mechanism to hide classes // TODO: define a mechanism to hide classes
// String export = manifest.getMainAttributes().getValue("Export"); // String export = manifest.getMainAttributes().getValue("Export");
List<URL> paths = new ArrayList<URL>(); List<File> paths = new ArrayList<File>();
if (isLinked) { if (isLinked) {
parseClassPath(manifest, archive, paths, "Libraries", ","); parseClassPath(manifest, archive, paths, "Libraries", ",");
parseClassPath(manifest, archive, paths, "Class-Path", " +"); // backward parseClassPath(manifest, archive, paths, "Class-Path", " +"); // backward
...@@ -127,13 +130,11 @@ public class ClassicPluginStrategy implements PluginStrategy { ...@@ -127,13 +130,11 @@ public class ClassicPluginStrategy implements PluginStrategy {
} else { } else {
File classes = new File(expandDir, "WEB-INF/classes"); File classes = new File(expandDir, "WEB-INF/classes");
if (classes.exists()) if (classes.exists())
paths.add(classes.toURI().toURL()); paths.add(classes);
File lib = new File(expandDir, "WEB-INF/lib"); File lib = new File(expandDir, "WEB-INF/lib");
File[] libs = lib.listFiles(JAR_FILTER); File[] libs = lib.listFiles(JAR_FILTER);
if (libs != null) { if (libs != null)
for (File jar : libs) paths.addAll(Arrays.asList(libs));
paths.add(jar.toURI().toURL());
}
baseResourceURL = expandDir.toURI().toURL(); baseResourceURL = expandDir.toURI().toURL();
} }
...@@ -176,8 +177,10 @@ public class ClassicPluginStrategy implements PluginStrategy { ...@@ -176,8 +177,10 @@ public class ClassicPluginStrategy implements PluginStrategy {
ClassLoader dependencyLoader = new DependencyClassLoader(getClass() ClassLoader dependencyLoader = new DependencyClassLoader(getClass()
.getClassLoader(), Util.join(dependencies,optionalDependencies)); .getClassLoader(), Util.join(dependencies,optionalDependencies));
ClassLoader classLoader = new URLClassLoader(paths.toArray(new URL[paths.size()]),
dependencyLoader); // using AntClassLoader with Closeable so that we can predictably release jar files opened by URLClassLoader
AntClassLoader2 classLoader = new AntClassLoader2(dependencyLoader);
classLoader.addPathFiles(paths);
return new PluginWrapper(archive, manifest, baseResourceURL, return new PluginWrapper(archive, manifest, baseResourceURL,
classLoader, disableFile, dependencies, optionalDependencies); classLoader, disableFile, dependencies, optionalDependencies);
...@@ -247,7 +250,7 @@ public class ClassicPluginStrategy implements PluginStrategy { ...@@ -247,7 +250,7 @@ public class ClassicPluginStrategy implements PluginStrategy {
return new File(base.getParentFile(),relative); return new File(base.getParentFile(),relative);
} }
private static void parseClassPath(Manifest manifest, File archive, List<URL> paths, String attributeName, String separator) throws IOException { private static void parseClassPath(Manifest manifest, File archive, List<File> paths, String attributeName, String separator) throws IOException {
String classPath = manifest.getMainAttributes().getValue(attributeName); String classPath = manifest.getMainAttributes().getValue(attributeName);
if(classPath==null) return; // attribute not found if(classPath==null) return; // attribute not found
for (String s : classPath.split(separator)) { for (String s : classPath.split(separator)) {
...@@ -259,12 +262,12 @@ public class ClassicPluginStrategy implements PluginStrategy { ...@@ -259,12 +262,12 @@ public class ClassicPluginStrategy implements PluginStrategy {
fs.setDir(dir); fs.setDir(dir);
fs.setIncludes(file.getName()); fs.setIncludes(file.getName());
for( String included : fs.getDirectoryScanner(new Project()).getIncludedFiles() ) { for( String included : fs.getDirectoryScanner(new Project()).getIncludedFiles() ) {
paths.add(new File(dir,included).toURI().toURL()); paths.add(new File(dir,included));
} }
} else { } else {
if(!file.exists()) if(!file.exists())
throw new IOException("No such file: "+file); throw new IOException("No such file: "+file);
paths.add(file.toURI().toURL()); paths.add(file);
} }
} }
} }
...@@ -359,4 +362,22 @@ public class ClassicPluginStrategy implements PluginStrategy { ...@@ -359,4 +362,22 @@ public class ClassicPluginStrategy implements PluginStrategy {
// TODO: delegate resources? watch out for diamond dependencies // TODO: delegate resources? watch out for diamond dependencies
} }
/**
* {@link AntClassLoader} with a few methods exposed and {@link Closeable} support.
*/
private static final class AntClassLoader2 extends AntClassLoader implements Closeable {
private AntClassLoader2(ClassLoader parent) {
super(parent,true);
}
public void addPathFiles(Collection<File> paths) throws IOException {
for (File f : paths)
addPathFile(f);
}
public void close() throws IOException {
cleanup();
}
}
} }
...@@ -322,9 +322,8 @@ public final class PluginManager extends AbstractModelObject { ...@@ -322,9 +322,8 @@ public final class PluginManager extends AbstractModelObject {
* Orderly terminates all the plugins. * Orderly terminates all the plugins.
*/ */
public void stop() { public void stop() {
for (PluginWrapper p : activePlugins) { for (PluginWrapper p : activePlugins)
p.stop(); p.stop();
}
// Work around a bug in commons-logging. // Work around a bug in commons-logging.
// See http://www.szegedi.org/articles/memleak.html // See http://www.szegedi.org/articles/memleak.html
LogFactory.release(uberClassLoader); LogFactory.release(uberClassLoader);
......
...@@ -30,13 +30,14 @@ import java.io.File; ...@@ -30,13 +30,14 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.Closeable;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
import java.util.jar.Manifest; import java.util.jar.Manifest;
import java.util.logging.Logger; import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.StaplerResponse;
/** /**
...@@ -283,6 +284,13 @@ public final class PluginWrapper { ...@@ -283,6 +284,13 @@ public final class PluginWrapper {
// Work around a bug in commons-logging. // Work around a bug in commons-logging.
// See http://www.szegedi.org/articles/memleak.html // See http://www.szegedi.org/articles/memleak.html
LogFactory.release(classLoader); LogFactory.release(classLoader);
if (classLoader instanceof Closeable)
try {
((Closeable) classLoader).close();
} catch (IOException e) {
LOGGER.log(WARNING, "Failed to shut down classloader",e);
}
} }
/** /**
...@@ -369,12 +377,13 @@ public final class PluginWrapper { ...@@ -369,12 +377,13 @@ public final class PluginWrapper {
// Action methods // Action methods
// //
// //
public void doMakeEnabled(StaplerRequest req, StaplerResponse rsp) throws IOException { public void doMakeEnabled(StaplerResponse rsp) throws IOException {
Hudson.getInstance().checkPermission(Hudson.ADMINISTER); Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
enable(); enable();
rsp.setStatus(200); rsp.setStatus(200);
} }
public void doMakeDisabled(StaplerRequest req, StaplerResponse rsp) throws IOException {
public void doMakeDisabled(StaplerResponse rsp) throws IOException {
Hudson.getInstance().checkPermission(Hudson.ADMINISTER); Hudson.getInstance().checkPermission(Hudson.ADMINISTER);
disable(); disable();
rsp.setStatus(200); rsp.setStatus(200);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册