This is an automated email from the ASF dual-hosted git repository.
desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new 3346ea4370 When `WorldFileStore` is closed, close also the stream
wrapped by `ImageInputStream`.
3346ea4370 is described below
commit 3346ea437045e07774151438559eed21b92bd032
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Jun 8 15:26:19 2022 +0200
When `WorldFileStore` is closed, close also the stream wrapped by
`ImageInputStream`.
---
.../sis/internal/storage/image/WorldFileStore.java | 43 +++++++++++++++++++---
.../org/apache/sis/storage/StorageConnector.java | 14 +++++++
.../storage/io/ChannelImageInputStreamTest.java | 1 +
3 files changed, 52 insertions(+), 6 deletions(-)
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java
index 70c73afc46..ccbc9473a3 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java
@@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.Map;
import java.util.HashMap;
import java.util.logging.Level;
+import java.io.Closeable;
import java.io.IOException;
import java.io.EOFException;
import java.io.FileNotFoundException;
@@ -168,6 +169,25 @@ public class WorldFileStore extends PRJDataStore {
*/
private ImageReader reader;
+ /**
+ * The object to close when {@code WorldFileStore} is closed. It may be a
different object than
+ * reader input or writer output, because some {@link
ImageInputStream#close()} implementations
+ * in the standard Java {@link javax.imageio.stream} package do not close
the underlying stream.
+ *
+ * <p>The type is {@link Closeable} instead of {@link AutoCloseable}
because the former is idempotent:
+ * invoking {@link Closeable#close()} many times has no effect. By
contrast {@link AutoCloseable} does
+ * not offer this guarantee. Because it is hard to know what {@link
ImageInputStream#close()} will do,
+ * we need idempotent {@code toClose} for safety. Note that {@link
ImageInputStream#close()} violates
+ * the idempotent contract of {@link Closeable#close()}, so an additional
check will be necessary in
+ * our {@link #close()} implementation.</p>
+ *
+ * @see javax.imageio.stream.FileCacheImageInputStream#close()
+ * @see javax.imageio.stream.FileCacheImageOutputStream#close()
+ * @see javax.imageio.stream.MemoryCacheImageInputStream#close()
+ * @see javax.imageio.stream.MemoryCacheImageOutputStream#close()
+ */
+ private Closeable toClose;
+
/**
* Width and height of the main image.
* The {@link #gridGeometry} is assumed valid only for images having this
size.
@@ -242,6 +262,9 @@ public class WorldFileStore extends PRJDataStore {
listeners.useReadOnlyEvents();
identifiers = new HashMap<>();
suffix = format.suffix;
+ if (format.storage instanceof Closeable) {
+ toClose = (Closeable) format.storage;
+ }
if (readOnly || !format.openAsWriter) {
reader = format.getOrCreateReader();
if (reader == null) {
@@ -784,16 +807,24 @@ loop: for (int convention=0;; convention++) {
public synchronized void close() throws DataStoreException {
listeners.close(); // Should never fail.
final ImageReader codec = reader;
+ final Closeable stream = toClose;
reader = null;
+ toClose = null;
metadata = null;
components = null;
gridGeometry = null;
- if (codec != null) try {
- final Object input = codec.getInput();
- codec.setInput(null);
- codec.dispose();
- if (input instanceof AutoCloseable) {
- ((AutoCloseable) input).close();
+ try {
+ Object input = null;
+ if (codec != null) {
+ input = codec.getInput();
+ codec.setInput(null);
+ codec.dispose();
+ if (input instanceof AutoCloseable) {
+ ((AutoCloseable) input).close();
+ }
+ }
+ if (stream != null && stream != input) {
+ stream.close();
}
} catch (Exception e) {
throw new DataStoreException(e);
diff --git
a/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
b/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
index 1f074814cc..2f2fab45f3 100644
---
a/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
+++
b/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
@@ -1036,6 +1036,10 @@ public class StorageConnector implements Serializable {
* FileCacheImageInputStream and related classes, but we don't do
that for now because this
* code should never be executed for InputStream storage. Instead
getChannelDataInput(true)
* should have created a ChannelImageInputStream or
ChannelDataInput.
+ *
+ * In Apache SIS, ImageInputStream is used only by WorldFileStore.
That store has its own
+ * mechanism for closing the stream used by ImageInputStream. It
gives an extra safety in
+ * case the above paragraph does not hold.
*/
}
return asDataInput;
@@ -1350,6 +1354,16 @@ public class StorageConnector implements Serializable {
reset();
asDataOutput = ImageIO.createImageOutputStream(storage);
addView(DataOutput.class, asDataOutput, null, (byte)
(CASCADE_ON_RESET | CASCADE_ON_CLOSE));
+ /*
+ * Note: Java Image I/O wrappers for Input/OutputStream do NOT
close the underlying streams.
+ * This is a complication for us. We could mitigate the problem by
subclassing the standard
+ * FileCacheImageOutputStream and related classes, but we don't do
that for now. A possible
+ * future evolution would be to complete ChannelImageOutputStream
implementation instead.
+ *
+ * In Apache SIS, ImageOutputStream is used only by
WorldFileStore. That store has its own
+ * mechanism for closing the stream used by ImageOutputStream. So
the problem described in
+ * above paragraph would hopefully not occur in practice.
+ */
}
return asDataOutput;
}
diff --git
a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/ChannelImageInputStreamTest.java
b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/ChannelImageInputStreamTest.java
index 10c4f54fc7..a62fc04916 100644
---
a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/ChannelImageInputStreamTest.java
+++
b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/ChannelImageInputStreamTest.java
@@ -69,6 +69,7 @@ public final strictfp class ChannelImageInputStreamTest
extends ChannelDataTestC
Channels.newChannel(new ByteArrayInputStream(data)), buffer,
false);
testedStream.setByteOrder(byteOrder);
transferRandomData(testedStream, data.length - ARRAY_MAX_LENGTH, 24);
+ testedStream.close();
}
/**