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 6cdeffb8f511a66b66465b3eb6be9d4b176f834d Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Fri Dec 6 14:32:59 2024 +0100 Add a `DataStores.open(Object, String)` method which allows to specify the preferred data store implementation. --- .../org/apache/sis/storage/DataStoreRegistry.java | 2 +- .../main/org/apache/sis/storage/DataStores.java | 63 +++++++++++++++++++++- .../apache/sis/storage/image/DataStoreFilter.java | 21 ++++---- 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreRegistry.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreRegistry.java index 6d1ce5d717..cd117b737b 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreRegistry.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreRegistry.java @@ -269,7 +269,7 @@ search: for (final Category category : Category.values()) { if (md == null) { accept = isFirstIteration; // If no metadata, test only during one iteration. } else { - accept = (md.yieldPriority() == category.yieldPriority) && + accept = (category.preferred || md.yieldPriority() == category.yieldPriority) && ArraysExt.contains(md.capabilities(), capability); if (accept & useSuffix) { accept = ArraysExt.containsIgnoreCase(md.fileSuffixes(), extension) == category.useSuffix; diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStores.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStores.java index c4ce0b2eb9..a5739a4d76 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStores.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStores.java @@ -37,7 +37,10 @@ import org.apache.sis.coverage.grid.DisjointExtentException; * @author Martin Desruisseaux (Geomatys) * @author Johann Sorel (Geomatys) * @version 1.5 - * @since 0.4 + * + * <a href="https://sis.apache.org/formats.html">Data formats supported by Apache SIS</a> + * + * @since 0.4 */ public final class DataStores extends Static { /** @@ -84,6 +87,9 @@ public final class DataStores extends Static { * <li>An existing {@link StorageConnector} instance.</li> * </ul> * + * The file format is detected automatically by inspection of the file header. + * The file suffix may also be used in case of ambiguity. + * * @param storage the input object as a URL, file, image input stream, <i>etc.</i>. * @return the object to use for reading geospatial data from the given storage. * @throws UnsupportedStorageException if no {@link DataStoreProvider} is found for the given storage object. @@ -93,6 +99,61 @@ public final class DataStores extends Static { return DataStoreRegistry.INSTANCE.open(storage, Capability.READ, null); } + /** + * Creates a {@link DataStore} capable to read the given storage, with a preference for the specified reader. + * The {@code storage} argument can be of the same types as documented in {@link #open(Object)}. + * The {@code preferredFormat} argument can be one of the following (non-exhaustive list). + * Note that which formats are available depend on which modules are on the module-path. + * + * <table class="sis"> + * <caption>Common formats</caption> + * <tr><th>Format</th> <th>Description</th></tr> + * <tr><td>{@code "ASCII Grid"}</td> <td>ESRI ASCII Grid raster format</td></tr> + * <tr><td>{@code "BIL/BIP/BSQ"}</td> <td>ESRI RAW binary encoding</td></tr> + * <tr><td>{@code "CSV"}</td> <td>Comma-Separated Values, optionally with Moving Features</td></tr> + * <tr><td>{@code "folder"}</td> <td>Directory of more files</td></tr> + * <tr><td>{@code "GDAL"}</td> <td>Binding to the <abbr>GDAL</abbr> C/C++ library</td></tr> + * <tr><td>{@code "GeoTIFF"}</td> <td>GeoTIFF, including big and <abbr>COG</abbr> variants</td></tr> + * <tr><td>{@code "GPX"}</td> <td><abbr>GPS</abbr> Exchange Format</td></tr> + * <tr><td>{@code "Landsat"}</td> <td>Landsat 8 level 1-2 data</td></tr> + * <tr><td>{@code "NetCDF"}</td> <td>NetCDF 3 (or 4 if UCAR dependency is included)</td></tr> + * <tr><td>{@code "SQL"}</td> <td>Connection to a <abbr>SQL</abbr> database</td></tr> + * <tr><td>{@code "WKT"}</td> <td>CRS definition in Well-Known Text format</td></tr> + * <tr><td>{@code "World file"}</td> <td>World File image read through Java Image I/O</td></tr> + * <tr><td>{@code "XML"}</td> <td>Metadata in <abbr>GML</abbr> format</td></tr> + * </table> + * + * The preferred format is only a hint. If the {@link DataStore} identified by {@code preferredFormat} + * cannot open the given storage, another data store will be searched as with {@link #open(Object)}. + * The actual format which has been selected is given by {@code DataStore.getProvider().getShortName()}. + * + * <h4>Example</h4> + * If both the {@code org.apache.sis.storage.geotiff} and {@code org.apache.sis.storage.gdal} modules + * are present on the module-path, then the Apache <abbr>SIS</abbr> implementation is used by default + * for opening GeoTIFF files. For using <abbr>GDAL</abbr> instead, use this method with {@code "GDAL"} + * argument value. + * + * @param storage the input object as a URL, file, image input stream, <i>etc.</i>. + * @param preferredFormat identification of the preferred {@code DataStore} implementation, or {@code null}. + * @return the object to use for reading geospatial data from the given storage. + * @throws UnsupportedStorageException if no {@link DataStoreProvider} is found for the given storage object. + * @throws DataStoreException if an error occurred while opening the storage in read mode. + * + * @see DataStore#getProvider() + * @see DataStoreProvider#getShortName() + * + * @since 1.5 + */ + public static DataStore open(final Object storage, final String preferredFormat) + throws UnsupportedStorageException, DataStoreException + { + Predicate<DataStoreProvider> preferred = null; + if (preferredFormat != null) { + preferred = new DataStoreFilter(preferredFormat, false); + } + return DataStoreRegistry.INSTANCE.open(storage, Capability.READ, preferred); + } + /** * Creates a {@link DataStore} capable to write or update the given storage. * The {@code storage} argument can be any of the types documented in {@link #open(Object)}. diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/DataStoreFilter.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/DataStoreFilter.java index a4639d0c6c..9b86a20d75 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/DataStoreFilter.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/image/DataStoreFilter.java @@ -16,6 +16,7 @@ */ package org.apache.sis.storage.image; +import java.util.Objects; import java.util.function.Predicate; import javax.imageio.ImageIO; import org.apache.sis.util.ArraysExt; @@ -57,7 +58,7 @@ public final class DataStoreFilter implements Predicate<DataStoreProvider> { * Creates a new filter for the given data store name. * * @param preferred name of the data store to search, or Image I/O format name. - * @param writer whether to search among writers intead of readers. + * @param writer whether to search among writers instead of readers. */ public DataStoreFilter(final String preferred, final boolean writer) { this.preferred = preferred; @@ -84,13 +85,15 @@ public final class DataStoreFilter implements Predicate<DataStoreProvider> { */ @Override public boolean test(final DataStoreProvider candidate) { - final String formatName = StoreUtilities.getFormatName(candidate); - if (CharSequences.equalsFiltered(formatName, preferred, Characters.Filter.UNICODE_IDENTIFIER, true)) { - return true; - } - if (WorldFileStoreProvider.NAME.equals(formatName)) { - String[] formats = writer ? ImageIO.getWriterFormatNames() : ImageIO.getReaderFormatNames(); - return ArraysExt.containsIgnoreCase(formats, preferred); + if (other == null || other.test(candidate)) { + final String formatName = StoreUtilities.getFormatName(candidate); + if (CharSequences.equalsFiltered(formatName, preferred, Characters.Filter.UNICODE_IDENTIFIER, true)) { + return true; + } + if (WorldFileStoreProvider.NAME.equals(formatName)) { + String[] formats = writer ? ImageIO.getWriterFormatNames() : ImageIO.getReaderFormatNames(); + return ArraysExt.containsIgnoreCase(formats, preferred); + } } return false; } @@ -102,6 +105,6 @@ public final class DataStoreFilter implements Predicate<DataStoreProvider> { */ @Override public Predicate<DataStoreProvider> and(Predicate<? super DataStoreProvider> other) { - return new DataStoreFilter(this, other); + return new DataStoreFilter(this, Objects.requireNonNull(other)); } }