Hello -
I have a scenario where I want to close an InputStream that is an instance
of a DelegatingInputStream. The network connection has been dropped, so the
InputStream cannot be read from. However, the DelegatingInputStream.close()
method attempts internally to do a consume() call which involves a read that
blocks forever.
How can I close this DelegatingInputStream and avoid it doing a read as part
of the close operation? I hacked some code to get around this (basically
cycle through the underlying nested InputStreams until I find one that is
not a DelegatingInputStream, e.g., MimeBodyPartInputStream and do the close
on it and just call the setClosed(true) method on the intermediate
DelegatingInputStreams. But this is way too CXF specific and brittle code.
Below is a thread dump of the blocked thread with the
DelegatingInputStream.close() causing my issue. After that is the hacked up
code I wrote to get around the close issue.
Any help is very much appreciated.
Hugh
"pool-67-thread-1" prio=6 tid=0x000000000ab8b800 nid=0x1b44 waiting for
monitor entry [0x000000001c87e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:654)
- waiting to lock <0x00000007d9233528> (a
sun.net.www.http.ChunkedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:116)
at
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2707)
at
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2702)
at
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2691)
at java.io.FilterInputStream.read(FilterInputStream.java:66)
at java.io.PushbackInputStream.read(PushbackInputStream.java:122)
at
org.apache.cxf.attachment.MimeBodyPartInputStream.read(MimeBodyPartInputStream.java:214)
at
org.apache.cxf.attachment.DelegatingInputStream.read(DelegatingInputStream.java:64)
at org.apache.cxf.helpers.IOUtils.consume(IOUtils.java:259)
at
org.apache.cxf.attachment.DelegatingInputStream.close(DelegatingInputStream.java:47)
at org.apache.commons.io.IOUtils.closeQuietly(IOUtils.java:281)
at org.apache.commons.io.IOUtils.closeQuietly(IOUtils.java:224)
at ddf.catalog.cache.CachedResource.cacheFile(CachedResource.java:353)
at ddf.catalog.cache.CachedResource.access$100(CachedResource.java:52)
at ddf.catalog.cache.CachedResource$1.run(CachedResource.java:211)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
// IOUtils.closeQuietly(source);
if (source instanceof DelegatingInputStream) {
LOGGER.debug("Setting DelegatingInputStream closed");
InputStream is = ((DelegatingInputStream)
source).getInputStream();
if (is != null) {
LOGGER.debug("is InputStream is type {}",
is.getClass().getName());
if (is instanceof DelegatingInputStream) {
LOGGER.debug("Setting DelegatingInputStream
closed");
InputStream is2 = ((DelegatingInputStream)
is).getInputStream();
if (is2 != null) {
try {
is2.close();
} catch (IOException e) {
LOGGER.error("IOException closing
DelegatingInputStream2", e);
((DelegatingInputStream) is).setClosed(true);
} else {
try {
is.close();
} catch (IOException e) {
LOGGER.error("IOException closing
DelegatingInputStream1", e);
((DelegatingInputStream) source).setClosed(true);
I have a scenario where I want to close an InputStream that is an instance
of a DelegatingInputStream. The network connection has been dropped, so the
InputStream cannot be read from. However, the DelegatingInputStream.close()
method attempts internally to do a consume() call which involves a read that
blocks forever.
How can I close this DelegatingInputStream and avoid it doing a read as part
of the close operation? I hacked some code to get around this (basically
cycle through the underlying nested InputStreams until I find one that is
not a DelegatingInputStream, e.g., MimeBodyPartInputStream and do the close
on it and just call the setClosed(true) method on the intermediate
DelegatingInputStreams. But this is way too CXF specific and brittle code.
Below is a thread dump of the blocked thread with the
DelegatingInputStream.close() causing my issue. After that is the hacked up
code I wrote to get around the close issue.
Any help is very much appreciated.
Hugh
"pool-67-thread-1" prio=6 tid=0x000000000ab8b800 nid=0x1b44 waiting for
monitor entry [0x000000001c87e000]
java.lang.Thread.State: BLOCKED (on object monitor)
at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:654)
- waiting to lock <0x00000007d9233528> (a
sun.net.www.http.ChunkedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:116)
at
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2707)
at
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2702)
at
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2691)
at java.io.FilterInputStream.read(FilterInputStream.java:66)
at java.io.PushbackInputStream.read(PushbackInputStream.java:122)
at
org.apache.cxf.attachment.MimeBodyPartInputStream.read(MimeBodyPartInputStream.java:214)
at
org.apache.cxf.attachment.DelegatingInputStream.read(DelegatingInputStream.java:64)
at org.apache.cxf.helpers.IOUtils.consume(IOUtils.java:259)
at
org.apache.cxf.attachment.DelegatingInputStream.close(DelegatingInputStream.java:47)
at org.apache.commons.io.IOUtils.closeQuietly(IOUtils.java:281)
at org.apache.commons.io.IOUtils.closeQuietly(IOUtils.java:224)
at ddf.catalog.cache.CachedResource.cacheFile(CachedResource.java:353)
at ddf.catalog.cache.CachedResource.access$100(CachedResource.java:52)
at ddf.catalog.cache.CachedResource$1.run(CachedResource.java:211)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at
java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
// IOUtils.closeQuietly(source);
if (source instanceof DelegatingInputStream) {
LOGGER.debug("Setting DelegatingInputStream closed");
InputStream is = ((DelegatingInputStream)
source).getInputStream();
if (is != null) {
LOGGER.debug("is InputStream is type {}",
is.getClass().getName());
if (is instanceof DelegatingInputStream) {
LOGGER.debug("Setting DelegatingInputStream
closed");
InputStream is2 = ((DelegatingInputStream)
is).getInputStream();
if (is2 != null) {
try {
is2.close();
} catch (IOException e) {
LOGGER.error("IOException closing
DelegatingInputStream2", e);
((DelegatingInputStream) is).setClosed(true);
} else {
try {
is.close();
} catch (IOException e) {
LOGGER.error("IOException closing
DelegatingInputStream1", e);
((DelegatingInputStream) source).setClosed(true);