Search in sources :

Example 16 with FactoryException

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

the class AbstractSingleOperation method afterUnmarshal.

/**
 * Invoked by JAXB after unmarshalling. This method needs information provided by:
 *
 * <ul>
 *   <li>{@link #setSource(CoordinateReferenceSystem)}</li>
 *   <li>{@link #setTarget(CoordinateReferenceSystem)}</li>
 *   <li>{@link #setParameters(GeneralParameterValue[])}</li>
 * </ul>
 *
 * @see <a href="http://issues.apache.org/jira/browse/SIS-291">SIS-291</a>
 */
@Override
final void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
    super.afterUnmarshal(unmarshaller, parent);
    final CoordinateReferenceSystem sourceCRS = super.getSourceCRS();
    final CoordinateReferenceSystem targetCRS = super.getTargetCRS();
    if (transform == null && sourceCRS != null && targetCRS != null && parameters != null)
        try {
            transform = DefaultFactories.forBuildin(MathTransformFactory.class).createBaseToDerived(sourceCRS, parameters, targetCRS.getCoordinateSystem());
        } catch (FactoryException e) {
            Context.warningOccured(Context.current(), AbstractSingleOperation.class, "afterUnmarshal", e, true);
        }
}
Also used : MathTransformFactory(org.opengis.referencing.operation.MathTransformFactory) FactoryException(org.opengis.util.FactoryException) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem)

Example 17 with FactoryException

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

the class CoordinateOperationRegistry method search.

/**
 * Returns operations for conversions or transformations between two coordinate reference systems.
 * This method extracts the authority code from the supplied {@code sourceCRS} and {@code targetCRS},
 * and submit them to the {@link #registry}. If no operation is found for those codes, then this method
 * returns {@code null}.
 *
 * @param  sourceCRS  source coordinate reference system.
 * @param  targetCRS  target coordinate reference system.
 * @return a coordinate operation from {@code sourceCRS} to {@code targetCRS}, or {@code null}
 *         if no such operation is explicitly defined in the underlying database.
 * @throws IllegalArgumentException if the coordinate systems are not of the same type or axes do not match.
 * @throws IncommensurableException if the units are not compatible or a unit conversion is non-linear.
 * @throws FactoryException if an error occurred while creating the operation.
 */
private List<CoordinateOperation> search(final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS) throws IllegalArgumentException, IncommensurableException, FactoryException {
    final List<String> sources = findCode(sourceCRS);
    if (sources.isEmpty())
        return null;
    final List<String> targets = findCode(targetCRS);
    if (targets.isEmpty())
        return null;
    final List<CoordinateOperation> operations = new ArrayList<>();
    boolean foundDirectOperations = false;
    boolean useDeprecatedOperations = false;
    for (final String sourceID : sources) {
        for (final String targetID : targets) {
            if (sourceID.equals(targetID)) {
                /*
                     * Above check is necessary because this method may be invoked in some situations where the code
                     * are equal while the CRS are not. Such situation should be illegal, but unfortunately it still
                     * happen because many software products are not compliant with EPSG definition of axis order.
                     * In such cases we will need to compute a transform from sourceCRS to targetCRS ignoring the
                     * source and target codes. The CoordinateOperationFinder class can do that, providing that we
                     * prevent this CoordinateOperationRegistry to (legitimately) claims that the operation from
                     * sourceCode to targetCode is the identity transform.
                     */
                return null;
            }
            /*
                 * Some pairs of CRS have a lot of coordinate operations backed by datum shift grids.
                 * We do not want to load all of them until we found the right coordinate operation.
                 * The non-public Semaphores.METADATA_ONLY mechanism instructs EPSGDataAccess to
                 * instantiate DeferredCoordinateOperation instead of full coordinate operations.
                 */
            final boolean mdOnly = Semaphores.queryAndSet(Semaphores.METADATA_ONLY);
            try {
                Collection<CoordinateOperation> authoritatives;
                try {
                    authoritatives = registry.createFromCoordinateReferenceSystemCodes(sourceID, targetID);
                    final boolean inverse = Containers.isNullOrEmpty(authoritatives);
                    if (inverse) {
                        /*
                             * No operation from 'source' to 'target' available. But maybe there is an inverse operation.
                             * This is typically the case when the user wants to convert from a projected to a geographic CRS.
                             * The EPSG database usually contains transformation paths for geographic to projected CRS only.
                             */
                        if (foundDirectOperations) {
                            // Ignore inverse operations if we already have direct ones.
                            continue;
                        }
                        authoritatives = registry.createFromCoordinateReferenceSystemCodes(targetID, sourceID);
                        if (Containers.isNullOrEmpty(authoritatives)) {
                            continue;
                        }
                    } else if (!foundDirectOperations) {
                        foundDirectOperations = true;
                        // Keep only direct operations.
                        operations.clear();
                    }
                } catch (NoSuchAuthorityCodeException | MissingFactoryResourceException e) {
                    /*
                         * sourceCode or targetCode is unknown to the underlying authority factory.
                         * Ignores the exception and fallback on the generic algorithm provided by
                         * CoordinateOperationFinder.
                         */
                    log(null, e);
                    continue;
                }
                /*
                     * If we found at least one non-deprecated operation, we will stop the search at
                     * the first deprecated one (assuming that deprecated operations are sorted last).
                     * Deprecated operations are kept only if there is no non-deprecated operations.
                     */
                try {
                    for (final CoordinateOperation candidate : authoritatives) {
                        if (candidate != null) {
                            // Paranoiac check.
                            if ((candidate instanceof Deprecable) && ((Deprecable) candidate).isDeprecated()) {
                                if (!useDeprecatedOperations && !operations.isEmpty())
                                    break;
                                useDeprecatedOperations = true;
                            } else if (useDeprecatedOperations) {
                                useDeprecatedOperations = false;
                                // Replace deprecated operations by non-deprecated ones.
                                operations.clear();
                            }
                            operations.add(candidate);
                        }
                    }
                } catch (BackingStoreException exception) {
                    throw exception.unwrapOrRethrow(FactoryException.class);
                }
            } finally {
                if (!mdOnly) {
                    Semaphores.clear(Semaphores.METADATA_ONLY);
                }
            }
        }
    }
    /*
         * At this point we got the list of coordinate operations. Now, sort them in preference order.
         * We will loop over all coordinate operations and select the one having the largest intersection
         * with the area of interest. Note that if the user did not specified an area of interest himself,
         * then we need to get one from the CRS. This is necessary for preventing the transformation from
         * NAD27 to NAD83 in Idaho to select the transform for Alaska (since the later has a larger area).
         */
    CoordinateOperationSorter.sort(operations, Extents.getGeographicBoundingBox(areaOfInterest));
    final ListIterator<CoordinateOperation> it = operations.listIterator();
    while (it.hasNext()) {
        /*
             * At this point we filtered a CoordinateOperation by looking only at its metadata.
             * Code following this point will need the full coordinate operation, including its
             * MathTransform. So if we got a deferred operation, we need to resolve it now.
             * Conversely, we should not use metadata below this point because the call to
             * inverse(CoordinateOperation) is not guaranteed to preserve all metadata.
             */
        CoordinateOperation operation = it.next();
        try {
            if (operation instanceof DeferredCoordinateOperation) {
                operation = ((DeferredCoordinateOperation) operation).create();
            }
            if (operation instanceof SingleOperation && operation.getMathTransform() == null) {
                operation = fromDefiningConversion((SingleOperation) operation, foundDirectOperations ? sourceCRS : targetCRS, foundDirectOperations ? targetCRS : sourceCRS);
                if (operation == null) {
                    it.remove();
                    continue;
                }
            }
            if (!foundDirectOperations) {
                operation = inverse(operation);
            }
        } catch (NoninvertibleTransformException | MissingFactoryResourceException e) {
            /*
                 * If we failed to get the real CoordinateOperation instance, remove it from
                 * the collection and try again in order to get the next best choices.
                 */
            log(null, e);
            it.remove();
            // Try again with the next best case.
            continue;
        }
        /*
             * It is possible that the CRS given to this method were not quite right.  For example the user
             * may have created his CRS from a WKT using a different axis order than the order specified by
             * the authority and still (wrongly) call those CRS "EPSG:xxxx".  So we check if the source and
             * target CRS for the operation we just created are equivalent to the CRS specified by the user.
             *
             * NOTE: FactoryException may be thrown if we fail to create a transform from the user-provided
             * CRS to the authority-provided CRS. That transform should have been only an identity transform,
             * or a simple affine transform if the user specified wrong CRS as explained in above paragraph.
             * If we fail here, we are likely to fail for all other transforms. So we are better to let the
             * FactoryException propagate.
             */
        operation = complete(operation, sourceCRS, targetCRS);
        if (filter(operation)) {
            if (stopAtFirst) {
                operations.clear();
                operations.add(operation);
                break;
            }
            it.set(operation);
        } else {
            it.remove();
        }
    }
    return operations;
}
Also used : NoSuchAuthorityCodeException(org.opengis.referencing.NoSuchAuthorityCodeException) FactoryException(org.opengis.util.FactoryException) NoSuchAuthorityFactoryException(org.apache.sis.referencing.factory.NoSuchAuthorityFactoryException) ArrayList(java.util.ArrayList) BackingStoreException(org.apache.sis.util.collection.BackingStoreException) DeferredCoordinateOperation(org.apache.sis.internal.referencing.DeferredCoordinateOperation) DeferredCoordinateOperation(org.apache.sis.internal.referencing.DeferredCoordinateOperation) MissingFactoryResourceException(org.apache.sis.referencing.factory.MissingFactoryResourceException) Deprecable(org.apache.sis.util.Deprecable)

Example 18 with FactoryException

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

the class ConcurrentAuthorityFactory method close.

/**
 * Immediately closes all Data Access Objects that are closeable.
 * This method does not clear the cache and does not disallow further usage of this factory:
 * this {@code ConcurrentAuthorityFactory} can still be used as usual after it has been "closed".
 * {@linkplain #newDataAccess() New Data Access Objects} will be created if needed for replacing
 * the ones closed by this method.
 *
 * <p>The main purpose of this method is to force immediate release of JDBC connections or other kind of resources
 * that Data Access Objects may hold. If this method is not invoked, Data Access Objects will be closed
 * when this {@code ConcurrentAuthorityFactory} will be garbage collected or at JVM shutdown time,
 * depending which event happen first.</p>
 *
 * @throws FactoryException if an error occurred while closing the Data Access Objects.
 *
 * @see #canClose(GeodeticAuthorityFactory)
 */
@Override
public void close() throws FactoryException {
    try {
        final List<DAO> factories;
        synchronized (availableDAOs) {
            factories = clear(availableDAOs);
        }
        confirmClose(factories);
        // Must be invoked outside the synchronized block.
        close(factories);
    } catch (Exception e) {
        if (e instanceof FactoryException) {
            throw (FactoryException) e;
        } else {
            throw new FactoryException(e);
        }
    }
}
Also used : FactoryException(org.opengis.util.FactoryException) NoSuchAuthorityCodeException(org.opengis.referencing.NoSuchAuthorityCodeException) FactoryException(org.opengis.util.FactoryException)

Example 19 with FactoryException

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

the class ConcurrentAuthorityFactory method getDataAccess.

/**
 * Returns a Data Access Object. This method <strong>must</strong>
 * be used together with {@link #release(String, Class, String)}
 * in a {@code try ... finally} block.
 *
 * @return Data Access Object (DAO) to use in {@code createFoo(String)} methods.
 * @throws FactoryException if the Data Access Object creation failed.
 */
@SuppressWarnings("null")
private DAO getDataAccess() throws FactoryException {
    /*
         * First checks if the current thread is already using a factory. If yes, we will
         * avoid creating new factories on the assumption that factories are reentrant.
         */
    DataAccessRef<DAO> usage = currentDAO.get();
    if (usage == null) {
        synchronized (availableDAOs) {
            /*
                 * If we have reached the maximal amount of Data Access Objects allowed, wait for an instance
                 * to become available. In theory the 0.2 second timeout is not necessary, but we put it as a
                 * safety in case we fail to invoke a notify() matching this wait(), for example someone else
                 * is waiting on this monitor or because the release(…) method threw an exception.
                 */
            while (remainingDAOs == 0) {
                try {
                    availableDAOs.wait(TIMEOUT_RESOLUTION);
                } catch (InterruptedException e) {
                    // Someone does not want to let us sleep.
                    throw new FactoryException(e.getLocalizedMessage(), e);
                }
            }
            /*
                 * Reuse the most recently used factory, if available. If there is no factory available for reuse,
                 * creates a new one. We do not add it to the queue now; it will be done by the release(…) method.
                 */
            usage = availableDAOs.pollLast();
            // Should be done last when we are sure to not fail.
            remainingDAOs--;
        }
        /*
             * If there is a need to create a new factory, do that outside the synchronized block because this
             * creation may involve a lot of client code. This is better for reducing the dead-lock risk.
             * Subclasses are responsible of synchronizing their newDataAccess() method if necessary.
             */
        try {
            if (usage == null) {
                final DAO factory = newDataAccess();
                if (factory == null) {
                    UnavailableFactoryException e = new UnavailableFactoryException(Errors.format(Errors.Keys.FactoryNotFound_1, GeodeticAuthorityFactory.class));
                    e.setUnavailableFactory(this);
                    throw e;
                }
                usage = new DataAccessRef<>(factory);
            }
            assert usage.depth == 0 : usage;
            usage.timestamp = System.nanoTime();
        } catch (Throwable e) {
            /*
                 * If any kind of error occurred, restore the 'remainingDAO' field as if no code were executed.
                 * This code would not have been needed if we were allowed to decrement 'remainingDAO' only as
                 * the very last step (when we know that everything else succeed).
                 * But it needed to be decremented inside the synchronized block.
                 */
            synchronized (availableDAOs) {
                remainingDAOs++;
            }
            throw e;
        }
        currentDAO.set(usage);
    }
    /*
         * Increment below is safe even if outside the synchronized block,
         * because each thread own exclusively its DataAccessRef instance.
         */
    usage.depth++;
    return usage.factory;
}
Also used : FactoryException(org.opengis.util.FactoryException)

Example 20 with FactoryException

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

the class IdentifiedObjectFinder method findSingleton.

/**
 * Lookups only one object which is approximatively equal to the specified object.
 * This method invokes {@link #find(IdentifiedObject)}, then examine the returned {@code Set} as below:
 *
 * <ul>
 *   <li>If the set is empty, then this method returns {@code null}.</li>
 *   <li>If the set contains exactly one element, then this method returns that element.</li>
 *   <li>If the set contains more than one element, but only one element has the same axis order
 *       than {@code object} and all other elements have different axis order,
 *       then this method returns the single element having the same axis order.</li>
 *   <li>Otherwise this method considers that there is ambiguity and returns {@code null}.</li>
 * </ul>
 *
 * @param  object  the object looked up.
 * @return the identified object, or {@code null} if none or ambiguous.
 * @throws FactoryException if an error occurred while creating an object.
 */
public IdentifiedObject findSingleton(final IdentifiedObject object) throws FactoryException {
    /*
         * Do not invoke Set.size() because it may be a costly operation if the subclass
         * implements a mechanism that create IdentifiedObject instances only on demand.
         */
    IdentifiedObject result = null;
    boolean sameAxisOrder = false;
    boolean ambiguous = false;
    try {
        for (final IdentifiedObject candidate : find(object)) {
            final boolean so = !ignoreAxes || Utilities.deepEquals(candidate, object, COMPARISON_MODE);
            if (result != null) {
                ambiguous = true;
                if (sameAxisOrder && so) {
                    // Found two matches even when taking in account axis order.
                    return null;
                }
            }
            result = candidate;
            sameAxisOrder = so;
        }
    } catch (BackingStoreException e) {
        throw e.unwrapOrRethrow(FactoryException.class);
    }
    return (sameAxisOrder || !ambiguous) ? result : null;
}
Also used : FactoryException(org.opengis.util.FactoryException) BackingStoreException(org.apache.sis.util.collection.BackingStoreException) IdentifiedObject(org.opengis.referencing.IdentifiedObject) AbstractIdentifiedObject(org.apache.sis.referencing.AbstractIdentifiedObject)

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