Search in sources :

Example 21 with FactoryException

use of org.opengis.util.FactoryException in project sis by apache.

the class IdentifiedObjectFinder method createFromNames.

/**
 * Creates an object equals (optionally ignoring metadata), to the specified object using only the
 * {@linkplain AbstractIdentifiedObject#getName name} and {@linkplain AbstractIdentifiedObject#getAlias aliases}.
 * If no such object is found, returns {@code null}.
 *
 * <p>This method may be used with some {@linkplain GeodeticAuthorityFactory authority factory}
 * implementations like the one backed by the EPSG database, which are capable to find an object
 * from its name when the identifier is unknown.</p>
 *
 * @param  object  the object looked up.
 * @return the identified object, or {@code null} if not found.
 * @throws FactoryException if an error occurred while creating an object.
 *
 * @see #createFromCodes(IdentifiedObject)
 * @see #createFromIdentifiers(IdentifiedObject)
 */
private IdentifiedObject createFromNames(final IdentifiedObject object) throws FactoryException {
    String code = object.getName().getCode();
    IdentifiedObject candidate;
    try {
        candidate = create(code);
    } catch (FactoryException e) {
        /*
             * The identifier was not recognized. We will continue later with aliases.
             * Note: we catch a more generic exception than NoSuchAuthorityCodeException because
             *       this attempt may fail for various reasons (character string not supported
             *       by the underlying database for primary key, duplicated name found, etc.).
             */
        exceptionOccurred(e);
        candidate = null;
    }
    if (match(candidate, object)) {
        return candidate;
    }
    for (final GenericName id : object.getAlias()) {
        code = id.toString();
        try {
            candidate = create(code);
        } catch (FactoryException e) {
            // The name was not recognized. No problem, let's go on.
            exceptionOccurred(e);
            continue;
        }
        if (match(candidate, object)) {
            return candidate;
        }
    }
    return null;
}
Also used : GenericName(org.opengis.util.GenericName) FactoryException(org.opengis.util.FactoryException) IdentifiedObject(org.opengis.referencing.IdentifiedObject) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject)

Example 22 with FactoryException

use of org.opengis.util.FactoryException in project sis by apache.

the class IdentifiedObjectSet method get.

/**
 * Returns the identified object for the specified value, creating it if needed.
 *
 * @throws BackingStoreException if the object creation failed.
 *
 * @see #createObject(String)
 */
final T get(final String code) throws BackingStoreException {
    T object;
    boolean success;
    synchronized (objects) {
        object = objects.get(code);
        success = (object != null || !objects.containsKey(code));
    }
    /*
         * If we need to create the object, it should be done outside synchronized block.
         * There is a risk that the same object is created twice in concurrent threads.
         * If this happen, we will discard the duplicated value.
         */
    if (!success) {
        try {
            object = createObject(code);
            // Shall be set only after above line succeed.
            success = true;
        } catch (FactoryException exception) {
            if (!isRecoverableFailure(exception)) {
                throw new BackingStoreException(exception);
            }
            final LogRecord record = Messages.getResources(getLocale()).getLogRecord(Level.WARNING, Messages.Keys.CanNotInstantiateForIdentifier_3, type, code, getCause(exception));
            record.setLoggerName(Loggers.CRS_FACTORY);
            Logging.log(IdentifiedObjectSet.class, "createObject", record);
        }
        synchronized (objects) {
            if (success) {
                /*
                     * The check for 'containsKey' is a paranoiac check in case the element has been removed
                     * in another thread while we were creating the object. This is likely to be unnecessary
                     * in the vast majority of cases where the set of codes is never modified after this set
                     * has been published. However, if someone decided to do such concurrent modifications,
                     * not checking for concurrent removal could be a subtle and hard-to-find bug, so we are
                     * better to be safe. Note that if a concurrent removal happened, we still return the non-null
                     * object but we do not put it in this IdentifiedObjectSet. This behavior is as if this method
                     * has been invoked before the concurrent removal happened.
                     */
                if (objects.containsKey(code)) {
                    // Needed because code may be associated to null value.
                    final T c = objects.putIfAbsent(code, object);
                    if (c != null) {
                        // The object has been created concurrently.
                        object = c;
                    }
                }
            } else if (objects.remove(code, null)) {
                // Do not remove if a concurrent thread succeeded.
                codes = null;
            }
        }
    }
    return object;
}
Also used : FactoryException(org.opengis.util.FactoryException) LogRecord(java.util.logging.LogRecord) BackingStoreException(org.apache.sis.util.collection.BackingStoreException)

Example 23 with FactoryException

use of org.opengis.util.FactoryException in project sis by apache.

the class DefaultCoordinateOperationFactory method createSingleOperation.

/**
 * Creates a transformation or conversion from the given properties.
 * This method infers by itself if the operation to create is a
 * {@link Transformation}, a {@link Conversion} or a {@link Projection} sub-type
 * ({@link CylindricalProjection}, {@link ConicProjection} or {@link PlanarProjection})
 * using the {@linkplain DefaultOperationMethod#getOperationType() information provided by the given method}.
 *
 * <p>The properties given in argument follow the same rules than for the
 * {@linkplain AbstractCoordinateOperation#AbstractCoordinateOperation(Map, CoordinateReferenceSystem,
 * CoordinateReferenceSystem, CoordinateReferenceSystem, MathTransform) coordinate operation} constructor.
 * The following table is a reminder of main (not all) properties:</p>
 *
 * <table class="sis">
 *   <caption>Recognized properties (non exhaustive list)</caption>
 *   <tr>
 *     <th>Property name</th>
 *     <th>Value type</th>
 *     <th>Returned by</th>
 *   </tr>
 *   <tr>
 *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
 *     <td>{@link org.opengis.metadata.Identifier} or {@link String}</td>
 *     <td>{@link DefaultConversion#getName()}</td>
 *   </tr>
 *   <tr>
 *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
 *     <td>{@link org.opengis.metadata.Identifier} (optionally as array)</td>
 *     <td>{@link DefaultConversion#getIdentifiers()}</td>
 *   </tr>
 *   <tr>
 *     <td>{@value org.opengis.referencing.operation.CoordinateOperation#DOMAIN_OF_VALIDITY_KEY}</td>
 *     <td>{@link org.opengis.metadata.extent.Extent}</td>
 *     <td>{@link DefaultConversion#getDomainOfValidity()}</td>
 *   </tr>
 * </table>
 *
 * @param  properties        the properties to be given to the identified object.
 * @param  sourceCRS         the source CRS.
 * @param  targetCRS         the target CRS.
 * @param  interpolationCRS  the CRS of additional coordinates needed for the operation, or {@code null} if none.
 * @param  method            the coordinate operation method (mandatory in all cases).
 * @param  transform         transform from positions in the source CRS to positions in the target CRS.
 * @return the coordinate operation created from the given arguments.
 * @throws FactoryException if the object creation failed.
 *
 * @see DefaultOperationMethod#getOperationType()
 * @see DefaultTransformation
 * @see DefaultConversion
 */
public SingleOperation createSingleOperation(final Map<String, ?> properties, final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS, final CoordinateReferenceSystem interpolationCRS, final OperationMethod method, MathTransform transform) throws FactoryException {
    ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
    ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
    ArgumentChecks.ensureNonNull("method", method);
    /*
         * Undocumented (for now) feature: if the 'transform' argument is null but parameters are
         * found in the given properties, create the MathTransform instance from those parameters.
         * This is needed for WKT parsing of CoordinateOperation[…] among others.
         */
    if (transform == null) {
        final ParameterValueGroup parameters = Containers.property(properties, ReferencingServices.PARAMETERS_KEY, ParameterValueGroup.class);
        if (parameters == null) {
            throw new NullArgumentException(Errors.format(Errors.Keys.NullArgument_1, "transform"));
        }
        transform = getMathTransformFactory().createBaseToDerived(sourceCRS, parameters, targetCRS.getCoordinateSystem());
    }
    /*
         * The "operationType" property is currently undocumented. The intent is to help this factory method in
         * situations where the given operation method is not an Apache SIS implementation or does not override
         * getOperationType(), or the method is ambiguous (e.g. "Affine" can be used for both a transformation
         * or a conversion).
         *
         * If we have both a 'baseType' and a Method.getOperationType(), take the most specific type.
         * An exception will be thrown if the two types are incompatible.
         */
    Class<?> baseType = Containers.property(properties, ReferencingServices.OPERATION_TYPE_KEY, Class.class);
    if (baseType == null) {
        baseType = SingleOperation.class;
    }
    if (method instanceof DefaultOperationMethod) {
        final Class<? extends SingleOperation> c = ((DefaultOperationMethod) method).getOperationType();
        if (c != null) {
            // Paranoiac check (above method should not return null).
            if (baseType.isAssignableFrom(c)) {
                baseType = c;
            } else if (!c.isAssignableFrom(baseType)) {
                throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatiblePropertyValue_1, ReferencingServices.OPERATION_TYPE_KEY));
            }
        }
    }
    /*
         * If the base type is still abstract (probably because it was not specified neither in the given OperationMethod
         * or in the properties), then try to find a concrete type using the following rules derived from the definitions
         * given in ISO 19111:
         *
         *   - If the two CRS uses the same datum (ignoring metadata), assume that we have a Conversion.
         *   - Otherwise we have a datum change, which implies that we have a Transformation.
         *
         * In the case of Conversion, we can specialize one step more if the conversion is going from a geographic CRS
         * to a projected CRS. It may seems that we should check if ProjectedCRS.getBaseCRS() is equals (ignoring meta
         * data) to source CRS. But we already checked the datum, which is the important part. The axis order and unit
         * could be different, which we want to allow.
         */
    if (baseType == SingleOperation.class) {
        if (isConversion(sourceCRS, targetCRS)) {
            if (interpolationCRS == null && sourceCRS instanceof GeographicCRS && targetCRS instanceof ProjectedCRS) {
                baseType = Projection.class;
            } else {
                baseType = Conversion.class;
            }
        } else {
            baseType = Transformation.class;
        }
    }
    /*
         * Now create the coordinate operation of the requested type. If we can not find a concrete class for the
         * requested type, we will instantiate a SingleOperation in last resort.  The later action is a departure
         * from ISO 19111 since 'SingleOperation' is conceptually abstract.  But we do that as a way to said that
         * we are missing this important piece of information but still go ahead.
         *
         * It is inconvenient to guarantee that the created operation is an instance of 'baseType' since the user
         * could have specified an implementation class or a custom sub-interface. We will perform the type check
         * only after object creation.
         */
    final AbstractSingleOperation op;
    if (Transformation.class.isAssignableFrom(baseType)) {
        op = new DefaultTransformation(properties, sourceCRS, targetCRS, interpolationCRS, method, transform);
    } else if (Projection.class.isAssignableFrom(baseType)) {
        ArgumentChecks.ensureCanCast("sourceCRS", GeographicCRS.class, sourceCRS);
        ArgumentChecks.ensureCanCast("targetCRS", ProjectedCRS.class, targetCRS);
        if (interpolationCRS != null) {
            throw new IllegalArgumentException(Errors.format(Errors.Keys.ForbiddenAttribute_2, "interpolationCRS", baseType));
        }
        final GeographicCRS baseCRS = (GeographicCRS) sourceCRS;
        final ProjectedCRS crs = (ProjectedCRS) targetCRS;
        if (CylindricalProjection.class.isAssignableFrom(baseType)) {
            op = new DefaultCylindricalProjection(properties, baseCRS, crs, method, transform);
        } else if (ConicProjection.class.isAssignableFrom(baseType)) {
            op = new DefaultConicProjection(properties, baseCRS, crs, method, transform);
        } else if (PlanarProjection.class.isAssignableFrom(baseType)) {
            op = new DefaultPlanarProjection(properties, baseCRS, crs, method, transform);
        } else {
            op = new DefaultProjection(properties, baseCRS, crs, method, transform);
        }
    } else if (Conversion.class.isAssignableFrom(baseType)) {
        op = new DefaultConversion(properties, sourceCRS, targetCRS, interpolationCRS, method, transform);
    } else {
        // See above comment about this last-resort fallback.
        op = new AbstractSingleOperation(properties, sourceCRS, targetCRS, interpolationCRS, method, transform);
    }
    if (!baseType.isInstance(op)) {
        throw new FactoryException(Resources.format(Resources.Keys.CanNotCreateObjectAsInstanceOf_2, baseType, op.getName()));
    }
    return pool.unique(op);
}
Also used : ParameterValueGroup(org.opengis.parameter.ParameterValueGroup) FactoryException(org.opengis.util.FactoryException) NullArgumentException(org.apache.sis.util.NullArgumentException) ProjectedCRS(org.opengis.referencing.crs.ProjectedCRS) GeographicCRS(org.opengis.referencing.crs.GeographicCRS)

Example 24 with FactoryException

use of org.opengis.util.FactoryException in project sis by apache.

the class MultiAuthoritiesFactory method getAuthorityCodes.

/**
 * Returns the set of authority codes for objects of the given type.
 * This method returns the union of codes returned by all factories specified at construction time.
 *
 * <p>The {@link Set#contains(Object)} method of the returned set is lenient:
 * it accepts various ways to format a code even if the iterator returns only one form.
 * For example the {@code contains(Object)} method may return {@code true} for {@code "EPSG:4326"},
 * {@code "EPSG::4326"}, {@code "urn:ogc:def:crs:EPSG::4326"}, <i>etc.</i> even if
 * the iterator returns only {@code "EPSG:4326"}.</p>
 *
 * <p><b>Warnings:</b></p>
 * <ul>
 *   <li>Callers should not retain a reference to the returned collection for a long time,
 *       since it may be backed by database connections (depending on the factory implementations).</li>
 *   <li>The returned set is not thread-safe. Each thread should ask its own instance and let
 *       the garbage collector disposes it as soon as the collection is not needed anymore.</li>
 *   <li>Call to the {@link Set#size()} method on the returned collection should be avoided
 *       since it may be costly.</li>
 * </ul>
 *
 * @param  type  the spatial reference objects type.
 * @return the set of authority codes for spatial reference objects of the given type.
 * @throws FactoryException if access to an underlying factory failed.
 */
@Override
public Set<String> getAuthorityCodes(final Class<? extends IdentifiedObject> type) throws FactoryException {
    return new SetOfUnknownSize<String>() {

        /**
         * Returns an iterator over all authority codes.
         * Codes are fetched on-the-fly.
         */
        @Override
        public Iterator<String> iterator() {
            return new AbstractIterator<String>() {

                /**
                 * An iterator over the factories for which to return codes.
                 */
                private final Iterator<AuthorityFactory> factories = getAllFactories();

                /**
                 * An iterator over the codes of the current factory.
                 */
                private Iterator<String> codes = Collections.emptyIterator();

                /**
                 * The prefix to prepend before codes, or {@code null} if none.
                 */
                private String prefix;

                /**
                 * For filtering duplicated codes when there is many versions of the same authority.
                 */
                private final Set<String> done = new HashSet<>();

                /**
                 * Tests if there is more codes to return.
                 */
                @Override
                public boolean hasNext() {
                    while (next == null) {
                        while (!codes.hasNext()) {
                            do {
                                if (!factories.hasNext()) {
                                    return false;
                                }
                                final AuthorityFactory factory = factories.next();
                                codes = getAuthorityCodes(factory).iterator();
                                prefix = getCodeSpace(factory);
                            } while (!done.add(prefix));
                        }
                        next = codes.next();
                    }
                    return true;
                }

                /**
                 * Returns the next element, with namespace inserted before the code if needed.
                 */
                @Override
                public String next() {
                    String code = super.next();
                    if (prefix != null && code.indexOf(DefaultNameSpace.DEFAULT_SEPARATOR) < 0) {
                        code = prefix + DefaultNameSpace.DEFAULT_SEPARATOR + code;
                    }
                    return code;
                }
            };
        }

        /**
         * The cache of values returned by {@link #getAuthorityCodes(AuthorityFactory)}.
         */
        private final Map<AuthorityFactory, Set<String>> cache = new IdentityHashMap<>();

        /**
         * Returns the authority codes for the given factory.
         * This method invokes {@link AuthorityFactory#getAuthorityCodes(Class)}
         * only once per factory and caches the returned {@code Set<String>}.
         */
        final Set<String> getAuthorityCodes(final AuthorityFactory factory) {
            Set<String> codes = cache.get(factory);
            if (codes == null) {
                try {
                    codes = factory.getAuthorityCodes(type);
                } catch (FactoryException e) {
                    throw new BackingStoreException(e);
                }
                if (cache.put(factory, codes) != null) {
                    throw new ConcurrentModificationException();
                }
            }
            return codes;
        }

        /**
         * The collection size, or a negative value if we have not yet computed the size.
         * A negative value different than -1 means that we have not counted all elements,
         * but we have determined that the set is not empty.
         */
        private int size = -1;

        /**
         * Returns {@code true} if the {@link #size()} method is cheap.
         */
        @Override
        protected boolean isSizeKnown() {
            return size >= 0;
        }

        /**
         * Returns the number of elements in this set (costly operation).
         */
        @Override
        public int size() {
            if (size < 0) {
                int n = 0;
                final Set<String> done = new HashSet<>();
                for (final Iterator<AuthorityFactory> it = getAllFactories(); it.hasNext(); ) {
                    final AuthorityFactory factory = it.next();
                    if (done.add(getCodeSpace(factory))) {
                        n += getAuthorityCodes(factory).size();
                    }
                }
                size = n;
            }
            return size;
        }

        /**
         * Returns {@code true} if the set does not contain any element.
         * This method is much more efficient than testing {@code size() != 0}
         * since it will stop iteration as soon as an element is found.
         */
        @Override
        public boolean isEmpty() {
            if (size == -1) {
                for (final Iterator<AuthorityFactory> it = getAllFactories(); it.hasNext(); ) {
                    if (!getAuthorityCodes(it.next()).isEmpty()) {
                        // Size still unknown, but we know that the set is not empty.
                        size = -2;
                        return false;
                    }
                }
                size = 0;
            }
            return size == 0;
        }

        /**
         * The proxy for the {@code GeodeticAuthorityFactory.getAuthorityCodes(type).contains(String)}.
         * Used by {@link #contains(Object)} for delegating its work to the most appropriate factory.
         */
        private final AuthorityFactoryProxy<Boolean> contains = new AuthorityFactoryProxy<Boolean>(Boolean.class, AuthorityFactoryIdentifier.ANY) {

            @Override
            Boolean createFromAPI(AuthorityFactory factory, String code) throws FactoryException {
                return getAuthorityCodes(factory).contains(code);
            }

            @Override
            AuthorityFactoryProxy<Boolean> specialize(String typeName) {
                return this;
            }
        };

        /**
         * Returns {@code true} if the factory contains the given code.
         */
        @Override
        public boolean contains(final Object code) {
            if (code instanceof String)
                try {
                    return create(contains, (String) code);
                } catch (NoSuchAuthorityCodeException e) {
                // Ignore - will return false.
                } catch (FactoryException e) {
                    throw new BackingStoreException(e);
                }
            return false;
        }

        /**
         * Declared soon as unsupported operation for preventing a call to {@link #size()}.
         */
        @Override
        public boolean removeAll(Collection<?> c) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean retainAll(Collection<?> c) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean remove(Object o) {
            throw new UnsupportedOperationException();
        }
    };
}
Also used : ConcurrentModificationException(java.util.ConcurrentModificationException) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) LazySet(org.apache.sis.internal.referencing.LazySet) FactoryException(org.opengis.util.FactoryException) BackingStoreException(org.apache.sis.util.collection.BackingStoreException) InternationalString(org.opengis.util.InternationalString) SetOfUnknownSize(org.apache.sis.internal.util.SetOfUnknownSize) AbstractIterator(org.apache.sis.internal.util.AbstractIterator) Iterator(java.util.Iterator) Collection(java.util.Collection) AbstractIterator(org.apache.sis.internal.util.AbstractIterator) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 25 with FactoryException

use of org.opengis.util.FactoryException in project sis by apache.

the class MultiAuthoritiesFactory method combine.

/**
 * Invoked when a {@code createFoo(…)} method is given a combined URI.
 * A combined URI is a URN or URL referencing other components. For example if the given URI
 * is {@code "urn:ogc:def:crs, crs:EPSG::27700, crs:EPSG::5701"}, then the components are:
 * <ol>
 *   <li>{@code "urn:ogc:def:crs:EPSG:9.1:27700"}</li>
 *   <li>{@code "urn:ogc:def:crs:EPSG:9.1:5701"}</li>
 * </ol>
 *
 * We do not require the components to be instance of CRS, since the "Definition identifier URNs in
 * OGC namespace" best practice paper allows other kinds of combination (e.g. of coordinate operations).
 *
 * @param  <T>         compile-time value of {@code type} argument.
 * @param  type        type of object to create.
 * @param  references  parsed URI of the components.
 * @param  isHTTP      whether the user URI is an URL (i.e. {@code "http://something"}) instead than a URN.
 * @return the combined object.
 * @throws FactoryException if an error occurred while creating the combined object.
 */
private <T> T combine(final Class<T> type, final DefinitionURI[] references, final boolean isHTTP) throws FactoryException {
    /*
         * 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
         * its non-null value only if the array stay of the expected sub-type.
         */
    final byte requestedType;
    IdentifiedObject[] components;
    Class<? extends IdentifiedObject> componentType;
    if (CoordinateReferenceSystem.class.isAssignableFrom(type)) {
        requestedType = AuthorityFactoryIdentifier.CRS;
        componentType = CoordinateReferenceSystem.class;
        // Intentional covariance.
        components = new CoordinateReferenceSystem[references.length];
    } else if (CoordinateOperation.class.isAssignableFrom(type)) {
        requestedType = AuthorityFactoryIdentifier.OPERATION;
        componentType = CoordinateOperation.class;
        // Intentional covariance.
        components = new CoordinateOperation[references.length];
    } else {
        throw new FactoryException(Resources.format(Resources.Keys.CanNotCombineUriAsType_1, type));
    }
    // Note: "compound-crs" ⟶ "crs".
    final String expected = NameMeaning.toObjectType(componentType);
    for (int i = 0; i < references.length; i++) {
        final DefinitionURI ref = references[i];
        final IdentifiedObject component = createObject(ref.toString());
        if (componentType != null && (!componentType.isInstance(component) || !expected.equalsIgnoreCase(ref.type))) {
            componentType = null;
            components = Arrays.copyOf(components, components.length, IdentifiedObject[].class);
        }
        components[i] = component;
    }
    /*
         * At this point we have successfully created all components. The way to interpret those components
         * depends mostly on the type of object requested by the user. For a given requested type, different
         * rules apply depending on the type of components. Those rules are described in OGC 07-092r1 (2007):
         * "Definition identifier URNs in OGC namespace".
         */
    IdentifiedObject combined = null;
    switch(requestedType) {
        case AuthorityFactoryIdentifier.OPERATION:
            {
                if (componentType != null) {
                    /*
                     * URN combined references for concatenated operations. We build an operation name from
                     * the operation identifiers (rather than CRS identifiers) because this is what the user
                     * gave to us, and because source/target CRS are not guaranteed to be defined. We do not
                     * yet support swapping roles of source and target CRS if an implied-reverse coordinate
                     * operation is included.
                     */
                    final CoordinateOperation[] ops = (CoordinateOperation[]) components;
                    String name = IdentifiedObjects.getIdentifierOrName(ops[0]) + " ⟶ " + IdentifiedObjects.getIdentifierOrName(ops[ops.length - 1]);
                    combined = DefaultFactories.forBuildin(CoordinateOperationFactory.class).createConcatenatedOperation(Collections.singletonMap(CoordinateOperation.NAME_KEY, name), ops);
                }
                break;
            }
        case AuthorityFactoryIdentifier.CRS:
            {
                if (componentType != null) {
                    /*
                     * URN combined references for compound coordinate reference systems.
                     * The URNs of the individual well-known CRSs are listed in the same order in which the
                     * individual coordinate tuples are combined to form the CompoundCRS coordinate tuple.
                     */
                    combined = CRS.compound((CoordinateReferenceSystem[]) components);
                } else if (!isHTTP) {
                    final CoordinateSystem cs = remove(references, components, CoordinateSystem.class);
                    if (cs != null) {
                        final Datum datum = remove(references, components, Datum.class);
                        if (datum != null) {
                            /*
                             * URN combined references for datum and coordinate system. In this case, the URN shall
                             * concatenate the URNs of one well-known datum and one well-known coordinate system.
                             */
                            if (ArraysExt.allEquals(references, null)) {
                                combined = combine((GeodeticDatum) datum, cs);
                            }
                        } else {
                            /*
                             * URN combined references for projected or derived CRSs. In this case, the URN shall
                             * concatenate the URNs of the one well-known CRS, one well-known Conversion, and one
                             * well-known CartesianCS. Similar action can be taken for derived CRS.
                             */
                            CoordinateReferenceSystem baseCRS = remove(references, components, CoordinateReferenceSystem.class);
                            CoordinateOperation op = remove(references, components, CoordinateOperation.class);
                            if (ArraysExt.allEquals(references, null) && op instanceof Conversion) {
                                combined = combine(baseCRS, (Conversion) op, cs);
                            }
                        }
                    }
                }
                break;
            }
    }
    /*
         * At this point the combined object has been created if we know how to create it.
         * Maybe the result matches the definition of an existing object in the database,
         * in which case we will use the existing definition for better metadata.
         */
    if (combined == null) {
        throw new FactoryException(Resources.format(Resources.Keys.UnexpectedComponentInURI));
    }
    final IdentifiedObject existing = newIdentifiedObjectFinder().findSingleton(combined);
    return type.cast(existing != null ? existing : combined);
}
Also used : FactoryException(org.opengis.util.FactoryException) InternationalString(org.opengis.util.InternationalString) DefinitionURI(org.apache.sis.internal.util.DefinitionURI)

Aggregations

FactoryException (org.opengis.util.FactoryException)84 TransformException (org.opengis.referencing.operation.TransformException)27 GeometryWrapper (org.apache.jena.geosparql.implementation.GeometryWrapper)21 MismatchedDimensionException (org.opengis.geometry.MismatchedDimensionException)19 ExprEvalException (org.apache.jena.sparql.expr.ExprEvalException)17 MathTransform (org.opengis.referencing.operation.MathTransform)15 DatatypeFormatException (org.apache.jena.datatypes.DatatypeFormatException)12 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)10 IdentifiedObject (org.opengis.referencing.IdentifiedObject)8 Envelope (org.locationtech.jts.geom.Envelope)7 ArrayList (java.util.ArrayList)6 ParameterValueGroup (org.opengis.parameter.ParameterValueGroup)6 NoninvertibleTransformException (org.opengis.referencing.operation.NoninvertibleTransformException)6 Literal (org.apache.jena.rdf.model.Literal)5 UnavailableFactoryException (org.apache.sis.referencing.factory.UnavailableFactoryException)5 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)5 ParseException (java.text.ParseException)4 AbstractIdentifiedObject (org.apache.sis.referencing.AbstractIdentifiedObject)4 BackingStoreException (org.apache.sis.util.collection.BackingStoreException)4 Test (org.junit.Test)4