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

commit 796ddbbf0407444efed6d9f32b2882ac218e047a
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Apr 4 11:22:58 2022 +0200

    Search for auxiliary files using Path in addition or URI.
    Those two kinds of object does not always open the same streams.
---
 .../apache/sis/internal/storage/PRJDataStore.java  | 79 ++++++++++++++--------
 .../apache/sis/internal/storage/URIDataStore.java  | 59 +++++++++++++---
 2 files changed, 97 insertions(+), 41 deletions(-)

diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java
index 0a5a54846a..4c04ec072a 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java
@@ -18,13 +18,13 @@ package org.apache.sis.internal.storage;
 
 import java.net.URL;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.FileNotFoundException;
 import java.nio.charset.Charset;
-import java.nio.file.FileSystemNotFoundException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
+import java.nio.file.NoSuchFileException;
 import java.text.ParseException;
 import java.util.Arrays;
 import java.util.Locale;
@@ -137,7 +137,7 @@ public abstract class PRJDataStore extends URIDataStore {
                 crs = (CoordinateReferenceSystem) format.parseObject(wkt);
                 format.validate(crs);
             }
-        } catch (FileNotFoundException e) {
+        } catch (NoSuchFileException | FileNotFoundException e) {
             
listeners.warning(Resources.format(Resources.Keys.CanNotReadAuxiliaryFile_1, 
PRJ), e);
         } catch (IOException | ParseException | ClassCastException e) {
             throw new 
DataStoreException(Resources.format(Resources.Keys.CanNotReadAuxiliaryFile_1, 
PRJ), e);
@@ -153,18 +153,37 @@ public abstract class PRJDataStore extends URIDataStore {
      * @param  extension  the filename extension of the auxiliary file to open.
      * @param  encoding   the encoding to use for reading the file content, or 
{@code null} for default.
      * @return a stream opened on the specified file, or {@code null} if the 
file is not found.
-     * @throws FileNotFoundException if the auxiliary file has not been found.
+     * @throws NoSuchFileException if the auxiliary file has not been found 
(when opened from path).
+     * @throws FileNotFoundException if the auxiliary file has not been found 
(when opened from URL).
      * @throws IOException if another error occurred while opening the stream.
      */
     protected final String readAuxiliaryFile(final String extension, Charset 
encoding) throws IOException {
-        final URL url = IOUtilities.toAuxiliaryURL(location, extension);
-        if (url == null) {
-            return null;
-        }
         if (encoding == null) {
             encoding = Charset.defaultCharset();
         }
-        try (InputStreamReader reader = new 
InputStreamReader(url.openStream(), encoding)) {
+        /*
+         * Try to open the stream using the storage type (Path or URL) closest 
to the type
+         * given at construction time. We do that because those two types can 
not open the
+         * same streams. For example Path does not open HTTP or FTP 
connections by default,
+         * and URL does not open S3 files in current implementation.
+         */
+        final InputStream stream;
+        Path path = getSpecifiedPath();
+        if (path != null) {
+            final String base = getBaseFilename(path);
+            path = path.resolveSibling(base.concat(PRJ));
+            stream = Files.newInputStream(path);
+        } else {
+            final URL url = IOUtilities.toAuxiliaryURL(location, extension);
+            if (url == null) {
+                return null;
+            }
+            stream = url.openStream();
+        }
+        /*
+         * Reads the auxiliary file fully.
+         */
+        try (InputStreamReader reader = new InputStreamReader(stream, 
encoding)) {
             char[] buffer = new char[1024];
             int offset = 0, count;
             while ((count = reader.read(buffer, offset, buffer.length - 
offset)) >= 0) {
@@ -202,29 +221,29 @@ public abstract class PRJDataStore extends URIDataStore {
      * @throws DataStoreException if the URI can not be converted to a {@link 
Path}.
      */
     protected final Path[] listComponentFiles(final String... auxiliaries) 
throws DataStoreException {
-        final Path path;
-        if (location == null) {
-            return new Path[0];
-        } else try {
-            path = Paths.get(location);
-        } catch (IllegalArgumentException | FileSystemNotFoundException e) {
-            throw new DataStoreException(e);
-        }
-        String base = path.getFileName().toString();
-        final int s = base.lastIndexOf('.');
-        if (s >= 0) {
-            base = base.substring(0, s+1);
-        }
-        final Path[] paths = new Path[auxiliaries.length + 1];
-        paths[0] = path;
-        int count = 1;
-        for (final String extension : auxiliaries) {
-            final Path p = path.resolveSibling(base.concat(extension));
-            if (Files.isRegularFile(p)) {
-                paths[count++] = p;
+        Path[] paths = super.getComponentFiles();
+        int count = paths.length;
+        if (count != 0) {
+            final Path path = paths[0];
+            final String base = getBaseFilename(path);
+            for (final String extension : auxiliaries) {
+                final Path p = path.resolveSibling(base.concat(extension));
+                if (Files.isRegularFile(p)) {
+                    if (count >= paths.length) {
+                        paths = Arrays.copyOf(paths, count + 
auxiliaries.length);
+                    }
+                    paths[count++] = p;
+                }
             }
+            paths = ArraysExt.resize(paths, count);
         }
-        return ArraysExt.resize(paths, count);
+        return paths;
+    }
+
+    private static String getBaseFilename(final Path path) {
+        final String base = path.getFileName().toString();
+        final int s = base.lastIndexOf('.');
+        return (s >= 0) ? base.substring(0, s+1) : base + '.';
     }
 
     /**
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java
index 181f44b4ee..ce4faf81d0 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.storage;
 
+import java.io.File;
 import java.net.URI;
 import java.util.Optional;
 import java.nio.file.Path;
@@ -54,6 +55,25 @@ public abstract class URIDataStore extends DataStore 
implements StoreResource, R
      */
     protected final URI location;
 
+    /**
+     * The {@link #location} as a path, computed when first needed.
+     * If the storage given at construction time was a {@link Path} or a 
{@link File} instance,
+     * then this field is initialized in the constructor in order to avoid a 
"path → URI → path" roundtrip
+     * (such roundtrip transforms relative paths into {@linkplain 
Path#toAbsolutePath() absolute paths}).
+     *
+     * @see #getSpecifiedPath()
+     * @see #getComponentFiles()
+     */
+    private volatile Path locationAsPath;
+
+    /**
+     * Whether {@link #locationAsPath} was initialized at construction time 
({@code true})
+     * of inferred from the {@link #location} URI at a later time ({@code 
false}).
+     *
+     * @see #getSpecifiedPath()
+     */
+    private final boolean locationIsPath;
+
     /**
      * Creates a new data store.
      *
@@ -64,6 +84,22 @@ public abstract class URIDataStore extends DataStore 
implements StoreResource, R
     protected URIDataStore(final DataStoreProvider provider, final 
StorageConnector connector) throws DataStoreException {
         super(provider, connector);
         location = connector.getStorageAs(URI.class);
+        final Object storage = connector.getStorage();
+        if (storage instanceof Path) {
+            locationAsPath = (Path) storage;
+        } else if (storage instanceof File) {
+            locationAsPath = ((File) storage).toPath();
+        }
+        locationIsPath = (locationAsPath != null);
+    }
+
+    /**
+     * If the location was specified as a {@link Path} or {@link File} 
instance, returns that path.
+     * Otherwise returns {@code null}. This method does not try to convert URI 
to {@link Path}
+     * because this conversion may fail for HTTP and FTP connections.
+     */
+    final Path getSpecifiedPath() {
+        return locationIsPath ? locationAsPath : null;
     }
 
     /**
@@ -78,23 +114,24 @@ public abstract class URIDataStore extends DataStore 
implements StoreResource, R
 
     /**
      * Returns the {@linkplain #location} as a {@code Path} component or an 
empty array if none.
-     * The default implementation converts the URI to a {@link Path}. Note 
that if the original
-     * {@link StorageConnector} argument given by user at construction time 
already contained a
-     * {@link Path}, then the {@code Path} → {@code URI} → {@code Path} 
roundtrip is equivalent
-     * to returning the {@link Path#toAbsolutePath()} value of user argument.
+     * The default implementation returns the storage specified at 
construction time if it was
+     * a {@link Path} or {@link File}, or converts the URI to a {@link Path} 
otherwise.
      *
      * @return the URI as a path, or an empty array if the URI is null.
      * @throws DataStoreException if the URI can not be converted to a {@link 
Path}.
      */
     @Override
     public Path[] getComponentFiles() throws DataStoreException {
-        final Path path;
-        if (location == null) {
-            return new Path[0];
-        } else try {
-            path = Paths.get(location);
-        } catch (IllegalArgumentException | FileSystemNotFoundException e) {
-            throw new DataStoreException(e);
+        Path path = locationAsPath;
+        if (path == null) {
+            if (location == null) {
+                return new Path[0];
+            } else try {
+                path = Paths.get(location);
+            } catch (IllegalArgumentException | FileSystemNotFoundException e) 
{
+                throw new DataStoreException(e);
+            }
+            locationAsPath = path;
         }
         return new Path[] {path};
     }

Reply via email to