# Class StorageConnector

Object
StorageConnector

All Implemented Interfaces:
  `Serializable`

public class StorageConnector extends Object implements Serializable
Information for creating a connection to a `DataStore` in read and/or write mode. `StorageConnector` wraps an input `Object`, which can be any of the following types:

- A `Path` or a `File` for a file or a directory.
- A `URI` or a `URL` to a distant resource.
- A `CharSequence` interpreted as a filename or a URL.
- A `Channel`, `DataInput`, `InputStream` or `Reader`.
- A `DataSource` or a `Connection` to a JDBC database.
- Any other `DataStore`-specific object, for example `NetcdfFile`.

The `getStorageAs(Class)` method provides the storage as an object of the given type, opening the input stream if necessary. This class tries to open the stream only once - subsequent invocation of `getStorageAs(…)` may return the same input stream.

This class is used only for discovery of a `DataStore` implementation capable to handle the input. Once a suitable `DataStore` has been found, the `StorageConnector` instance is typically discarded since each data store implementation will use their own input/output objects.

## Limitations

This class is not thread-safe. Not only `StorageConnector` should be used by a single thread, but the objects returned by `getStorageAs(Class)` should also be used by the same thread.

Instances of this class are serializable if the `storage` object given at construction time is serializable.

Since:
  0.3
See Also:
  - Serialized Form

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final int`
  `DEFAULT_BUFFER_SIZE`
  The default size (in bytes) of `ByteBuffer`s created by storage connectors.
  `static final int`
  `READ_AHEAD_LIMIT`
  The read-ahead limit for mark operations before probing input streams.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `StorageConnector(Object storage)`
  Creates a new data store connection wrapping the given input/output object.
  `StorageConnector(StorageConnector parent, Object storage)`
  Creates a new data store connection which has a sub-component of a larger data store.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `closeAllExcept(Object view)`
  Closes all streams and connections created by this `StorageConnector` except the given view.
  `<S> S`
  `commit(Class<S> type, String format)`
  Returns the storage as a view of the given type and closes all other views.
  `String`
  `getFileExtension()`
  Returns the filename extension of the input/output object.
  `<T> T`
  `getOption(OptionKey<T> key)`
  Returns the option value for the given key, or `null` if none.
  `Object`
  `getStorage()`
  Returns the input/output object given at construction time.
  `<S> S`
  `getStorageAs(Class<S> type)`
  Returns the storage as a view of the given type if possible, or `null` otherwise.
  `String`
  `getStorageName()`
  Returns a short name of the input/output object.
  `final boolean`
  `isClosed()`
  Returns whether this storage connector has been closed.
  `<T> void`
  `setOption(OptionKey<T> key, T value)`
  Sets the option value for the given key.
  `String`
  `toString()`
  Returns a string representation of this `StorageConnector` for debugging purpose.
  `boolean`
  `wasProbingAbsentFile()`
  Returns whether returning the storage would have required the creation of a new file.

  ### Methods inherited from class Object

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

- ## Field Details

  - ### DEFAULT_BUFFER_SIZE

    public static final int DEFAULT_BUFFER_SIZE
    The default size (in bytes) of `ByteBuffer`s created by storage connectors. Those buffers are typically created when the specified storage object is a `File`, `Path`, `URL` or `URI`.

    The default buffer size is arbitrary and may change in any future Apache SIS version. The current value is 32768. Users can override this value by providing a pre-allocated buffer with `OptionKey​.BYTE_BUFFER`.

    Since:
      1.4
    See Also:
      - `OptionKey​.BYTE_BUFFER`
      - Constant Field Values

  - ### READ_AHEAD_LIMIT

    public static final int READ_AHEAD_LIMIT
    The read-ahead limit for mark operations before probing input streams. When the storage is an `InputStream` or a `Reader`, the `getStorageAs(Class)` method marks the current position with this "read ahead limit" value for resetting the stream to its original position if the caller does not recognize the stream content. Implementations of the `DataStoreProvider​.probeContent(StorageConnector)` method should avoid reading more bytes or characters from an `InputStream` or from a `Reader` than this value.

    The read ahead limit is arbitrary and may change in any future Apache SIS version. However it is guaranteed to be smaller than or equal to `DEFAULT_BUFFER_SIZE`. The current value is 8192.

    Note for maintainer: this value should not be greater than the `BufferedInputStream` default buffer size.
    Since:
      1.5
    See Also:
      - `InputStream​.mark(int)`
      - `Reader​.mark(int)`
      - Constant Field Values

- ## Constructor Details

  - ### StorageConnector

    public StorageConnector(Object storage)
    Creates a new data store connection wrapping the given input/output object. The object can be of any type, but the class javadoc lists the most typical ones.
    Parameters:
      `storage` - the input/output object as a URL, file, image input stream, etc..

  - ### StorageConnector

    public StorageConnector(StorageConnector parent, Object storage)
    Creates a new data store connection which has a sub-component of a larger data store. The new storage connector inherits all options that were specified in the parent connector.
    Parameters:
      `parent` - the storage connector from which to inherit options.
      `storage` - the input/output object as a URL, file, image input stream, etc..
    Since:
      1.5

- ## Method Details

  - ### setOption

    public <T> void setOption(OptionKey<T> key, T value)
    Sets the option value for the given key. The `StorageConnector` class uses the following options, if present:
    - `OptionKey​.ENCODING` for decoding characters in an input stream, if needed.
    - `OptionKey​.URL_ENCODING` for converting URL to URI or filename, if needed.
    - `OptionKey​.OPEN_OPTIONS` for specifying whether the data store shall be read only or read/write.
    - `OptionKey​.BYTE_BUFFER` for allowing users to control the byte buffer to be created.
    In addition, each `DataStore` implementation may use more options.
    Type Parameters:
      `T` - the type of option value.
    Parameters:
      `key` - the option for which to set the value.
      `value` - the new value for the given option, or `null` for removing the value.

  - ### getOption

    public <T> T getOption(OptionKey<T> key)
    Returns the option value for the given key, or `null` if none. This is the value specified by the last call to a `setOption(…)` with the given key.
    Type Parameters:
      `T` - the type of option value.
    Parameters:
      `key` - the option for which to get the value.
    Returns:
      the current value for the given option, or `null` if none.

  - ### getStorage

    public Object getStorage() throws DataStoreException
    Returns the input/output object given at construction time. The object can be of any type, but the class javadoc lists the most typical ones.
    Returns:
      the input/output object as a URL, file, image input stream, etc..
    Throws:
      `DataStoreException` - if the storage object has already been used and cannot be reused.
    See Also:
      - `getStorageAs(Class)`

  - ### getStorageName

    public String getStorageName()
    Returns a short name of the input/output object. For example if the storage is a file, this method returns the filename without the path (but including the file extension). The default implementation performs the following choices based on the type of the storage object:
    - For `Path`, `File`, `URI` or `URL` instances, this method uses dedicated API like `Path​.getFileName()`.
    - For `CharSequence` instances, this method gets a string representation of the storage object and returns the part after the last `'/'` character or platform-dependent name separator.
    - For instances of unknown type, this method builds a string representation using the class name. Note that the string representation of unknown types may change in any future SIS version.
    Returns:
      a short name of the storage object.

  - ### getFileExtension

    public String getFileExtension()
    Returns the filename extension of the input/output object. The default implementation performs the following choices based on the type of the storage object:
    - For `Path`, `File`, `URI`, `URL` or `CharSequence` instances, this method returns the string after the last `'.'` character in the filename, provided that the `'.'` is not the first filename character. This may be an empty string if the filename has no extension, but never `null`.
    - For instances of unknown type, this method returns `null`.
    Returns:
      the filename extension, or an empty string if none, or `null` if the storage is an object of unknown type.

  - ### getStorageAs

    public <S> S getStorageAs(Class<S> type) throws IllegalArgumentException, DataStoreException
    Returns the storage as a view of the given type if possible, or `null` otherwise. The default implementation accepts the following types:
    - `String`:
      - If the storage object is an instance of the `Path`, `File`, `URL`, `URI` or `CharSequence` types, returns the string representation of their path.
      - Otherwise, this method returns `null`.
    - `Path`, `URI`, `URL`, `File`:
      - If the storage object is an instance of the `Path`, `File`, `URL`, `URI` or `CharSequence` types and that type can be converted to the requested type, returned the conversion result.
      - Otherwise, this method returns `null`.
    - `ByteBuffer`:
      - If the storage object can be obtained as described in bullet 2 of the `DataInput` section below, then this method returns the associated byte buffer.
      - Otherwise, this method returns `null`.
    - `DataInput`:
      - If the storage object is already an instance of `DataInput` (including the `ImageInputStream` and `ImageOutputStream` types), then it is returned unchanged.
      - Otherwise, if the input is an instance of `ByteBuffer`, then an `ImageInputStream` backed by a read-only view of that buffer is created when first needed and returned. The properties (position, mark, limit) of the original buffer are unmodified.
      - Otherwise, if the input is an instance of `Path`, `File`, `URI`, `URL`, `CharSequence`, `InputStream` or `ReadableByteChannel`, then an `ImageInputStream` backed by a `ByteBuffer` is created when first needed and returned.
      - Otherwise, if `ImageIO​.createImageInputStream(Object)` returns a non-null value, then this value is cached and returned.
      - Otherwise, this method returns `null`.
    - `ImageInputStream`:
      - If the above `DataInput` can be created and cast to `ImageInputStream`, returns it.
      - Otherwise this method returns `null`.
    - `InputStream`:
      - If the storage object is already an instance of `InputStream`, then it is returned unchanged.
      - Otherwise, if the above `ImageInputStream` can be created, returns a wrapper around that stream.
      - Otherwise, this method returns `null`.
    - `Reader`:
      - If the storage object is already an instance of `Reader`, then it is returned unchanged.
      - Otherwise, if the above `InputStream` can be created, returns an `InputStreamReader` using the encoding specified by `OptionKey​.ENCODING` if any, or using the system default encoding otherwise.
      - Otherwise, this method returns `null`.
    - `DataOutput`:
      - If the storage object is already an instance of `DataOutput` (including the `ImageOutputStream` type), then it is returned unchanged.
      - Otherwise, if the output is an instance of `Path`, `File`, `URI`, `URL`, `CharSequence`, `OutputStream` or `WritableByteChannel`, then an `ImageInputStream` backed by a `ByteBuffer` is created when first needed and returned.
      - Otherwise, if `ImageIO​.createImageOutputStream(Object)` returns a non-null value, then this value is cached and returned.
      - Otherwise, this method returns `null`.
    - `ImageOutputStream`:
      - If the above `DataOutput` can be created and cast to `ImageOutputStream`, returns it.
      - Otherwise this method returns `null`.
    - `OutputStream`:
      - If the above `DataOutput` can be created and cast to `OutputStream`, returns it.
      - Otherwise this method returns `null`.
    - `DataSource`:
      - If the storage object is already an instance of `DataSource`, then it is returned unchanged.
      - Otherwise, if the storage is convertible to an `URI` and the URI scheme is "jdbc" (ignoring case), then a data source delegating to `DriverManager` is created when first needed and returned.
      - Otherwise, this method returns `null`.
    - `Connection`:
      - If the storage object is already an instance of `Connection`, then it is returned unchanged.
      - Otherwise, if the storage is convertible to a `DataSource`, then a connection is obtained when first needed and returned.
      - Otherwise, this method returns `null`.
    - Any other types:
      - If the storage given at construction time is already an instance of the requested type, returns it as-is.
      - Otherwise, this method throws `IllegalArgumentException`.

    #### Usage for probing operations

    Multiple invocations of this method on the same `StorageConnector` instance will try to return the same instance on a best effort basis. Consequently, implementations of `DataStoreProvider​.probeContent(StorageConnector)` methods shall not close the stream or database connection returned by this method. In addition, those `probeContent(StorageConnector)` methods are responsible for restoring the stream or byte buffer to its original position on return. For an easier and safer way to ensure that the storage position is not modified, see `DataStoreProvider​.probeContent(StorageConnector, Class, Prober)`.
    Type Parameters:
      `S` - the compile-time type of the `type` argument (the source or storage type).
    Parameters:
      `type` - the desired type as one of `ByteBuffer`, `DataInput`, `Connection` class or other types supported by `StorageConnector` subclasses.
    Returns:
      the storage as a view of the given type, or `null` if the given type is one of the supported types listed in javadoc but no view can be created for the source given at construction time. In the latter case, `wasProbingAbsentFile()` can be invoked for determining whether the reason is that the file does not exist but could be created.
    Throws:
      `IllegalArgumentException` - if the given `type` argument is not one of the supported types listed in this javadoc or in subclass javadoc.
      `IllegalStateException` - if this `StorageConnector` has been closed.
      `DataStoreException` - if an error occurred while opening a stream or database connection.
    See Also:
      - `getStorage()`
      - `closeAllExcept(Object)`
      - `DataStoreProvider​.probeContent(StorageConnector, Class, Prober)`

  - ### wasProbingAbsentFile

    public boolean wasProbingAbsentFile()
    Returns whether returning the storage would have required the creation of a new file. This method may return `true` if all the following conditions are true:
    - The options given to this `StorageConnector` include `StandardOpenOption​.CREATE` or `CREATE_NEW`.
    - The `getStorageAs(…)` and `wasProbingAbsentFile()` calls happened in the context of `DataStores` probing the storage content in order to choose a `DataStoreProvider`.
    - A previous `getStorageAs(Class)` call requested some kind of input stream (e.g. `InputStream`, `ImageInputStream`, `DataInput`, `Reader`).
    - One of the following conditions is true:
      - The input stream is empty.
      - The storage is an object convertible to a `Path` and the file identified by that path does not exist.
    If all above conditions are true, then `getStorageAs(Class)` returns `null` instead of creating a new empty file. In such case, `DataStoreProvider` may use this `wasProbingAbsentFile()` method for deciding whether to report `ProbeResult​.SUPPORTED` or `ProbeResult​.UNSUPPORTED_STORAGE`.

    #### Rational

    When the file does not exist and the `CREATE` or `CREATE_NEW` option is provided, `getStorageAs(…)` would normally create a new empty file. However this behavior is modified during probing (the first condition in above list) because newly created files are empty and probing empty files may result in `EOFException` to be thrown or in providers declaring that they do not support the storage.

    IF the `CREATE` or `CREATE_NEW` options were not provided, then probing the storage content of an absent file will rather throw `NoSuchFileException` or `FileNotFoundException`. So this method is useful only for `DataStore` having write capabilities.

    Returns:
      whether returning the storage would have required the creation of a new file.
    Since:
      1.4

  - ### commit

    public <S> S commit(Class<S> type, String format) throws IllegalArgumentException, DataStoreException
    Returns the storage as a view of the given type and closes all other views. Invoking this method is equivalent to invoking `getStorageAs(Class)` followed by `closeAllExcept(Object)` except that the latter method is always invoked (in a way similar to "try with resource") and that this method never returns `null`.
    Type Parameters:
      `S` - the compile-time type of the `type` argument (the source or storage type).
    Parameters:
      `type` - the desired type as one of the types documented in `getStorageAs(Class)` (example: `ByteBuffer`, `DataInput`, `Connection`).
      `format` - short name or abbreviation of the data format (e.g. "CSV", "GML", "WKT", etc). Used for information purpose in error messages if needed.
    Returns:
      the storage as a view of the given type. Never `null`.
    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.
    Since:
      1.2
    See Also:
      - `getStorageAs(Class)`
      - `closeAllExcept(Object)`

  - ### closeAllExcept

    public void closeAllExcept(Object view) throws DataStoreException
    Closes all streams and connections created by this `StorageConnector` except the given view. This method closes all objects created by the `getStorageAs(Class)` method except the given `view`. If `view` is `null`, then this method closes everything including the storage if it is closeable.

    This method is invoked when a suitable `DataStore` has been found - in which case the view used by the data store is given in argument to this method - or when no suitable `DataStore` has been found - in which case the `view` argument is null.

    This `StorageConnector` instance shall not be used anymore after invocation of this method.

    Parameters:
      `view` - the view to leave open, or `null` if none.
    Throws:
      `DataStoreException` - if an error occurred while closing the stream or database connection.
    See Also:
      - `getStorageAs(Class)`
      - `DataStoreProvider​.open(StorageConnector)`

  - ### isClosed

    public final boolean isClosed()
    Returns whether this storage connector has been closed. If this method returns `true`, then any call to `getStorageAs(Class)` will throw `IllegalStateException`.
    Returns:
      `true` if this storage connector is closed.
    Since:
      1.5

  - ### toString

    public String toString()
    Returns a string representation of this `StorageConnector` for debugging purpose. This string representation is for diagnostic and may change in any future version.
    Overrides:
      `toString` in class `Object`
    Returns:
      a string representation of this `StorageConnector` for debugging purpose.