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 a62860a7a5aa17688d67b14af1ccdd01be14c53f Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Wed Feb 21 15:15:50 2024 +0100 Make the code more robust to absence of EPSG database. --- .../apache/sis/referencing/IdentifiedObjects.java | 7 +++-- .../operation/CoordinateOperationRegistry.java | 32 ++++++++++++---------- .../sis/storage/geotiff/writer/GeoEncoder.java | 17 +++++++++++- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/IdentifiedObjects.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/IdentifiedObjects.java index 9586af09ce..3ab9c02293 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/IdentifiedObjects.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/IdentifiedObjects.java @@ -50,6 +50,7 @@ import org.apache.sis.metadata.internal.NameToIdentifier; import org.apache.sis.metadata.iso.citation.Citations; import org.apache.sis.referencing.factory.IdentifiedObjectFinder; import org.apache.sis.referencing.factory.GeodeticAuthorityFactory; +import org.apache.sis.referencing.factory.UnavailableFactoryException; import org.apache.sis.referencing.factory.NoSuchAuthorityFactoryException; // Specific to the geoapi-3.1 and geoapi-4.0 branches: @@ -443,7 +444,8 @@ public final class IdentifiedObjects extends Static { * @param authority the authority for the identifier to return, or {@code null} for * the first identifier regardless its authority. * @return the identifier, or {@code null} if none was found without ambiguity or if the given object was null. - * @throws FactoryException if an error occurred during the search. + * @throws UnavailableFactoryException if the factory for the authority identified in the URN is not available. + * @throws FactoryException if the lookup failed for another reason. * * @see #newFinder(String) * @see #toURN(Class, Identifier) @@ -561,7 +563,8 @@ public final class IdentifiedObjects extends Static { * @param object the object (usually a {@linkplain org.apache.sis.referencing.crs.AbstractCRS * coordinate reference system}) whose EPSG code is to be found, or {@code null}. * @return the EPSG code, or {@code null} if none was found without ambiguity or if the given object was null. - * @throws FactoryException if an error occurred during the search. + * @throws UnavailableFactoryException if the EPSG factory is not available. + * @throws FactoryException if the lookup failed for another reason. * * @see #newFinder(String) * diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java index 0c47339489..2ca694b97a 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java @@ -57,6 +57,7 @@ import org.apache.sis.referencing.operation.transform.MathTransforms; import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory; import org.apache.sis.referencing.factory.IdentifiedObjectFinder; import org.apache.sis.referencing.factory.GeodeticAuthorityFactory; +import org.apache.sis.referencing.factory.UnavailableFactoryException; import org.apache.sis.referencing.factory.MissingFactoryResourceException; import org.apache.sis.referencing.factory.InvalidGeodeticParameterException; import org.apache.sis.referencing.factory.NoSuchAuthorityFactoryException; @@ -169,7 +170,7 @@ class CoordinateOperationRegistry { * @see #authorityCodes * @see #findCode(CoordinateReferenceSystem) */ - private final IdentifiedObjectFinder codeFinder; + private IdentifiedObjectFinder codeFinder; /** * The factory to use for creating operations as defined by authority, or {@code null} if none. @@ -265,9 +266,6 @@ class CoordinateOperationRegistry { @SuppressWarnings("LocalVariableHidesMemberVariable") Map<CoordinateReferenceSystem, List<String>> authorityCodes = Collections.emptyMap(); - - @SuppressWarnings("LocalVariableHidesMemberVariable") - IdentifiedObjectFinder codeFinder = null; if (registry != null) { if (registry instanceof GeodeticAuthorityFactory) { codeFinder = ((GeodeticAuthorityFactory) registry).newIdentifiedObjectFinder(); @@ -280,7 +278,6 @@ class CoordinateOperationRegistry { authorityCodes = new IdentityHashMap<>(5); // Rarely more than 4 entries. } } - this.codeFinder = codeFinder; this.authorityCodes = authorityCodes; if (context != null) { areaOfInterest = context.getAreaOfInterest(); @@ -308,7 +305,7 @@ class CoordinateOperationRegistry { /** * Finds the authority codes for the given coordinate reference system. - * This method does not trust the code given by the user in its CRS - we verify it. + * This method does not trust the code given by the user in the CRS - it verifies it. * This method may return codes even if the axis order does not match; * it will be caller's responsibility to make necessary adjustments. * @@ -329,17 +326,22 @@ class CoordinateOperationRegistry { : IdentifiedObjectFinder.Domain.VALID_DATASET); int matchCount = 0; final Citation authority = registry.getAuthority(); - for (final IdentifiedObject candidate : codeFinder.find(crs)) { - final Identifier identifier = IdentifiedObjects.getIdentifier(candidate, authority); - if (identifier != null) { - final String code = identifier.getCode(); - if (Utilities.deepEquals(candidate, crs, ComparisonMode.APPROXIMATE)) { - // If axis order matches, give precedence to that CRS. - codes.add(matchCount++, code); - } else { - codes.add(code); + try { + for (final IdentifiedObject candidate : codeFinder.find(crs)) { + final Identifier identifier = IdentifiedObjects.getIdentifier(candidate, authority); + if (identifier != null) { + final String code = identifier.getCode(); + if (Utilities.deepEquals(candidate, crs, ComparisonMode.APPROXIMATE)) { + // If axis order matches, give precedence to that CRS. + codes.add(matchCount++, code); + } else { + codes.add(code); + } } } + } catch (UnavailableFactoryException e) { + log(null, e); + codeFinder = null; } authorityCodes.put(crs, codes); } diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java index 0124b98495..25c445efbc 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/writer/GeoEncoder.java @@ -18,6 +18,7 @@ package org.apache.sis.storage.geotiff.writer; import java.util.List; import java.util.EnumMap; +import java.util.logging.Level; import static javax.imageio.plugins.tiff.GeoTIFFTagSet.TAG_GEO_ASCII_PARAMS; import static javax.imageio.plugins.tiff.GeoTIFFTagSet.TAG_GEO_DOUBLE_PARAMS; import javax.measure.Unit; @@ -56,6 +57,7 @@ import org.apache.sis.referencing.IdentifiedObjects; import org.apache.sis.referencing.cs.CoordinateSystems; import org.apache.sis.referencing.operation.matrix.Matrices; import org.apache.sis.referencing.operation.transform.MathTransforms; +import org.apache.sis.referencing.factory.UnavailableFactoryException; import org.apache.sis.referencing.util.ReferencingUtilities; import org.apache.sis.referencing.util.WKTKeywords; import org.apache.sis.coverage.grid.GridGeometry; @@ -184,6 +186,13 @@ public final class GeoEncoder { */ private int citationLengthIndex; + /** + * Whether to disable attempts to write EPSG codes. This is set to {@code true} on the first attempt to use the + * EPSG database if it appears to be unavailable. This is used for avoiding many retries which will continue to + * fail. + */ + private boolean disableEPSG; + /** * Prepares information for writing GeoTIFF tags for the given grid geometry. * Caller shall invoke {@link #write(GridGeometry, MetadataFetcher)} exactly once after construction. @@ -558,7 +567,13 @@ public final class GeoEncoder { * This is not necessarily a bad thing, because there is a possibility that future GeoTIFF * specifications become stricter, so we are already "strict" regarding usages of EPSG codes. */ - final short epsg = toShortEPSG(IdentifiedObjects.lookupEPSG(object)); + short epsg = GeoCodes.userDefined; + if (!disableEPSG) try { + epsg = toShortEPSG(IdentifiedObjects.lookupEPSG(object)); + } catch (UnavailableFactoryException e) { + listeners.warning(Level.FINE, null, e); + disableEPSG = true; + } writeShort(key, epsg); return (epsg == GeoCodes.userDefined); }