Search in sources :

Example 1 with BackingStoreException

use of org.apache.sis.util.collection.BackingStoreException in project sis by apache.

the class Types method forStandardName.

/**
 * Returns the Java type (usually a GeoAPI interface) for the given ISO name, or {@code null} if none.
 * The identifier argument shall be the value documented in the {@link UML#identifier()} annotation on
 * the Java type.
 *
 * <div class="note"><b>Examples:</b>
 * <ul>
 *   <li>{@code forStandardName("CI_Citation")}      returns <code>{@linkplain org.opengis.metadata.citation.Citation}.class</code></li>
 *   <li>{@code forStandardName("CS_AxisDirection")} returns <code>{@linkplain org.opengis.referencing.cs.AxisDirection}.class</code></li>
 * </ul>
 * </div>
 *
 * Only identifiers for the stable part of GeoAPI or for some Apache SIS classes are recognized.
 * This method does not handle the identifiers for interfaces in the {@code geoapi-pending} module.
 *
 * <div class="note"><b>Future evolution:</b>
 * when a new ISO type does not yet have a corresponding GeoAPI interface,
 * this method may temporarily return an Apache SIS class instead until a future version can use the interface.
 * For example {@code forStandardName("CI_Individual")} returns
 * <code>{@linkplain org.apache.sis.metadata.iso.citation.DefaultIndividual}.class</code> in Apache SIS versions
 * that depend on GeoAPI 3.0, but the return type may be changed to {@code Individual.class} when Apache SIS will
 * be upgraded to GeoAPI 3.1.</div>
 *
 * @param  identifier  the ISO {@linkplain UML} identifier, or {@code null}.
 * @return the GeoAPI interface, or {@code null} if the given identifier is {@code null} or unknown.
 */
public static synchronized Class<?> forStandardName(final String identifier) {
    if (identifier == null) {
        return null;
    }
    if (typeForNames == null) {
        final Class<Types> c = Types.class;
        final InputStream in = c.getResourceAsStream("class-index.properties");
        if (in == null) {
            throw new MissingResourceException("class-index.properties", c.getName(), identifier);
        }
        final Properties props = new Properties();
        try {
            props.load(in);
            in.close();
        } catch (IOException | IllegalArgumentException e) {
            throw new BackingStoreException(e);
        }
        typeForNames = new HashMap<>(props);
        typeForNames.putIfAbsent("MI_SensorTypeCode", "org.apache.sis.internal.metadata.SensorType");
    }
    final Object value = typeForNames.get(identifier);
    if (value == null || value instanceof Class<?>) {
        return (Class<?>) value;
    }
    final Class<?> type;
    try {
        type = Class.forName((String) value);
    } catch (ClassNotFoundException e) {
        throw new TypeNotPresentException((String) value, e);
    }
    typeForNames.put(identifier, type);
    return type;
}
Also used : InputStream(java.io.InputStream) MissingResourceException(java.util.MissingResourceException) BackingStoreException(org.apache.sis.util.collection.BackingStoreException) IOException(java.io.IOException) InternationalString(org.opengis.util.InternationalString) Properties(java.util.Properties)

Example 2 with BackingStoreException

use of org.apache.sis.util.collection.BackingStoreException in project sis by apache.

the class Store method components.

/**
 * Returns all resources found in the folder given at construction time.
 * Only the resources recognized by a {@link DataStore} will be included.
 * This includes sub-folders. Resources are in no particular order.
 */
@Override
@SuppressWarnings("ReturnOfCollectionOrArrayField")
public synchronized Collection<Resource> components() throws DataStoreException {
    if (components == null) {
        final List<DataStore> resources = new ArrayList<>();
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(location, this)) {
            for (final Path candidate : stream) {
                /*
                     * The candidate path may be a symbolic link to a file that we have previously read.
                     * In such case, use the existing data store.   A use case is a directory containing
                     * hundred of GeoTIFF files all accompanied by ".prj" files having identical content.
                     * (Note: those ".prj" files should be invisible since they should be identified as
                     * GeoTIFF auxiliary files, but current Store implementation does not know that).
                     */
                final Path real = candidate.toRealPath();
                DataStore next = children.get(real);
                if (next instanceof Store) {
                    // Warn about directories only.
                    ((Store) next).sharedRepository(real);
                }
                if (next == null) {
                    /*
                         * The candidate file has never been read before. Try to read it now.
                         * If the file format is unknown (UnsupportedStorageException), we will
                         * check if we can open it as a child folder store before to skip it.
                         */
                    final StorageConnector connector = new StorageConnector(candidate);
                    connector.setOption(OptionKey.LOCALE, locale);
                    connector.setOption(OptionKey.TIMEZONE, timezone);
                    connector.setOption(OptionKey.ENCODING, encoding);
                    try {
                        if (componentProvider == null) {
                            // May throw UnsupportedStorageException.
                            next = DataStores.open(connector);
                        } else if (componentProvider.probeContent(connector).isSupported()) {
                            // Open a file of specified format.
                            next = componentProvider.open(connector);
                        } else if (Files.isDirectory(candidate)) {
                            // Open a sub-directory.
                            next = new Store(this, connector);
                        } else {
                            // Not the format specified at construction time.
                            connector.closeAllExcept(null);
                            continue;
                        }
                    } catch (UnsupportedStorageException ex) {
                        if (!Files.isDirectory(candidate)) {
                            connector.closeAllExcept(null);
                            listeners.warning(Level.FINE, null, ex);
                            continue;
                        }
                        next = new Store(this, connector);
                    } catch (DataStoreException ex) {
                        try {
                            connector.closeAllExcept(null);
                        } catch (DataStoreException s) {
                            ex.addSuppressed(s);
                        }
                        throw ex;
                    }
                    /*
                         * At this point we got the data store. It could happen that a store for
                         * the same file has been added concurrently, so we need to check again.
                         */
                    final DataStore existing = children.putIfAbsent(real, next);
                    if (existing != null) {
                        next.close();
                        next = existing;
                        if (next instanceof Store) {
                            // Warn about directories only.
                            ((Store) next).sharedRepository(real);
                        }
                    }
                }
                resources.add(next);
            }
        } catch (DirectoryIteratorException | UncheckedIOException ex) {
            // The cause is an IOException (no other type allowed).
            throw new DataStoreException(canNotRead(), ex.getCause());
        } catch (IOException ex) {
            throw new DataStoreException(canNotRead(), ex);
        } catch (BackingStoreException ex) {
            throw ex.unwrapOrRethrow(DataStoreException.class);
        }
        components = UnmodifiableArrayList.wrap(resources.toArray(new Resource[resources.size()]));
    }
    // Safe because unmodifiable list.
    return components;
}
Also used : Path(java.nio.file.Path) DirectoryIteratorException(java.nio.file.DirectoryIteratorException) StorageConnector(org.apache.sis.storage.StorageConnector) DataStoreException(org.apache.sis.storage.DataStoreException) ArrayList(java.util.ArrayList) UnmodifiableArrayList(org.apache.sis.internal.util.UnmodifiableArrayList) BackingStoreException(org.apache.sis.util.collection.BackingStoreException) DataStore(org.apache.sis.storage.DataStore) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException) DataStore(org.apache.sis.storage.DataStore) UnsupportedStorageException(org.apache.sis.storage.UnsupportedStorageException)

Example 3 with BackingStoreException

use of org.apache.sis.util.collection.BackingStoreException in project sis by apache.

the class Store method write.

/**
 * Replaces the content of this GPX file by the given metadata and features.
 *
 * @param  metadata  the metadata to write, or {@code null} if none.
 * @param  features  the features to write, or {@code null} if none.
 * @throws ConcurrentReadException if the {@code features} stream was provided by this data store.
 * @throws DataStoreException if an error occurred while writing the data.
 */
public synchronized void write(final Metadata metadata, final Stream<? extends AbstractFeature> features) throws DataStoreException {
    try {
        /*
             * If we created a reader for reading metadata, we need to close that reader now otherwise the call
             * to 'new Writer(…)' will fail.  Note that if that reader was in use by someone else, the 'reader'
             * field would be null and the 'new Writer(…)' call should detect that a reader is in use somewhere.
             */
        final Reader r = reader;
        if (r != null) {
            reader = null;
            r.close();
        }
        /*
             * Get the writer if no read or other write operation is in progress, then write the data.
             */
        try (Writer writer = new Writer(this, org.apache.sis.internal.storage.gpx.Metadata.castOrCopy(metadata, locale))) {
            writer.writeStartDocument();
            if (features != null) {
                features.forEachOrdered(writer);
            }
            writer.writeEndDocument();
        }
    } catch (BackingStoreException e) {
        final Throwable cause = e.getCause();
        if (cause instanceof DataStoreException) {
            throw (DataStoreException) cause;
        }
        throw new DataStoreException(e.getLocalizedMessage(), cause);
    } catch (Exception e) {
        if (e instanceof UncheckedIOException) {
            e = ((UncheckedIOException) e).getCause();
        }
        throw new DataStoreException(e);
    }
}
Also used : DataStoreException(org.apache.sis.storage.DataStoreException) BackingStoreException(org.apache.sis.util.collection.BackingStoreException) UncheckedIOException(java.io.UncheckedIOException) URISyntaxException(java.net.URISyntaxException) IllegalNameException(org.apache.sis.storage.IllegalNameException) DataStoreContentException(org.apache.sis.storage.DataStoreContentException) DataStoreException(org.apache.sis.storage.DataStoreException) BackingStoreException(org.apache.sis.util.collection.BackingStoreException) UncheckedIOException(java.io.UncheckedIOException) ConcurrentReadException(org.apache.sis.storage.ConcurrentReadException) FactoryException(org.opengis.util.FactoryException)

Example 4 with BackingStoreException

use of org.apache.sis.util.collection.BackingStoreException 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 5 with BackingStoreException

use of org.apache.sis.util.collection.BackingStoreException 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

BackingStoreException (org.apache.sis.util.collection.BackingStoreException)7 FactoryException (org.opengis.util.FactoryException)5 IOException (java.io.IOException)2 UncheckedIOException (java.io.UncheckedIOException)2 ArrayList (java.util.ArrayList)2 DataStoreException (org.apache.sis.storage.DataStoreException)2 InternationalString (org.opengis.util.InternationalString)2 InputStream (java.io.InputStream)1 URISyntaxException (java.net.URISyntaxException)1 DirectoryIteratorException (java.nio.file.DirectoryIteratorException)1 Path (java.nio.file.Path)1 Collection (java.util.Collection)1 ConcurrentModificationException (java.util.ConcurrentModificationException)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 IdentityHashMap (java.util.IdentityHashMap)1 Iterator (java.util.Iterator)1 LinkedHashSet (java.util.LinkedHashSet)1 Map (java.util.Map)1 MissingResourceException (java.util.MissingResourceException)1