Support #4833
closedResource leak when using an URIResolver
0%
Description
Hi,
I've been pointed to an issue, that included resources of some Schematrons cannot be deleted after compilations, because the resource is "in use". When debugging through the relevant code pieces, I stumbled upon this code snippet in clas DocumentFN lines 385ff (Saxon-HE Java, 10.3):
if (source instanceof StreamSource && ((StreamSource)source).getInputStream() == null && ((StreamSource)source).getReader() == null) {
String uri = source.getSystemId();
...
}
In my scenario ((StreamSource)source).getInputStream()
opens a File and returns the respective handle (the same applies of course to ((StreamSource)source).getReader()
) as well.
As this InputStream is never closed it creates a resource leak.
So please make sure InputStream and Reader are closed if they are opened.
Thanks, Philip
Updated by Michael Kay over 3 years ago
Are you sure? Looking at the source code for StreamSource
, it's simply
public InputStream getInputStream() {
return inputStream;
}
public Reader getReader() {
return reader;
}
so unless you've subclassed StreamSource
to do something different, these methods don't attempt to open the stream and should have no such side-effects.
Now, of course it's always possible that we're opening the stream somewhere else, not in the code that you're pointing to as the culprit. In fact the design of StreamSource
and URIResolver
makes this all quite difficult. As a general rule, we follow the policy that whoever creates a Stream
is responsible for closing it after use; that would mean that if your URIResolver
creates the Stream then it's responsible for closing it, and of course that doesn't work because the URIResolver
API doesn't have a close()
method that would enable that to happen.
As a workaround we introduced AugmentedSource
, which can wrap around a StreamSource
and has a flag pleaseCloseAfterUse
. If your URIResolver
returns a StreamSource
with this flag set, then we will indeed call close()
on the InputStream
when parsing is done.
We could have chosen to always wrap a StreamSource
returned by a URIResolver
in an AugmentedSource
with this flag set. I'm pretty sure there was a reason we didn't, but I can't remember what the reasoning was. I fear though that if we changed the code to do the close()
implicitly, someone's application would almost certainly break.
Updated by Philip Helger over 3 years ago
Hello Michael, Thank you very much for the swift response.
Indeed I am using a subclass of StreamSource
that overwrites these two methods.
Using the AugmentedSource
is not really an option for me as I am trying to work with the standard API only without explicitly relying on Saxon directly.
Also looking at the implementation of AugmentedSource.close
which calls ParseOptions.close
I am convinced it will not solve my issue:
StreamSource ss = (StreamSource) source;
if (ss.getInputStream() != null) {
ss.getInputStream().close();
}
if (ss.getReader() != null) {
ss.getReader().close();
}
Each call to getInputStream
effectively returns a new FileInputStream(file)
....
So basically I should only use StreamSource
implementations that have a single, fixed InputStream
or Reader
. Hmmm....
Updated by Michael Kay over 3 years ago
Yes, I think StreamSource
has an implicit contract that getInputStream
and getReader
are side-effect-free methods, and you've broken that contract in your subclass.
Updated by Philip Helger over 3 years ago
Using this assumption, the issue can be closed as "won't fix". Thank you.
Updated by Michael Kay over 3 years ago
- Tracker changed from Bug to Support
- Category set to JAXP Java API
- Status changed from New to Closed
- Assignee set to Michael Kay
Please register to edit this issue