You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2023/12/27 21:12:03 UTC
(sis) 02/04: When parsing a GML or WKT from a URI, store the URI on a new `DefaultParameterValue.sourceFile` property. This information allows to resolve `ParameterValue.valueFile` relatively to the source document.
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 9beb499ee7bfed73abfcde27e63b4db74a4f62a1
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Dec 27 16:17:41 2023 +0100
When parsing a GML or WKT from a URI, store the URI on a new `DefaultParameterValue.sourceFile` property.
This information allows to resolve `ParameterValue.valueFile` relatively to the source document.
https://issues.apache.org/jira/browse/SIS-593
---
.../apache/sis/xml/util/ExternalLinkHandler.java | 3 +-
.../main/org/apache/sis/io/wkt/AbstractParser.java | 23 ++-
.../apache/sis/io/wkt/GeodeticObjectParser.java | 11 +-
.../org/apache/sis/io/wkt/MathTransformParser.java | 20 ++-
.../main/org/apache/sis/io/wkt/Parser.java | 4 +-
.../main/org/apache/sis/io/wkt/WKTFormat.java | 129 ++++++++++------
.../sis/parameter/AbstractParameterDescriptor.java | 13 +-
.../sis/parameter/DefaultParameterDescriptor.java | 15 +-
.../parameter/DefaultParameterDescriptorGroup.java | 15 +-
.../sis/parameter/DefaultParameterValue.java | 171 ++++++++++++++++-----
.../sis/parameter/UnmodifiableParameterValue.java | 10 ++
.../org/apache/sis/parameter/package-info.java | 2 +-
.../main/org/apache/sis/referencing/CRS.java | 7 +-
.../referencing/factory/GeodeticObjectFactory.java | 8 +-
.../transform/DefaultMathTransformFactory.java | 8 +-
.../test/org/apache/sis/io/wkt/ElementTest.java | 4 +-
.../sis/io/wkt/GeodeticObjectParserTest.java | 4 +-
.../org/apache/sis/storage/base/PRJDataStore.java | 21 ++-
18 files changed, 315 insertions(+), 153 deletions(-)
diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/ExternalLinkHandler.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/ExternalLinkHandler.java
index 6bd949f064..6bb7082bc7 100644
--- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/ExternalLinkHandler.java
+++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/util/ExternalLinkHandler.java
@@ -132,7 +132,7 @@ public class ExternalLinkHandler {
if (b == null) {
return null;
}
- final URI baseURI;
+ URI baseURI;
if (b instanceof URI) { // `instanceof` check of final classes are efficient.
baseURI = (URI) b;
} else {
@@ -151,6 +151,7 @@ public class ExternalLinkHandler {
warningOccured(b, e);
return null;
}
+ baseURI = baseURI.normalize();
base = baseURI;
}
return baseURI;
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/AbstractParser.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/AbstractParser.java
index 439d33516c..03b137c7b2 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/AbstractParser.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/AbstractParser.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.io.wkt;
+import java.net.URI;
import java.util.Map;
import java.util.List;
import java.util.Date;
@@ -35,11 +36,10 @@ import org.opengis.util.FactoryException;
import org.opengis.util.InternationalString;
import org.apache.sis.system.Loggers;
import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.internal.StandardDateFormat;
import org.apache.sis.measure.Units;
import org.apache.sis.measure.UnitFormat;
-import org.apache.sis.util.resources.Errors;
-import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
/**
@@ -83,6 +83,13 @@ abstract class AbstractParser implements Parser {
*/
static final int MANDATORY = 2;
+ /**
+ * The URI to declare as the source of the WKT definitions, or {@code null} if unknown.
+ * This information is not used directly by the parser, but will be stored in parameter values
+ * as a hint for resolving relative paths as absolute paths.
+ */
+ final URI sourceFile;
+
/**
* The locale for formatting error messages if parsing fails, or {@code null} for system default.
* This is <strong>not</strong> the locale for parsing number or date values.
@@ -151,22 +158,24 @@ abstract class AbstractParser implements Parser {
/**
* Constructs a parser using the specified set of symbols.
*
- * @param symbols the set of symbols to use.
+ * @param sourceFile URI to declare as the source of the WKT definitions, or {@code null} if unknown.
* @param fragments reference to the {@link WKTFormat#fragments} map, or an empty map if none.
+ * @param symbols the set of symbols to use. Cannot be null.
* @param numberFormat the number format provided by {@link WKTFormat}, or {@code null} for a default format.
* @param dateFormat the date format provided by {@link WKTFormat}, or {@code null} for a default format.
* @param unitFormat the unit format provided by {@link WKTFormat}, or {@code null} for a default format.
* @param errorLocale the locale for error messages (not for parsing), or {@code null} for the system default.
*/
- AbstractParser(final Symbols symbols, final Map<String,StoredTree> fragments, NumberFormat numberFormat,
- final DateFormat dateFormat, final UnitFormat unitFormat, final Locale errorLocale)
+ AbstractParser(final URI sourceFile, final Map<String,StoredTree> fragments, final Symbols symbols,
+ NumberFormat numberFormat, final DateFormat dateFormat, final UnitFormat unitFormat,
+ final Locale errorLocale)
{
- ensureNonNull("symbols", symbols);
if (numberFormat == null) {
numberFormat = symbols.createNumberFormat();
}
- this.symbols = symbols;
+ this.sourceFile = sourceFile;
this.fragments = fragments;
+ this.symbols = symbols;
this.dateFormat = dateFormat;
this.unitFormat = unitFormat;
this.errorLocale = errorLocale;
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
index 1610727a53..be411c60d7 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.io.wkt;
+import java.net.URI;
import java.util.Map;
import java.util.List;
import java.util.Locale;
@@ -94,6 +95,7 @@ import org.apache.sis.util.iso.Types;
* @author Martin Desruisseaux (IRD, Geomatys)
* @author Johann Sorel (Geomatys)
*/
+@SuppressWarnings("LocalVariableHidesMemberVariable") // We hide with the same value made final.
class GeodeticObjectParser extends MathTransformParser implements Comparator<CoordinateSystemAxis> {
/*
* Force class initialization of `AxisDirections` in order to have
@@ -182,7 +184,7 @@ class GeodeticObjectParser extends MathTransformParser implements Comparator<Coo
public GeodeticObjectParser(final Map<String,?> defaultProperties,
final ObjectFactory factories, final MathTransformFactory mtFactory)
{
- super(Symbols.getDefault(), Collections.emptyMap(), null, null, null,
+ super(null, Collections.emptyMap(), Symbols.getDefault(), null, null, null,
new ReferencingFactoryContainer(defaultProperties,
(CRSFactory) factories,
(CSFactory) factories,
@@ -198,8 +200,9 @@ class GeodeticObjectParser extends MathTransformParser implements Comparator<Coo
* Constructs a parser for the specified set of symbols using the specified set of factories.
* This constructor is for {@link WKTFormat} usage only.
*
- * @param symbols the set of symbols to use.
+ * @param sourceFile URI to declare as the source of the WKT definitions, or {@code null} if unknown.
* @param fragments reference to the {@link WKTFormat#fragments} map, or an empty map if none.
+ * @param symbols the set of symbols to use. Cannot be null.
* @param numberFormat the number format provided by {@link WKTFormat}, or {@code null} for a default format.
* @param dateFormat the date format provided by {@link WKTFormat}, or {@code null} for a default format.
* @param unitFormat the unit format provided by {@link WKTFormat}, or {@code null} for a default format.
@@ -207,12 +210,12 @@ class GeodeticObjectParser extends MathTransformParser implements Comparator<Coo
* @param errorLocale the locale for error messages (not for parsing), or {@code null} for the system default.
* @param factories on input, the factories to use. On output, the factories used. Can be null.
*/
- GeodeticObjectParser(final Symbols symbols, final Map<String,StoredTree> fragments,
+ GeodeticObjectParser(final URI sourceFile, final Map<String,StoredTree> fragments, final Symbols symbols,
final NumberFormat numberFormat, final DateFormat dateFormat, final UnitFormat unitFormat,
final Convention convention, final Transliterator transliterator, final Locale errorLocale,
final ReferencingFactoryContainer factories)
{
- super(symbols, fragments, numberFormat, dateFormat, unitFormat, factories, errorLocale);
+ super(sourceFile, fragments, symbols, numberFormat, dateFormat, unitFormat, factories, errorLocale);
this.transliterator = transliterator;
usesCommonUnits = convention.usesCommonUnits;
ignoreAxes = convention == Convention.WKT1_IGNORE_AXES;
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/MathTransformParser.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/MathTransformParser.java
index 1afebc6c84..af4f45d5d5 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/MathTransformParser.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/MathTransformParser.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.io.wkt;
+import java.net.URI;
import java.util.Map;
import java.util.Arrays;
import java.util.Locale;
@@ -40,13 +41,13 @@ import org.opengis.referencing.operation.OperationMethod;
import org.apache.sis.referencing.util.CoordinateOperations;
import org.apache.sis.referencing.util.ReferencingFactoryContainer;
import org.apache.sis.referencing.util.WKTKeywords;
+import org.apache.sis.parameter.DefaultParameterValue;
import org.apache.sis.util.Numbers;
+import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.internal.Constants;
import org.apache.sis.math.DecimalFunctions;
import org.apache.sis.measure.UnitFormat;
import org.apache.sis.measure.Units;
-import org.apache.sis.util.resources.Errors;
-import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
/**
@@ -134,28 +135,28 @@ class MathTransformParser extends AbstractParser {
* @param mtFactory the factory to use for creating {@link MathTransform} objects.
*/
public MathTransformParser(final MathTransformFactory mtFactory) {
- this(Symbols.getDefault(), Map.of(), null, null, null,
+ this(null, Map.of(), Symbols.getDefault(), null, null, null,
new ReferencingFactoryContainer(null, null, null, null, null, mtFactory), null);
}
/**
* Creates a parser using the specified set of symbols and factories.
*
- * @param symbols the set of symbols to use.
+ * @param sourceFile URI to declare as the source of the WKT definitions, or {@code null} if unknown.
* @param fragments reference to the {@link WKTFormat#fragments} map, or an empty map if none.
+ * @param symbols the set of symbols to use. Cannot be null.
* @param numberFormat the number format provided by {@link WKTFormat}, or {@code null} for a default format.
* @param dateFormat the date format provided by {@link WKTFormat}, or {@code null} for a default format.
* @param unitFormat the unit format provided by {@link WKTFormat}, or {@code null} for a default format.
* @param factories the factories to use for creating math transforms and geodetic objects.
* @param errorLocale the locale for error messages (not for parsing), or {@code null} for the system default.
*/
- MathTransformParser(final Symbols symbols, final Map<String,StoredTree> fragments,
+ MathTransformParser(final URI sourceFile, final Map<String,StoredTree> fragments, final Symbols symbols,
final NumberFormat numberFormat, final DateFormat dateFormat, final UnitFormat unitFormat,
final ReferencingFactoryContainer factories, final Locale errorLocale)
{
- super(symbols, fragments, numberFormat, dateFormat, unitFormat, errorLocale);
+ super(sourceFile, fragments, symbols, numberFormat, dateFormat, unitFormat, errorLocale);
this.factories = factories;
- ensureNonNull("factories", factories);
}
/**
@@ -347,7 +348,7 @@ class MathTransformParser extends AbstractParser {
final Unit<?> defaultSI = (defaultUnit != null) ? defaultUnit.getSystemUnit() : null;
Element param = element;
try {
- while ((param = element.pullElement(OPTIONAL, WKTKeywords.Parameter)) != null) {
+ while ((param = element.pullElement(OPTIONAL, WKTKeywords.Parameter, WKTKeywords.ParameterFile)) != null) {
final String name = param.pullString("name");
Unit<?> unit = parseUnit(param);
param.pullElement(OPTIONAL, ID_KEYWORDS);
@@ -386,6 +387,9 @@ class MathTransformParser extends AbstractParser {
} else {
parameter.setValue(param.pullString("stringValue"));
}
+ if (sourceFile != null && parameter instanceof DefaultParameterValue<?>) {
+ ((DefaultParameterValue<?>) parameter).setSourceFile(sourceFile);
+ }
param.close(ignoredElements);
}
} catch (ParameterNotFoundException e) {
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Parser.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Parser.java
index eee7b89b1c..1076ef12cc 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Parser.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Parser.java
@@ -60,9 +60,9 @@ public interface Parser {
* For processing warnings in a different way than logging them, one can use
* {@link WKTFormat#parseObject(String)} followed by a call to {@link WKTFormat#getWarnings()}.
*
- * @param text object encoded in Well-Known Text format (version 1 or 2).
+ * @param wkt object encoded in Well-Known Text format (version 1 or 2).
* @return the result of parsing the given text.
* @throws FactoryException if the object creation failed.
*/
- Object createFromWKT(String text) throws FactoryException;
+ Object createFromWKT(String wkt) throws FactoryException;
}
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/WKTFormat.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/WKTFormat.java
index cc7047cc0f..8fcc5b6679 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/WKTFormat.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/WKTFormat.java
@@ -25,10 +25,12 @@ import java.util.HashMap;
import java.util.TreeMap;
import java.util.List;
import java.util.ArrayList;
+import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogRecord;
import java.util.function.Function;
+import java.net.URI;
import java.io.IOException;
import java.text.Format;
import java.text.NumberFormat;
@@ -119,7 +121,7 @@ import org.opengis.metadata.Identifier;
*
* @author Martin Desruisseaux (Geomatys)
* @author Rémi Eve (IRD)
- * @version 1.4
+ * @version 1.5
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
* @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
@@ -236,6 +238,15 @@ public class WKTFormat extends CompoundFormat<Object> {
*/
private TreeMap<String,StoredTree> fragments;
+ /**
+ * The URI to declare as the source of the WKT definitions, or {@code null} if unknown.
+ * This information is not used directly by the parser, but will be stored in parameter values
+ * as a hint for resolving relative paths as absolute paths.
+ *
+ * @see #getSourceFile()
+ */
+ private URI sourceFile;
+
/**
* {@code true} if the {@link #fragments} map is shared by two or more {@code WKTFormat} instances.
* In such case, the map shall not be modified; instead it must be copied before any modification.
@@ -386,12 +397,11 @@ public class WKTFormat extends CompoundFormat<Object> {
/**
* Sets the symbols used for parsing and formatting WKT.
*
- * @param symbols the new set of symbols to use for parsing and formatting WKT.
+ * @param style the new set of symbols to use for parsing and formatting WKT.
*/
- public void setSymbols(final Symbols symbols) {
- ArgumentChecks.ensureNonNull("symbols", symbols);
- if (!symbols.equals(this.symbols)) {
- this.symbols = symbols.immutable();
+ public void setSymbols(final Symbols style) {
+ if (!style.equals(symbols)) { // Intentional NullPointerException.
+ symbols = style.immutable();
formatter = null;
parser = null;
}
@@ -428,13 +438,13 @@ public class WKTFormat extends CompoundFormat<Object> {
* then the default mapper is {@link Transliterator#DEFAULT} except for WKT formatted according
* the {@linkplain Convention#INTERNAL internal convention}.</p>
*
- * @param transliterator the new mapper to use, or {@code null} for restoring the default value.
+ * @param map the new mapper to use, or {@code null} for restoring the default value.
*
* @since 0.6
*/
- public void setTransliterator(final Transliterator transliterator) {
- if (this.transliterator != transliterator) {
- this.transliterator = transliterator;
+ public void setTransliterator(final Transliterator map) {
+ if (transliterator != map) {
+ transliterator = map;
updateFormatter(formatter);
parser = null;
}
@@ -452,11 +462,10 @@ public class WKTFormat extends CompoundFormat<Object> {
/**
* Sets whether WKT keywords should be written with upper cases or camel cases.
*
- * @param keywordCase the case to use for formatting keywords.
+ * @param style the case to use for formatting keywords.
*/
- public void setKeywordCase(final KeywordCase keywordCase) {
- ArgumentChecks.ensureNonNull("keywordCase", keywordCase);
- this.keywordCase = keywordCase;
+ public void setKeywordCase(final KeywordCase style) {
+ keywordCase = Objects.requireNonNull(style);
updateFormatter(formatter);
}
@@ -474,13 +483,12 @@ public class WKTFormat extends CompoundFormat<Object> {
/**
* Sets whether to use short or long WKT keywords.
*
- * @param keywordStyle the style to use for formatting keywords.
+ * @param style the style to use for formatting keywords.
*
* @since 0.6
*/
- public void setKeywordStyle(final KeywordStyle keywordStyle) {
- ArgumentChecks.ensureNonNull("keywordStyle", keywordStyle);
- this.keywordStyle = keywordStyle;
+ public void setKeywordStyle(final KeywordStyle style) {
+ keywordStyle = Objects.requireNonNull(style);
updateFormatter(formatter);
}
@@ -505,13 +513,13 @@ public class WKTFormat extends CompoundFormat<Object> {
* method tries to highlight most of the elements that are relevant to
* {@link org.apache.sis.util.Utilities#equalsIgnoreMetadata(Object, Object)}.</p>
*
- * @param colors the colors for syntax coloring, or {@code null} if none.
+ * @param emphasis the colors for syntax coloring, or {@code null} if none.
*/
- public void setColors(Colors colors) {
- if (colors != null) {
- colors = colors.immutable();
+ public void setColors(Colors emphasis) {
+ if (emphasis != null) {
+ emphasis = emphasis.immutable();
}
- this.colors = colors;
+ colors = emphasis;
updateFormatter(formatter);
}
@@ -528,12 +536,11 @@ public class WKTFormat extends CompoundFormat<Object> {
/**
* Sets the convention for parsing and formatting WKT elements.
*
- * @param convention the new convention to use for parsing and formatting WKT elements.
+ * @param variant the new convention to use for parsing and formatting WKT elements.
*/
- public void setConvention(final Convention convention) {
- ArgumentChecks.ensureNonNull("convention", convention);
- if (this.convention != convention) {
- this.convention = convention;
+ public void setConvention(final Convention variant) {
+ if (convention != variant) {
+ convention = Objects.requireNonNull(variant);
updateFormatter(formatter);
parser = null;
}
@@ -625,13 +632,13 @@ public class WKTFormat extends CompoundFormat<Object> {
* Sets a new indentation to be used for formatting objects.
* The {@value #SINGLE_LINE} value means that the whole WKT is to be formatted on a single line.
*
- * @param indentation the new indentation to use.
+ * @param numSpaces the new indentation to use in number of spaces.
*
* @see org.apache.sis.setup.OptionKey#INDENTATION
*/
- public void setIndentation(final int indentation) {
- ArgumentChecks.ensureBetween("indentation", SINGLE_LINE, Byte.MAX_VALUE, indentation);
- this.indentation = (byte) indentation;
+ public void setIndentation(final int numSpaces) {
+ ArgumentChecks.ensureBetween("indentation", SINGLE_LINE, Byte.MAX_VALUE, numSpaces);
+ indentation = (byte) numSpaces;
updateFormatter(formatter);
}
@@ -658,7 +665,7 @@ public class WKTFormat extends CompoundFormat<Object> {
* @since 1.0
*/
public void setMaximumListElements(final int limit) {
- ArgumentChecks.ensureStrictlyPositive("limit", limit);
+ ArgumentChecks.ensureStrictlyPositive("listSizeLimit", limit);
listSizeLimit = limit;
updateFormatter(formatter);
}
@@ -668,7 +675,7 @@ public class WKTFormat extends CompoundFormat<Object> {
* explicit {@code ID[…]} or {@code AUTHORITY[…]} element. The main use case is for implementing
* a {@link org.opengis.referencing.crs.CRSAuthorityFactory} backed by definitions in WKT format.
*
- * <p>Note that this identifier apply to all objects to be created, which is generally not desirable.
+ * <p>Note that this identifier applies to all objects to be created, which is generally not desirable.
* Callers should invoke {@code setDefaultIdentifier(null)} in a {@code finally} block.</p>
*
* <p>This is not a publicly committed API. If we want to make this functionality public in a future
@@ -747,9 +754,47 @@ public class WKTFormat extends CompoundFormat<Object> {
}
}
+ /**
+ * Returns the URI to declare as the source of the WKT definitions. This value is not used directly by the parser,
+ * but stored as a hint for allowing users to interpret the {@code PARAMETERFILE[…]} value as a file relative to
+ * the file containing the WKT. The default value is {@code null}.
+ *
+ * @return the URI to declare as the source of the WKT definitions, or {@code null} if none.
+ *
+ * @see #setSourceFile(URI)
+ * @see org.apache.sis.parameter.DefaultParameterValue#getSourceFile()
+ * @see org.apache.sis.xml.MarshalContext#getDocumentURI()
+ * @see URI#resolve(URI)
+ *
+ * @since 1.5
+ */
+ public URI getSourceFile() {
+ return sourceFile;
+ }
+
+ /**
+ * Sets the URI to declare as the source of the WKT definitions. This information will be stored in
+ * {@link org.apache.sis.parameter.DefaultParameterValue#getSourceFile()} at WKT parsing time as a
+ * hint for resolving relative paths as absolute paths. This value has no effect at formatting time.
+ *
+ * @param document URI to the file that contains the WKT definitions to parse, or {@code null} if none.
+ *
+ * @see #getSourceFile()
+ * @see org.apache.sis.parameter.DefaultParameterValue#setSourceFile(URI)
+ * @see URI#resolve(URI)
+ *
+ * @since 1.5
+ */
+ public void setSourceFile(final URI document) {
+ if (!Objects.equals(sourceFile, document)) {
+ sourceFile = document;
+ parser = null;
+ }
+ }
+
/**
* Returns the type of objects formatted by this class. This method has to return {@code Object.class}
- * since it is the only common parent to all object types accepted by this formatter.
+ * because it is the only common parent to all object types accepted by this formatter.
*
* @return {@code Object.class}
*/
@@ -947,14 +992,12 @@ public class WKTFormat extends CompoundFormat<Object> {
* @param modifiable whether the caller intents to modify the {@link #fragments} map.
*/
private AbstractParser parser(final boolean modifiable) {
- @SuppressWarnings("LocalVariableHidesMemberVariable")
- AbstractParser parser = this.parser;
/*
* `parser` is always null on a fresh clone. However, the `fragments`
* map may need to be cloned if the caller intents to modify it.
*/
if (parser == null || (isCloned & modifiable)) {
- this.parser = parser = new Parser(symbols, fragments(modifiable),
+ parser = new Parser(sourceFile, fragments(modifiable), symbols,
(NumberFormat) getFormat(Number.class),
(DateFormat) getFormat(Date.class),
(UnitFormat) getFormat(Unit.class),
@@ -973,12 +1016,12 @@ public class WKTFormat extends CompoundFormat<Object> {
*/
private final class Parser extends GeodeticObjectParser implements Function<Object,Object> {
/** Creates a new parser. */
- Parser(final Symbols symbols, final Map<String,StoredTree> fragments,
- final NumberFormat numberFormat, final DateFormat dateFormat, final UnitFormat unitFormat,
- final Convention convention, final Transliterator transliterator, final Locale errorLocale,
- final ReferencingFactoryContainer factories)
+ Parser(final URI sourceFile, final Map<String,StoredTree> fragments, final Symbols symbols,
+ final NumberFormat numberFormat, final DateFormat dateFormat, final UnitFormat unitFormat,
+ final Convention convention, final Transliterator transliterator, final Locale errorLocale,
+ final ReferencingFactoryContainer factories)
{
- super(symbols, fragments, numberFormat, dateFormat, unitFormat, convention, transliterator, errorLocale, factories);
+ super(sourceFile, fragments, symbols, numberFormat, dateFormat, unitFormat, convention, transliterator, errorLocale, factories);
}
/** Returns the source class and method to declare in log records. */
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/AbstractParameterDescriptor.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/AbstractParameterDescriptor.java
index 8d8a015c42..9f89555788 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/AbstractParameterDescriptor.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/AbstractParameterDescriptor.java
@@ -52,8 +52,7 @@ import static org.apache.sis.util.Utilities.deepEquals;
* <th class="sep">WPS</th>
* <th class="sep">ISO 19115</th>
* <th class="sep">Remarks</th>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@link #getName() getName()}</td>
* <td class="sep">{@code name}</td>
* <td class="sep">{@code Identifier}</td>
@@ -67,22 +66,19 @@ import static org.apache.sis.util.Utilities.deepEquals;
* <td class="sep">{@code Abstract}</td>
* <td class="sep">{@code description}</td>
* <td class="sep">Also known as “definition”.</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@link #getDirection()}</td>
* <td class="sep"></td>
* <td class="sep"></td>
* <td class="sep">{@code direction}</td>
* <td class="sep">Tells if the parameter is a WPS {@code Input} or {@code Output} structure.</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@link #getMinimumOccurs()}</td>
* <td class="sep">{@code minimumOccurs}</td>
* <td class="sep">{@code MinOccurs}</td>
* <td class="sep">{@code optionality}</td>
* <td class="sep">{@code optionality = (minimumOccurs > 0)}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@link #getMaximumOccurs()}</td>
* <td class="sep">{@code maximumOccurs}</td>
* <td class="sep">{@code MaxOccurs}</td>
@@ -171,6 +167,7 @@ public abstract class AbstractParameterDescriptor extends AbstractIdentifiedObje
* @param maximumOccurs the {@linkplain #getMaximumOccurs() maximum number of times} that values
* for this parameter group are required, or {@link Integer#MAX_VALUE} if no restriction.
*/
+ @SuppressWarnings("this-escape")
protected AbstractParameterDescriptor(final Map<String,?> properties,
final int minimumOccurs, final int maximumOccurs)
{
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterDescriptor.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterDescriptor.java
index c0d020d969..17ae032cbb 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterDescriptor.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterDescriptor.java
@@ -137,28 +137,23 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
* <th>Property name</th>
* <th>Value type</th>
* <th>Returned by</th>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
* <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
* <td>{@link #getName()}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#ALIAS_KEY}</td>
* <td>{@link org.opengis.util.GenericName} or {@link CharSequence} (optionally as array)</td>
* <td>{@link #getAlias()}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
* <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
* <td>{@link #getIdentifiers()}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.metadata.Identifier#DESCRIPTION_KEY}</td>
* <td>{@link org.opengis.util.InternationalString} or {@link String}</td>
* <td>{@link #getDescription()}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td>
* <td>{@link org.opengis.util.InternationalString} or {@link String}</td>
* <td>{@link #getRemarks()}</td>
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
index aa17f0fcdf..472656654e 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
@@ -122,28 +122,23 @@ public class DefaultParameterDescriptorGroup extends AbstractParameterDescriptor
* <th>Property name</th>
* <th>Value type</th>
* <th>Returned by</th>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
* <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
* <td>{@link #getName()}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#ALIAS_KEY}</td>
* <td>{@link org.opengis.util.GenericName} or {@link CharSequence} (optionally as array)</td>
* <td>{@link #getAlias()}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
* <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
* <td>{@link #getIdentifiers()}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.metadata.Identifier#DESCRIPTION_KEY}</td>
* <td>{@link org.opengis.util.InternationalString} or {@link String}</td>
* <td>{@link #getDescription()}</td>
- * </tr>
- * <tr>
+ * </tr><tr>
* <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td>
* <td>{@link org.opengis.util.InternationalString} or {@link String}</td>
* <td>{@link #getRemarks()}</td>
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 d9817c7107..7cdc01b585 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
@@ -18,6 +18,7 @@ package org.apache.sis.parameter;
import java.lang.reflect.Array;
import java.util.Objects;
+import java.util.Optional;
import java.util.logging.Logger;
import java.io.Serializable;
import java.io.File;
@@ -41,37 +42,38 @@ import org.apache.sis.io.wkt.FormattableObject;
import org.apache.sis.io.wkt.Formatter;
import org.apache.sis.io.wkt.Convention;
import org.apache.sis.io.wkt.ElementKind;
+import org.apache.sis.xml.bind.Context;
import org.apache.sis.xml.bind.gml.Measure;
import org.apache.sis.xml.bind.gml.MeasureList;
+import org.apache.sis.xml.util.ExternalLinkHandler;
+import org.apache.sis.metadata.internal.ImplementationHelper;
import org.apache.sis.referencing.internal.Resources;
import org.apache.sis.referencing.util.WKTUtilities;
import org.apache.sis.referencing.util.WKTKeywords;
-import org.apache.sis.metadata.internal.ImplementationHelper;
-import org.apache.sis.util.Numbers;
+import org.apache.sis.math.DecimalFunctions;
+import org.apache.sis.system.Loggers;
+import org.apache.sis.util.Utilities;
+import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.LenientComparable;
import org.apache.sis.util.ObjectConverters;
import org.apache.sis.util.UnconvertibleObjectException;
+import org.apache.sis.util.Numbers;
import org.apache.sis.util.internal.Numerics;
-import org.apache.sis.system.Loggers;
-import org.apache.sis.math.DecimalFunctions;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.logging.Logging;
-import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-import static org.apache.sis.util.Utilities.deepEquals;
/**
- * A single parameter value used by an operation method. {@code ParameterValue} instances are elements in
- * a {@linkplain DefaultParameterValueGroup parameter value group}, in a way similar to {@code Map.Entry}
- * instances in a {@code java.util.Map}.
- *
- * <p>In the context of coordinate operations, most parameter values are numeric and can be obtained by the
+ * A single parameter value used by an operation method. Each {@code ParameterValue} is a
+ * (<var>key</var>, <var>value</var>) pair, and an arbitrary number of those pairs can be
+ * stored in a a {@linkplain DefaultParameterValueGroup parameter value group}.
+ * In the context of coordinate operations, parameter values are often numeric and can be obtained by the
* {@link #intValue()} or {@link #doubleValue()} methods. But other types of parameter values are possible
* and can be handled by the more generic {@link #getValue()} and {@link #setValue(Object)} methods.
* All {@code xxxValue()} methods in this class are convenience methods converting the value from {@code Object}
* to some commonly used types. Those types are specified in ISO 19111 as an union of attributes, listed below with
- * the corresponding getter and setter methods:</p>
+ * the corresponding getter and setter methods:
*
* <table class="sis">
* <caption>Mapping from ISO attributes to getters and setters</caption>
@@ -96,28 +98,44 @@ import static org.apache.sis.util.Utilities.deepEquals;
* Class<T> valueClass = parameter.getDescriptor().getValueClass();
* }
*
+ * <h2>Absolute paths of value files</h2>
+ * Parameters that are too complex for being expressed as an {@code int[]}, {@code double[]} or {@code String} type
+ * may be encoded in auxiliary files. It is the case, for example, of gridded data such as datum shift grids.
+ * The name of an auxiliary file is given by {@link #valueFile()}, but often as a <em>relative</em> path.
+ * The directory where that file is located depends on the operation using the parameter.
+ * For example, datum shift grids used by coordinate transformations are searched in the
+ * {@code $SIS_DATA/DatumChanges} directory, where {@code $SIS_DATA} is the value of the environment variable.
+ * However, the latest approach requires that all potentially used auxiliary files are preexisting on the local machine.
+ * This assumption may be applicable for parameters coming from a well-known registry such as EPSG, but cannot work
+ * with arbitrary operations where the auxiliary files need to be transferred together with the parameter values.
+ * For the latter case, an alternative is to consider the auxiliary files as relative to the GML document or WKT file
+ * that provides the parameter values. For allowing users to resolve or download auxiliary files in that way,
+ * a {@link #getSourceFile()} method is provided. Operations can then use {@link URI#resolve(URI)} for getting the
+ * absolute path of an auxiliary file from the same server or directory than the GML or WKT file of parameter values.
+ *
* <h2>Instantiation</h2>
* A {@linkplain DefaultParameterDescriptor parameter descriptor} must be defined before parameter value can be created.
- * Descriptors are usually predefined by map projection or process providers. Given a descriptor, a parameter value can
- * be created by a call to the {@link #DefaultParameterValue(ParameterDescriptor)} constructor or by a call to the
- * {@link ParameterDescriptor#createValue()} method. The latter is recommended since it allows descriptors to return
- * specialized implementations.
+ * Descriptors are usually predefined (often hard-coded) by map projection or process providers. Given a descriptor,
+ * the preferred way to create a parameter value is to invoke the {@link ParameterDescriptor#createValue()} method.
+ * It is also possible to invoke the {@linkplain #DefaultParameterValue(ParameterDescriptor) constructor} directly,
+ * but the former is recommended because it allows descriptors to return specialized implementations.
*
* <h2>Implementation note for subclasses</h2>
- * All read and write operations (except constructors, {@link #equals(Object)} and {@link #hashCode()})
+ * All read and write operations except constructors, {@link #equals(Object)} and {@link #hashCode()},
* ultimately delegates to the following methods:
*
* <ul>
- * <li>All getter methods will invoke {@link #getValue()} and {@link #getUnit()} (if needed),
+ * <li>The source file property is accessed by {@link #getSourceFile()} and {@link #setSourceFile(URI)}.</li>
+ * <li>All other getter methods will invoke {@link #getValue()} and {@link #getUnit()} (if needed),
* then perform their processing on the values returned by those methods.</li>
- * <li>All setter methods delegate to the {@link #setValue(Object, Unit)} method.</li>
+ * <li>All other setter methods delegate to the {@link #setValue(Object, Unit)} method.</li>
* </ul>
*
* Consequently, the above-cited methods provide single points that subclasses can override
* for modifying the behavior of all getter and setter methods.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.4
+ * @version 1.5
*
* @param <T> the type of the value stored in this parameter.
*
@@ -175,6 +193,17 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
@SuppressWarnings("serial") // Most SIS implementations are serializable.
protected Unit<?> unit;
+ /**
+ * If the parameter value is a relative path, the base URI to use for resolving that path.
+ * This field is {@code null} by default, unless this parameter value has been read from a
+ * GML document or a WKT file, in which case this field contains the URI of that document.
+ * This information allows to interpret {@link #valueFile()} as relative to the GML or WKT file.
+ *
+ * @see #getSourceFile()
+ * @see URI#resolve(URI)
+ */
+ private URI sourceFile;
+
/**
* Creates a parameter value from the specified descriptor.
* The value will be initialized to the default value, if any.
@@ -182,7 +211,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
* @param descriptor the abstract definition of this parameter.
*/
public DefaultParameterValue(final ParameterDescriptor<T> descriptor) {
- ensureNonNull("descriptor", descriptor);
+ ArgumentChecks.ensureNonNull("descriptor", descriptor);
this.descriptor = descriptor;
this.value = descriptor.getDefaultValue();
this.unit = descriptor.getUnit();
@@ -190,8 +219,8 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
/**
* Creates a new instance initialized with the values from the specified parameter object.
- * This is a <em>shallow</em> copy constructor, since the value contained in the given
- * object is not cloned.
+ * This is a <em>shallow</em> copy constructor, since the {@linkplain #getValue() value}
+ * contained in the given object is not cloned.
*
* @param parameter the parameter to copy values from.
*
@@ -199,16 +228,17 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
* @see #unmodifiable(ParameterValue)
*/
public DefaultParameterValue(final ParameterValue<T> parameter) {
- ensureNonNull("parameter", parameter);
+ ArgumentChecks.ensureNonNull("parameter", parameter);
descriptor = parameter.getDescriptor();
value = parameter.getValue();
unit = parameter.getUnit();
+ if (parameter instanceof DefaultParameterValue<?>) {
+ sourceFile = ((DefaultParameterValue<?>) parameter).getSourceFile().orElse(null);
+ }
}
/**
- * Returns the definition of this parameter.
- *
- * @return the definition of this parameter.
+ * {@return the definition of this parameter}.
*/
@Override
@XmlElement(name = "operationParameter", required = true)
@@ -216,6 +246,28 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
return descriptor;
}
+ /**
+ * {@return the URI of the GML document or WKT file from which this parameter value has been read}.
+ * This information allows to interpret {@link #valueFile()} as a path relative to the file that defined
+ * this parameter value. For example, the following snippet gets the file, then tries to make it absolute:
+ *
+ * {@snippet lang="java" :
+ * DefaultParameterValue<?> pv = ...;
+ * URI file = pv.valueFile();
+ * file = pv.getSourceFile().map((base) -> base.resolve(file)).orElse(file);
+ * }
+ *
+ * @see #setSourceFile(URI)
+ * @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() {
+ return Optional.ofNullable(sourceFile);
+ }
+
/**
* Returns the unit of measure of the parameter value.
* If the parameter value has no unit (for example because it is a {@link String} type),
@@ -272,6 +324,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
*/
@Override
public boolean booleanValue() throws IllegalStateException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final T value = getValue();
if (value instanceof Boolean) {
return (Boolean) value;
@@ -296,6 +349,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
*/
@Override
public int intValue() throws IllegalStateException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final T value = getValue();
if (value instanceof Number) {
final int integer = ((Number) value).intValue();
@@ -323,6 +377,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
*/
@Override
public int[] intValueList() throws IllegalStateException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final T value = getValue();
if (value instanceof int[]) {
return ((int[]) value).clone();
@@ -349,6 +404,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
*/
@Override
public double doubleValue() throws IllegalStateException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final T value = getValue();
if (value instanceof Number) {
return ((Number) value).doubleValue();
@@ -374,6 +430,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
*/
@Override
public double[] doubleValueList() throws IllegalStateException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final T value = getValue();
if (value instanceof double[]) {
return ((double[]) value).clone();
@@ -384,20 +441,20 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
/**
* Returns the converter to be used by {@link #doubleValue(Unit)} and {@link #doubleValueList(Unit)}.
*/
- private UnitConverter getConverterTo(final Unit<?> unit) {
+ private UnitConverter getConverterTo(final Unit<?> target) {
final Unit<?> source = getUnit();
if (source == null) {
throw new IllegalStateException(Resources.format(Resources.Keys.UnitlessParameter_1, Verifier.getDisplayName(descriptor)));
}
- ensureNonNull("unit", unit);
+ ArgumentChecks.ensureNonNull("unit", target);
final short expectedID = Verifier.getUnitMessageID(source);
- if (Verifier.getUnitMessageID(unit) != expectedID) {
- throw new IllegalArgumentException(Errors.format(expectedID, unit));
+ if (Verifier.getUnitMessageID(target) != expectedID) {
+ throw new IllegalArgumentException(Errors.format(expectedID, target));
}
try {
- return source.getConverterToAny(unit);
+ return source.getConverterToAny(target);
} catch (IncommensurableException e) {
- throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleUnits_2, source, unit), e);
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatibleUnits_2, source, target), e);
}
}
@@ -422,6 +479,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
*/
@Override
public double doubleValue(final Unit<?> unit) throws IllegalArgumentException, IllegalStateException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final double value = doubleValue(); // Invoke first in case it throws an exception.
return getConverterTo(unit).convert(value);
}
@@ -469,6 +527,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
*/
@Override
public String stringValue() throws IllegalStateException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final T value = getValue();
if (value instanceof CharSequence) {
return value.toString();
@@ -481,6 +540,12 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
* The default implementation can convert the following value types:
* {@link URI}, {@link URL}, {@link Path}, {@link File}.
*
+ * <h4>Relative paths to absolute paths</h4>
+ * This parameter value is often a path relative to an unspecified directory. The base directory
+ * depends on the context. For example, it may be a directory where all datum grids are cached.
+ * Sometime, it is convenient to interpret the path as relative to the GML document or WKT file
+ * that defined this parameter value. For such resolution, see {@link #getSourceFile()}.
+ *
* @return the reference to a file containing parameter values.
* @throws InvalidParameterTypeException if the value is not a reference to a file or a URI.
* @throws IllegalStateException if the value is not defined and there is no default value.
@@ -490,6 +555,7 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
*/
@Override
public URI valueFile() throws IllegalStateException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final T value = getValue();
if (value instanceof URI) return (URI) value;
if (value instanceof File) return ((File) value).toURI();
@@ -528,6 +594,23 @@ public class DefaultParameterValue<T> extends FormattableObject implements Param
return isFile(newValue);
}
+ /**
+ * Sets the URI of the GML document or WKT file from which this parameter value has been read.
+ * The given URI is a hint to be returned by {@link #getSourceFile()} for allowing callers to
+ * {@linkplain URI#resolve(URI) resolve} relative {@linkplain #valueFile() value files}.
+ *
+ * @param document URI of the document from which this parameter value has been read, or {@code null} if none.
+ *
+ * @see #getSourceFile()
+ * @see org.apache.sis.io.wkt.WKTFormat#setSourceFile(URI)
+ * @see URI#resolve(URI)
+ *
+ * @see 1.5
+ */
+ public void setSourceFile(final URI document) {
+ sourceFile = document;
+ }
+
/**
* Returns the exception to throw when an incompatible method is invoked for the value type.
*/
@@ -723,8 +806,8 @@ convert: if (componentType != null) {
setValue(n, unit);
/*
* Above code used `unit` instead of `getUnit()` despite class Javadoc claim because units are not expected
- * to be involved in this method. We access this field only as a matter of principle, for making sure that no
- * property other than the value is altered by this method call.
+ * to be involved in this method. We access this field only as a matter of principle, for making sure that
+ * no property other than the value is altered by this method call.
*/
}
@@ -841,15 +924,16 @@ convert: if (componentType != null) {
if (mode == ComparisonMode.STRICT) {
if (getClass() == object.getClass()) {
final DefaultParameterValue<?> that = (DefaultParameterValue<?>) object;
- return Objects.equals(descriptor, that.descriptor) &&
- Objects.deepEquals(value, that.value) &&
- Objects.equals(unit, that.unit);
+ return Objects.equals (descriptor, that.descriptor) &&
+ Objects.deepEquals(sourceFile, that.sourceFile) &&
+ Objects.deepEquals(value, that.value) &&
+ Objects.equals (unit, that.unit);
}
} else if (object instanceof ParameterValue<?>) {
final ParameterValue<?> that = (ParameterValue<?>) object;
- return deepEquals(getDescriptor(), that.getDescriptor(), mode) &&
- deepEquals(getValue(), that.getValue(), mode) &&
- deepEquals(getUnit(), that.getUnit(), mode);
+ return Utilities.deepEquals(getDescriptor(), that.getDescriptor(), mode) &&
+ Utilities.deepEquals(getValue(), that.getValue(), mode) &&
+ Utilities.deepEquals(getUnit(), that.getUnit(), mode);
}
}
return false;
@@ -1162,6 +1246,7 @@ convert: if (componentType != null) {
@XmlElement(name = "valueList", type = MeasureList.class)
})
private Object getXmlValue() {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
final Object value = getValue(); // Give to user a chance to override.
if (value != null) {
if (value instanceof Number) {
@@ -1196,6 +1281,10 @@ convert: if (componentType != null) {
*/
@SuppressWarnings("unchecked")
private void setXmlValue(Object xmlValue) {
+ ExternalLinkHandler linkHandler = Context.linkHandler(Context.current());
+ if (linkHandler != null) {
+ sourceFile = linkHandler.getURI();
+ }
if (value == null && unit == null) {
if (xmlValue instanceof Measure) {
final Measure measure = (Measure) xmlValue;
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/UnmodifiableParameterValue.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/UnmodifiableParameterValue.java
index 8939067bee..fb22b0c6eb 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/UnmodifiableParameterValue.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/UnmodifiableParameterValue.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.parameter;
+import java.net.URI;
import jakarta.xml.bind.annotation.XmlTransient;
import javax.measure.Unit;
import org.opengis.parameter.ParameterValue;
@@ -92,6 +93,7 @@ final class UnmodifiableParameterValue<T> extends DefaultParameterValue<T> {
*/
@Override
public T getValue() {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
T value = super.getValue();
if (value instanceof Cloneable) {
final Class<T> type = getDescriptor().getValueClass(); // May be null after GML unmarshalling.
@@ -112,6 +114,14 @@ final class UnmodifiableParameterValue<T> extends DefaultParameterValue<T> {
throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, getClass()));
}
+ /**
+ * Do not allow modification of the parameter value.
+ */
+ @Override
+ public void setSourceFile(final URI source) {
+ throw new UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, getClass()));
+ }
+
/**
* Returns a modifiable copy of this parameter.
*/
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/package-info.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/package-info.java
index 4b3a2e0910..1299b3c4eb 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/package-info.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/parameter/package-info.java
@@ -85,7 +85,7 @@
* if the given value is not assignable to the expected class or is not inside the value domain.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.4
+ * @version 1.5
* @since 0.4
*/
@XmlSchema(elementFormDefault= XmlNsForm.QUALIFIED, namespace = Namespaces.GML, xmlns = {
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CRS.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CRS.java
index ca0cba5a49..cc2600eaa3 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CRS.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CRS.java
@@ -306,7 +306,7 @@ public final class CRS extends Static {
* Applications which need to parse a large amount of WKT strings should consider to use
* the {@link org.apache.sis.io.wkt.WKTFormat} class instead of this method.
*
- * @param text coordinate system encoded in Well-Known Text format (version 1 or 2).
+ * @param wkt coordinate system encoded in Well-Known Text format (version 1 or 2).
* @return the parsed Coordinate Reference System.
* @throws FactoryException if the given WKT cannot be parsed.
*
@@ -317,9 +317,8 @@ public final class CRS extends Static {
*
* @since 0.6
*/
- public static CoordinateReferenceSystem fromWKT(final String text) throws FactoryException {
- ArgumentChecks.ensureNonNull("text", text);
- final CoordinateReferenceSystem crs = GeodeticObjectFactory.provider().createFromWKT(text);
+ public static CoordinateReferenceSystem fromWKT(final String wkt) throws FactoryException {
+ final CoordinateReferenceSystem crs = GeodeticObjectFactory.provider().createFromWKT(wkt);
DefinitionVerifier.withAuthority(crs, Loggers.WKT, CRS.class, "fromWKT");
return crs;
}
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
index 95c4401371..ca55b08f28 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
@@ -1661,7 +1661,7 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory
* Applications which need to parse a large amount of WKT strings should consider to use
* the {@link org.apache.sis.io.wkt.WKTFormat} class instead of this method.
*
- * @param text coordinate system encoded in Well-Known Text format (version 1 or 2).
+ * @param wkt coordinate system encoded in Well-Known Text format (version 1 or 2).
* @throws FactoryException if the object creation failed.
*
* @see org.apache.sis.io.wkt
@@ -1670,8 +1670,8 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory
* @see <a href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy WKT 1</a>
*/
@Override
- public CoordinateReferenceSystem createFromWKT(final String text) throws FactoryException {
- ArgumentChecks.ensureNonEmpty("text", text);
+ public CoordinateReferenceSystem createFromWKT(final String wkt) throws FactoryException {
+ ArgumentChecks.ensureNonEmpty("wkt", wkt);
Parser p = parser.getAndSet(null);
if (p == null) try {
Constructor<? extends Parser> c = parserConstructor;
@@ -1687,7 +1687,7 @@ public class GeodeticObjectFactory extends AbstractFactory implements CRSFactory
}
final Object object;
try {
- object = p.createFromWKT(text);
+ object = p.createFromWKT(wkt);
} catch (FactoryException e) {
/*
* In the case of map projection, the parsing may fail because a projection parameter is not known to SIS.
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
index e634c53788..6360e9bdd4 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
@@ -1659,15 +1659,15 @@ public class DefaultMathTransformFactory extends AbstractFactory implements Math
* inverse matrix but those information are lost at WKT formatting time. A similar "hidden" information
* lost may also happen with {@link WraparoundTransform}, also making that transform non-invertible.</p>
*
- * @param text math transform encoded in Well-Known Text format.
+ * @param wkt math transform encoded in Well-Known Text format.
* @return the math transform (never {@code null}).
* @throws FactoryException if the Well-Known Text cannot be parsed,
* or if the math transform creation failed from some other reason.
*/
@Override
- public MathTransform createFromWKT(final String text) throws FactoryException {
+ public MathTransform createFromWKT(final String wkt) throws FactoryException {
lastMethod.remove();
- ArgumentChecks.ensureNonEmpty("text", text);
+ ArgumentChecks.ensureNonEmpty("wkt", wkt);
Parser p = parser.getAndSet(null);
if (p == null) try {
Constructor<? extends Parser> c = parserConstructor;
@@ -1687,7 +1687,7 @@ public class DefaultMathTransformFactory extends AbstractFactory implements Math
*/
final Object object;
try {
- object = p.createFromWKT(text);
+ object = p.createFromWKT(wkt);
} catch (FactoryException e) {
/*
* The parsing may fail because a operation parameter is not known to SIS. If this happen, replace
diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/ElementTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/ElementTest.java
index b807ffad0f..c8ddc5db8c 100644
--- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/ElementTest.java
+++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/ElementTest.java
@@ -46,8 +46,8 @@ public final class ElementTest extends TestCase {
/**
* A dummy parser to be given to the {@link Element} constructor.
*/
- private final AbstractParser parser = new AbstractParser(Symbols.SQUARE_BRACKETS, new HashMap<>(2),
- null, null, null, Locale.ENGLISH)
+ private final AbstractParser parser = new AbstractParser(
+ null, new HashMap<>(2), Symbols.SQUARE_BRACKETS, null, null, null, Locale.ENGLISH)
{
@Override String getPublicFacade() {
throw new UnsupportedOperationException();
diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/GeodeticObjectParserTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
index 8ff779723e..32e34d9968 100644
--- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
+++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
@@ -92,8 +92,8 @@ public final class GeodeticObjectParserTest extends TestCase {
* Instantiates the parser to test.
*/
private void newParser(final Convention convention) {
- parser = new GeodeticObjectParser(Symbols.getDefault(), Map.of(),
- null, null, null, convention, Transliterator.DEFAULT, null, new ReferencingFactoryContainer());
+ parser = new GeodeticObjectParser(null, Map.of(), Symbols.getDefault(), null, null, null,
+ convention, Transliterator.DEFAULT, null, new ReferencingFactoryContainer());
assertEquals(GeodeticObjectFactory.class.getCanonicalName(), parser.getPublicFacade());
}
diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PRJDataStore.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PRJDataStore.java
index 3249a57314..13449a229e 100644
--- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PRJDataStore.java
+++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/PRJDataStore.java
@@ -144,7 +144,7 @@ public abstract class PRJDataStore extends URIDataStore {
* @throws DataStoreException if an error occurred while reading the file.
*/
protected final void readPRJ() throws DataStoreException {
- Exception cause = null;
+ Exception cause = null, suppressed = null;
try {
final AuxiliaryContent content = readAuxiliaryFile(PRJ);
if (content == null) {
@@ -154,6 +154,11 @@ public abstract class PRJDataStore extends URIDataStore {
final String wkt = content.toString();
final StoreFormat format = new StoreFormat(locale, timezone, null, listeners);
format.setConvention(Convention.WKT1_COMMON_UNITS); // Ignored if the format is WKT 2.
+ try {
+ format.setSourceFile(content.getURI());
+ } catch (URISyntaxException e) {
+ suppressed = e;
+ }
final ParsePosition pos = new ParsePosition(0);
crs = (CoordinateReferenceSystem) format.parse(wkt, pos);
if (crs != null) {
@@ -171,7 +176,9 @@ public abstract class PRJDataStore extends URIDataStore {
} catch (IOException | ParseException | ClassCastException e) {
cause = e;
}
- throw new DataStoreReferencingException(cannotReadAuxiliaryFile(PRJ), cause);
+ final var e = new DataStoreReferencingException(cannotReadAuxiliaryFile(PRJ), cause);
+ if (suppressed != null) e.addSuppressed(suppressed);
+ throw e;
}
/**
@@ -273,6 +280,16 @@ public abstract class PRJDataStore extends URIDataStore {
return IOUtilities.filename(source);
}
+ /**
+ * Returns the source as an URI if possible.
+ *
+ * @return the source as an URI, or {@code null} if none.
+ * @throws URISyntaxException if the URI cannot be parsed.
+ */
+ public URI getURI() throws URISyntaxException {
+ return IOUtilities.toURI(source);
+ }
+
/**
* Returns the number of valid characters in this sequence.
*/