This is an automated email from the ASF dual-hosted git repository.

amanin pushed a commit to branch refactor/strict_storage_connector
in repository https://gitbox.apache.org/repos/asf/sis.git

commit ffe5d46242ba08c53f990ba9abdd4b0695e0ed96
Author: Alexis Manin <[email protected]>
AuthorDate: Thu Mar 4 17:12:00 2021 +0100

    chore(Storage): report improvements done in Geotk copy
---
 .../apache/sis/storage/StrictStorageConnector.java | 73 ++++++++++++++++++----
 .../sis/storage/StrictStorageConnectorTest.java    |  4 +-
 2 files changed, 62 insertions(+), 15 deletions(-)

diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/StrictStorageConnector.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/StrictStorageConnector.java
index ea9975c..34f4e8e 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/StrictStorageConnector.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/StrictStorageConnector.java
@@ -95,11 +95,12 @@ public class StrictStorageConnector implements 
AutoCloseable {
      * To know how many bytes are available, refer to the buffer {@link 
ByteBuffer#remaining() remaining byte count}.
      * User <em>do not</em> need to rewind buffer after use. It is the storage 
connector responsability.
      *
-     * @param operator User operation to perform against preovided buffer.
-     * @param <T>
-     * @return
-     * @throws DataStoreException
-     * @throws IOException
+     * @param operator User operation to perform against provided buffer.
+     * @param <T> Type of result produced by user operator.
+     * @return The value computed by input operator.
+     * @throws UnsupportedStorageException If queried storage type cannot be 
accessed in current context.
+     * @throws IOException If given operator throws IOException on execution.
+     * @throws DataStoreException If an error occurs while fetching queried 
storage.
      */
     public <T> T useAsBuffer(StorageOperatingFunction<ByteBuffer, T> operator) 
throws DataStoreException, IOException {
         return doUnderControl(() -> {
@@ -110,6 +111,9 @@ public class StrictStorageConnector implements 
AutoCloseable {
         });
     }
 
+    /**
+     * Specialization of {@link #useAs(Class, StorageOperatingFunction)} for 
{@link ImageInputStream ImageIO API}.
+     */
     public <T> T 
useAsImageInputStream(StorageOperatingFunction<ImageInputStream, T> operator) 
throws IOException, DataStoreException {
         return doUnderControl(() -> {
             ImageInputStream stream = getOrFail(ImageInputStream.class);
@@ -119,9 +123,13 @@ public class StrictStorageConnector implements 
AutoCloseable {
             try ( Closeable rewindOnceDone = stream::reset ) {
                 result = operator.apply(stream);
             }
-            if (stream.getStreamPosition() != positionCtrl) {
+            final long rewindPosition = stream.getStreamPosition();
+            if (rewindPosition != positionCtrl) {
                 concurrentFlag = -1; // mark this connector as closed/not 
valid anymore
-                throw new DataStoreException("Operator has messed with stream 
marks");
+                throw new StorageControlException(String.format(
+                        "Operator has messed with stream marks. Rewind should 
have positioned at %d, but ended at %d",
+                        positionCtrl, rewindPosition
+                ), ImageInputStream.class);
             }
             return result;
         });
@@ -129,23 +137,41 @@ public class StrictStorageConnector implements 
AutoCloseable {
 
     /**
      * Temporarily expose storage through queried interface/class to be used 
by a user defined operator.
-     * Note that provided storage is checked after use, to ensure it has not 
been corrupted by input operator.
+     * Notes:
+     * <ul>
+     *     <li>
+     *         This method handles mark before / rewind after usage. User 
responsability is to not leave additional
+     *         marks unrewinded. Therefore, if you just need to sequentially 
read input, you don't have to mark/rewind
+     *         the storage.
+     *     </li>
+     *     <li>
+     *         Provided storage is checked after use, to ensure it has not 
been corrupted by input operator. If control
+     *         fails, a {@link StorageControlException} is raised.
+     *     </li>
+     * </ul>
      *
      * @param storageType Storage access interface to provide to the operator.
      * @param operator The operator that will access storage to compute a 
result.
      * @param <S> Storage class
      * @param <T> Type of result computed by user operator.
      * @return The value computed by user operator.
-     * @throws IOException If given operator throws IOException on execution.
      * @throws UnsupportedStorageException If queried storage type cannot be 
accessed in current context.
+     * @throws StorageControlException If connector has detected storage 
corruption after operator usage.
+     * @throws IOException If given operator throws IOException on execution.
      * @throws DataStoreException If an error occurs while fetching queried 
storage.
      */
-    public <S, T> T useAs(Class<T> storageType, StorageOperatingFunction<S, T> 
operator) throws IOException, DataStoreException {
+    public <S, T> T useAs(Class<S> storageType, StorageOperatingFunction<? 
super S, ? extends T> operator) throws IOException, DataStoreException {
         if (ByteBuffer.class.isAssignableFrom(storageType)) return 
useAsBuffer((StorageOperatingFunction<ByteBuffer, T>) operator);
         else if (ImageInputStream.class.isAssignableFrom(storageType)) return 
useAsImageInputStream((StorageOperatingFunction<ImageInputStream, T>) operator);
-        else if (URI.class.isAssignableFrom(storageType)) return 
((StorageOperatingFunction<URI, T>) operator).apply(getURI().orElseThrow(() -> 
new UnsupportedStorageException("Cannot acquire an URI")));
-        else if (Path.class.isAssignableFrom(storageType)) return 
((StorageOperatingFunction<Path, T>) operator).apply(getPath().orElseThrow(() 
-> new UnsupportedStorageException("Cannot acquire a path")));
-        else if (File.class.isAssignableFrom(storageType)) return 
((StorageOperatingFunction<File, T>) operator).apply(getPath().map(p -> 
p.toFile()).orElseThrow(() -> new UnsupportedStorageException("Cannot acquire a 
file")));
+        else if (URI.class.isAssignableFrom(storageType)) return 
((StorageOperatingFunction<URI, T>) operator).apply(
+                getURI().orElseThrow(() -> new 
UnsupportedStorageException("Cannot acquire an URI"))
+        );
+        else if (Path.class.isAssignableFrom(storageType)) return 
((StorageOperatingFunction<Path, T>) operator).apply(
+                getPath().orElseThrow(() -> new 
UnsupportedStorageException("Cannot acquire a path"))
+        );
+        else if (File.class.isAssignableFrom(storageType)) return 
((StorageOperatingFunction<File, T>) operator).apply(
+                getPath().map(p -> p.toFile()).orElseThrow(() -> new 
UnsupportedStorageException("Cannot acquire a file"))
+        );
         else throw new UnsupportedStorageException("Queried storage type is 
not supported yet: "+storageType);
     }
 
@@ -235,4 +261,25 @@ public class StrictStorageConnector implements 
AutoCloseable {
     public interface StorageOperatingFunction<I, O> {
         O apply(I storage) throws IOException, DataStoreException;
     }
+
+    public class StorageControlException extends RuntimeException {
+        public final Class<?> storageType;
+
+        public StorageControlException(Class<?> storageType) {
+            this(null, null, storageType);
+        }
+
+        public StorageControlException(String message, Class<?> storageType) {
+            this(message, null, storageType);
+        }
+
+        public StorageControlException(Throwable cause, Class<?> storageType) {
+            this(null, cause, storageType);
+        }
+
+        public StorageControlException(String message, Throwable cause, 
Class<?> storageType) {
+            super(message, cause);
+            this.storageType = storageType;
+        }
+    }
 }
diff --git 
a/storage/sis-storage/src/test/java/org/apache/sis/storage/StrictStorageConnectorTest.java
 
b/storage/sis-storage/src/test/java/org/apache/sis/storage/StrictStorageConnectorTest.java
index 40110a4..266fd05 100644
--- 
a/storage/sis-storage/src/test/java/org/apache/sis/storage/StrictStorageConnectorTest.java
+++ 
b/storage/sis-storage/src/test/java/org/apache/sis/storage/StrictStorageConnectorTest.java
@@ -3,12 +3,12 @@ package org.apache.sis.storage;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
-import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import org.apache.sis.setup.OptionKey;
+import org.apache.sis.storage.StrictStorageConnector.StorageControlException;
 import org.apache.sis.test.DependsOn;
 import org.junit.Test;
 
@@ -94,7 +94,7 @@ public class StrictStorageConnectorTest {
                     return 0;
                 });
                 fail("We should have detected something has gone wrong");
-            } catch (DataStoreException e) {
+            } catch (StorageControlException e) {
                 // Expected behavior: connector has detected that rewind did 
not work properly.
             }
         }

Reply via email to