Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: let Plugin implement AutoCloseable #2025

Merged
merged 1 commit into from May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,7 @@ Currently the versioning policy of this project follows [Semantic Versioning v2.
## Unreleased - 2022-??-??
### Changed
- Updated documentation by adding parenthesis `()` to the negative odd check message ([#1995](https://github.com/spotbugs/spotbugs/issues/1995))
- Let the Plugin class implement AutoCloseable so we can release the .jar file ([#2024](https://github.com/spotbugs/spotbugs/issues/2024))

### Fixed
- Bumped Saxon-HE from 10.6 to 11.3 ([#1955](https://github.com/spotbugs/spotbugs/pull/1955), [#1999](https://github.com/spotbugs/spotbugs/pull/1999))
Expand Down
12 changes: 11 additions & 1 deletion spotbugs/src/main/java/edu/umd/cs/findbugs/Plugin.java
Expand Up @@ -20,10 +20,12 @@
package edu.umd.cs.findbugs;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -53,7 +55,7 @@
* @see PluginLoader
* @author David Hovemeyer
*/
public class Plugin {
public class Plugin implements AutoCloseable {


private static final String USE_FINDBUGS_VERSION = "USE_FINDBUGS_VERSION";
Expand Down Expand Up @@ -696,4 +698,12 @@ public static synchronized void removeCustomPlugin(Plugin plugin) {
DetectorFactoryCollection.instance().unLoadPlugin(plugin);
}

/**
* Closes the underlying {@link PluginLoader}, in turn this closes the {@link URLClassLoader}.
* When loading a custom plugin from a .jar file this method needs to be called to release the reference on that file.
*/
@Override
public void close() throws IOException {
pluginLoader.close();
}
}
57 changes: 52 additions & 5 deletions spotbugs/src/main/java/edu/umd/cs/findbugs/PluginLoader.java
Expand Up @@ -102,7 +102,7 @@
* @see Plugin
* @see PluginException
*/
public class PluginLoader {
public class PluginLoader implements AutoCloseable {

private static final String XPATH_PLUGIN_SHORT_DESCRIPTION = "/MessageCollection/Plugin/ShortDescription";
private static final String XPATH_PLUGIN_WEBSITE = "/FindbugsPlugin/@website";
Expand Down Expand Up @@ -140,6 +140,9 @@ public class PluginLoader {

private final URI loadedFromUri;

// The classloaders we have created, so we can close then if we want to close the plugin
private List<URLClassLoader> createdClassLoaders = new ArrayList<>();

/** plugin Id for parent plugin */
String parentId;

Expand Down Expand Up @@ -196,7 +199,7 @@ public boolean hasParent() {
*/
private PluginLoader(@Nonnull URL url, URI uri, ClassLoader parent, boolean isInitial, boolean optional) throws PluginException {
URL[] loaderURLs = createClassloaderUrls(url);
classLoaderForResources = new URLClassLoader(loaderURLs);
classLoaderForResources = buildURLClassLoader(loaderURLs);
loadedFrom = url;
loadedFromUri = uri;
jarName = getJarName(url);
Expand All @@ -205,15 +208,15 @@ private PluginLoader(@Nonnull URL url, URI uri, ClassLoader parent, boolean isIn
optionalPlugin = optional;
plugin = init();
if (!hasParent()) {
classLoader = new URLClassLoader(loaderURLs, parent);
classLoader = buildURLClassLoader(loaderURLs, parent);
} else {
if (parent != PluginLoader.class.getClassLoader()) {
throw new IllegalArgumentException("Can't specify parentid " + parentId + " and provide a separate class loader");
}
Plugin parentPlugin = Plugin.getByPluginId(parentId);
if (parentPlugin != null) {
parent = parentPlugin.getClassLoader();
classLoader = new URLClassLoader(loaderURLs, parent);
classLoader = buildURLClassLoader(loaderURLs, parent);
}
}
if (classLoader == null) {
Expand Down Expand Up @@ -246,7 +249,7 @@ private static void finishLazyInitialization() {
i.remove();
try {
URL[] loaderURLs = PluginLoader.createClassloaderUrls(pluginLoader.loadedFrom);
pluginLoader.classLoader = new URLClassLoader(loaderURLs, parent.getClassLoader());
pluginLoader.classLoader = pluginLoader.buildURLClassLoader(loaderURLs, parent.getClassLoader());
pluginLoader.loadPluginComponents();
Plugin.putPlugin(pluginLoader.loadedFromUri, pluginLoader.plugin);
} catch (PluginException e) {
Expand Down Expand Up @@ -275,6 +278,50 @@ private static void finishLazyInitialization() {
lazyInitialization = false;
}

/**
* Creates a new {@link URLClassLoader} and adds it to the list of classloaders
* we need to close if we close the corresponding plugin
*
* @param
* urls the URLs from which to load classes and resources
* @return a new {@link URLClassLoader}
*/
private URLClassLoader buildURLClassLoader(URL[] urls) {
URLClassLoader urlClassLoader = new URLClassLoader(urls);
createdClassLoaders.add(urlClassLoader);

return urlClassLoader;
}

/**
* Creates a new {@link URLClassLoader} and adds it to the list of classloaders
* we need to close if we close the corresponding plugin
*
* @param
* urls the URLs from which to load classes and resources
* @param
* parent the parent class loader for delegation
* @return a new {@link URLClassLoader}
*/
private URLClassLoader buildURLClassLoader(URL[] urls, ClassLoader parent) {
URLClassLoader urlClassLoader = new URLClassLoader(urls, parent);
createdClassLoaders.add(urlClassLoader);

return urlClassLoader;
}

/**
* Closes the class loaders created in this {@link PluginLoader}
* @throws IOException if a class loader fails to close, in that case the other classloaders won't be closed
*/
@Override
public void close() throws IOException {
for (URLClassLoader urlClassLoader : createdClassLoaders) {
urlClassLoader.close();
}
}


/**
* Patch for issue 3429143: allow plugins load classes/resources from 3rd
* party jars
Expand Down