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

# Class DataStore

Object
DataStore

All Implemented Interfaces:
  `AutoCloseable`, `Resource`, `Localized`

Direct Known Subclasses:
  `GeoTiffStore`, `LandsatStore`, `NetcdfStore`, `SQLStore`

public abstract class DataStore extends Object implements Resource, Localized, AutoCloseable
Manages a series of features, coverages or sensor data. Different `DataStore` subclasses exist for different formats (netCDF, GeoTIFF, etc.). The supported format can be identified by the provider.

Each data store is itself a `Resource`. The data store subclasses should implement a more specialized `Resource` interface depending on the format characteristics. For example, a `DataStore` for ShapeFiles will implement the `FeatureSet` interface, while a `DataStore` for netCDF files will implement the `Aggregate` interface.

## Thread safety policy

Data stores should be thread-safe, but their synchronization lock is implementation-dependent. This base class uses only the `synchronized` keyword, applied on the following methods:

- `getLocale()`
- `setLocale(Locale)`

Since above properties are used only for information purpose, concurrent modifications during a read or write operation should be harmless. Consequently, subclasses are free use their own synchronization mechanism instead than `synchronized(this)` lock.

Since:
  0.3
See Also:
  - `DataStores​.open(Object)`

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `protected final StoreListeners`
  `listeners`
  The set of registered `StoreListener`s for this data store.
  `protected final DataStoreProvider`
  `provider`
  The factory that created this `DataStore` instance, or `null` if unspecified.

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  `protected`
  `DataStore()`
  Creates a new instance with no provider and initially no listener.
  `protected`
  `DataStore(DataStoreProvider provider, StorageConnector connector)`
  Creates a new instance for the given storage (typically file or database).
  `protected`
  `DataStore(DataStore parent, DataStoreProvider provider, StorageConnector connector, boolean hidden)`
  Creates a new instance as a child of another data store instance.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `<T extends StoreEvent>
  void`
  `addListener(Class<T> eventType, StoreListener<? super T> listener)`
  Registers a listener to notify when the specified kind of event occurs in this data store or in a resource.
  `abstract void`
  `close()`
  Closes this data store and releases any underlying resources.
  `Resource`
  `findResource(String identifier)`
  Searches for a resource identified by the given identifier.
  `String`
  `getDisplayName()`
  Returns a short name or label for this data store.
  `Optional<GenericName>`
  `getIdentifier()`
  Returns an identifier for the root resource of this data store, or an empty value if none.
  `Locale`
  `getLocale()`
  The locale to use for formatting warnings and other messages.
  `abstract Metadata`
  `getMetadata()`
  Returns information about the data store as a whole.
  `Optional<TreeTable>`
  `getNativeMetadata()`
  Returns implementation-specific metadata.
  `abstract Optional<ParameterValueGroup>`
  `getOpenParameters()`
  Returns the parameters used to open this data store.
  `DataStoreProvider`
  `getProvider()`
  Returns the factory that created this `DataStore` instance.
  `<T extends StoreEvent>
  void`
  `removeListener(Class<T> eventType, StoreListener<? super T> listener)`
  Unregisters a listener previously added to this data store for the given type of events.
  `void`
  `setLocale(Locale locale)`
  Sets the locale to use for formatting warnings and other messages.
  `String`
  `toString()`
  Returns a string representation of this data store for debugging purpose.

  ### Methods inherited from class Object

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

- ## Field Details

  - ### provider

    protected final DataStoreProvider provider
    The factory that created this `DataStore` instance, or `null` if unspecified. This information can be useful for fetching information common to all `DataStore` instances of the same class.
    Since:
      0.8
    See Also:
      - `getProvider()`

  - ### listeners

    protected final StoreListeners listeners
    The set of registered `StoreListener`s for this data store.

- ## Constructor Details

  - ### DataStore

    protected DataStore()
    Creates a new instance with no provider and initially no listener.

  - ### DataStore

    protected DataStore(DataStoreProvider provider, StorageConnector connector) throws DataStoreException
    Creates a new instance for the given storage (typically file or database). The `provider` argument is an optional but recommended information. The `connector` argument is mandatory.
    Parameters:
      `provider` - the factory that created this `DataStore` instance, or `null` if unspecified.
      `connector` - information about the storage (URL, stream, reader instance, etc).
    Throws:
      `DataStoreException` - if an error occurred while creating the data store for the given storage.
    Since:
      0.8

  - ### DataStore

    protected DataStore(DataStore parent, DataStoreProvider provider, StorageConnector connector, boolean hidden) throws DataStoreException
    Creates a new instance as a child of another data store instance. Events will be sent not only to registered listeners of this `DataStore`, but also to listeners of the `parent` data store. Each listener will be notified only once, even if the same listener is registered in the two places.
    Parameters:
      `parent` - the parent that contains this new `DataStore` component, or `null` if none.
      `provider` - the factory that created this `DataStore` instance, or `null` if unspecified.
      `connector` - information about the storage (URL, stream, reader instance, etc).
      `hidden` - `true` if this store will not be directly accessible from the parent. It is the case if this store is an `Aggregate` and the parent store will expose only some components of the aggregate instead of the aggregate itself.
    Throws:
      `DataStoreException` - if an error occurred while creating the data store for the given storage.
    Since:
      1.1

- ## Method Details

  - ### getProvider

    public DataStoreProvider getProvider()
    Returns the factory that created this `DataStore` instance. The provider gives additional information on this `DataStore` such as a format description and a list of parameters that can be used for opening data stores of the same class.

    The return value should never be null if this `DataStore` has been created by `DataStores​.open(Object)` or by a `DataStoreProvider` `open(…)` method. However, it may be null if this object has been instantiated by a direct call to its constructor.

    Returns:
      the factory that created this `DataStore` instance, or `null` if unspecified.
    Since:
      0.8
    See Also:
      - `provider`

  - ### getOpenParameters

    public abstract Optional<ParameterValueGroup> getOpenParameters()
    Returns the parameters used to open this data store. The collection of legal parameters is implementation-dependent (their description is given by `DataStoreProvider​.getOpenParameters()`), but should contain at least a parameter named "location" with a `URI`, `Path` or `DataSource` value.

    In the event a data store must be closed and reopened later, those parameters can be stored in a file or database and used for creating a new store later.

    In some cases, for stores reading in-memory data or other inputs that cannot fit with `ParameterDescriptorGroup` requirements (for example an `InputStream` connected to unknown or no `URL`), this method may return an empty value.

    Returns:
      parameters used for opening this `DataStore`.
    Since:
      0.8
    See Also:
      - `DataStoreProvider​.getOpenParameters()`

  - ### setLocale

    public void setLocale(Locale locale)
    Sets the locale to use for formatting warnings and other messages. In a client-server architecture, it should be the locale on the client side.

    This locale is used on a best-effort basis; whether messages will honor this locale or not depends on the code that logged warnings or threw exceptions. In Apache SIS implementation, this locale has better chances to be honored by the `DataStoreException​.getLocalizedMessage()` method rather than `getMessage()`. See `getLocalizedMessage()` javadoc for more information.

    Parameters:
      `locale` - the new locale to use.
    See Also:
      - `DataStoreException​.getLocalizedMessage()`

  - ### getLocale

    public Locale getLocale()
    The locale to use for formatting warnings and other messages. This locale is for user interfaces only – it has no effect on the data to be read or written from/to the data store.

    The default value is the system default locale.

    Specified by:
      `getLocale` in interface `Localized`
    Returns:
      the locale, or `null` if not explicitly defined.
    See Also:
      - `StoreEvent​.getLocale()`

  - ### getDisplayName

    public String getDisplayName()
    Returns a short name or label for this data store. The returned name can be used in user interfaces or in error messages. It may be a title in natural language, but should be relatively short. The name may be localized in the language specified by the value of `getLocale()` if this data store is capable to produce a name in various languages.

    This name should not be used as an identifier since there is no guarantee that the name is unique among data stores, and no guarantee that the name is the same in all locales. The name may also contain any Unicode characters, including characters usually not allowed in identifiers like white spaces.

    This method should never throw an exception since it may be invoked for producing error messages, in which case throwing an exception here would hide the original exception.

    This method differs from `getIdentifier()` in that it is typically a file name known at construction time instead of a property read from metadata. Default implementation returns the `StorageConnector​.getStorageName()` value, or `null` if this data store has been created by the no-argument constructor. Subclasses should override this method if they can provide a better name.

    Returns:
      a short name of label for this data store, or `null` if unknown.
    Since:
      0.8
    See Also:
      - `getIdentifier()`
      - `getLocale()`

  - ### getIdentifier

    public Optional<GenericName> getIdentifier() throws DataStoreException
    Returns an identifier for the root resource of this data store, or an empty value if none. If this data store contains many resources (as in an `Aggregate`), the returned identifier shall be different than the identifiers of those child resources. In other words, the following equality shall hold without ambiguity:

        findResource(getIdentifier().toString()) == this

    Note that this identifier is not guaranteed to be unique between different `DataStore` instances; it only needs to be unique among the resources provided by this data store instance.

    #### Default implementation

    The default implementation searches for an identifier in the metadata, at the location shown below, provided that conditions are met:

    > Path: `metadata` / `identificationInfo` / `citation` / `identifier`

    > Condition: in default implementation, the identifier is presents only if exactly one `citation` is found at above path. If two or more `citation` instances are found, the identification is considered ambiguous and an empty value is returned.

    > Selection: the first identifier implementing the `GenericName` interface is returned. If there is no such identifier, then a `NamedIdentifier` is created from the first identifier. If there is no identifier at all, then an empty value is returned.

    Subclasses are encouraged to override this method with more efficient implementations.
    Specified by:
      `getIdentifier` in interface `Resource`
    Returns:
      an identifier for the root resource of this data store.
    Throws:
      `DataStoreException` - if an error occurred while fetching the identifier.
    Since:
      1.0
    See Also:
      - `getMetadata()`
      - `getDisplayName()`

  - ### getMetadata

    public abstract Metadata getMetadata() throws DataStoreException
    Returns information about the data store as a whole. The returned metadata object can contain information such as the spatiotemporal extent of all contained resources, contact information about the creator or distributor, data quality, update frequency, usage constraints, file format and more.
    Specified by:
      `getMetadata` in interface `Resource`
    Returns:
      information about resources in the data store. Should not be `null`.
    Throws:
      `DataStoreException` - if an error occurred while reading the metadata.
    See Also:
      - `getIdentifier()`
      - `DefaultMetadata​.deepCopy(Metadata)`

  - ### getNativeMetadata

    public Optional<TreeTable> getNativeMetadata() throws DataStoreException
    Returns implementation-specific metadata. The structure of those metadata varies for each file format. The standard metadata should be preferred since they allow abstraction of format details, but those native metadata are sometimes useful when an information is not provided by the standard metadata.

    The tree table should contain at least the following columns:

    - `TableColumn​.NAME` — a name for the metadata property, e.g. "Title".
    - `TableColumn​.VALUE` — the property value typically as a string, number or date.
    The `TableColumn​.NAME` of the root node should be a format name such as "NetCDF" or "GeoTIFF". That name should be short since it may be used in widget as a designation of implementation-specific details.
    Returns:
      resources information structured in an implementation-specific way.
    Throws:
      `DataStoreException` - if an error occurred while reading the metadata.
    Since:
      1.1

  - ### findResource

    public Resource findResource(String identifier) throws DataStoreException
    Searches for a resource identified by the given identifier. The given identifier should be the string representation of the return value of `Resource​.getIdentifier()` on the desired resource. Implementation may also accept aliases for convenience. For example if the full name of a resource is `"foo:bar"`, then this method may accept `"bar"` as a synonymous of `"foo:bar"` provided that it is unambiguous.

    The default implementation verifies if above criterion apply to this `DataStore` (which is itself a resource), then iterates recursively over `Aggregate` components if this data store is an aggregate. If a match is found without ambiguity, the associated resource is returned. Otherwise an exception is thrown. Subclasses are encouraged to override this method with a more efficient implementation.

    Parameters:
      `identifier` - identifier of the resource to fetch. Must be non-null.
    Returns:
      resource associated to the given identifier (never `null`).
    Throws:
      `IllegalNameException` - if no resource is found for the given identifier, or if more than one resource is found.
      `DataStoreException` - if another kind of error occurred while searching resources.
    See Also:
      - `Resource​.getIdentifier()`
      - `FeatureNaming`

  - ### addListener

    public <T extends StoreEvent> void addListener(Class<T> eventType, StoreListener<? super T> listener)
    Registers a listener to notify when the specified kind of event occurs in this data store or in a resource. The data store will call the `StoreListener​.eventOccured(StoreEvent)` method when new events matching the `eventType` occur. An event may be a change in data store content or structure, or a warning that occurred during a read or write operation.

    Registering a listener for a given `eventType` also register the listener for all event sub-types. The same listener can be registered many times, but its `StoreListener​.eventOccured(StoreEvent)` method will be invoked only once per event. This filtering applies even if the listener is registered on individual resources of this data store.

    If this data store may produce events of the given type, then the given listener is kept by strong reference; it will not be garbage collected unless explicitly removed or unless this `DataStore` is itself garbage collected. However if the given type of events can never happen with this data store, then this method is not required to keep a reference to the given listener.

    #### Warning events

    If `eventType` is assignable from `WarningEvent.class`, then registering that listener turns off logging of warning messages for this data store. This side-effect is applied on the assumption that the registered listener will handle warnings in its own way, for example by showing warnings in a widget.
    Specified by:
      `addListener` in interface `Resource`
    Type Parameters:
      `T` - compile-time value of the `eventType` argument.
    Parameters:
      `eventType` - type of `StoreEvent` to listen (cannot be `null`).
      `listener` - listener to notify about events.
    Since:
      1.0

  - ### removeListener

    public <T extends StoreEvent> void removeListener(Class<T> eventType, StoreListener<? super T> listener)
    Unregisters a listener previously added to this data store for the given type of events. The `eventType` must be the exact same class than the one given to the `addListener(…)` method; this method does not remove listeners registered for subclasses and does not remove listeners registered in children resources.

    If the same listener has been registered many times for the same even type, then this method removes only the most recent registration. In other words if `addListener(type, ls)` has been invoked twice, then `removeListener(type, ls)` needs to be invoked twice in order to remove all instances of that listener. If the given listener is not found, then this method does nothing (no exception is thrown).

    #### Warning events

    If `eventType` is `WarningEvent.class` and if, after this method invocation, there are no remaining listeners for warning events, then this `DataStore` will send future warnings to the loggers.
    Specified by:
      `removeListener` in interface `Resource`
    Type Parameters:
      `T` - compile-time value of the `eventType` argument.
    Parameters:
      `eventType` - type of `StoreEvent` which were listened (cannot be `null`).
      `listener` - listener to stop notifying about events.
    Since:
      1.0

  - ### close

    public abstract void close() throws DataStoreException
    Closes this data store and releases any underlying resources. A `CloseEvent` is sent to listeners before the data store is closed.

    If this method is invoked asynchronously while a read operation is in progress in another thread, then the behavior is implementation dependent. Some implementations will interrupt the read process, for example with an `AsynchronousCloseException`. This is useful if the data store was downloading a large file from a network connection.

    #### Note for implementers

    Implementations should invoke `listeners​.close()` on their first line for sending notification to all listeners before the data store is actually closed.
    Specified by:
      `close` in interface `AutoCloseable`
    Throws:
      `DataStoreException` - if an error occurred while closing this data store.
    See Also:
      - `StoreListeners​.close()`

  - ### toString

    public String toString()
    Returns a string representation of this data store for debugging purpose. The content of the string returned by this method may change in any future SIS version.
    Overrides:
      `toString` in class `Object`
    Returns:
      a string representation of this data store for debugging purpose.