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 02e6ffe626 Add an implementation of `RegisterOperations` (a new
interface added in ISO 19111:2019).
02e6ffe626 is described below
commit 02e6ffe626b5eaae5747b80a54567bb01982e9e3
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Jun 28 20:09:55 2024 +0200
Add an implementation of `RegisterOperations` (a new interface added in ISO
19111:2019).
---
.../geometry/wrapper/SpatialOperationContext.java | 4 +-
.../org/apache/sis/util/iso/AbstractFactory.java | 22 +-
.../main/module-info.java | 3 +
.../main/org/apache/sis/referencing/CRS.java | 3 +-
.../sis/referencing/MultiRegisterOperations.java | 445 +++++++++++++++++++++
.../factory/MultiAuthoritiesFactory.java | 22 +-
.../operation/CoordinateOperationRegistry.java | 5 +-
.../DefaultCoordinateOperationFactory.java | 4 +-
.../factory/GeodeticObjectFactoryTest.java | 18 +-
.../referencing/geoapi/AuthorityFactoryTest.java | 3 +-
geoapi/snapshot | 2 +-
11 files changed, 513 insertions(+), 18 deletions(-)
diff --git
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/geometry/wrapper/SpatialOperationContext.java
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/geometry/wrapper/SpatialOperationContext.java
index 208b00e466..7fa87083ee 100644
---
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/geometry/wrapper/SpatialOperationContext.java
+++
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/geometry/wrapper/SpatialOperationContext.java
@@ -357,8 +357,8 @@ select: if (commonCRS == null) {
/** Creates the {@link #INSTANCE} singleton. */
private Projector() throws FactoryException {
- final ReferencingFactoryContainer f = new
ReferencingFactoryContainer();
- method =
f.getCoordinateOperationFactory().getOperationMethod("Mercator_2SP");
+ final var f = new ReferencingFactoryContainer();
+ method = f.findOperationMethod("Mercator_2SP");
cartCS = f.getStandardProjectedCS();
name = Map.of(DefaultConversion.NAME_KEY,
new ImmutableIdentifier(Citations.SIS, "SIS",
"Mercator for geometry"));
diff --git
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/AbstractFactory.java
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/AbstractFactory.java
index 26b8a18ef3..11a32493d4 100644
---
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/AbstractFactory.java
+++
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/AbstractFactory.java
@@ -19,13 +19,14 @@ package org.apache.sis.util.iso;
import org.opengis.util.Factory;
import org.opengis.metadata.citation.Citation;
import org.apache.sis.metadata.simple.SimpleCitation;
+import org.apache.sis.util.privy.Strings;
/**
* Base class of factories provided in the Apache SIS library.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.3
+ * @version 1.5
* @since 0.3
*/
public abstract class AbstractFactory implements Factory {
@@ -55,4 +56,23 @@ public abstract class AbstractFactory implements Factory {
}
return null;
}
+
+ /**
+ * Returns a string representation of this factory for debugging purposes.
+ * This string representation may change in any future version of Apache
SIS.
+ *
+ * @return a string representation of this factory.
+ *
+ * @since 1.5
+ */
+ @Override
+ public String toString() {
+ final var args = new Object[2];
+ Citation c = getVendor();
+ if (c != null) {
+ args[0] = "vendor";
+ args[1] = c.getTitle();
+ }
+ return Strings.toString(getClass(), args);
+ }
}
diff --git a/endorsed/src/org.apache.sis.referencing/main/module-info.java
b/endorsed/src/org.apache.sis.referencing/main/module-info.java
index c19d16bee7..ba29bb0806 100644
--- a/endorsed/src/org.apache.sis.referencing/main/module-info.java
+++ b/endorsed/src/org.apache.sis.referencing/main/module-info.java
@@ -33,6 +33,9 @@ module org.apache.sis.referencing {
provides org.apache.sis.metadata.sql.privy.Initializer
with org.apache.sis.referencing.internal.DatabaseListener;
+ provides org.opengis.referencing.RegisterOperations
+ with org.apache.sis.referencing.MultiRegisterOperations;
+
provides org.opengis.referencing.crs.CRSFactory
with org.apache.sis.referencing.factory.GeodeticObjectFactory;
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 8003fd784a..7cb26286f0 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
@@ -1576,8 +1576,7 @@ check: while (lower != 0 || upper != dimension) {
* @return the system-wide authority factory used by SIS for the given
authority.
* @throws FactoryException if no factory can be returned for the given
authority.
*
- * @see #forCode(String)
- * @see org.apache.sis.referencing.factory.MultiAuthoritiesFactory
+ * @see MultiRegisterOperations
*
* @since 0.7
*/
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/MultiRegisterOperations.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/MultiRegisterOperations.java
new file mode 100644
index 0000000000..6bf7628dbd
--- /dev/null
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/MultiRegisterOperations.java
@@ -0,0 +1,445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+import java.util.Iterator;
+import java.util.AbstractSet;
+import java.util.Objects;
+import java.util.Optional;
+import org.opengis.util.Factory;
+import org.opengis.util.FactoryException;
+import org.opengis.util.InternationalString;
+import org.opengis.metadata.citation.Citation;
+import org.opengis.metadata.extent.GeographicBoundingBox;
+import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.AuthorityFactory;
+import org.opengis.referencing.RegisterOperations;
+import org.opengis.referencing.crs.SingleCRS;
+import org.opengis.referencing.crs.CRSFactory;
+import org.opengis.referencing.crs.CRSAuthorityFactory;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.cs.CSFactory;
+import org.opengis.referencing.cs.CSAuthorityFactory;
+import org.opengis.referencing.datum.DatumFactory;
+import org.opengis.referencing.datum.DatumAuthorityFactory;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.referencing.operation.CoordinateOperationFactory;
+import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.apache.sis.referencing.factory.GeodeticObjectFactory;
+import org.apache.sis.referencing.factory.MultiAuthoritiesFactory;
+import org.apache.sis.referencing.factory.NoSuchAuthorityFactoryException;
+import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
+import
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
+import org.apache.sis.util.Utilities;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.iso.AbstractFactory;
+
+
+/**
+ * Finds <abbr>CRS</abbr>s or coordinate operations in one or many geodetic
registries.
+ * Each {@code MultiRegisterOperations} instance can narrow the search to a
single registry,
+ * a specific version of that registry, or to a domain of validity.
+ * Each instance is immutable and thread-safe.
+ *
+ * <p>This class delegates its work to {@linkplain CRS#forCode(String) static
methods} or to
+ * {@link MultiAuthoritiesFactory}. It does not provide new services compared
to the above,
+ * but provides a more high-level <abbr>API</abbr> with the most important
registry-based
+ * services in a single place. {@link RegisterOperations} can also be used as
en entry point,
+ * with accesses to the low-level <abbr>API</abbr> granted by {@link
#getFactory(Class)}.</p>
+ *
+ * <h2>User-defined geodetic registries</h2>
+ * User-defined authorities can be added to the SIS environment by creating
{@link CRSAuthorityFactory}
+ * implementations with a public no-argument constructor or a public static
{@code provider()} method,
+ * and declaring the name of those classes in the {@code module-info.java}
file as a provider of the
+ * {@code org.opengis.referencing.crs.CRSAuthorityFactory} service.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.5
+ * @since 1.5
+ */
+public class MultiRegisterOperations extends AbstractFactory implements
RegisterOperations {
+ /**
+ * Types of factories supported by this implementation.
+ * A value of {@code true} means that the factory is an authority factory.
+ * A value of {@code false} means that the factory is an object factory.
+ *
+ * @see #getFactory(Class)
+ */
+ private static final Map<Class<?>, Boolean> FACTORY_TYPES = Map.of(
+ CoordinateOperationAuthorityFactory.class, Boolean.TRUE,
+ DatumAuthorityFactory.class, Boolean.TRUE,
+ CRSAuthorityFactory.class, Boolean.TRUE,
+ CSAuthorityFactory.class, Boolean.TRUE,
+ DatumFactory.class, Boolean.FALSE,
+ CRSFactory.class, Boolean.FALSE,
+ CSFactory.class, Boolean.FALSE);
+
+ /**
+ * The authority of the <abbr>CRS</abbr> and coordinate operations to
search,
+ * or {@code null} for all authorities. In the latter case, the authority
must
+ * be specified in the code, for example {@code "EPSG:4326"} instead of
"4326".
+ *
+ * @see #withAuthority(String)
+ */
+ private final String authority;
+
+ /**
+ * Version of the registry to use, or {@code null} for the default version.
+ * Can be non-null only if {@link #authority} is also non-null.
+ * If null, the default version is usually the latest one.
+ *
+ * @see #withVersion(String)
+ */
+ private final String version;
+
+ /**
+ * The area of interest for coordinate operations, or {@code null} for the
whole world.
+ *
+ * @see #withAreaOfInterest(GeographicBoundingBox)
+ */
+ private final GeographicBoundingBox areaOfInterest;
+
+ /**
+ * The authority factory to use for extracting <abbr>CRS</abbr> instances,
or {@code null} if no
+ * authority has been specified. In the latter case, {@link CRS} static
methods should be used.
+ * In Apache SIS implementation, this is also an {@link
CoordinateOperationAuthorityFactory}.
+ *
+ * @see #findCoordinateReferenceSystem(String)
+ * @see #findCoordinateOperation(String)
+ */
+ private final CRSAuthorityFactory crsFactory;
+
+ /**
+ * The singleton instance for all authorities in their default versions,
with no <abbr>AOI</abbr>.
+ *
+ * @see #provider()
+ */
+ private static final MultiRegisterOperations DEFAULT = new
MultiRegisterOperations();
+
+ /**
+ * Returns an instance which will search <abbr>CRS</abbr> definitions in
all registries that are known to SIS.
+ * Because this instance is not for a specific registry, the authority
will need to be part of the {@code code}
+ * argument given to {@code create(String)} methods. For example, {@code
"EPSG:4326"} instead of {@code "4326"}.
+ * The registry can be made implicit by a call to {@link
#withAuthority(String)}.
+ *
+ * @return the default instance for all registries known to SIS.
+ */
+ public static MultiRegisterOperations provider() {
+ return DEFAULT;
+ }
+
+ /**
+ * Creates an instance which will search <abbr>CRS</abbr> definitions in
all registries that are known to SIS.
+ *
+ * @see #provider()
+ */
+ private MultiRegisterOperations() {
+ authority = null;
+ version = null;
+ crsFactory = null;
+ areaOfInterest = null;
+ }
+
+ /**
+ * Creates an instance with the same register than the given instance, but
a different <abbr>AOI</abbr>.
+ *
+ * @param source the register from which to copy the authority
and version.
+ * @param areaOfInterest the new area of interest (<abbr>AOI</abbr>), or
{@code null} if none.
+ *
+ * @see #withAreaOfInterest(GeographicBoundingBox)
+ */
+ protected MultiRegisterOperations(final MultiRegisterOperations source,
final GeographicBoundingBox areaOfInterest) {
+ authority = source.authority;
+ version = source.version;
+ crsFactory = source.crsFactory;
+ this.areaOfInterest = areaOfInterest;
+ }
+
+ /**
+ * Creates an instance which will use the registry of the specified
authority, optionally at a specified version.
+ *
+ * @param source the register from which to copy the area of interest.
+ * @param authority identification of the registry to use (e.g., "EPSG").
+ * @param version the registry version to use, or {@code null} for the
default version.
+ * @throws NoSuchAuthorityFactoryException if the specified registry has
not been found.
+ *
+ * @see #withAuthority(String)
+ * @see #withVersion(String)
+ */
+ protected MultiRegisterOperations(final MultiRegisterOperations source,
final String authority, final String version)
+ throws NoSuchAuthorityFactoryException
+ {
+ this.authority = Objects.requireNonNull(authority);
+ this.version = version;
+ this.areaOfInterest = source.areaOfInterest;
+ crsFactory =
AuthorityFactories.ALL.getAuthorityFactory(CRSAuthorityFactory.class,
authority, version);
+ }
+
+ /**
+ * Returns the <abbr>CRS</abbr> authority factory.
+ */
+ private CRSAuthorityFactory crsFactory() {
+ return (crsFactory != null) ? crsFactory : AuthorityFactories.ALL;
+ }
+
+ /**
+ * Returns the organization or party responsible for definition and
maintenance of the register.
+ * If an authority has been specified by a call to {@link
#withAuthority(String)}, then this method
+ * returns that authority. Otherwise, this method returns {@code null}.
+ *
+ * @return the organization responsible for definitions in the registry,
or {@code null} if none or many.
+ *
+ * @see MultiAuthoritiesFactory#getAuthority()
+ */
+ @Override
+ public Citation getAuthority() {
+ return crsFactory().getAuthority();
+ }
+
+ /**
+ * Returns an instance for a geodetic registry of the specified authority,
such as "EPSG".
+ * If a {@linkplain #withVersion(String) version number was specified}
previously, that version is cleared.
+ * If an area of interest was specified, the same area of interest is
reused.
+ *
+ * <h2>User-defined geodetic registries</h2>
+ * A user-defined authority can be specified if the implementation is
declared in a {@code module-info}
+ * file as a {@link CRSAuthorityFactory} service. See class javadoc for
more information.
+ *
+ * @param newValue the desired authority, or {@code null} for all of
them.
+ * @return register operations for the specified authority.
+ * @throws NoSuchAuthorityFactoryException if the given authority is
unknown to SIS.
+ *
+ * @see CRS#getAuthorityFactory(String)
+ */
+ public MultiRegisterOperations withAuthority(final String newValue) throws
NoSuchAuthorityFactoryException {
+ if (version == null && Objects.equals(authority, newValue)) {
+ return this;
+ } else if (newValue == null) {
+ return DEFAULT.withAreaOfInterest(areaOfInterest);
+ } else {
+ return new MultiRegisterOperations(this, newValue, null);
+ }
+ }
+
+ /**
+ * Returns an instance for the specified version of the geodetic registry.
+ * A non-null authority must have been {@linkplain #withAuthority(String)
specified} before to invoke this method.
+ * If an area of interest was specified, the same area of interest is
reused.
+ *
+ * @param newValue the desired version, or {@code null} for the default
version.
+ * @return register operations for the specified version of the geodetic
registry.
+ * @throws IllegalStateException if the version is non-null and no
authority has been specified previously.
+ * @throws NoSuchAuthorityFactoryException if the given version is unknown
to SIS.
+ */
+ public MultiRegisterOperations withVersion(final String newValue) throws
NoSuchAuthorityFactoryException {
+ if (Objects.equals(version, newValue)) {
+ return this;
+ } else if (newValue == null && authority == null) {
+ return DEFAULT.withAreaOfInterest(areaOfInterest);
+ } else if (authority != null) {
+ return new MultiRegisterOperations(this, authority, newValue);
+ } else {
+ throw new
IllegalStateException(Errors.format(Errors.Keys.MissingValueForProperty_1,
"authority"));
+ }
+ }
+
+ /**
+ * Returns an instance for the specified area of interest
(<abbr>AOI</abbr>).
+ * The area of interest is used for filtering coordinate operations between
+ * a {@linkplain #findCoordinateOperations between a pair of CRSs}.
+ *
+ * @param newValue the desired area of interest, or {@code null} for the
world.
+ * @return register operations for the specified area of interest.
+ */
+ public MultiRegisterOperations withAreaOfInterest(final
GeographicBoundingBox newValue) {
+ if (Objects.equals(areaOfInterest, newValue)) {
+ return this;
+ } else if (newValue == null && authority == null && version == null) {
+ return DEFAULT;
+ } else {
+ return new MultiRegisterOperations(this, newValue);
+ }
+ }
+
+ /**
+ * Returns the set of authority codes for objects of the given type.
+ * The {@code type} argument specifies the base type of identified objects.
+ * For example, {@code CoordinateReferenceSystem.class} is for requesting
the <abbr>CRS</abbr> codes.
+ *
+ * <h4>Limitations</h4>
+ * In the current implementation, codes are filtered by authority and
registry version,
+ * but not for the area of interest.
+ *
+ * @param type the type of referencing object for which to get authority
codes.
+ * @return the set of authority codes for referencing objects of the given
type.
+ * @throws FactoryException if access to the underlying database failed.
+ */
+ @Override
+ public Set<String> getAuthorityCodes(Class<? extends IdentifiedObject>
type) throws FactoryException {
+ return crsFactory().getAuthorityCodes(type);
+ }
+
+ /**
+ * Returns a textual description of the object corresponding to a code.
+ * The description may be used in graphical user interfaces.
+ *
+ * @param type the type of object for which to get a description.
+ * @param code value allocated by the authority for an object of the
given type.
+ * @return a description of the object, or empty if the object has no
description.
+ * @throws NoSuchAuthorityCodeException if the specified {@code code} was
not found.
+ * @throws FactoryException if the query failed for some other reason.
+ */
+ @Override
+ public Optional<InternationalString> getDescriptionText(Class<? extends
IdentifiedObject> type, String code)
+ throws FactoryException
+ {
+ return crsFactory().getDescriptionText(type, code);
+ }
+
+ /**
+ * Extracts <abbr>CRS</abbr> details from the registry. If this {@code
RegisterOperations} has not
+ * been restricted to a specific authority by a call to {@link
#withAuthority(String)}, then the
+ * given code must contain the authority (e.g., {@code "EPSG:4326"}
instead of {@code "4326"}.
+ * Otherwise, this method delegates to {@link CRS#forCode(jString)}.
+ *
+ * <p>By default, this method recognizes the {@code "EPSG"} and {@code
"OGC"} authorities.
+ * In the {@code "EPSG"} case, whether the full set of EPSG 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 uses a small embedded
+ * EPSG factory containing at least the CRS defined in the {@link
#forCode(String)} method javadoc.</p>
+ *
+ * @param code <abbr>CRS</abbr> identifier allocated by the authority.
+ * @return the <abbr>CRS</abbr> for the given authority code.
+ * @throws NoSuchAuthorityCodeException if the specified {@code code} was
not found.
+ * @throws FactoryException if the search failed for some other reason.
+ *
+ * @see CRS#forCode(String)
+ */
+ @Override
+ public CoordinateReferenceSystem findCoordinateReferenceSystem(final
String code) throws FactoryException {
+ if (crsFactory != null) {
+ return crsFactory.createCoordinateReferenceSystem(code);
+ }
+ return CRS.forCode(code);
+ }
+
+ /**
+ * Extracts coordinate operation details from the registry. If this {@code
RegisterOperations}
+ * has not been restricted to a specific authority by a call to {@link
#withAuthority(String)},
+ * then the given code must contain the authority.
+ *
+ * @param code operation identifier allocated by the authority.
+ * @return the operation for the given authority code.
+ * @throws NoSuchAuthorityCodeException if the specified {@code code} was
not found.
+ * @throws FactoryException if the search failed for some other reason.
+ */
+ @Override
+ public CoordinateOperation findCoordinateOperation(String code) throws
FactoryException {
+ if (crsFactory instanceof CoordinateOperationAuthorityFactory) {
+ ((CoordinateOperationAuthorityFactory)
crsFactory).createCoordinateOperation(code);
+ }
+ return AuthorityFactories.ALL.createCoordinateOperation(code);
+ }
+
+ /**
+ * Finds or infers any coordinate operations for which the given
<abbr>CRS</abbr>s are the source and target,
+ * in that order. This method searches for operation paths defined in the
registry.
+ * If none are found, this method tries to infer a path itself.
+ *
+ * @param source the source <abbr>CRS</abbr>.
+ * @param target the target <abbr>CRS</abbr>.
+ * @return coordinate operations found or inferred between the given pair
<abbr>CRS</abbr>s. May be an empty set.
+ * @throws FactoryException if an error occurred while searching for
coordinate operations.
+ */
+ @Override
+ public Set<CoordinateOperation>
findCoordinateOperations(CoordinateReferenceSystem source,
CoordinateReferenceSystem target)
+ throws FactoryException
+ {
+ final List<CoordinateOperation> operations =
CRS.findOperations(source, target, areaOfInterest);
+ return new AbstractSet<>() { // Assuming that the list does not
contain duplicated elements.
+ @Override public Iterator<CoordinateOperation> iterator() {return
operations.iterator();}
+ @Override public boolean isEmpty() {return operations.isEmpty();}
+ @Override public int size() {return operations.size();}
+ };
+ }
+
+ /**
+ * Determines whether two <abbr>CRS</abbr>s are members of one ensemble.
+ * If this method returns {@code true}, then for low accuracy purposes
coordinate sets referenced
+ * to these <abbr>CRS</abbr>s may be merged without coordinate
transformation.
+ * The attribute {@link DatumEnsemble#getEnsembleAccuracy()} gives some
indication
+ * of the inaccuracy introduced through such merger.
+ *
+ * @param source the source <abbr>CRS</abbr>.
+ * @param target the target <abbr>CRS</abbr>.
+ * @return whether the two <abbr>CRS</abbr>s are members of one ensemble.
+ * @throws FactoryException if an error occurred while searching for
ensemble information in the registry.
+ */
+ @Override
+ public boolean areMembersOfSameEnsemble(CoordinateReferenceSystem source,
CoordinateReferenceSystem target)
+ throws FactoryException
+ {
+ return (source instanceof SingleCRS) && (target instanceof SingleCRS)
+ && Utilities.equalsIgnoreMetadata(
+ ((SingleCRS) source).getDatumEnsemble(),
+ ((SingleCRS) target).getDatumEnsemble());
+ }
+
+ /**
+ * Returns a factory used for building components of <abbr>CRS</abbr> or
coordinate operations.
+ * The factories returned by this method provide accesses to the low-level
services used by this
+ * {@code RegisterOperations} instance for implementing its high-level
services.
+ *
+ * @param <T> compile-time value of the {@code type} argument.
+ * @param type the desired type of factory.
+ * @return factory of the specified type.
+ * @throws NullPointerException if the specified type is null.
+ * @throws IllegalArgumentException if the specified type is not one of
the above-cited values.
+ */
+ @Override
+ public <T extends Factory> Optional<T> getFactory(final Class<T> type) {
+ final Factory factory;
+ final Boolean b = FACTORY_TYPES.get(type);
+ if (b != null) {
+ if (b) {
+ final MultiAuthoritiesFactory mf = AuthorityFactories.ALL;
+ if (authority == null) {
+ factory = mf;
+ } else try {
+ factory =
mf.getAuthorityFactory(type.asSubclass(AuthorityFactory.class), authority,
version);
+ } catch (NoSuchAuthorityFactoryException e) {
+ Logging.recoverableException(AuthorityFactories.LOGGER,
MultiRegisterOperations.class, "getFactory", e);
+ return Optional.empty();
+ }
+ } else {
+ factory = GeodeticObjectFactory.provider();
+ }
+ } else if (type == CoordinateOperationFactory.class) {
+ factory = DefaultCoordinateOperationFactory.provider();
+ } else if (type == MathTransformFactory.class) {
+ factory = DefaultMathTransformFactory.provider();
+ } else {
+ throw new
IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2,
"type", type));
+ }
+ return Optional.of(type.cast(factory));
+ }
+}
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 3582606d22..b3a3d07594 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
@@ -46,6 +46,7 @@ import org.opengis.metadata.extent.Extent;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.util.FactoryException;
import org.opengis.util.InternationalString;
+import org.opengis.util.NoSuchIdentifierException;
import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.ArgumentChecks;
@@ -61,6 +62,7 @@ import org.apache.sis.referencing.privy.LazySet;
import org.apache.sis.referencing.internal.Resources;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
+import
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.collection.BackingStoreException;
@@ -289,8 +291,10 @@ public class MultiAuthoritiesFactory extends
GeodeticAuthorityFactory implements
/**
* Returns the database or specification that defines the codes recognized
by this factory.
- * The default implementation returns {@code null} since {@code
MultiAuthoritiesFactory} is not
- * about a particular authority.
+ * The default implementation returns {@code null} because {@code
MultiAuthoritiesFactory}
+ * is not about a particular authority.
+ *
+ * @return the organization responsible for definitions in the registry,
or {@code null} if none or many.
*/
@Override
public Citation getAuthority() {
@@ -1430,12 +1434,24 @@ public class MultiAuthoritiesFactory extends
GeodeticAuthorityFactory implements
*
<li><code>http://www.opengis.net/def/<b>method</b>/</code><var>authority</var>{@code
/}<var>version</var>{@code /}<var>code</var></li>
* </ul>
*
+ * If the given code is not found in the geodetic registry, then this
method searches also among
+ * the {@linkplain DefaultMathTransformFactory#getOperationMethod(String)
build-in methods}.
+ *
* @return the operation method for the given code.
* @throws FactoryException if the object creation failed.
*/
@Override
public OperationMethod createOperationMethod(final String code) throws
FactoryException {
- return create(AuthorityFactoryProxy.METHOD, code);
+ try {
+ return create(AuthorityFactoryProxy.METHOD, code);
+ } catch (NoSuchAuthorityCodeException e) {
+ try {
+ return
DefaultMathTransformFactory.provider().getOperationMethod(code);
+ } catch (NoSuchIdentifierException s) {
+ e.addSuppressed(s);
+ throw e;
+ }
+ }
}
/**
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 33c46f35e5..6bbb7f6814 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
@@ -63,6 +63,7 @@ import
org.apache.sis.referencing.factory.NoSuchAuthorityFactoryException;
import org.apache.sis.referencing.privy.CoordinateOperations;
import org.apache.sis.referencing.privy.EllipsoidalHeightCombiner;
import org.apache.sis.referencing.privy.PositionalAccuracyConstant;
+import org.apache.sis.referencing.privy.ReferencingFactoryContainer;
import org.apache.sis.referencing.privy.ReferencingUtilities;
import org.apache.sis.referencing.internal.DeferredCoordinateOperation;
import org.apache.sis.referencing.internal.Resources;
@@ -1337,7 +1338,9 @@ class CoordinateOperationRegistry {
if (descriptor != null) {
final Identifier name = descriptor.getName();
if (name != null) {
- method = factory.getOperationMethod(name.getCode());
+ final MathTransformFactory mtFactory =
factorySIS.getMathTransformFactory();
+ var c = new ReferencingFactoryContainer(null, null,
null, null, factory, mtFactory);
+ method = c.findOperationMethod(name.getCode());
}
if (method == null) {
method = factory.createOperationMethod(properties,
descriptor);
diff --git
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
index 7f72c76705..80e25bccd7 100644
---
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
+++
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
@@ -273,8 +273,10 @@ public class DefaultCoordinateOperationFactory extends
AbstractFactory implement
* @throws FactoryException if the requested operation method cannot be
fetched.
*
* @see DefaultMathTransformFactory#getOperationMethod(String)
+ *
+ * @deprecated Use {@link DefaultMathTransformFactory} instead.
*/
- @Override
+ @Deprecated(since="1.5", forRemoval=true)
public OperationMethod getOperationMethod(String name) throws
FactoryException {
return new ReferencingFactoryContainer(null, null, null, null, null,
mtFactory).findOperationMethod(name);
}
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/GeodeticObjectFactoryTest.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/GeodeticObjectFactoryTest.java
index d96503c7c5..762cad6ece 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/GeodeticObjectFactoryTest.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/GeodeticObjectFactoryTest.java
@@ -22,13 +22,16 @@ import javax.measure.quantity.Angle;
import javax.measure.quantity.Length;
import org.opengis.util.FactoryException;
import org.opengis.referencing.IdentifiedObject;
+import org.opengis.referencing.cs.CSFactory;
import org.opengis.referencing.cs.CartesianCS;
import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.crs.CRSFactory;
import org.opengis.referencing.crs.GeodeticCRS;
import org.opengis.referencing.crs.GeographicCRS;
import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.datum.DatumFactory;
import org.opengis.referencing.datum.Ellipsoid;
import org.opengis.referencing.datum.PrimeMeridian;
import org.opengis.referencing.datum.GeodeticDatum;
@@ -36,8 +39,9 @@ import org.opengis.referencing.operation.OperationMethod;
import org.opengis.referencing.operation.Conversion;
import org.opengis.parameter.ParameterValueGroup;
import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.MultiRegisterOperations;
import org.apache.sis.referencing.operation.DefaultConversion;
-import org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory;
+import
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
import org.apache.sis.io.wkt.Convention;
import org.apache.sis.measure.Units;
@@ -63,10 +67,7 @@ public final class GeodeticObjectFactoryTest extends
ObjectFactoryTest {
* Creates a new test suite using the singleton factory instance.
*/
public GeodeticObjectFactoryTest() {
- super(GeodeticObjectFactory.provider(),
- GeodeticObjectFactory.provider(),
- GeodeticObjectFactory.provider(),
- DefaultCoordinateOperationFactory.provider());
+ super(MultiRegisterOperations.provider());
}
/**
@@ -78,6 +79,7 @@ public final class GeodeticObjectFactoryTest extends
ObjectFactoryTest {
*/
@Test
public void testCreateFromWKT() throws FactoryException {
+ final CRSFactory crsFactory =
factories.getFactory(CRSFactory.class).orElseThrow();
final GeodeticCRS crs = (GeodeticCRS) crsFactory.createFromWKT(
"GEOGCS[“WGS 84”,\n" +
" DATUM[“World Geodetic System 1984”,\n" +
@@ -97,6 +99,7 @@ public final class GeodeticObjectFactoryTest extends
ObjectFactoryTest {
*/
@Test
public void testInvalidParameterInWKT() throws FactoryException {
+ final CRSFactory crsFactory =
factories.getFactory(CRSFactory.class).orElseThrow();
var e = assertThrows(InvalidGeodeticParameterException.class,
() -> crsFactory.createFromWKT(
"PROJCRS[“Custom”,\n" +
@@ -134,6 +137,9 @@ public final class GeodeticObjectFactoryTest extends
ObjectFactoryTest {
*/
@Test
public void testStepByStepCreation() throws FactoryException {
+ final CRSFactory crsFactory =
factories.getFactory(CRSFactory.class).orElseThrow();
+ final CSFactory csFactory =
factories.getFactory(CSFactory.class).orElseThrow();
+ final DatumFactory datumFactory =
factories.getFactory(DatumFactory.class).orElseThrow();
/*
* List of all objects to be created in this test.
*/
@@ -189,7 +195,7 @@ public final class GeodeticObjectFactoryTest extends
ObjectFactoryTest {
/*
* Defining conversion
*/
- method = copFactory.getOperationMethod("Transverse_Mercator");
+ method =
DefaultMathTransformFactory.provider().getOperationMethod("Transverse_Mercator");
parameters = method.getParameters().createValue();
parameters.parameter("semi_major")
.setValue(ellipsoid.getSemiMajorAxis());
parameters.parameter("semi_minor")
.setValue(ellipsoid.getSemiMinorAxis());
diff --git
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/geoapi/AuthorityFactoryTest.java
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/geoapi/AuthorityFactoryTest.java
index 4942e3c371..9912eeb342 100644
---
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/geoapi/AuthorityFactoryTest.java
+++
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/geoapi/AuthorityFactoryTest.java
@@ -18,6 +18,7 @@ package org.apache.sis.referencing.geoapi;
import org.opengis.util.FactoryException;
import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.MultiRegisterOperations;
// Test dependencies
import org.junit.jupiter.api.Disabled;
@@ -42,7 +43,7 @@ public final class AuthorityFactoryTest extends
org.opengis.test.referencing.Aut
* @throws FactoryException if no factory can be returned for the given
authority.
*/
public AuthorityFactoryTest() throws FactoryException {
- super(CRS.getAuthorityFactory(null), null, null);
+ super(MultiRegisterOperations.provider());
}
/**
diff --git a/geoapi/snapshot b/geoapi/snapshot
index a07e965123..a0ae30dd67 160000
--- a/geoapi/snapshot
+++ b/geoapi/snapshot
@@ -1 +1 @@
-Subproject commit a07e965123706be9092d0dc615592c23c8401450
+Subproject commit a0ae30dd67b67a718b74bd8a90140ea0a559e8b6