Modify ResourceLoader to close underlying JarFile if using
JarURLConnection to avoid open file leaks. Clarify on JavaDoc that
caller must close the returned InputStream.

Minor test usage cleanups.
This commit is contained in:
Ryan Gustafson
2017-04-14 01:16:18 -05:00
parent 852c4ccf18
commit effe71ed54
3 changed files with 33 additions and 2 deletions

View File

@ -10,7 +10,9 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import net.sourceforge.pmd.RuleSetNotFoundException;
@ -41,6 +43,8 @@ public final class ResourceLoader {
* Method to find a file, first by finding it as a file (either by the
* absolute or relative path), then as a URL, and then finally seeing if it
* is on the classpath.
* <p>
* Caller is responsible for closing the {@link InputStream}.
*
* @param name
* String
@ -59,6 +63,8 @@ public final class ResourceLoader {
/**
* Uses the ClassLoader passed in to attempt to load the resource if it's
* not a File or a URL
* <p>
* Caller is responsible for closing the {@link InputStream}.
*
* @param name
* String
@ -91,8 +97,30 @@ public final class ResourceLoader {
if (resource == null) {
// Don't throw RuleSetNotFoundException, keep API compatibility
return null;
} else {
final URLConnection connection = resource.openConnection();
final InputStream inputStream = connection.getInputStream();
if (connection instanceof JarURLConnection) {
// Wrap the InputStream to also close the underlying JarFile if from a JarURLConnection.
// See https://github.com/pmd/pmd/issues/337
return new InputStream() {
@Override
public int read() throws IOException {
return inputStream.read();
}
@Override
public void close() throws IOException {
inputStream.close();
if (connection instanceof JarURLConnection) {
((JarURLConnection) connection).getJarFile().close();
}
}
};
} else {
return inputStream;
}
}
return resource.openStream();
} catch (IOException e1) {
// Ignored
}

View File

@ -55,6 +55,7 @@ public class RuleSetFactoryTest {
InputStream in = ResourceLoader.loadResourceAsStream("net/sourceforge/pmd/rulesets/reference-ruleset.xml",
this.getClass().getClassLoader());
Assert.assertNotNull("Test ruleset not found - can't continue with test!", in);
in.close();
RuleSetFactory rsf = new RuleSetFactory();
RuleSets rs = rsf.createRuleSets("net/sourceforge/pmd/rulesets/reference-ruleset.xml");

View File

@ -229,7 +229,9 @@ public abstract class AbstractRuleSetFactoryTest {
List<String> ruleSetFileNames = new ArrayList<>();
try {
Properties properties = new Properties();
properties.load(ResourceLoader.loadResourceAsStream("rulesets/" + language + "/rulesets.properties"));
try (InputStream is = ResourceLoader.loadResourceAsStream("rulesets/" + language + "/rulesets.properties")) {
properties.load(is);
}
String fileNames = properties.getProperty("rulesets.filenames");
StringTokenizer st = new StringTokenizer(fileNames, ",");
while (st.hasMoreTokens()) {