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 e79df9c2d3 Ensure that recursive method calls to `EPSGFactory` reach 
the same factory instance. Opportunistic documentation fixes.
e79df9c2d3 is described below

commit e79df9c2d3f81a6dd6be593795f18b8d41a65873
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue Aug 5 11:11:42 2025 +0200

    Ensure that recursive method calls to `EPSGFactory` reach the same factory 
instance.
    Opportunistic documentation fixes.
---
 .../apache/sis/coverage/grid/GridDerivation.java   |  2 +-
 .../main/org/apache/sis/referencing/CRS.java       | 22 ++++++++++++-----
 .../referencing/factory/sql/EPSGDataAccess.java    | 28 ++++++++++++++++++++--
 .../internal/ParameterizedTransformBuilder.java    |  9 +++++++
 4 files changed, 52 insertions(+), 9 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridDerivation.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridDerivation.java
index a1932913f5..7ad8920b1f 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridDerivation.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridDerivation.java
@@ -615,7 +615,7 @@ public class GridDerivation {
                 nowraparound = finder.gridToGrid();
                 /*
                  * At this point, the transform between the coordinate systems 
of the two grids is known.
-                 * The `gridToGrid` transform is the main one. If the user did 
not specified an AOI for
+                 * The `gridToGrid` transform is the main one. If the user did 
not specify an AOI for
                  * all dimensions, then `gridToGrid` is for low coordinates 
and `gridToGridHigh` is for
                  * high coordinates.
                  */
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 84becac5f3..aa52105478 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
@@ -81,6 +81,7 @@ import 
org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
 import org.apache.sis.referencing.operation.DefaultConversion;
 import org.apache.sis.referencing.factory.GeodeticObjectFactory;
 import org.apache.sis.referencing.factory.UnavailableFactoryException;
+import org.apache.sis.referencing.internal.ParameterizedTransformBuilder;
 import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
 import org.apache.sis.metadata.iso.extent.Extents;
 import org.apache.sis.util.ArgumentChecks;
@@ -88,6 +89,7 @@ import org.apache.sis.util.OptionalCandidate;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.privy.Numerics;
+import org.apache.sis.util.privy.Constants;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.logging.Logging;
 
@@ -1564,18 +1566,20 @@ check:  while (lower != 0 || upper != dimension) {
     }
 
     /**
-     * Returns the system-wide authority factory used by {@link 
#forCode(String)} and other SIS methods.
+     * Returns the system-wide authority factory used by {@link 
#forCode(String)} and other <abbr>SIS</abbr> methods.
      * If the given authority is non-null, then this method returns a factory 
specifically for that authority.
      * Otherwise, this method returns the {@link 
org.apache.sis.referencing.factory.MultiAuthoritiesFactory}
      * instance that manages all other factories.
      *
-     * <p>The {@code authority} argument can be {@code "EPSG"}, {@code "OGC"} 
or any other authority found
-     * on the module path. In the {@code "EPSG"} case, whether the full set of 
EPSG codes is supported or not
+     * <p>The {@code authority} argument can be {@code "EPSG"}, {@code "OGC"}
+     * or any other authority found on the module path.
+     * In the {@code "EPSG"} case, whether the full set of <abbr>EPSG</abbr> 
codes is supported or not
      * depends on whether a {@linkplain org.apache.sis.referencing.factory.sql 
connection to the database}
      * can be established. If no connection can be established, then this 
method returns a small embedded
-     * EPSG factory containing at least the CRS defined in the {@link 
#forCode(String)} method javadoc.</p>
+     * <abbr>EPSG</abbr> factory containing at least the <abbr>CRS</abbr>s 
defined in the
+     * {@link #forCode(String)} method javadoc.</p>
      *
-     * <p>User-defined authorities can be added to the SIS environment by 
creating a {@code CRSAuthorityFactory}
+     * <p>User-defined authorities can be added to the <abbr>SIS</abbr> 
environment by creating a {@code CRSAuthorityFactory}
      * implementation with a public no-argument constructor or a public static 
{@code provider()} method,
      * and declaring the name of that class in the {@code module-info.java} 
file as a provider of the
      * {@code org.opengis.referencing.crs.CRSAuthorityFactory} service.</p>
@@ -1583,7 +1587,7 @@ check:  while (lower != 0 || upper != dimension) {
      * @param  authority  the authority of the desired factory (typically 
{@code "EPSG"} or {@code "OGC"}),
      *         or {@code null} for the {@link 
org.apache.sis.referencing.factory.MultiAuthoritiesFactory}
      *         instance that manage all factories.
-     * @return the system-wide authority factory used by SIS for the given 
authority.
+     * @return the system-wide authority factory used by <abbr>SIS</abbr> for 
the given authority.
      * @throws FactoryException if no factory can be returned for the given 
authority.
      *
      * @see MultiRegisterOperations
@@ -1594,6 +1598,12 @@ check:  while (lower != 0 || upper != dimension) {
         if (authority == null) {
             return AuthorityFactories.ALL;
         }
+        if (authority.equalsIgnoreCase(Constants.EPSG)) {
+            CRSAuthorityFactory factory = 
ParameterizedTransformBuilder.CREATOR.get();
+            if (factory != null) {
+                return factory;
+            }
+        }
         return 
AuthorityFactories.ALL.getAuthorityFactory(CRSAuthorityFactory.class, 
authority, null);
     }
 
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index 44aff1352a..59997d0496 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -1505,6 +1505,30 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
         R create(F factory, Map<String, Object> properties) throws 
FactoryException;
     }
 
+    /**
+     * Invokes the {@code create(…)} method of the given constructor in a 
block which ensures that recursive method
+     * calls will be redirected to this factory. This is needed only when the 
constructor may indirectly invoke the
+     * {@link org.apache.sis.referencing.CRS#getAuthorityFactory(String)} 
method.
+     */
+    private <F extends Factory, R extends IdentifiedObject> R create(
+            final FactoryCall<F, R> constructor,
+            final F factory,
+            final Map<String, Object> properties) throws FactoryException
+    {
+        final ThreadLocal<CRSAuthorityFactory> caller = 
ParameterizedTransformBuilder.CREATOR;
+        final CRSAuthorityFactory old = caller.get();
+        caller.set(owner);
+        try {
+            return constructor.create(factory, properties);
+        } finally {
+            if (old != null) {
+                caller.set(old);
+            } else {
+                caller.remove();
+            }
+        }
+    }
+
     /**
      * Creates an arbitrary coordinate reference system from a code.
      * The returned object will typically be an instance of {@link 
GeographicCRS}, {@link ProjectedCRS},
@@ -1785,7 +1809,7 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
                 @SuppressWarnings("LocalVariableHidesMemberVariable")
                 final Map<String,Object> properties = createProperties(
                         "Coordinate Reference System", epsg, name, null, area, 
scope, remarks, deprecated);
-                final CoordinateReferenceSystem crs = 
constructor.create(owner.crsFactory, properties);
+                final CoordinateReferenceSystem crs = create(constructor, 
owner.crsFactory, properties);
                 returnValue = ensureSingleton(crs, returnValue, code);
                 if (result.isClosed()) break;   // See createProperties(…) for 
explanation.
             }
@@ -3316,7 +3340,7 @@ next:                   while (r.next()) {
                 properties.put(CoordinateOperation .OPERATION_VERSION_KEY, 
version);
                 properties.put(CoordinateOperation 
.COORDINATE_OPERATION_ACCURACY_KEY,
                                
PositionalAccuracyConstant.transformation(accuracy));
-                CoordinateOperation operation = 
constructor.create(owner.copFactory, properties);
+                CoordinateOperation operation = create(constructor, 
owner.copFactory, properties);
                 returnValue = ensureSingleton(operation, returnValue, code);
                 if (result.isClosed()) break;   // See createProperties(…) for 
explanation.
             }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/ParameterizedTransformBuilder.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/ParameterizedTransformBuilder.java
index a9b2cda5df..b970f5f415 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/ParameterizedTransformBuilder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/ParameterizedTransformBuilder.java
@@ -39,6 +39,7 @@ import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.CRSAuthorityFactory;
 import org.opengis.util.NoSuchIdentifierException;
 import org.opengis.util.FactoryException;
 import org.apache.sis.util.ArgumentChecks;
@@ -90,6 +91,14 @@ import org.opengis.util.UnimplementedServiceException;
  * @author  Martin Desruisseaux (Geomatys)
  */
 public class ParameterizedTransformBuilder extends MathTransformBuilder 
implements MathTransformProvider.Context {
+    /**
+     * The factory which is creating the coordinate operation.
+     * The value is read indirectly by {@link 
#getMatrix(ContextualParameters.MatrixRole)}
+     * when normalizing axes, because it invokes a method that may search for 
the authority
+     * codes of normalized coordinate systems.
+     */
+    public static final ThreadLocal<CRSAuthorityFactory> CREATOR = new 
ThreadLocal<>();
+
     /**
      * Minimal precision of ellipsoid semi-major and semi-minor axis lengths, 
in metres.
      * If the length difference between the axis of two ellipsoids is greater 
than this threshold,

Reply via email to