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 fae2e065467f5a89fccc9dd4c22065f6a79c29f3 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Wed Dec 14 20:21:44 2022 +0100 Improve the error message when failing to open a connection on an AWS S3 bucket. --- .../org/apache/sis/internal/gui/DataStoreOpener.java | 7 +++++-- .../org/apache/sis/internal/gui/ExceptionReporter.java | 6 +++++- .../org/apache/sis/cloud/aws/internal/Resources.java | 5 +++++ .../apache/sis/cloud/aws/internal/Resources.properties | 1 + .../sis/cloud/aws/internal/Resources_fr.properties | 1 + .../java/org/apache/sis/cloud/aws/s3/FileService.java | 18 ++++++++++++++++-- .../main/java/org/apache/sis/cloud/aws/s3/KeyPath.java | 6 +++--- .../java/org/apache/sis/cloud/aws/s3/package-info.java | 2 +- .../apache/sis/internal/storage/io/ChannelFactory.java | 4 ++-- .../apache/sis/internal/storage/io/IOUtilities.java | 6 ++++++ .../java/org/apache/sis/storage/StorageConnector.java | 11 ++++++++--- .../main/java/org/apache/sis/storage/package-info.java | 2 +- 12 files changed, 54 insertions(+), 15 deletions(-) diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java index 5eee24824c..ee57ad6dc2 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java @@ -204,9 +204,12 @@ public final class DataStoreOpener extends Task<DataStore> { if (source instanceof StorageConnector) { return ((StorageConnector) source).getStorageName(); } - String name = IOUtilities.filename(source); + String name = Strings.trimOrNull(IOUtilities.filename(source)); if (name == null) { - name = Vocabulary.format(Vocabulary.Keys.Unknown); + name = Strings.trimOrNull(IOUtilities.toString(source)); + if (name == null) { + name = Vocabulary.format(Vocabulary.Keys.Unknown); + } } return name; } diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java index 42af7b15bf..b64d7b8f37 100644 --- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java +++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java @@ -293,7 +293,11 @@ public final class ExceptionReporter extends Widget { Platform.runLater(() -> show(owner, title, text, exception)); return; } - String message = exception.getLocalizedMessage(); + String message = null; + for (Throwable e = exception; e != null; e = e.getCause()) { + message = e.getLocalizedMessage(); + if (message != null && !message.equalsIgnoreCase(text)) break; + } if (message == null) { message = Classes.getShortClassName(exception); } diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java index a422154e41..f567e52c63 100644 --- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java +++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java @@ -71,6 +71,11 @@ public final class Resources extends IndexedResourceBundle { */ public static final short FileSystemInitialized_2 = 4; + /** + * Invalid bucket name in “{0}”. + */ + public static final short InvalidBucketName_1 = 8; + /** * Missing {0,choice,0#public|1#secret} access key in “{1}” URI. */ diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.properties b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.properties index 5e0486617a..4fd28f876c 100644 --- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.properties +++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.properties @@ -22,6 +22,7 @@ CanNotChangeToAbsolutePath = Cannot change a relative path to an absolute path. EmptyPath = Empty path. FileSystemInitialized_2 = File system {0,choice,0#not|1#already} initialized for the \u201c{1}\u201d access key. +InvalidBucketName_1 = Invalid bucket name in \u201c{0}\u201d. MissingAccessKey_2 = Missing {0,choice,0#public|1#secret} access key in \u201c{1}\u201d URI. MustBeAbsolutePath = Specified path must be an absolute S3 path. MustHaveKeyComponent = Specified path cannot be the root. diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.properties b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.properties index 9086b8e853..110a56ad77 100644 --- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.properties +++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.properties @@ -27,6 +27,7 @@ CanNotChangeToAbsolutePath = Ne peut pas changer un chemin relatif en chemin absolu. EmptyPath = Le chemin est vide. FileSystemInitialized_2 = Le syst\u00e8me de fichier {0,choice,0#n\u2019a pas \u00e9t\u00e9|1#est d\u00e9j\u00e0} initialis\u00e9 pour la cl\u00e9 d\u2019acc\u00e8s \u00ab\u202f{1}\u202f\u00bb. +InvalidBucketName_1 = Le nom du compartiment dans \u00ab\u202f{0}\u202f\u00bb est invalide. MissingAccessKey_2 = Il manque la cl\u00e9 d'acc\u00e8s {0,choice,0#publique|1#secr\u00e8te} dans l'URI \u00ab\u202f{1}\u202f\u00bb. MustBeAbsolutePath = Le chemin sp\u00e9cifi\u00e9 doit \u00eatre un chemin S3 absolu. MustHaveKeyComponent = Le chemin sp\u00e9cifi\u00e9 ne peut pas \u00eatre la racine. diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/FileService.java b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/FileService.java index d1f7b63803..9b44d65de7 100644 --- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/FileService.java +++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/FileService.java @@ -43,6 +43,7 @@ import java.nio.file.NotDirectoryException; import java.nio.file.AccessDeniedException; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributeView; +import org.apache.sis.util.CharSequences; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.collection.Containers; @@ -74,7 +75,7 @@ import software.amazon.awssdk.services.s3.model.NoSuchBucketException; * instead of the data to access, and can be a global configuration for the server. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.4 * @since 1.2 * @module */ @@ -290,7 +291,20 @@ public class FileService extends FileSystemProvider { // TODO: we may need a way to get password here. fs = fileSystems.computeIfAbsent(accessKey, (key) -> new ClientFileSystem(FileService.this, null, key, null, null)); } - return new KeyPath(fs, uri.getHost(), new String[] {uri.getPath()}, true); + String host = uri.getHost(); + if (host == null) { + /* + * The host is null if the authority contains characters that are invalid for a host name. + * For example if the host contains underscore character ('_'), then it is considered invalid. + * We could use the authority instead, but that authority may contain a user name, port number, etc. + * Current version do not try to parse that string. + */ + host = uri.getAuthority(); + if (host == null) host = uri.toString(); + throw new IllegalArgumentException(Resources.format(Resources.Keys.InvalidBucketName_1, host)); + } + final String path = uri.getPath(); + return new KeyPath(fs, host, (path != null) ? new String[] {path} : CharSequences.EMPTY_ARRAY, true); } /** diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/KeyPath.java b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/KeyPath.java index 87e10e774e..117c33a966 100644 --- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/KeyPath.java +++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/KeyPath.java @@ -48,7 +48,7 @@ import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; * The interpretation of {@link ClientFileSystem#separator} as a path separator is done by this class.</p> * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.4 * @since 1.2 * @module */ @@ -338,8 +338,8 @@ final class KeyPath implements Path { /** * Returns a new path with the same file system than this path. */ - private KeyPath newPath(final String path) { - return new KeyPath(fs, path, CharSequences.EMPTY_ARRAY, false); + private KeyPath newPath(final String other) { + return new KeyPath(fs, Objects.requireNonNull(other, "other"), CharSequences.EMPTY_ARRAY, false); } /** diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/package-info.java b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/package-info.java index ba209f9fcb..92e86f5e6f 100644 --- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/package-info.java +++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/package-info.java @@ -49,7 +49,7 @@ * All classes provided by this package are safe of usage in multi-threading environment. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.4 * * @see <a href="https://sdk.amazonaws.com/java/api/latest/index.html">AWS SDK for Java</a> * diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java index 117f4035a4..943a8fe371 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java @@ -230,8 +230,8 @@ public abstract class ChannelFactory { try { storage = uri.toURL(); } catch (MalformedURLException ioe) { - ioe.addSuppressed(e); - throw ioe; + e.addSuppressed(ioe); + throw e; } /* * We have been able to convert to URL, but the given OpenOptions may not be used. diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java index fba5a3cd8d..60616119ad 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java @@ -99,6 +99,9 @@ public final class IOUtilities extends Static { * * @param path the path as an instance of one of the above-cited types, or {@code null}. * @return the filename in the given path, or {@code null} if the given object is null or of unknown type. + * + * @see #extension(Object) + * @see #toString(Object) */ public static String filename(final Object path) { return part(path, false); @@ -176,6 +179,9 @@ public final class IOUtilities extends Static { * * @param path the path for which to return a string representation. * @return the string representation, or {@code null} if none. + * + * @see #filename(Object) + * @see #extension(Object) */ public static String toString(final Object path) { /* 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 b5c6ea837d..0765ebb80e 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 @@ -100,7 +100,7 @@ import org.apache.sis.setup.OptionKey; * * @author Martin Desruisseaux (Geomatys) * @author Alexis Manin (Geomatys) - * @version 1.3 + * @version 1.4 * @since 0.3 * @module */ @@ -227,6 +227,8 @@ public class StorageConnector implements Serializable { /** * A name for the input/output object, or {@code null} if none. * This field is initialized only when first needed. + * + * @see #getStorageName() */ private transient String name; @@ -639,9 +641,12 @@ public class StorageConnector implements Serializable { */ public String getStorageName() { if (name == null) { - name = IOUtilities.filename(storage); + name = Strings.trimOrNull(IOUtilities.filename(storage)); if (name == null) { - name = Classes.getShortClassName(storage); + name = Strings.trimOrNull(IOUtilities.toString(storage)); + if (name == null) { + name = Classes.getShortClassName(storage); + } } } return name; diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/package-info.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/package-info.java index e70c106729..b2be40c355 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/storage/package-info.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/package-info.java @@ -26,7 +26,7 @@ * * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) - * @version 1.3 + * @version 1.4 * @since 0.3 * @module */