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 2024/10/04 15:23:00 UTC
(sis) 03/05: Better detection of when EPSG data are not available and fallback should be used. This is needed for fixing test failures when SIS is built without local EPSG dataset.
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 2866e75668c04dc6a7a3f577714afd0183338b15
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Thu Oct 3 18:00:36 2024 +0200
Better detection of when EPSG data are not available and fallback should be used.
This is needed for fixing test failures when SIS is built without local EPSG dataset.
---
.../apache/sis/referencing/AuthorityFactories.java | 202 ++++++++++++---------
.../main/org/apache/sis/referencing/CRS.java | 5 +-
.../main/org/apache/sis/referencing/CommonCRS.java | 10 +-
.../apache/sis/referencing/IdentifiedObjects.java | 2 +
.../factory/IdentifiedObjectFinder.java | 105 ++++++++++-
.../factory/MultiAuthoritiesFactory.java | 16 +-
.../sis/referencing/EPSGFactoryFallbackTest.java | 4 +-
.../sis/storage/sql/feature/InfoStatements.java | 4 +-
.../storage/sql/feature/InfoStatementsTest.java | 8 +-
9 files changed, 253 insertions(+), 103 deletions(-)
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/AuthorityFactories.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/AuthorityFactories.java
index 064e7f6daa..8b5d66f2dd 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/AuthorityFactories.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/AuthorityFactories.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.referencing;
+import java.util.Set;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.logging.Level;
@@ -24,6 +25,7 @@ import java.util.logging.Logger;
import java.sql.SQLTransientException;
import org.opengis.util.FactoryException;
import org.opengis.referencing.AuthorityFactory;
+import org.opengis.referencing.IdentifiedObject;
import org.opengis.referencing.cs.CSAuthorityFactory;
import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.datum.DatumAuthorityFactory;
@@ -37,6 +39,7 @@ import org.apache.sis.system.SystemListener;
import org.apache.sis.referencing.internal.EPSGFactoryProxy;
import org.apache.sis.referencing.factory.MultiAuthoritiesFactory;
import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
+import org.apache.sis.referencing.factory.IdentifiedObjectFinder;
import org.apache.sis.referencing.factory.UnavailableFactoryException;
import org.apache.sis.referencing.factory.sql.EPSGFactory;
import org.apache.sis.util.logging.Logging;
@@ -57,11 +60,10 @@ final class AuthorityFactories<T extends AuthorityFactory> extends LazySet<T> {
static final Logger LOGGER = Logger.getLogger(Loggers.CRS_FACTORY);
/**
- * An array containing only the EPSG factory. Content of this array is initially null.
+ * The EPSG factory, or {@code null} if not yet initialized.
* The EPSG factory will be created when first needed by {@link #initialValues()}.
- * This array is returned directly (not cloned) by {@link #initialValues()}.
*/
- private static final GeodeticAuthorityFactory[] EPSG = new GeodeticAuthorityFactory[1];
+ private static GeodeticAuthorityFactory EPSG;
/**
* The unique system-wide authority factory instance that contains all factories found on the module path,
@@ -80,7 +82,7 @@ final class AuthorityFactories<T extends AuthorityFactory> extends LazySet<T> {
@Override
public void reload() {
- EPSG(null);
+ setEPSG(null);
super.reload();
}
};
@@ -115,38 +117,59 @@ final class AuthorityFactories<T extends AuthorityFactory> extends LazySet<T> {
return ServiceLoader.load(service, Reflect.getContextClassLoader()).iterator();
}
+ /**
+ * Invoked by {@link LazySet} for adding the EPSG factory before any other factory fetched by {@code ServiceLoader}.
+ * We put the EPSG factory first because it is often used anyway even for {@code CRS} and {@code AUTO} namespaces.
+ * This method tries to instantiate an {@link EPSGFactory} if possible, or an {@link EPSGFactoryFallback} otherwise.
+ *
+ * @return the EPSG factory in an array.
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ protected T[] initialValues() {
+ return (T[]) new GeodeticAuthorityFactory[] {getEPSG()};
+ }
+
+ /**
+ * Invoked by {@link LazySet} for fetching the next element from the given iterator.
+ * Skips the {@link EPSGFactoryProxy} if possible, or returns {@code null} otherwise.
+ * Note that {@link MultiAuthoritiesFactory} is safe to null values.
+ */
+ @Override
+ protected T next(final Iterator<? extends T> it) {
+ T e = it.next();
+ if (e instanceof EPSGFactoryProxy) {
+ e = it.hasNext() ? it.next() : null;
+ }
+ return e;
+ }
+
/**
* Sets the EPSG factory to the given value.
+ *
+ * @param factory the factory to use, or {@code null} for reloading.
*/
@Configuration
- static void EPSG(final GeodeticAuthorityFactory factory) {
- synchronized (EPSG) {
- EPSG[0] = factory;
- }
+ static synchronized void setEPSG(final GeodeticAuthorityFactory factory) {
+ EPSG = factory;
}
/**
* Returns the factory connected to the EPSG geodetic dataset if possible, or the EPSG fallback otherwise.
- * If an EPSG data source has been found, then this method returns an instance of {@link EPSGFactory} but
- * there is no guarantee that attempts to use that factory will succeed; for example maybe the EPSG schema
+ * If an EPSG data source has been found, then this method returns an instance of {@link EPSGFactory}, but
+ * there is no guarantee that attempts to use that factory will succeed. For example, maybe the EPSG schema
* does not exist. Callers should be prepared to either receive an {@link EPSGFactoryFallback} directly if
* the EPSG data source does not exist, or replace the {@code EPSGFactory} by a {@code EPSGFactoryFallback}
* later if attempt to use the returned factory fails.
*/
- static GeodeticAuthorityFactory EPSG() {
- synchronized (EPSG) {
- GeodeticAuthorityFactory factory = EPSG[0];
- if (factory == null) {
- try {
- factory = new EPSGFactory(null);
- } catch (FactoryException e) {
- log(e, false);
- factory = EPSGFactoryFallback.INSTANCE;
- }
- EPSG[0] = factory;
- }
- return factory;
+ static synchronized GeodeticAuthorityFactory getEPSG() {
+ if (EPSG == null) try {
+ EPSG = new EPSGFactory(null);
+ } catch (FactoryException e) {
+ log(e, false);
+ EPSG = EPSGFactoryFallback.INSTANCE;
}
+ return EPSG;
}
/**
@@ -155,47 +178,42 @@ final class AuthorityFactories<T extends AuthorityFactory> extends LazySet<T> {
* the same exception to be thrown and logged on every calls to {@link CRS#forCode(String)}.
*/
static GeodeticAuthorityFactory fallback(final UnavailableFactoryException e) throws UnavailableFactoryException {
- final boolean isTransient = (e.getCause() instanceof SQLTransientException);
final AuthorityFactory unavailable = e.getUnavailableFactory();
- GeodeticAuthorityFactory factory;
- final boolean alreadyDone;
- synchronized (EPSG) {
- factory = EPSG[0];
- alreadyDone = (factory == EPSGFactoryFallback.INSTANCE);
- if (!alreadyDone) { // May have been set in another thread (race condition).
- if (unavailable != factory) {
- throw e; // Exception did not come from a factory that we control.
- }
- factory = EPSGFactoryFallback.INSTANCE;
- if (!isTransient) {
- ALL.reload();
- EPSG[0] = factory;
+ if (unavailable instanceof EPSGFactoryFallback) {
+ throw e;
+ }
+ boolean isWarning = true;
+ if (!(e.getCause() instanceof SQLTransientException)) {
+ synchronized (AuthorityFactories.class) {
+ if (unavailable == EPSG) {
+ ALL.reload(); // Must be before setting the `EPSG` field.
+ EPSG = EPSGFactoryFallback.INSTANCE;
+ isWarning = false; // Use config level.
}
}
}
- if (!alreadyDone) {
- log(e, true);
- }
- return factory;
+ log(e, isWarning);
+ return EPSGFactoryFallback.INSTANCE; // Do not return `EPSG` because it may still have the previous value.
}
/**
- * Notifies that a factory is unavailable, but without giving a fallback and without logging.
- * The caller is responsible for throwing an exception, or for logging a warning and provide its own fallback.
+ * Notifies that a factory is unavailable, but without logging.
+ * The callers are responsible for either throwing an exception,
+ * or for logging a warning and do their own fallback.
*
- * @return {@code false} if the caller can try again, or {@code true} if the failure can be considered final.
+ * @return {@code false} if the caller may want to try again, or
+ * {@code true} if the failure is considered definitive.
*/
- static boolean failure(final UnavailableFactoryException e) {
- if (!(e.getCause() instanceof SQLTransientException)) {
- final AuthorityFactory unavailable = e.getUnavailableFactory();
- synchronized (EPSG) {
- final GeodeticAuthorityFactory factory = EPSG[0];
- if (factory == EPSGFactoryFallback.INSTANCE) { // May have been set in another thread.
- return false;
- }
- if (unavailable == factory) {
- ALL.reload();
- EPSG[0] = EPSGFactoryFallback.INSTANCE;
+ static boolean isUnavailable(final UnavailableFactoryException e) {
+ final AuthorityFactory unavailable = e.getUnavailableFactory();
+ if (!(unavailable instanceof EPSGFactoryFallback)) {
+ if (e.getCause() instanceof SQLTransientException) {
+ return false;
+ }
+ synchronized (AuthorityFactories.class) {
+ if (unavailable == EPSG) {
+ ALL.reload(); // Must be before setting the `EPSG` field.
+ EPSG = EPSGFactoryFallback.INSTANCE;
return false;
}
}
@@ -205,14 +223,14 @@ final class AuthorityFactories<T extends AuthorityFactory> extends LazySet<T> {
/**
* Logs the given exception at the given level. This method pretends that the logging come from
- * {@link CRS#getAuthorityFactory(String)}, which is the public facade for {@link #EPSG()}.
+ * {@link CRS#getAuthorityFactory(String)}, which is the public facade for {@link #getEPSG()}.
*/
private static void log(final Exception e, final boolean isWarning) {
String message = e.getMessage(); // Prefer the locale of system administrator.
if (message == null) {
message = e.toString();
}
- final LogRecord record = new LogRecord(isWarning ? Level.WARNING : Level.CONFIG, message);
+ final var record = new LogRecord(isWarning ? Level.WARNING : Level.CONFIG, message);
if (isWarning && !(e instanceof UnavailableFactoryException)) {
record.setThrown(e);
}
@@ -220,32 +238,54 @@ final class AuthorityFactories<T extends AuthorityFactory> extends LazySet<T> {
}
/**
- * Invoked by {@link LazySet} for adding the EPSG factory before any other factory fetched by {@code ServiceLoader}.
- * We put the EPSG factory first because it is often used anyway even for {@code CRS} and {@code AUTO} namespaces.
+ * Creates a finder which can be used for looking up unidentified objects using the EPSG database.
+ * The returned finder uses the fallback if the main <abbr>EPSG</abbr> factory appears to be unavailable.
*
- * <p>This method tries to instantiate an {@link EPSGFactory} if possible,
- * or an {@link EPSGFactoryFallback} otherwise.</p>
- *
- * @return the EPSG factory in an array. Callers shall not modify the returned array.
+ * @return a finder to use for looking up unidentified objects.
+ * @throws FactoryException if the finder cannot be created.
*/
- @Override
- @SuppressWarnings("unchecked")
- protected T[] initialValues() {
- EPSG(); // Force EPSGFactory instantiation if not already done.
- return (T[]) EPSG;
- }
-
- /**
- * Invoked by {@link LazySet} for fetching the next element from the given iterator.
- * Skips the {@link EPSGFactoryProxy} if possible, or returns {@code null} otherwise.
- * Note that {@link MultiAuthoritiesFactory} is safe to null values.
- */
- @Override
- protected T next(final Iterator<? extends T> it) {
- T e = it.next();
- if (e instanceof EPSGFactoryProxy) {
- e = it.hasNext() ? it.next() : null;
+ static IdentifiedObjectFinder finderForEPSG() throws FactoryException {
+ final GeodeticAuthorityFactory factory = getEPSG();
+ if (factory instanceof EPSGFactoryFallback) {
+ return ((EPSGFactoryFallback) factory).newIdentifiedObjectFinder();
}
- return e;
+ return new IdentifiedObjectFinder.Wrapper(factory.newIdentifiedObjectFinder()) {
+ /** Whether the fallback has already been set. */
+ private boolean isUsingFallback;
+
+ /** Report that the main factory is not available and switch to the fallback. */
+ private void report(UnavailableFactoryException e) throws FactoryException {
+ if (isUsingFallback) throw e;
+ isUsingFallback = true;
+ delegate(fallback(e).newIdentifiedObjectFinder());
+ }
+
+ /** Lookups objects which are approximately equal, using the fallback if necessary. */
+ @Override public Set<IdentifiedObject> find(final IdentifiedObject object) throws FactoryException {
+ for (;;) try { // Executed at most twice.
+ return super.find(object);
+ } catch (UnavailableFactoryException e) {
+ report(e);
+ }
+ }
+
+ /** Lookups an object which is approximately equal, using the fallback if necessary. */
+ @Override public IdentifiedObject findSingleton(final IdentifiedObject object) throws FactoryException {
+ for (;;) try { // Executed at most twice.
+ return super.findSingleton(object);
+ } catch (UnavailableFactoryException e) {
+ report(e);
+ }
+ }
+
+ /** Returns a set of authority codes, using the fallback if necessary. */
+ @Override protected Set<String> getCodeCandidates(final IdentifiedObject object) throws FactoryException {
+ for (;;) try { // Executed at most twice.
+ return super.getCodeCandidates(object);
+ } catch (UnavailableFactoryException e) {
+ report(e);
+ }
+ }
+ };
}
}
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 98c9574f51..13609d693e 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
@@ -713,7 +713,7 @@ public final class CRS extends Static {
try {
return factory.createOperation(sourceCRS, targetCRS, context);
} catch (UnavailableFactoryException e) {
- if (AuthorityFactories.failure(e)) {
+ if (AuthorityFactories.isUnavailable(e)) {
throw e;
} else try {
// Above method call replaced the EPSG factory by a fallback. Try again.
@@ -755,9 +755,10 @@ public final class CRS extends Static {
try {
return factory.createOperations(sourceCRS, targetCRS, context);
} catch (UnavailableFactoryException e) {
- if (AuthorityFactories.failure(e)) {
+ if (AuthorityFactories.isUnavailable(e)) {
throw e;
} else try {
+ // Above method call replaced the EPSG factory by a fallback. Try again.
return List.of(factory.createOperation(sourceCRS, targetCRS, context));
} catch (FactoryException ex) {
ex.addSuppressed(e);
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
index cb5394aeac..68d218eee4 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
@@ -2121,7 +2121,7 @@ public enum CommonCRS {
* Returns the same properties as the given object, except for the identifier which is set to the given code.
*/
private static Map<String,?> properties(final IdentifiedObject template, final short code) {
- final Map<String,Object> properties = new HashMap<>(IdentifiedObjects.getProperties(template, exclude()));
+ final var properties = new HashMap<String,Object>(IdentifiedObjects.getProperties(template, exclude()));
properties.put(GeographicCRS.IDENTIFIERS_KEY, new NamedIdentifier(Citations.EPSG, String.valueOf(code)));
return properties;
}
@@ -2139,7 +2139,7 @@ public enum CommonCRS {
*/
private static GeodeticAuthorityFactory factory() {
if (!EPSGFactoryFallback.FORCE_HARDCODED) {
- final GeodeticAuthorityFactory factory = AuthorityFactories.EPSG();
+ final GeodeticAuthorityFactory factory = AuthorityFactories.getEPSG();
if (!(factory instanceof EPSGFactoryFallback)) {
return factory;
}
@@ -2154,9 +2154,9 @@ public enum CommonCRS {
private static void failure(final Object caller, final String method, final FactoryException e, final int code) {
String message = Resources.format(Resources.Keys.CanNotInstantiateGeodeticObject_1, (Constants.EPSG + ':') + code);
message = Exceptions.formatChainedMessages(null, message, e);
- final LogRecord record = new LogRecord(Level.WARNING, message);
- if (!(e instanceof UnavailableFactoryException) || AuthorityFactories.failure((UnavailableFactoryException) e)) {
- // Append the stack trace only if the exception is the one we expect when the factory is not available.
+ final var record = new LogRecord(Level.WARNING, message);
+ if (!(e instanceof UnavailableFactoryException && AuthorityFactories.isUnavailable((UnavailableFactoryException) e))) {
+ // Append the stack trace only if the exception is for a reason different than unavailable factory.
record.setThrown(e);
}
Logging.completeAndLog(AuthorityFactories.LOGGER, caller.getClass(), method, record);
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 c8b2c0c321..18cfc6617d 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
@@ -713,6 +713,8 @@ public final class IdentifiedObjects extends Static {
final GeodeticAuthorityFactory factory;
if (authority == null) {
factory = AuthorityFactories.ALL;
+ } else if (authority.equalsIgnoreCase(Constants.EPSG)) {
+ return AuthorityFactories.finderForEPSG();
} else {
factory = AuthorityFactories.ALL.getAuthorityFactory(GeodeticAuthorityFactory.class, authority, null);
}
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
index 387556425c..4f179926bf 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
@@ -554,7 +554,7 @@ public class IdentifiedObjectFinder {
}
/**
- * Returns a set of authority codes that <strong>may</strong> identify the same object as the specified one.
+ * Returns a set of authority codes that <em>may</em> identify the same object as the specified one.
* The returned set must contains <em>at least</em> the code of every objects that are
* {@link ComparisonMode#APPROXIMATE approximately equal} to the specified one.
* However, the set may conservatively contains the code for more objects if an exact search is too expensive.
@@ -590,4 +590,107 @@ public class IdentifiedObjectFinder {
Logging.completeAndLog(GeodeticAuthorityFactory.LOGGER, IdentifiedObjectFinder.class,
"find", new LogRecord(Level.FINER, exception.getMessage()));
}
+
+ /**
+ * An object finder which delegates some or all work to another object finder.
+ * The default implementation of all {@code Wrapper} methods delegates the work to the object finder
+ * specified at construction time or in the last call to {@link #delegate(IdentifiedObjectFinder)}.
+ * Subclasses can override methods for modifying some find operations.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.5
+ * @since 1.5
+ */
+ public static abstract class Wrapper extends IdentifiedObjectFinder {
+ /**
+ * The finder doing the actual work, or {@code this} for using the
+ * default method implementation provided by the parent class.
+ */
+ private IdentifiedObjectFinder delegate;
+
+ /**
+ * Creates a new object finder which will delegate the actual work to the given finder.
+ *
+ * @param finder the object finder to which to delegate the work.
+ */
+ protected Wrapper(final IdentifiedObjectFinder finder) {
+ super(finder.factory);
+ delegate = finder;
+ }
+
+ /**
+ * Sets a new finder to which to delegate the actual search operations.
+ * If the specified finder is {@code this}, then this class will delegate to the default
+ * method implementations provided by the {@code IdentifiedObjectFinder} parent class.
+ * Otherwise, the specified finder should be a new instance not in use by other code.
+ *
+ * @param finder the object finder to which to delegate the work. Can be {@code this}.
+ * @throws FactoryException if the delegate cannot be set.
+ */
+ protected void delegate(final IdentifiedObjectFinder finder) throws FactoryException {
+ if (delegate != null) {
+ delegate.wrapper = null;
+ }
+ delegate = Objects.requireNonNull(finder);
+ }
+
+ /**
+ * Returns the object finder to which to delegate the actual search operations.
+ * If this method returns {@code this}, then the search operations will be delegated
+ * to the default methods provided by the {@code IdentifiedObjectFinder} parent class.
+ *
+ * @return the object finder to which to delegate the work. May be {@code this}.
+ * @throws FactoryException if the delegate cannot be created.
+ */
+ protected IdentifiedObjectFinder delegate() throws FactoryException {
+ if (delegate != this) {
+ delegate.setWrapper(this); // Done on each call because it also copies the configuration.
+ }
+ return delegate;
+ }
+
+ /**
+ * Lookups objects which are approximately equal to the specified object.
+ * The default method implementation delegates the work to the finder specified by {@link #delegate()}.
+ */
+ @Override
+ public Set<IdentifiedObject> find(final IdentifiedObject object) throws FactoryException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final IdentifiedObjectFinder delegate = delegate();
+ return (delegate != this) ? delegate.find(object) : super.find(object);
+ }
+
+ /**
+ * Lookups only one object which is approximately equal to the specified object.
+ * The default method implementation delegates the work to the finder specified by {@link #delegate()}.
+ */
+ @Override
+ public IdentifiedObject findSingleton(final IdentifiedObject object) throws FactoryException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final IdentifiedObjectFinder delegate = delegate();
+ return (delegate != this) ? delegate.findSingleton(object) : super.findSingleton(object);
+ }
+
+ /**
+ * Creates an object equals (optionally ignoring metadata), to the specified object.
+ * The default method implementation delegates the work to the finder specified by {@link #delegate()}.
+ */
+ @Override
+ Set<IdentifiedObject> createFromCodes(final IdentifiedObject object) throws FactoryException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final IdentifiedObjectFinder delegate = delegate();
+ return (delegate != this) ? delegate.createFromCodes(object) : super.createFromCodes(object);
+ }
+
+ /**
+ * Returns a set of authority codes that <em>may</em> identify the same object as the specified one.
+ * The default method implementation delegates the work to the finder specified by {@link #delegate()}.
+ */
+ @Override
+ protected Set<String> getCodeCandidates(final IdentifiedObject object) throws FactoryException {
+ @SuppressWarnings("LocalVariableHidesMemberVariable")
+ final IdentifiedObjectFinder delegate = delegate();
+ return (delegate != this) ? delegate.getCodeCandidates(object) : super.getCodeCandidates(object);
+ }
+ }
}
diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
index 02561e639f..682ea459d2 100644
--- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
+++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
@@ -581,8 +581,8 @@ public class MultiAuthoritiesFactory extends GeodeticAuthorityFactory implements
*/
/*
* This method is declared final for avoiding the false impression than overriding this method would change
- * the behavior of MultiAuthoritiesFactory. It would not because the 'create(…)' method invokes the private
- * 'getAuthorityFactory(…)' instead of the public one.
+ * the behavior of MultiAuthoritiesFactory. It would not because the `create(…)` method invokes the private
+ * `getAuthorityFactory(…)` instead of the public one.
*/
public final <T extends AuthorityFactory> T getAuthorityFactory(final Class<T> type,
final String authority, final String version) throws NoSuchAuthorityFactoryException
@@ -636,7 +636,7 @@ public class MultiAuthoritiesFactory extends GeodeticAuthorityFactory implements
final Iterable<? extends AuthorityFactory> provider = providers.get(request.type);
if (provider != null) {
final Iterator<? extends AuthorityFactory> it;
- synchronized (provider) { // Should never be null because of the 'doneMask' check.
+ synchronized (provider) { // Should never be null because of the `doneMask` check.
it = provider.iterator();
while (it.hasNext()) {
factory = it.next();
@@ -664,7 +664,7 @@ public class MultiAuthoritiesFactory extends GeodeticAuthorityFactory implements
/*
* Before to cache the factory with a key containing the factory version, make sure
* that we took in account the version of the default factory. This will prevent the
- * call to 'cache(versioned, factory)' to overwrite the default factory.
+ * call to `cache(versioned, factory)` to overwrite the default factory.
*/
if (factory != cached) {
cache(unversioned.versionOf(cached.getAuthority()), cached);
@@ -786,7 +786,7 @@ public class MultiAuthoritiesFactory extends GeodeticAuthorityFactory implements
* is present. The remainder steps are the same as if the user gave a simple code (e.g. "EPSG:4326").
*/
if (uri.authority == null) {
- // We want this check before the 'code' value is modified below.
+ // We want this check before the `code` value is modified below.
throw new NoSuchAuthorityCodeException(
Resources.format(Resources.Keys.MissingAuthority_1, code), null, uri.code, code);
}
@@ -1540,7 +1540,7 @@ public class MultiAuthoritiesFactory extends GeodeticAuthorityFactory implements
/*
* Identify the type requested by the user and create all components with the assumption that they will
* be of that type. This is the most common case. If during iteration we find an object of another kind,
- * then the array type will be downgraded to IdentifiedObject[]. The 'componentType' variable will keep
+ * then the array type will be downgraded to IdentifiedObject[]. The `componentType` variable will keep
* its non-null value only if the array stay of the expected sub-type.
*/
final AuthorityFactoryIdentifier.Type requestedType;
@@ -1823,8 +1823,8 @@ public class MultiAuthoritiesFactory extends GeodeticAuthorityFactory implements
((ServiceLoader<?>) provider).reload();
}
/*
- * Clear the 'iterationCompleted' bit before to clear the cache so that if another thread
- * invokes 'getAuthorityFactory(…)', it will block on the synchronized(provider) statement
+ * Clear the `iterationCompleted` bit before to clear the cache so that if another thread
+ * invokes `getAuthorityFactory(…)`, it will block on the synchronized(provider) statement
* until we finished the cleanup.
*/
final int type = entry.getKey().ordinal();
diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/EPSGFactoryFallbackTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
index dc82cff0f2..30ef5d3382 100644
--- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
+++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
@@ -241,7 +241,7 @@ public final class EPSGFactoryFallbackTest extends TestCaseWithLogs {
*/
@Configuration
private static void setEPSGFactory(final GeodeticAuthorityFactory factory) {
- AuthorityFactories.EPSG(factory);
+ AuthorityFactories.setEPSG(factory);
for (final CommonCRS crs : CommonCRS .values()) crs.clear();
for (final CommonCRS.Vertical crs : CommonCRS.Vertical.values()) crs.clear();
for (final CommonCRS.Temporal crs : CommonCRS.Temporal.values()) crs.clear();
@@ -255,7 +255,7 @@ public final class EPSGFactoryFallbackTest extends TestCaseWithLogs {
*/
@Test
public void compareAllCodes() throws FactoryException {
- final GeodeticAuthorityFactory EPSG = AuthorityFactories.EPSG();
+ final GeodeticAuthorityFactory EPSG = AuthorityFactories.getEPSG();
try {
setEPSGFactory(EPSGFactoryFallback.INSTANCE);
final var codes = new ArrayList<String>(EPSGFactoryFallback.INSTANCE.getAuthorityCodes(CoordinateReferenceSystem.class));
diff --git a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/InfoStatements.java b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/InfoStatements.java
index ce1545dd4f..111d0ae99f 100644
--- a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/InfoStatements.java
+++ b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/InfoStatements.java
@@ -641,11 +641,11 @@ public class InfoStatements implements Localized, AutoCloseable {
if (error == null) error = e;
else error.addSuppressed(e);
}
- continue; // Ignore codes that are not integers.
+ continue; // Ignore codes that are not integers.
}
final SRID search = new SRID(crs, authority, code);
if (done.putIfAbsent(search, code > 0) != null) {
- continue; // Skip "authority:code" that we already tried.
+ continue; // Skip "authority:code" that we already tried.
}
/*
* Found an "authority:code" pair that we did not tested before.
diff --git a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/InfoStatementsTest.java b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/InfoStatementsTest.java
index 7a3f333d12..c84a671fa1 100644
--- a/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/InfoStatementsTest.java
+++ b/endorsed/src/org.apache.sis.storage.sql/test/org/apache/sis/storage/sql/feature/InfoStatementsTest.java
@@ -139,8 +139,12 @@ public final class InfoStatementsTest extends TestCase {
CoordinateReferenceSystem.IDENTIFIERS_KEY, new ImmutableIdentifier(null, "FOO", "4326")),
HardCodedDatum.SPHERE, null, HardCodedCS.GEODETIC_2D);
- c.setReadOnly(false); assertEquals(1, info.findSRID(clash));
- c.setReadOnly(true); assertEquals(1, info.findSRID(clash));
+ c.setReadOnly(false);
+ final int code = info.findSRID(clash);
+ assertNotEquals(4326, code);
+ assertTrue(code > 0);
+ c.setReadOnly(true);
+ assertEquals(code, info.findSRID(clash));
}
}