Module org.apache.sis.storage
Package org.apache.sis.storage

# Class DataStoreProvider

Object
DataStoreProvider

Direct Known Subclasses:
  `GeoTiffStoreProvider`, `LandsatStoreProvider`, `NetcdfStoreProvider`, `SQLStoreProvider`

public abstract class DataStoreProvider extends Object
Provides information about a specific `DataStore` implementation. There is typically one `DataStoreProvider` instance for each format supported by a library. Each `DataStoreProvider` instances provides the following services:

- Provide generic information about the storage (name, etc.).
- Create instances of the `DataStore` implementation described by this provider.
- Test if a `DataStore` instance created by this provider would have reasonable chances to open a given `StorageConnector`.

## Packaging data stores

JAR files that provide implementations of this class shall declare the implementation class names in `module-info​.java` as providers of the `org​.apache​.sis​.storage​.DataStoreProvider` service. See `ServiceLoader` for more general discussion about this lookup mechanism.

## Thread safety

All `DataStoreProvider` implementations shall be thread-safe. However, the `DataStore` instances created by the providers do not need to be thread-safe.

Since:
  0.3

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Class
  Description
  `protected static interface`
  `DataStoreProvider​.Prober<S>`
  An action to execute for testing if a `StorageConnector` input can be read.

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final String`
  `CREATE`
  Name of the parameter that specifies whether to allow creation of a new `DataStore` if none exist at the given location.
  `static final String`
  `LOCATION`
  Name of the parameter that specifies the data store location.

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  `protected`
  `DataStoreProvider()`
  Creates a new provider.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `Format`
  `getFormat()`
  Returns a description of the data format.
  `Logger`
  `getLogger()`
  Returns the logger where to report warnings or loading operations.
  `abstract ParameterDescriptorGroup`
  `getOpenParameters()`
  Returns a description of all parameters accepted by this provider for opening a data store.
  `abstract String`
  `getShortName()`
  Returns a short name or abbreviation for the data format.
  `Range<Version>`
  `getSupportedVersions()`
  Returns the range of versions supported by the data store, or `null` if unspecified.
  `abstract DataStore`
  `open(StorageConnector connector)`
  Returns a data store implementation associated with this provider.
  `DataStore`
  `open(ParameterValueGroup parameters)`
  Returns a data store implementation associated with this provider for the given parameters.
  `abstract ProbeResult`
  `probeContent(StorageConnector connector)`
  Indicates if the given storage appears to be supported by the `DataStore`s created by this provider.
  `protected <S> ProbeResult`
  `probeContent(StorageConnector connector, Class<S> type, DataStoreProvider​.Prober<? super S> prober)`
  Applies the specified test on the storage content without modifying buffer or input stream position.

  ### Methods inherited from class Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### LOCATION

    public static final String LOCATION
    Name of the parameter that specifies the data store location. A parameter named "location" should be included in the group of parameters returned by `getOpenParameters()`. The parameter value is often a `URI` or a `Path`, but other types are allowed.

    Implementers are encouraged to define a parameter with this name to ensure a common and consistent definition among providers. The parameter should be defined as mandatory and typed with a well-known Java class such as `URI`, `Path`, JDBC DataSource, etc. The type should have a compact textual representation, for serialization in XML or configuration files. Consequently, `InputStream` and `Channel` should be avoided.

    See Also:
      - `CREATE`
      - `getOpenParameters()`
      - Constant Field Values

  - ### CREATE

    public static final String CREATE
    Name of the parameter that specifies whether to allow creation of a new `DataStore` if none exist at the given location. A parameter named "create" may be included in the group of parameters returned by `getOpenParameters()` if the data store supports write operations. The parameter value is often a `Boolean` and the default value should be `Boolean​.FALSE` or equivalent.

    Implementers are encouraged to define an optional parameter with this name in complement to the "location" parameter only if write operations are supported. If this parameter value is not set or is set to `false`, then the `open(ParameterValueGroup)` method should fail if no file or database exists at the URL or path given by the "location" parameter. Otherwise if this parameter is set to `true`, then the `open(…)` method may create files, a directory or a database at the given location.

    #### Relationship with standard file open options

    For data stores on file systems, a `"create" = true` parameter value is equivalent to opening a file with `StandardOpenOption​.CREATE` and `APPEND`. The other file standard options like `CREATE_NEW` and `TRUNCATE_EXISTING` should not be accessible through this "create" parameter. The reason is that `ParameterValueGroup` may be used for storing parameters permanently (for example in a configuration file or in a database) for reopening the same `DataStore` many times. File options designed for being used only once like `CREATE_NEW` and `TRUNCATE_EXISTING` are incompatible with this usage.
    See Also:
      - `LOCATION`
      - `getOpenParameters()`
      - Constant Field Values

- ## Constructor Details

  - ### DataStoreProvider

    protected DataStoreProvider()
    Creates a new provider.

- ## Method Details

  - ### getShortName

    public abstract String getShortName()
    Returns a short name or abbreviation for the data format. This name is used in some warnings or exception messages. It may contain any characters, including white spaces, and is not guaranteed to be unique. For a more comprehensive format name, see `getFormat()`.

    #### Examples

    `"CSV"`, `"GeoTIFF"`, `"GML"`, `"GPX"`, `"JPEG"`, `"JPEG 2000"`, `"NetCDF"`, `"PNG"`, `"Shapefile"`.
    Returns:
      a short name or abbreviation for the data format.
    Since:
      0.8
    See Also:
      - `getFormat()`

  - ### getFormat

    public Format getFormat()
    Returns a description of the data format. The description should contain (if available):
    - A reference to the format specification citation, including:
      - a format specification title (example: “PNG (Portable Network Graphics) Specification”),
      - the format short name as a citation alternate title (example: “PNG”),
      - the format version as the citation edition,
      - link to an online version of the specification.
    - The title of the file decompression technique used for reading the data.
    The default implementation returns a format containing only the value returned by `getShortName()`. Subclasses are encouraged to override this method for providing a more complete description, if available.
    Returns:
      a description of the data format.
    Since:
      0.8
    See Also:
      - `getShortName()`
      - `DefaultFormat`

  - ### getSupportedVersions

    public Range<Version> getSupportedVersions()
    Returns the range of versions supported by the data store, or `null` if unspecified.
    Returns:
      the range of supported versions, or `null` if unspecified.
    Since:
      0.8

  - ### getOpenParameters

    public abstract ParameterDescriptorGroup getOpenParameters()
    Returns a description of all parameters accepted by this provider for opening a data store. Those parameters provide an alternative to `StorageConnector` for opening a `DataStore` from a path or URL, together with additional information like character encoding.

    Implementers are responsible for declaring all parameters and whether they are mandatory or optional. It is recommended to define at least a parameter named "location", completed by "create" if the data store supports write operations. Those parameters will be recognized by the default `DataStoreProvider` methods and used whenever a `StorageConnector` is required.

    #### Alternative

    The main differences between the use of `StorageConnector` and parameters are:
    - `StorageConnector` is designed for use with file or stream of unknown format; the format is automatically detected. By contrast, the use of parameters require to determine the format first (i.e. select a `DataStoreProvider`).
    - Parameters can be used to dynamically generate user configuration interfaces and provide fine grain control over the store general behavior such as caching, time-outs, encoding, etc.
    - Parameters can more easily be serialized in XML or configuration files.
    Returns:
      description of the parameters required or accepted for opening a `DataStore`.
    Since:
      0.8
    See Also:
      - `LOCATION`
      - `CREATE`
      - `open(ParameterValueGroup)`
      - `DataStore​.getOpenParameters()`

  - ### probeContent

    public abstract ProbeResult probeContent(StorageConnector connector) throws DataStoreException
    Indicates if the given storage appears to be supported by the `DataStore`s created by this provider. Implementations will typically check the first bytes of the input stream for a "magic number" associated with the format. The most typical return values are:
    - `ProbeResult​.SUPPORTED` or another instance with supported status if the `DataStore`s created by this provider can open the given storage.
    - `ProbeResult​.UNSUPPORTED_STORAGE` if the given storage does not appear to be in a format supported by this `DataStoreProvider`.
    Note that the `SUPPORTED` value does not guarantee that reading or writing will succeed, only that there appears to be a reasonable chance of success based on a brief inspection of the storage object or contents.

    #### Note for implementers

    Implementations are responsible for restoring the storage object to its original position on return of this method. Implementers can use the mark/reset mechanism for this purpose. Marks are available as `ByteBuffer​.mark()`, `InputStream​.mark(int)` and `ImageInputStream​.mark()`. Alternatively, the `probeContent(StorageConnector, Class, Prober)` helper method manages automatically the marks for a set of known types.
    Parameters:
      `connector` - information about the storage (URL, stream, JDBC connection, etc).
    Returns:
      a supported status if the given storage seems to be readable by the `DataStore` instances created by this provider.
    Throws:
      `DataStoreException` - if an I/O or SQL error occurred. The error shall be unrelated to the logical structure of the storage.

  - ### probeContent

    protected <S> ProbeResult probeContent(StorageConnector connector, Class<S> type, DataStoreProvider.Prober<? super S> prober) throws DataStoreException
    Applies the specified test on the storage content without modifying buffer or input stream position. This is a helper method for `probeContent(StorageConnector)` implementations, providing an alternative safer than `StorageConnector​.getStorageAs(Class)` for performing an arbitrary number of independent tests on the same `StorageConnector`. Current implementation accepts the following types (this list may be expanded in future versions):

    > `ByteBuffer` (default byte order fixed to `BIG_ENDIAN`), `InputStream`, `DataInput`, `ImageInputStream` and `Reader`.

    The following types are also accepted for completeness but provide no additional safety compared to direct use of `StorageConnector​.getStorageAs(Class)`:

    > `URI`, `URL`, `File`, `Path` and `String` (interpreted as a file path).

    This method marks and resets streams automatically with an arbitrary read-ahead limit (typically okay for the first 8 kilobytes).

    #### Usage example

    `probeContent(StorageConnector)` implementations often check the first bytes of the input stream for a "magic number" associated with the format, as in the following example:

            @Override
            public ProbeResult probeContent(StorageConnector connector) throws DataStoreException {
                return probeContent(connector, ByteBuffer.class, (buffer) -> {
                    if (buffer.remaining() >= Integer.BYTES) {
                        if (buffer.getInt() == MAGIC_NUMBER) {
                            return ProbeResult.SUPPORTED;
                        }
                        return ProbeResult.UNSUPPORTED_STORAGE;
                    }
                    // If the buffer does not contain enough bytes for the integer type, this is not
                    // necessarily because the file is truncated. It may be because the data were not
                    // yet available at the time this method has been invoked.
                    return ProbeResult.INSUFFICIENT_BYTES;
                });
            }

    Type Parameters:
      `S` - the compile-time type of the `type` argument (the source or storage type).
    Parameters:
      `connector` - information about the storage (URL, stream, JDBC connection, etc).
      `type` - the desired type as one of `ByteBuffer`, `DataInput`, `Connection` class or other documented types.
      `prober` - the test to apply on the source of the given type.
    Returns:
      the result of executing the probe action with a source of the given type, or `ProbeResult​.UNSUPPORTED_STORAGE` if the given type is supported but no view can be created for the source given at construction time.
    Throws:
      `IllegalArgumentException` - if the given `type` argument is not one of the supported types.
      `IllegalStateException` - if this `StorageConnector` has been closed.
      `DataStoreException` - if an error occurred while opening a stream or database connection, or during the execution of the probe action.
    Since:
      1.2
    See Also:
      - `probeContent(StorageConnector)`
      - `StorageConnector​.getStorageAs(Class)`

  - ### open

    public abstract DataStore open(StorageConnector connector) throws DataStoreException
    Returns a data store implementation associated with this provider. This method is typically invoked when the format is not known in advance (the `probeContent(StorageConnector)` method can be tested on many providers) or when the input is not a type accepted by `open(ParameterValueGroup)` (for example an `InputStream`).

    #### Implementation note

    Implementers shall invoke `StorageConnector​.closeAllExcept(Object)` after `DataStore` creation, keeping open only the needed resource.
    Parameters:
      `connector` - information about the storage (URL, stream, JDBC connection, etc).
    Returns:
      a data store implementation associated with this provider for the given storage.
    Throws:
      `DataStoreException` - if an error occurred while creating the data store instance.
    See Also:
      - `DataStores​.open(Object)`

  - ### open

    public DataStore open(ParameterValueGroup parameters) throws DataStoreException
    Returns a data store implementation associated with this provider for the given parameters. The `DataStoreProvider` instance needs to be known before parameters are initialized, since the parameters are implementation-dependent. Example:

        DataStoreProvider provider = ...;
        ParameterValueGroup pg = provider.getOpenParameters().createValue();
        pg.parameter(DataStoreProvider.LOCATION, myURL);
        // Set any other parameters if desired.
        try (DataStore ds = provider.open(pg)) {
            // Use the data store.
        }

    #### Implementation note

    The default implementation gets the value of a parameter named "location". That value (typically a path or URL) is given to `StorageConnector` constructor, which is then passed to `open(StorageConnector)`.
    Parameters:
      `parameters` - opening parameters as defined by `getOpenParameters()`.
    Returns:
      a data store implementation associated with this provider for the given parameters.
    Throws:
      `DataStoreException` - if an error occurred while creating the data store instance.
    Since:
      0.8
    See Also:
      - `LOCATION`
      - `CREATE`
      - `getOpenParameters()`

  - ### getLogger

    public Logger getLogger()
    Returns the logger where to report warnings or loading operations. This logger is used only if no `StoreListener` has been registered for `WarningEvent`.

    The default implementation returns a logger with the same name as the package name of the subclass of this `DataStoreProvider` instance. Subclasses should override this method if they can provide a more specific logger.

    Returns:
      the logger to use as a fallback (when there are no listeners) for warning messages.
    Since:
      1.0
    See Also:
      - `StoreListeners​.getLogger()`