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 2514bc80b8 Replace the use of `java.net.URI` by an internal `GridFile` class which take in charge the URI resolutions. This is for making easier the cases where the URI needs to be resolved relatively to the GML or WKT file instead of resolved in the "$SIS_DATA/DatumChanges" directory. 2514bc80b8 is described below commit 2514bc80b80d9987fbee054eac5aa4ed9af9c355 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Thu Dec 28 17:23:01 2023 +0100 Replace the use of `java.net.URI` by an internal `GridFile` class which take in charge the URI resolutions. This is for making easier the cases where the URI needs to be resolved relatively to the GML or WKT file instead of resolved in the "$SIS_DATA/DatumChanges" directory. --- .../sis/parameter/DefaultParameterValue.java | 1 + .../main/org/apache/sis/parameter/Parameters.java | 24 ++ .../referencing/operation/gridded/GridFile.java | 290 +++++++++++++++++++++ .../referencing/operation/gridded/GridGroup.java | 5 +- .../referencing/operation/gridded/GridLoader.java | 79 +----- .../referencing/operation/gridded/LoadedGrid.java | 22 +- .../provider/FranceGeocentricInterpolation.java | 35 +-- .../sis/referencing/operation/provider/NADCON.java | 34 +-- .../sis/referencing/operation/provider/NTv2.java | 18 +- .../operation/provider/DatumShiftTestCase.java | 5 +- .../FranceGeocentricInterpolationTest.java | 13 +- .../referencing/operation/provider/NADCONTest.java | 7 +- .../referencing/operation/provider/NTv2Test.java | 19 +- .../sis/test/integration/DatumShiftTest.java | 5 +- .../main/org/apache/sis/system/DataDirectory.java | 36 +-- 15 files changed, 402 insertions(+), 191 deletions(-) diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterValue.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterValue.java index 7cdc01b585..ce89c5b038 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterValue.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterValue.java @@ -258,6 +258,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param * } * * @see #setSourceFile(URI) + * @see Parameters#getSourceFile(ParameterDescriptor) * @see org.apache.sis.io.wkt.WKTFormat#getSourceFile() * @see org.apache.sis.xml.MarshalContext#getDocumentURI() * @see URI#resolve(URI) diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/Parameters.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/Parameters.java index 7f62e5f7d0..c4257787bb 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/Parameters.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/Parameters.java @@ -19,7 +19,9 @@ package org.apache.sis.parameter; import java.util.Map; import java.util.HashMap; import java.util.List; +import java.util.Optional; import java.util.function.Predicate; +import java.net.URI; import java.io.Serializable; import jakarta.xml.bind.annotation.XmlTransient; import javax.measure.Unit; @@ -513,6 +515,28 @@ public abstract class Parameters implements ParameterValueGroup, Cloneable, Prin return false; } + /** + * {@return the URI of the GML document or WKT file from which a parameter value has been read}. + * This information can be used together with {@code getValue(ParameterDescriptor<URI>)} for + * resolving a parameter value as a path relative to the GML or WKT file declaring the parameter. + * Note that the source file is not necessarily the same for all parameters in a group, because a GML + * document could define parameters in files referenced by different {@code xlink:href} attribute values. + * + * @see DefaultParameterValue#getSourceFile() + * @see org.apache.sis.io.wkt.WKTFormat#getSourceFile() + * @see org.apache.sis.xml.MarshalContext#getDocumentURI() + * @see URI#resolve(URI) + * + * @since 1.5 + */ + public Optional<URI> getSourceFile(final ParameterDescriptor<?> parameter) throws ParameterNotFoundException { + final ParameterValue<?> p = getParameter(parameter); + if (p instanceof DefaultParameterValue<?>) { + return ((DefaultParameterValue<?>) p).getSourceFile(); + } + return Optional.empty(); + } + /** * Returns the value of the parameter identified by the given descriptor, or {@code null} if none. * This method uses the following information from the given {@code parameter} descriptor: diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridFile.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridFile.java new file mode 100644 index 0000000000..c6fc045fa4 --- /dev/null +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridFile.java @@ -0,0 +1,290 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.referencing.operation.gridded; + +import java.net.URI; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.file.Path; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.FileSystemNotFoundException; +import java.util.logging.Level; +import java.util.concurrent.atomic.AtomicBoolean; +import org.opengis.util.FactoryException; +import org.opengis.parameter.ParameterDescriptor; +import org.opengis.parameter.ParameterNotFoundException; +import org.apache.sis.parameter.Parameters; +import org.apache.sis.referencing.factory.FactoryDataException; +import org.apache.sis.referencing.factory.MissingFactoryResourceException; +import org.apache.sis.referencing.operation.provider.AbstractProvider; +import org.apache.sis.referencing.internal.Resources; +import org.apache.sis.system.DataDirectory; +import org.apache.sis.util.logging.Logging; +import org.apache.sis.util.resources.Errors; +import org.apache.sis.util.resources.Messages; + + +/** + * Resolved path to a grid file. The starting point is the path specified by a parameter. + * If that path is relative, then this class tries to resolve it in a directory specified + * by the {@code SIS_DATA} environment variable. If the path cannot be resolved that way, + * then this method check if it can be resolved relatively to the GML or WKT file containing + * the parameter. + * + * @author Martin Desruisseaux (Geomatys) + */ +public final class GridFile { + /** + * Whether the tip about the location of datum shift files has been logged. + * We log this tip only once, and only if we failed to load at least one grid. + */ + private static final AtomicBoolean datumDirectoryLogged = new AtomicBoolean(); + + /** + * The directory where to search for a local copy of the data, or {@code null} if none. + */ + private final DataDirectory localDirectory; + + /** + * The URI specified in the parameter. This URI is usually relative to an unspecified directory. + * + * @see #resolved() + */ + public final URI parameter; + + /** + * The URI as an absolute path. + */ + private URI resolved; + + /** + * The base URI used for resolving the parameter, or {@code null} if none. + */ + private URI base; + + /** + * The resolved URI as a path, or {@code null} if not yet computed or not convertible. + */ + private Path asPath; + + /** + * Creates a file for the given URI, assumed already resolved. + * This constructor is for testing purposes. + * + * @param resolved the resolved URI. + */ + public GridFile(final URI resolved) { + parameter = resolved; + this.resolved = resolved; + localDirectory = DataDirectory.DATUM_CHANGES; + } + + /** + * Resolves the given parameter as an absolute URI, resolved in the {@code "$SIS_DATA/DatumChanges"} directory + * if the URI is relative. If the URI cannot be resolved, a {@link MissingFactoryResourceException} is thrown. + * That exception type is necessary for letting the caller know that a coordinate operation is probably valid + * but cannot be constructed because an optional configuration is missing. + * It is typically because the {@code SIS_DATA} environment variable has not been set. + * + * @param group the group of parameters from which to get the URI. + * @param param identification of the parameter to fetch. + * @throws ParameterNotFoundException if the specified parameter is not found in the given group. + * @throws MissingFactoryResourceException if the path cannot be resolved. + */ + public GridFile(final Parameters group, final ParameterDescriptor<URI> param) throws MissingFactoryResourceException { + this(group, param, DataDirectory.DATUM_CHANGES); + } + + /** + * Resolves the given parameter as an absolute URI, resolved with the specified {@code DataDirectory} + * if the URI is relative. If the URI cannot be resolved, a {@link MissingFactoryResourceException} is thrown. + * That exception type is necessary for letting the caller know that a coordinate operation is probably valid + * but cannot be constructed because an optional configuration is missing. + * It is typically because the {@code SIS_DATA} environment variable has not been set. + * + * @param group the group of parameters from which to get the URI. + * @param param identification of the parameter to fetch. + * @param localDirectory the directory where to search for a local copy of the data, or {@code null} if none. + * @throws ParameterNotFoundException if the specified parameter is not found in the given group. + * @throws MissingFactoryResourceException if the path cannot be resolved. + */ + public GridFile(final Parameters group, final ParameterDescriptor<URI> param, final DataDirectory localDirectory) + throws MissingFactoryResourceException + { + RuntimeException error = null; + this.localDirectory = localDirectory; + parameter = group.getMandatoryValue(param); + if (parameter.isAbsolute()) { + resolved = parameter.normalize(); + } else { + /* + * First, try to resolve the parameter relative to the "$SIS_DATA/DatumChanges" directory. + * That directory can be seen as a cache to be tried before to download data that may be + * on the network. + */ + if (localDirectory != null) { + base = localDirectory.getDirectoryAsURI(); + if (base != null) try { + resolved = base.resolve(parameter).normalize(); + asPath = Path.of(resolved); + if (Files.exists(asPath)) { + return; + } + } catch (IllegalArgumentException | FileSystemNotFoundException e) { + error = e; + } + } + /* + * If the "$SIS_DATA/DatumChanges" directory cannot be used, check if we + * have another base URI that we could try. If not, we cannot continue. + */ + final URI document = group.getSourceFile(param).orElse(null); + if (document == null) { + if (resolved != null) { + return; // NoSuchFileException will be thrown later by `newByteChannel()`. + } + final String message; + if (parameter.isOpaque()) { + message = Errors.format(Errors.Keys.CanNotOpen_1, parameter); + } else { + final String env = DataDirectory.getenv(); + if (env == null) { + message = Messages.format(Messages.Keys.DataDirectoryNotSpecified_1, DataDirectory.ENV); + } else { + message = Messages.format(Messages.Keys.DataDirectoryNotAccessible_2, DataDirectory.ENV, env); + } + } + throw new MissingFactoryResourceException(message, error); + } + /* + * Use the alternative base URI without checking if it exists. + * This check will be done when the file will be opened. + */ + base = document; + resolved = document.resolve(parameter).normalize(); + } + try { + asPath = Path.of(resolved); + } catch (IllegalArgumentException | FileSystemNotFoundException e) { + if (error == null) error = e; + else error.addSuppressed(e); + asPath = null; + } + if (error != null) { + Logging.ignorableException(AbstractProvider.LOGGER, GridFile.class, "<init>", error); + } + } + + /** + * {@return the resolved URI}. + * + * @see #parameter + */ + public URI resolved() { + return resolved; + } + + /** + * Creates a channel for reading bytes from the file at the path specified at construction time. + * This method tries to open using the file system before to open from the URL. + * + * @return a channel for reading bytes from the file. + * @throws IOException if the channel cannot be created. + */ + public ReadableByteChannel newByteChannel() throws IOException { + if (asPath != null) { + return Files.newByteChannel(asPath); + } else { + return Channels.newChannel(resolved.toURL().openStream()); + } + } + + /** + * Creates a buffered reader for reading characters from the file at the path specified at construction time. + * This method tries to open using the file system before to open from the URL. + * + * @return a channel for reading bytes from the file. + * @throws IOException if the reader cannot be created. + */ + public BufferedReader newBufferedReader() throws IOException { + if (asPath != null) { + return Files.newBufferedReader(asPath); + } else { + return new BufferedReader(new InputStreamReader(resolved.toURL().openStream())); + } + } + + /** + * Logs a message about a grid which is about to be loaded. + * The logger will be {@code "org.apache.sis.referencing.operation"} and the originating + * method will be {@code "createMathTransform"} in the specified {@code caller} class. + * + * @param caller the provider to logs as the source class. + */ + public void startLoading(final Class<?> caller) { + startLoading(caller, parameter); + } + + /** + * Logs a message about a grid which is about to be loaded. + * The logger will be {@code "org.apache.sis.referencing.operation"} and the originating + * method will be {@code "createMathTransform"} in the specified {@code caller} class. + * + * @param caller the provider to logs as the source class. + * @param file the grid file, as a {@link String} or a {@link URI}. + */ + public static void startLoading(final Class<?> caller, final Object file) { + GridLoader.log(caller, Resources.forLocale(null).getLogRecord(Level.FINE, Resources.Keys.LoadingDatumShiftFile_1, file)); + } + + /** + * Creates the exception to throw when the provider failed to load the grid file. + * The first time that this method is invoked, an information message is logged + * as a tip to the user about where data where searched. + * + * @param caller the provider to logs as the source class if a warning occurs. + * @param format the format name (e.g. "NTv2" or "NADCON"). + * @param cause the cause of the failure to load the grid file. + */ + public FactoryException canNotLoad(final Class<?> caller, final String format, final Exception cause) { + if (localDirectory != null && !datumDirectoryLogged.get()) { + final Path directory = localDirectory.getDirectory(); + if (directory != null && !datumDirectoryLogged.getAndSet(true)) { + GridLoader.log(caller, Resources.forLocale(null).getLogRecord(Level.INFO, + Resources.Keys.DatumChangesDirectory_1, directory)); + } + } + if (cause instanceof NoSuchFileException || cause instanceof FileNotFoundException) { + return new MissingFactoryResourceException(Resources.format(Resources.Keys.FileNotFound_2), cause); + } else { + return new FactoryDataException(Resources.format(Resources.Keys.FileNotReadable_2, format, parameter), cause); + } + } + + /** + * {@return a string representation of this path for debugging purposes}. + */ + @Override + public String toString() { + return String.valueOf(resolved); + } +} diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridGroup.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridGroup.java index 2216277902..497eff3efc 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridGroup.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridGroup.java @@ -19,7 +19,6 @@ package org.apache.sis.referencing.operation.gridded; import java.util.Map; import java.util.List; import java.util.LinkedHashMap; -import java.net.URI; import java.io.IOException; import java.awt.Dimension; import java.awt.Rectangle; @@ -156,7 +155,7 @@ public final class GridGroup<C extends Quantity<C>, T extends Quantity<T>> exten * @throws IOException declared because {@link Tile#getRegion()} declares it, but should not happen. */ public static <C extends Quantity<C>, T extends Quantity<T>> GridGroup<C,T> create( - final URI file, final List<LoadedGrid<C,T>> subgrids) + final GridFile file, final List<LoadedGrid<C,T>> subgrids) throws IOException, FactoryException, NoninvertibleTransformException { final TileOrganizer mosaic = new TileOrganizer(null); @@ -182,7 +181,7 @@ public final class GridGroup<C extends Quantity<C>, T extends Quantity<T>> exten */ final Map.Entry<Tile,Tile[]> result = CollectionsExt.singletonOrNull(mosaic.tiles().entrySet()); if (result == null) { - throw new FactoryException(Resources.format(Resources.Keys.MisalignedDatumShiftGrid_1, file)); + throw new FactoryException(Resources.format(Resources.Keys.MisalignedDatumShiftGrid_1, file.parameter)); } final Tile global = result.getKey(); return new GridGroup<>(result.getValue(), grids, global.getGridToCRS(), global.getSize()); diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridLoader.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridLoader.java index 17e9e5be3f..0deb5bdc4e 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridLoader.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/GridLoader.java @@ -16,27 +16,13 @@ */ package org.apache.sis.referencing.operation.gridded; -import java.util.logging.Level; import java.util.logging.LogRecord; -import java.util.concurrent.atomic.AtomicBoolean; import java.io.EOFException; import java.io.IOException; -import java.io.FileNotFoundException; import java.nio.ByteBuffer; -import java.net.URI; -import java.nio.file.Path; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.FileSystemNotFoundException; import java.nio.channels.ReadableByteChannel; -import java.nio.channels.Channels; -import org.opengis.util.FactoryException; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.logging.Logging; -import org.apache.sis.system.DataDirectory; -import org.apache.sis.referencing.internal.Resources; -import org.apache.sis.referencing.factory.FactoryDataException; -import org.apache.sis.referencing.factory.MissingFactoryResourceException; import org.apache.sis.referencing.operation.provider.AbstractProvider; @@ -72,7 +58,7 @@ public abstract class GridLoader { /** * The file to load, used for parameter declaration and if we have errors to report. */ - protected final URI file; + protected final GridFile file; /** * The channel opened on the file. @@ -84,12 +70,6 @@ public abstract class GridLoader { */ protected final ByteBuffer buffer; - /** - * Whether the tip about the location of datum shift files has been logged. - * We log this tip only once, and only if we failed to load at least one grid. - */ - private static final AtomicBoolean datumDirectoryLogged = new AtomicBoolean(); - /** * Creates a new loader for the given channel and an existing buffer. * @@ -97,7 +77,7 @@ public abstract class GridLoader { * @param buffer the buffer to use. * @param file path to the longitude or latitude difference file. Used for parameter declaration and error reporting. */ - protected GridLoader(final ReadableByteChannel channel, final ByteBuffer buffer, final URI file) throws IOException { + protected GridLoader(final ReadableByteChannel channel, final ByteBuffer buffer, final GridFile file) throws IOException { this.file = file; this.buffer = buffer; this.channel = channel; @@ -149,35 +129,6 @@ public abstract class GridLoader { buffer.position(p); } - /** - * Creates a channel for reading bytes from the file at the specified path. - * This method tries to open using the file system before to open from the URL. - * - * @param path the path from where to read bytes. - * @return a channel for reading bytes from the given path. - * @throws IOException if the channel cannot be created. - */ - public static ReadableByteChannel newByteChannel(final URI path) throws IOException { - try { - return Files.newByteChannel(Path.of(path)); - } catch (FileSystemNotFoundException e) { - Logging.ignorableException(AbstractProvider.LOGGER, GridLoader.class, "newByteChannel", e); - } - return Channels.newChannel(path.toURL().openStream()); - } - - /** - * Logs a message about a grid which is about to be loaded. - * The logger will be {@code "org.apache.sis.referencing.operation"} and the originating - * method will be {@code "createMathTransform"} in the specified {@code caller} class. - * - * @param caller the provider to logs as the source class. - * @param file the grid file, as a {@link String} or a {@link URI}. - */ - public static void startLoading(final Class<?> caller, final Object file) { - log(caller, Resources.forLocale(null).getLogRecord(Level.FINE, Resources.Keys.LoadingDatumShiftFile_1, file)); - } - /** * Logs the given record. * The logger will be {@code "org.apache.sis.referencing.operation"} and the originating @@ -189,30 +140,4 @@ public abstract class GridLoader { protected static void log(final Class<?> caller, final LogRecord record) { Logging.completeAndLog(AbstractProvider.LOGGER, caller, "createMathTransform", record); } - - /** - * Creates the exception to throw when the provider failed to load the grid file. - * - * @param caller the provider to logs as the source class if a warning occurs. - * @param format the format name (e.g. "NTv2" or "NADCON"). - * @param file the grid file that the subclass tried to load. - * @param cause the cause of the failure to load the grid file. - */ - public static FactoryException canNotLoad(final Class<?> caller, final String format, final URI file, final Exception cause) { - if (!datumDirectoryLogged.get()) { - final Path directory = DataDirectory.DATUM_CHANGES.getDirectory(); - if (directory != null && !datumDirectoryLogged.getAndSet(true)) { - log(caller, Resources.forLocale(null).getLogRecord(Level.INFO, - Resources.Keys.DatumChangesDirectory_1, directory)); - } - } - final boolean notFound = (cause instanceof NoSuchFileException) || (cause instanceof FileNotFoundException); - final String message = Resources.format(notFound ? Resources.Keys.FileNotFound_2 - : Resources.Keys.FileNotReadable_2, format, file); - if (notFound) { - return new MissingFactoryResourceException(message, cause); - } else { - return new FactoryDataException(message, cause); - } - } } diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/LoadedGrid.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/LoadedGrid.java index 81c85a28d7..9ba298bb2f 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/LoadedGrid.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/gridded/LoadedGrid.java @@ -179,7 +179,7 @@ public abstract class LoadedGrid<C extends Quantity<C>, T extends Quantity<T>> e * @param nx number of cells along the <var>x</var> axis in the grid. * @param ny number of cells along the <var>y</var> axis in the grid. * @param descriptor the parameter descriptor of the provider that created this grid. - * @param files the file(s) from which the grid has been loaded. This array is not cloned. + * @param files the file(s) from which the grid has been loaded. */ LoadedGrid(final Unit<C> coordinateUnit, final Unit<T> translationUnit, @@ -188,12 +188,15 @@ public abstract class LoadedGrid<C extends Quantity<C>, T extends Quantity<T>> e final double Δx, final double Δy, final int nx, final int ny, final ParameterDescriptorGroup descriptor, - final URI... files) throws NoninvertibleTransformException + final GridFile... sources) throws NoninvertibleTransformException { super(coordinateUnit, new AffineTransform2D(Δx, 0, 0, Δy, x0, y0).inverse(), new int[] {nx, ny}, isCellValueRatio, translationUnit); - this.descriptor = descriptor; - this.files = files; + files = new URI[sources.length]; + for (int i=0; i<sources.length; i++) { + files[i] = sources[i].resolved(); + } + this.descriptor = descriptor; this.scanlineStride = nx; if (Units.isAngular(coordinateUnit)) { periodX = Math.rint((Longitude.MAX_VALUE - Longitude.MIN_VALUE) / Math.abs(Δx)); @@ -260,10 +263,13 @@ public abstract class LoadedGrid<C extends Quantity<C>, T extends Quantity<T>> e * * @see GridLoader#canNotLoad(Class, String, URI, Exception) */ - public static LoadedGrid<?,?> getOrLoad(final URI f1, final URI f2, final Callable<LoadedGrid<?,?>> loader) + public static LoadedGrid<?,?> getOrLoad(final GridFile f1, final GridFile f2, final Callable<LoadedGrid<?,?>> loader) throws Exception { - final Object key = (f2 != null) ? new AbstractMap.SimpleImmutableEntry<>(f1, f2) : f1; + Object key = f1.resolved(); + if (f2 != null) { + key = new AbstractMap.SimpleImmutableEntry<>(key, f2.resolved()); + } return CACHE.getOrCreate(key, loader); } @@ -550,7 +556,7 @@ public abstract class LoadedGrid<C extends Quantity<C>, T extends Quantity<T>> e final double Δx, final double Δy, final int nx, final int ny, final ParameterDescriptorGroup descriptor, - final URI... files) throws NoninvertibleTransformException + final GridFile... files) throws NoninvertibleTransformException { super(coordinateUnit, translationUnit, isCellValueRatio, x0, y0, Δx, Δy, nx, ny, descriptor, files); offsets = new float[dim][Math.multiplyExact(nx, ny)]; @@ -663,7 +669,7 @@ public abstract class LoadedGrid<C extends Quantity<C>, T extends Quantity<T>> e final double Δx, final double Δy, final int nx, final int ny, final ParameterDescriptorGroup descriptor, - final URI... files) throws NoninvertibleTransformException + final GridFile... files) throws NoninvertibleTransformException { super(coordinateUnit, translationUnit, isCellValueRatio, x0, y0, Δx, Δy, nx, ny, descriptor, files); offsets = new double[dim][Math.multiplyExact(nx, ny)]; diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/FranceGeocentricInterpolation.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/FranceGeocentricInterpolation.java index c2cbceab50..44585f67ed 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/FranceGeocentricInterpolation.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/FranceGeocentricInterpolation.java @@ -28,7 +28,6 @@ import java.util.concurrent.Callable; import java.io.BufferedReader; import java.io.EOFException; import java.io.IOException; -import java.io.InputStreamReader; import static java.lang.Float.parseFloat; import jakarta.xml.bind.annotation.XmlTransient; import javax.measure.quantity.Angle; @@ -47,6 +46,7 @@ import org.opengis.referencing.operation.NoninvertibleTransformException; import org.opengis.util.FactoryException; import org.apache.sis.referencing.CommonCRS; import org.apache.sis.referencing.datum.DefaultEllipsoid; +import org.apache.sis.referencing.operation.gridded.GridFile; import org.apache.sis.referencing.operation.gridded.LoadedGrid; import org.apache.sis.referencing.operation.gridded.GridLoader; import org.apache.sis.referencing.operation.gridded.CompressedGrid; @@ -59,7 +59,6 @@ import org.apache.sis.measure.Units; import org.apache.sis.util.CharSequences; import org.apache.sis.util.logging.Logging; import org.apache.sis.util.resources.Errors; -import org.apache.sis.system.DataDirectory; import static org.apache.sis.util.internal.Constants.DIM; @@ -268,14 +267,14 @@ public final class FranceGeocentricInterpolation extends GeodeticOperation { /** * Returns {@code true} if the given path seems to be a grid published by the French mapping agency for France. * In principle this <q>France geocentric interpolation</q> is designed specifically for use with the - * {@code "gr3df97a.txt"} grid, but in fact the Apache SIS implementation should be flexible enough for use - * with other area. + * {@code "gr3df97a.txt"} grid, but in fact the Apache SIS implementation should be flexible enough + * for use with other area. * * @param file the grid file. * @return {@code true} if the given file looks like a fie from the French mapping agency. */ - public static boolean isRecognized(final URI file) { - final String filename = file.getPath(); + public static boolean isRecognized(final GridFile file) { + final String filename = file.resolved().getPath(); final int s = filename.lastIndexOf('/') + 1; return filename.regionMatches(true, s, DEFAULT, 0, 5); } @@ -344,13 +343,13 @@ public final class FranceGeocentricInterpolation extends GeodeticOperation { default: throw new InvalidParameterValueException(Errors.format( Errors.Keys.IllegalArgumentValue_2, DIM, dim), DIM, dim); } - final URI file = pg.getMandatoryValue(FILE); + final GridFile file = new GridFile(pg, FILE); final LoadedGrid<Angle,Length> grid; try { grid = getOrLoad(file, isRecognized(file) ? new double[] {TX, TY, TZ} : null, PRECISION); } catch (Exception e) { // NumberFormatException, ArithmeticException, NoSuchElementException, and more. - throw GridLoader.canNotLoad(FranceGeocentricInterpolation.class, HEADER, file, e); + throw file.canNotLoad(FranceGeocentricInterpolation.class, HEADER, e); } MathTransform tr = InterpolatedGeocentricTransform.createGeodeticTransformation(factory, createEllipsoid(pg, Molodensky.TGT_SEMI_MAJOR, @@ -377,11 +376,10 @@ public final class FranceGeocentricInterpolation extends GeodeticOperation { * * @see GridLoader#canNotLoad(Class, String, URI, Exception) */ - static LoadedGrid<Angle,Length> getOrLoad(final URI file, final double[] averages, final double scale) + static LoadedGrid<Angle,Length> getOrLoad(final GridFile file, final double[] averages, final double scale) throws Exception { - final URI resolved = DataDirectory.DATUM_CHANGES.toAbsolutePath(file); - return LoadedGrid.getOrLoad(resolved, null, new Loader(resolved, averages, scale)) + return LoadedGrid.getOrLoad(file, null, new Loader(file, averages, scale)) .castTo(Angle.class, Length.class); } @@ -391,7 +389,7 @@ public final class FranceGeocentricInterpolation extends GeodeticOperation { */ static final class Loader implements Callable<LoadedGrid<?,?>> { /** The file to load. */ - private final URI file; + private final GridFile file; /** An "average" value for the offset in each dimension, or {@code null} if unknown. */ private final double[] averages; @@ -400,17 +398,12 @@ public final class FranceGeocentricInterpolation extends GeodeticOperation { private final double scale; /** Creates a new loader for the given file. */ - Loader(final URI file, final double[] averages, final double scale) { + Loader(final GridFile file, final double[] averages, final double scale) { this.file = file; this.averages = averages; this.scale = scale; } - /** Returns the reader for the specified URI. */ - static BufferedReader newBufferedReader(final URI file) throws IOException { - return new BufferedReader(new InputStreamReader(file.toURL().openStream())); - } - /** * Invoked when the gridded data are not in the cache. * This method load grid data from the file specified at construction time. @@ -423,8 +416,8 @@ public final class FranceGeocentricInterpolation extends GeodeticOperation { @Override public LoadedGrid<?,?> call() throws Exception { final LoadedGrid<?,?> grid; - try (BufferedReader in = newBufferedReader(file)) { - GridLoader.startLoading(FranceGeocentricInterpolation.class, file); + try (BufferedReader in = file.newBufferedReader()) { + file.startLoading(FranceGeocentricInterpolation.class); final LoadedGrid.Float<Angle,Length> g = load(in, file); grid = CompressedGrid.compress(g, averages, scale); } @@ -442,7 +435,7 @@ public final class FranceGeocentricInterpolation extends GeodeticOperation { * @throws FactoryException if an problem is found with the file content. * @throws ArithmeticException if the width or the height exceed the integer capacity. */ - static LoadedGrid.Float<Angle,Length> load(final BufferedReader in, final URI file) + static LoadedGrid.Float<Angle,Length> load(final BufferedReader in, final GridFile file) throws IOException, FactoryException, NoninvertibleTransformException { LoadedGrid.Float<Angle,Length> grid = null; diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NADCON.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NADCON.java index 4aee4d03f4..43f0709f22 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NADCON.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NADCON.java @@ -39,12 +39,12 @@ import org.apache.sis.referencing.factory.MissingFactoryResourceException; import org.apache.sis.referencing.operation.gridded.CompressedGrid; import org.apache.sis.referencing.operation.gridded.GridLoader; import org.apache.sis.referencing.operation.gridded.LoadedGrid; +import org.apache.sis.referencing.operation.gridded.GridFile; import org.apache.sis.parameter.ParameterBuilder; import org.apache.sis.parameter.Parameters; import org.apache.sis.util.CharSequences; import org.apache.sis.util.resources.Errors; import org.apache.sis.measure.Units; -import org.apache.sis.system.DataDirectory; /** @@ -142,9 +142,11 @@ public final class NADCON extends AbstractProvider { throws ParameterNotFoundException, FactoryException { final Parameters pg = Parameters.castOrWrap(values); + final GridFile latitudeShifts = new GridFile(pg, LATITUDE); + final GridFile longitudeShifts = new GridFile(pg, LONGITUDE); try { - return LoadedGrid.createGeodeticTransformation(NADCON.class, factory, - getOrLoad(pg.getMandatoryValue(LATITUDE), pg.getMandatoryValue(LONGITUDE))); + LoadedGrid<Angle,Angle> grid = getOrLoad(latitudeShifts, longitudeShifts); + return LoadedGrid.createGeodeticTransformation(NADCON.class, factory, grid); } catch (NoSuchFileException e) { throw new MissingFactoryResourceException(e.getMessage(), e); } catch (Exception e) { @@ -160,36 +162,34 @@ public final class NADCON extends AbstractProvider { * @param longitudeShifts relative or absolute path name of the grid file for longitude shifts. * @throws Exception if an error occurred while loading the grid. */ - static LoadedGrid<Angle,Angle> getOrLoad(final URI latitudeShifts, final URI longitudeShifts) + static LoadedGrid<Angle,Angle> getOrLoad(final GridFile latitudeShifts, final GridFile longitudeShifts) throws Exception { - final URI rlat = DataDirectory.DATUM_CHANGES.toAbsolutePath(latitudeShifts); - final URI rlon = DataDirectory.DATUM_CHANGES.toAbsolutePath(longitudeShifts); - return LoadedGrid.getOrLoad(rlat, rlon, () -> { + return LoadedGrid.getOrLoad(latitudeShifts, longitudeShifts, () -> { final Loader loader; - URI file = latitudeShifts; + GridFile file = latitudeShifts; // Used if an error needs to be reported. final LoadedGrid<?,?> grid; try { // Note: buffer size must be divisible by the size of `float` data type. final ByteBuffer buffer = ByteBuffer.allocate(4096).order(ByteOrder.LITTLE_ENDIAN); final FloatBuffer fb = buffer.asFloatBuffer(); - try (ReadableByteChannel in = GridLoader.newByteChannel(rlat)) { - GridLoader.startLoading(NADCON.class, CharSequences.commonPrefix( + try (ReadableByteChannel in = latitudeShifts.newByteChannel()) { + GridFile.startLoading(NADCON.class, CharSequences.commonPrefix( latitudeShifts.toString(), longitudeShifts.toString()).toString() + '…'); - loader = new Loader(in, buffer, file); + loader = new Loader(in, buffer, latitudeShifts); loader.readGrid(fb, null, longitudeShifts); } buffer.clear(); file = longitudeShifts; - try (ReadableByteChannel in = GridLoader.newByteChannel(rlon)) { - new Loader(in, buffer, file).readGrid(fb, loader, null); + try (ReadableByteChannel in = longitudeShifts.newByteChannel()) { + new Loader(in, buffer, longitudeShifts).readGrid(fb, loader, null); } } catch (IOException | NoninvertibleTransformException | RuntimeException e) { /* * Handle the exception here instead of by the caller * because we know which of the 2 files is problematic. */ - throw GridLoader.canNotLoad(NADCON.class, "NADCON", file, e); + throw file.canNotLoad(NADCON.class, "NADCON", e); } grid = CompressedGrid.compress(loader.grid, null, loader.grid.accuracy); return grid.useSharedData(); @@ -270,7 +270,7 @@ public final class NADCON extends AbstractProvider { * and have a capacity divisible by the size of the {@code float} type. * @param file path to the longitude or latitude difference file. Used for parameter declaration and error reporting. */ - Loader(final ReadableByteChannel channel, final ByteBuffer buffer, final URI file) + Loader(final ReadableByteChannel channel, final ByteBuffer buffer, final GridFile file) throws IOException, FactoryException { super(channel, buffer, file); @@ -385,7 +385,7 @@ public final class NADCON extends AbstractProvider { * @param longitudeShifts the file for the longitude grid. */ @SuppressWarnings("lossy-conversions") // Implicit cast from double to float in compound assignment. - final void readGrid(final FloatBuffer fb, final Loader latitudeShifts, final URI longitudeShifts) + final void readGrid(final FloatBuffer fb, final Loader latitudeShifts, final GridFile longitudeShifts) throws IOException, FactoryException, NoninvertibleTransformException { final int dim; @@ -401,7 +401,7 @@ public final class NADCON extends AbstractProvider { y0 != latitudeShifts.y0 || Δy != latitudeShifts.Δy || ny != latitudeShifts.ny || nz != latitudeShifts.nz) { throw new FactoryException(Errors.format(Errors.Keys.MismatchedGridGeometry_2, - latitudeShifts.file.getPath(), file.getPath())); + latitudeShifts.file.parameter.getPath(), file.parameter.getPath())); } dim = 0; // Dimension of longitudes scale = -DEGREES_TO_SECONDS * Δx; // NADCON shifts are positive west. diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NTv2.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NTv2.java index 863f795653..1d6218a3a0 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NTv2.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/NTv2.java @@ -46,6 +46,7 @@ import org.opengis.referencing.operation.NoninvertibleTransformException; import org.apache.sis.referencing.operation.gridded.CompressedGrid; import org.apache.sis.referencing.operation.gridded.GridLoader; import org.apache.sis.referencing.operation.gridded.GridGroup; +import org.apache.sis.referencing.operation.gridded.GridFile; import org.apache.sis.referencing.operation.gridded.LoadedGrid; import org.apache.sis.referencing.util.Formulas; import org.apache.sis.referencing.internal.Resources; @@ -56,7 +57,6 @@ import org.apache.sis.util.internal.Strings; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.resources.Messages; import org.apache.sis.measure.Units; -import org.apache.sis.system.DataDirectory; /** @@ -145,13 +145,12 @@ public final class NTv2 extends AbstractProvider { final MathTransformFactory factory, final ParameterValueGroup values, final int version) throws ParameterNotFoundException, FactoryException { - final Parameters pg = Parameters.castOrWrap(values); - final URI file = pg.getMandatoryValue(FILE); + final GridFile file = new GridFile(Parameters.castOrWrap(values), FILE); final LoadedGrid<Angle,Angle> grid; try { grid = getOrLoad(provider, file, version); } catch (Exception e) { - throw GridLoader.canNotLoad(provider, provider.getSimpleName(), file, e); + throw file.canNotLoad(provider, provider.getSimpleName(), e); } return LoadedGrid.createGeodeticTransformation(provider, factory, grid); } @@ -169,13 +168,12 @@ public final class NTv2 extends AbstractProvider { * @see GridLoader#canNotLoad(String, URI, Exception) */ static LoadedGrid<Angle,Angle> getOrLoad(final Class<? extends AbstractProvider> provider, - final URI file, final int version) throws Exception + final GridFile file, final int version) throws Exception { - final URI resolved = DataDirectory.DATUM_CHANGES.toAbsolutePath(file); - return LoadedGrid.getOrLoad(resolved, null, () -> { + return LoadedGrid.getOrLoad(file, null, () -> { final LoadedGrid<?,?> grid; - try (ReadableByteChannel in = GridLoader.newByteChannel(resolved)) { - GridLoader.startLoading(provider, file); + try (ReadableByteChannel in = file.newByteChannel()) { + file.startLoading(provider); final Loader loader = new Loader(in, file, version); grid = loader.readAllGrids(); loader.report(provider); @@ -318,7 +316,7 @@ public final class NTv2 extends AbstractProvider { * @param version the expected version (1 or 2). * @throws FactoryException if a data record cannot be parsed. */ - Loader(final ReadableByteChannel channel, final URI file, int version) throws IOException, FactoryException { + Loader(final ReadableByteChannel channel, final GridFile file, int version) throws IOException, FactoryException { super(channel, ByteBuffer.allocate(4096), file); header = new LinkedHashMap<>(); ensureBufferContains(RECORD_LENGTH); diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/DatumShiftTestCase.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/DatumShiftTestCase.java index 915c1bebc2..7654b5c8e7 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/DatumShiftTestCase.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/DatumShiftTestCase.java @@ -19,6 +19,7 @@ package org.apache.sis.referencing.operation.provider; import java.net.URI; import java.net.URL; import java.net.URISyntaxException; +import org.apache.sis.referencing.operation.gridded.GridFile; // Test dependencies import static org.junit.Assert.*; @@ -64,11 +65,11 @@ public abstract class DatumShiftTestCase extends TestCase { * @param name name of the resource to get. * @return the requested resources. */ - static URI getResource(final String name) throws URISyntaxException { + static GridFile getResource(final String name) throws URISyntaxException { final URL file = getResourceAsConvertibleURL(name); if (file == null) { assumeFalse("Cannot read grid data in a JAR file.", "jar".equals(file.getProtocol())); } - return file.toURI(); + return new GridFile(file.toURI()); } } diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/FranceGeocentricInterpolationTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/FranceGeocentricInterpolationTest.java index d24a15cac0..cf741ae2f2 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/FranceGeocentricInterpolationTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/FranceGeocentricInterpolationTest.java @@ -25,6 +25,7 @@ import javax.measure.quantity.Length; import org.opengis.geometry.Envelope; import org.opengis.util.FactoryException; import org.opengis.referencing.operation.TransformException; +import org.apache.sis.referencing.operation.gridded.GridFile; import org.apache.sis.referencing.operation.gridded.LoadedGrid; import org.apache.sis.referencing.operation.gridded.CompressedGrid; @@ -101,10 +102,10 @@ public final class FranceGeocentricInterpolationTest extends DatumShiftTestCase */ @Test public void testIsRecognized() throws URISyntaxException { - assertTrue (FranceGeocentricInterpolation.isRecognized(new URI("GR3DF97A.txt"))); - assertTrue (FranceGeocentricInterpolation.isRecognized(new URI("gr3df"))); - assertFalse(FranceGeocentricInterpolation.isRecognized(new URI("gr3d"))); - assertTrue (FranceGeocentricInterpolation.isRecognized(new URI(TEST_FILE))); + assertTrue (FranceGeocentricInterpolation.isRecognized(new GridFile(new URI("GR3DF97A.txt")))); + assertTrue (FranceGeocentricInterpolation.isRecognized(new GridFile(new URI("gr3df")))); + assertFalse(FranceGeocentricInterpolation.isRecognized(new GridFile(new URI("gr3d")))); + assertTrue (FranceGeocentricInterpolation.isRecognized(new GridFile(new URI(TEST_FILE)))); } /** @@ -144,9 +145,9 @@ public final class FranceGeocentricInterpolationTest extends DatumShiftTestCase private static LoadedGrid<Angle,Length> testGridAsFloats() throws URISyntaxException, IOException, FactoryException, TransformException { - final URI file = getResource(TEST_FILE); + final GridFile file = getResource(TEST_FILE); final LoadedGrid.Float<Angle,Length> grid; - try (BufferedReader in = FranceGeocentricInterpolation.Loader.newBufferedReader(file)) { + try (BufferedReader in = file.newBufferedReader()) { grid = FranceGeocentricInterpolation.Loader.load(in, file); } assertEquals("cellPrecision", 0.005, grid.getCellPrecision(), STRICT); diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/NADCONTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/NADCONTest.java index 374aa14b37..e6179f07ee 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/NADCONTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/NADCONTest.java @@ -25,8 +25,9 @@ import java.nio.file.Files; import javax.measure.quantity.Angle; import org.opengis.geometry.Envelope; import org.opengis.referencing.operation.TransformException; -import org.apache.sis.referencing.operation.gridded.LoadedGrid; +import org.apache.sis.referencing.operation.gridded.GridFile; import org.apache.sis.referencing.operation.gridded.GridLoader; +import org.apache.sis.referencing.operation.gridded.LoadedGrid; import org.apache.sis.referencing.operation.matrix.Matrix3; import org.apache.sis.geometry.Envelope2D; import org.apache.sis.geometry.Envelopes; @@ -120,7 +121,7 @@ public final class NADCONTest extends DatumShiftTestCase { * @param longitudeShifts path to the official {@code "conus.los"} file. * @throws Exception if an error occurred while loading or computing the grid, or while testing transformations. */ - public static void testNADCON(final URI latitudeShifts, final URI longitudeShifts) throws Exception { + public static void testNADCON(final GridFile latitudeShifts, final GridFile longitudeShifts) throws Exception { testNADCON(latitudeShifts, longitudeShifts, -131, -63, 20, 50); } @@ -132,7 +133,7 @@ public final class NADCONTest extends DatumShiftTestCase { * @param ymin southmost latitude. * @param ymax northmost latitude. */ - private static void testNADCON(final URI latitudeShifts, final URI longitudeShifts, + private static void testNADCON(final GridFile latitudeShifts, final GridFile longitudeShifts, final double xmin, final double xmax, final double ymin, final double ymax) throws Exception { diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/NTv2Test.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/NTv2Test.java index b28c08f035..0d803d1d5c 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/NTv2Test.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/NTv2Test.java @@ -28,14 +28,16 @@ import java.nio.charset.StandardCharsets; import javax.measure.quantity.Angle; import org.opengis.geometry.Envelope; import org.opengis.referencing.operation.TransformException; -import org.apache.sis.referencing.operation.gridded.LoadedGrid; +import org.apache.sis.referencing.util.Formulas; +import org.apache.sis.referencing.operation.matrix.Matrix3; +import org.apache.sis.referencing.operation.gridded.GridFile; import org.apache.sis.referencing.operation.gridded.GridGroup; +import org.apache.sis.referencing.operation.gridded.LoadedGrid; import static org.apache.sis.referencing.operation.gridded.GridLoader.DEGREES_TO_SECONDS; -import org.apache.sis.referencing.operation.matrix.Matrix3; import org.apache.sis.geometry.Envelope2D; import org.apache.sis.geometry.Envelopes; import org.apache.sis.measure.Units; -import org.apache.sis.referencing.util.Formulas; +import org.apache.sis.parameter.Parameters; import org.apache.sis.system.DataDirectory; // Test dependencies @@ -109,7 +111,7 @@ public final class NTv2Test extends DatumShiftTestCase { * @param file path to the official {@code "NTF_R93.gsb"} file. * @throws Exception if an error occurred while loading or computing the grid, or while testing transformations. */ - public static void testRGF93(final URI file) throws Exception { + public static void testRGF93(final GridFile file) throws Exception { testRGF93(file, -19800, 36000, 147600, 187200); } @@ -121,7 +123,7 @@ public final class NTv2Test extends DatumShiftTestCase { * @param ymin value of the {@code "S_LAT"} record. * @param ymax value of the {@code "N_LAT"} record. */ - private static void testRGF93(final URI file, final double xmin, final double xmax, + private static void testRGF93(final GridFile file, final double xmin, final double xmax, final double ymin, final double ymax) throws Exception { final double cellSize = 360; @@ -188,8 +190,11 @@ public final class NTv2Test extends DatumShiftTestCase { public void testMultiGrids() throws Exception { assumeTrue(RUN_EXTENSIVE_TESTS); assumeTrue(DataDirectory.getenv() != null); - final URI file = DataDirectory.DATUM_CHANGES.toAbsolutePath(new URI(MULTIGRID_TEST_FILE)); - assumeTrue(Files.exists(Path.of(file))); + final Parameters pg = Parameters.castOrWrap(new NTv2().getParameters().createValue()); + pg.getOrCreate(NTv2.FILE).setValue(new URI(MULTIGRID_TEST_FILE)); + final GridFile file = new GridFile(pg, NTv2.FILE); + assumeTrue(Files.exists(Path.of(file.resolved()))); + final LoadedGrid<Angle,Angle> grid = NTv2.getOrLoad(NTv2.class, file, 2); assertInstanceOf("Should contain many grids.", GridGroup.class, grid); assertEquals("coordinateUnit", Units.ARC_SECOND, grid.getCoordinateUnit()); diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/DatumShiftTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/DatumShiftTest.java index e5d186752b..1fc24344a2 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/DatumShiftTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/DatumShiftTest.java @@ -18,6 +18,7 @@ package org.apache.sis.test.integration; import java.net.URI; import org.apache.sis.system.DataDirectory; +import org.apache.sis.referencing.operation.gridded.GridFile; // Test dependencies import org.junit.Test; @@ -57,7 +58,7 @@ public final class DatumShiftTest extends TestCase { @Test public void testRGF93() throws Exception { final URI file = assumeDataExists(DataDirectory.DATUM_CHANGES, "ntf_r93.gsb"); - NTv2Test.testRGF93(file); + NTv2Test.testRGF93(new GridFile(file)); } /** @@ -70,6 +71,6 @@ public final class DatumShiftTest extends TestCase { public void testNADCON() throws Exception { final URI latitudeShifts = assumeDataExists(DataDirectory.DATUM_CHANGES, "conus.las"); final URI longitudeShifts = assumeDataExists(DataDirectory.DATUM_CHANGES, "conus.los"); - NADCONTest.testNADCON(latitudeShifts, longitudeShifts); + NADCONTest.testNADCON(new GridFile(latitudeShifts), new GridFile(longitudeShifts)); } } diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/DataDirectory.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/DataDirectory.java index 81daa118a4..025851083c 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/DataDirectory.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/DataDirectory.java @@ -21,12 +21,10 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.InvalidPathException; -import java.nio.file.NoSuchFileException; import java.util.logging.Level; import java.util.logging.LogRecord; import org.apache.sis.util.logging.Logging; import org.apache.sis.util.internal.Strings; -import org.apache.sis.util.resources.Errors; import org.apache.sis.util.resources.Messages; @@ -238,7 +236,7 @@ public enum DataDirectory { * * @return the sub-directory, or {@code null} if unspecified. */ - private synchronized URI getDirectoryAsURI() { + public final synchronized URI getDirectoryAsURI() { if (directoryAsURI == null) { @SuppressWarnings("LocalVariableHidesMemberVariable") final Path directory = getDirectory(); @@ -252,36 +250,4 @@ public enum DataDirectory { } return directoryAsURI; } - - /** - * Returns the given URI as an absolute URI, resolved with this {@code DataDirectory} if the URI is relative. - * If the URI cannot be made absolute, a {@link NoSuchFileException} is thrown. This is necessary for letting - * the caller know that a coordinate operation is probably valid but cannot be constructed because an optional - * configuration is missing. It is typically because the {@code SIS_DATA} environment variable has not been set. - * - * @param path the URI to make absolute. - * @return an absolute URI to the data. - * @throws NoSuchFileException if the path cannot be made absolute. - */ - public final URI toAbsolutePath(URI path) throws NoSuchFileException { - final URI base = getDirectoryAsURI(); - if (base != null) { - path = base.resolve(path); - } - if (path.isAbsolute()) { - return path; - } - final String message; - if (path.isOpaque()) { - message = Errors.format(Errors.Keys.CanNotOpen_1, path); - } else { - final String env = getenv(); - if (env == null) { - message = Messages.format(Messages.Keys.DataDirectoryNotSpecified_1, ENV); - } else { - message = Messages.format(Messages.Keys.DataDirectoryNotAccessible_2, ENV, env); - } - } - throw new NoSuchFileException(path.toString(), null, message); - } }