Class StorageConnector
- All Implemented Interfaces:
Serializable
DataStore in read and/or write mode.
StorageConnector wraps an input Object, which can be any of the following types:
- A
Pathor aFilefor a file or a directory. - A
URIor aURLto a distant resource. - A
CharSequenceinterpreted as a filename or a URL. - A
Channel,DataInput,InputStreamorReader. - A
DataSourceor aConnectionto a JDBC database. - Any other
DataStore-specific object, for exampleucar.nc2.NetcdfFile.
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 onlyStorageConnector 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
- Version:
- 1.3
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static final classprivate static interfaceHandler toStorageConnector.createFoo()methods associated to given storage types. -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate static final byteA flag foraddView(…, view, source, flags)telling that after closing theview, we also need to close thesource.private static final byteA flag foraddView(…, view, source, flags)telling that before resetting theview, we need to reset thesourcefirst.private static final byteA flag foraddView(…, view, source, flags)telling thatviewcannot be reset, so it should be set tonullinstead.(package private) static final intThe default size of theByteBufferto be created.private StringThe filename extension, ornullif none.(package private) static final intThe minimal size of theByteBufferto be created.private StringA name for the input/output object, ornullif none.private static final Map<Class<?>,StorageConnector.Opener<?>> List of types recognized bygetStorageAs(Class), associated to the methods for opening stream of those types.The options, created only when first needed.private static final longFor cross-version compatibility.(package private) final ObjectThe input/output object given at construction time.private Map<Class<?>,StorageConnector.Coupled> Views ofstorageas instances of types different than the type of the object given to the constructor. -
Constructor Summary
ConstructorsConstructorDescriptionStorageConnector(Object storage) Creates a new data store connection wrapping the given input/output object. -
Method Summary
Modifier and TypeMethodDescriptionprivate static <S> voidadd(Class<S> type, StorageConnector.Opener<S> op) Helper method forOPENERSstatic initialization.private <S> voidAdds the given view in the cache, without dependencies.private <S> voidAdds the given view in the cache together with information about its dependency.voidcloseAllExcept(Object view) Closes all streams and connections created by thisStorageConnectorexcept the given view.<S> SReturns the storage as a view of the given type and closes all other views.private ByteBufferprivate ChannelDataInputcreateChannelDataInput(boolean asImageInputStream) Creates a view for the input as aChannelDataInputif possible.private ChannelDataOutputCreates a view for the storage as aChannelDataOutputif possible.private ConnectionCreates a database connection if possible.private DataInputCreates a view for the input as aDataInputif possible.private DataOutputCreates a view for the output as aDataOutputif possible.private ImageInputStreamCreates anImageInputStreamfrom theDataInputif possible.private InputStreamCreates an input stream fromReadableByteChannelif possible, or fromImageInputStreamotherwise.private OutputStreamCreates an output stream fromWritableByteChannelif possible, or fromImageOutputStreamotherwise.private ReaderCreates a character reader if possible.private StringReturns the storage as a path if possible, ornullotherwise.private ByteBuffergetChannelBuffer(ChannelFactory factory) Returns or allocate a buffer for use with theChannelDataInputorChannelDataOutput.Returns the filename extension of the input/output object.<T> TReturns the option value for the given key, ornullif none.Returns the input/output object given at construction time.<S> SgetStorageAs(Class<S> type) Returns the storage as a view of the given type if possible, ornullotherwise.Returns a short name of the input/output object.private StorageConnector.CoupledReturns the view for the given type from the cache.(package private) static booleanisSupportedType(Class<?> type) Returnstrueif the given type is one of the types supported byStorageConnector.(package private) final booleanprefetch()Transfers more bytes from theDataInputto theByteBuffer, if possible.private voidreset()Resets the rootstorageobject.private booleanResets the given view.<T> voidSets the option value for the given key.toString()Returns a string representation of thisStorageConnectorfor debugging purpose.private static IOExceptionReturns the cause of given exception if it exists, or the exception itself otherwise.
-
Field Details
-
serialVersionUID
private static final long serialVersionUIDFor cross-version compatibility.- See Also:
-
DEFAULT_BUFFER_SIZE
static final int DEFAULT_BUFFER_SIZEThe default size of theByteBufferto be created. Users can override this value by providing a value forOptionKey.BYTE_BUFFER.This buffer capacity is also used as read-ahead limit for mark operations. The rational is to allow as many bytes as contained in buffers of default size. For increasing the chances to meet that goal, this size should be the same than
BufferedInputStreamdefault buffer size. -
MINIMAL_BUFFER_SIZE
static final int MINIMAL_BUFFER_SIZEThe minimal size of theByteBufferto be created. This size is used only for temporary buffers that are unlikely to be used for the actual reading process.- See Also:
-
CASCADE_ON_CLOSE
private static final byte CASCADE_ON_CLOSEA flag foraddView(…, view, source, flags)telling that after closing theview, we also need to close thesource. This flag should be set when the view is anImageInputStreambecause Java I/OFileCacheImageInputStream.close()does not close the underlying stream. For most other kinds of view, this flag should not be set. -
CASCADE_ON_RESET
private static final byte CASCADE_ON_RESETA flag foraddView(…, view, source, flags)telling that before resetting theview, we need to reset thesourcefirst. This flag should can be unset if any change in the position ofviewis immediately reflected in the position ofsource, and vice-versa. -
CLEAR_ON_RESET
private static final byte CLEAR_ON_RESETA flag foraddView(…, view, source, flags)telling thatviewcannot be reset, so it should be set tonullinstead. This implies that a new view of the same type will be recreated next time it will be requested.When this flag is set, the
CASCADE_ON_RESETshould usually be set at the same time.- See Also:
-
OPENERS
List of types recognized bygetStorageAs(Class), associated to the methods for opening stream of those types. This map shall contain every types documented ingetStorageAs(Class)javadoc.nullvalues means to useObjectConvertersfor that particular type. -
storage
The input/output object given at construction time.- See Also:
-
name
A name for the input/output object, ornullif none. This field is initialized only when first needed. -
extension
The filename extension, ornullif none. This field is initialized only when first needed. -
options
The options, created only when first needed. -
views
Views ofstorageas instances of types different than the type of the object given to the constructor. Thenullreference can appear in various places:- A non-existent entry (equivalent to an entry associated to the
nullvalue) means that the value has not yet been computed. - A valid entry with
StorageConnector.Coupled.viewset tonullmeans the value has been computed and we have determined thatgetStorageAs(Class)shall returnnullfor that type. - By convention, the
nullkey is associated to thestoragevalue.
StorageConnectorhas been closed. - A non-existent entry (equivalent to an entry associated to the
-
-
Constructor Details
-
StorageConnector
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..
-
-
Method Details
-
add
Helper method forOPENERSstatic initialization. -
getOption
Returns the option value for the given key, ornullif none.- 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
nullif none.
-
setOption
Sets the option value for the given key. The default implementation recognizes the following options:OptionKey.ENCODINGfor decoding characters in an input stream, if needed.OptionKey.URL_ENCODINGfor converting URL to URI or filename, if needed.OptionKey.OPEN_OPTIONSfor specifying whether the data store shall be read only or read/write.OptionKey.BYTE_BUFFERfor allowing users to control the byte buffer to be created.
- 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, ornullfor removing the value.
-
getStorage
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:
-
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,URIorURLinstances, this method uses dedicated API likePath.getFileName(). - For
CharSequenceinstances, 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.
- For
-
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,URLorCharSequenceinstances, 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 nevernull. - For instances of unknown type, this method returns
null.
- Returns:
- the filename extension, or an empty string if none,
or
nullif the storage is an object of unknown type.
- For
-
isSupportedType
Returnstrueif the given type is one of the types supported byStorageConnector. The list of supported types is hard-coded and may change in any future version. -
getStorageAs
Returns the storage as a view of the given type if possible, ornullotherwise. The default implementation accepts the following types:String:Path,URI,URL,File:ByteBuffer:- If the storage object can be obtained as described in bullet 2 of the
DataInputsection below, then this method returns the associated byte buffer. - Otherwise this method returns
null.
- If the storage object can be obtained as described in bullet 2 of the
DataInput:- If the storage object is already an instance of
DataInput(including theImageInputStreamandImageOutputStreamtypes), then it is returned unchanged. - Otherwise if the input is an instance of
ByteBuffer, then anImageInputStreambacked 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,InputStreamorReadableByteChannel, then anImageInputStreambacked by aByteBufferis 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.
- If the storage object is already an instance of
ImageInputStream:- If the above
DataInputcan be created and casted toImageInputStream, returns it. - Otherwise this method returns
null.
- If the above
InputStream:- If the storage object is already an instance of
InputStream, then it is returned unchanged. - Otherwise if the above
ImageInputStreamcan be created, returns a wrapper around that stream. - Otherwise this method returns
null.
- If the storage object is already an instance of
Reader:- If the storage object is already an instance of
Reader, then it is returned unchanged. - Otherwise if the above
InputStreamcan be created, returns anInputStreamReaderusing the encoding specified byOptionKey.ENCODINGif any, or using the system default encoding otherwise. - Otherwise this method returns
null.
- If the storage object is already an instance of
Connection:- If the storage object is already an instance of
Connection, then it is returned unchanged. - Otherwise if the storage is an instance of
DataSource, then a connection is obtained when first needed and returned. - Otherwise this method returns
null.
- If the storage object is already an instance of
- 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 sameStorageConnectorinstance will try to return the same instance on a best effort basis. Consequently, implementations ofDataStoreProvider.probeContent(StorageConnector)methods shall not close the stream or database connection returned by this method. In addition, thoseprobeContent(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, seeDataStoreProvider.probeContent(StorageConnector, Class, Prober).- Type Parameters:
S- the compile-time type of thetypeargument (the source or storage type).- Parameters:
type- the desired type as one ofByteBuffer,DataInput,Connectionclass or other types supported byStorageConnectorsubclasses.- Returns:
- the storage as a view of the given type, or
nullif 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. - Throws:
IllegalArgumentException- if the giventypeargument is not one of the supported types listed in this javadoc or in subclass javadoc.IllegalStateException- if thisStorageConnectorhas been closed.DataStoreException- if an error occurred while opening a stream or database connection.- See Also:
-
reset
Resets the given view. If the view is an instance ofInputStream,ReadableByteChannelor other objects that may be affected by views operations, this method will reset the storage position. The view must have been previously marked byInputStream.mark(int)or equivalent method.This method is not a substitute for the requirement that users leave the
getStorageAs(Class)return value in the same state as they found it. This method is only for handling the cases where using a view has an indirect impact on another view.Rational:DataStoreProvider.probeContent(StorageConnector)contract requires that implementers reset the input stream themselves. However ifChannelDataInputorInputStreamReaderhas been used, then the user performed a call toChannelData.reset()(for instance), which did not reset the underlying input stream. So we need to perform the missingInputStream.reset()here, then synchronize theChannelDataInputposition accordingly.- Parameters:
c- container of the view to reset, ornullif none.- Returns:
trueif the given view, after reset, is valid. Note thatStorageConnector.Coupled.viewmay be null and valid.- Throws:
DataStoreException
-
reset
Resets the rootstorageobject.- Throws:
DataStoreException- if the storage cannot be reset.
-
createChannelDataInput
private ChannelDataInput createChannelDataInput(boolean asImageInputStream) throws IOException, DataStoreException Creates a view for the input as aChannelDataInputif possible. This is also a starting point forcreateDataInput()andcreateByteBuffer(). This method is one of theOPENERSmethods and should be invoked at most once perStorageConnectorinstance.- Parameters:
asImageInputStream- whether theChannelDataInputneeds to beChannelImageInputStreamsubclass.- Throws:
IOException- if an error occurred while opening a channel for the input.DataStoreException- See Also:
-
createDataInput
Creates a view for the input as aDataInputif possible. This method performs the choice documented in thegetStorageAs(Class)method for theDataInputcase. Opening the data input may imply creating aByteBuffer, in which case the buffer will be stored under theByteBuffer.classkey together with theDataInput.classcase.This method is one of the
OPENERSmethods and should be invoked at most once perStorageConnectorinstance.- Throws:
IOException- if an error occurred while opening a stream for the input.DataStoreException- See Also:
-
getChannelBuffer
Returns or allocate a buffer for use with theChannelDataInputorChannelDataOutput. If the user did not specified a buffer, this method may allocate a direct buffer for better leveraging ofChannelDataInput, which tries hard to transfer data in the most direct way between buffers and arrays. By contrast creating a heap buffer may imply the use of a temporary direct buffer cached by the JDK itself (in JDK internal implementation).- Parameters:
factory- the factory which will be used for creating the readable or writable channel.- Returns:
- the byte buffer to use with
ChannelDataInputorChannelDataOutput.
-
createByteBuffer
Creates aByteBufferfrom theChannelDataInputif possible, or from theImageInputStreamotherwise. The buffer will be initialized with an arbitrary amount of bytes read from the input. If this amount is not sufficient, it can be increased by a call toprefetch().This method is one of the
OPENERSmethods and should be invoked at most once perStorageConnectorinstance.- Throws:
IOException- if an error occurred while opening a stream for the input.DataStoreException
-
prefetch
Transfers more bytes from theDataInputto theByteBuffer, if possible. This method returnstrueon success, orfalseif input is not a readable channel or stream, we have reached the end of stream, or the buffer is full.This method is invoked when the amount of bytes in the buffer appears to be insufficient for
DataStoreProvider.probeContent(StorageConnector)purpose.- Returns:
trueon success.- Throws:
DataStoreException- if an error occurred while reading more bytes.
-
createImageInputStream
Creates anImageInputStreamfrom theDataInputif possible. This method simply castsDataInputif such cast is allowed. SincecreateDataInput()instantiatesChannelImageInputStream, this cast is usually possible.This method is one of the
OPENERSmethods and should be invoked at most once perStorageConnectorinstance.- Throws:
DataStoreException
-
createInputStream
Creates an input stream fromReadableByteChannelif possible, or fromImageInputStreamotherwise.This method is one of the
OPENERSmethods and should be invoked at most once perStorageConnectorinstance.- Throws:
IOExceptionDataStoreException- See Also:
-
createReader
Creates a character reader if possible.This method is one of the
OPENERSmethods and should be invoked at most once perStorageConnectorinstance.- Throws:
IOExceptionDataStoreException
-
createConnection
Creates a database connection if possible.This method is one of the
OPENERSmethods and should be invoked at most once perStorageConnectorinstance.- Throws:
SQLException
-
createString
Returns the storage as a path if possible, ornullotherwise.This method is one of the
OPENERSmethods and should be invoked at most once perStorageConnectorinstance. -
addView
Adds the given view in the cache, without dependencies.- Type Parameters:
S- the compile-time type of thetypeargument.- Parameters:
type- the view type.view- the view, ornullif none.
-
createChannelDataOutput
Creates a view for the storage as aChannelDataOutputif possible. This code is a partial copy ofcreateDataInput()adapted for output.- Throws:
IOException- if an error occurred while opening a channel for the output.DataStoreException- See Also:
-
createDataOutput
Creates a view for the output as aDataOutputif possible. This code is a copy ofcreateDataInput()adapted for output.- Throws:
IOException- if an error occurred while opening a stream for the output.DataStoreException- See Also:
-
createOutputStream
Creates an output stream fromWritableByteChannelif possible, or fromImageOutputStreamotherwise. This code is a partial copy ofcreateInputStream()adapted for output.- Throws:
IOExceptionDataStoreException- See Also:
-
addView
Adds the given view in the cache together with information about its dependency. For example,InputStreamReaderis a wrapper for aInputStream: read operations from the latter may change position of the former, and closing the latter also close the former.- Type Parameters:
S- the compile-time type of thetypeargument.- Parameters:
type- the view type.view- the view, ornullif none.source- the type of input thatviewis wrapping, ornullforstorage.cascade- bitwise combination ofCASCADE_ON_CLOSE,CASCADE_ON_RESETorCLEAR_ON_RESET.
-
getView
Returns the view for the given type from the cache. This method does not reset the view.- Parameters:
type- the view type, ornullfor thestoragecontainer.- Returns:
- information associated to the given type. May be
nullif the view has never been requested before.StorageConnector.Coupled.viewmay benullif the view has been requested and we determined that none can be created.
-
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 invokinggetStorageAs(Class)followed bycloseAllExcept(Object)except that the latter method is always invoked (in a way similar to "try with resource") and that this method never returnsnull.- Type Parameters:
S- the compile-time type of thetypeargument (the source or storage type).- Parameters:
type- the desired type as one of the types documented ingetStorageAs(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 giventypeargument is not one of the supported types.IllegalStateException- if thisStorageConnectorhas been closed.DataStoreException- if an error occurred while opening a stream or database connection.- Since:
- 1.2
- See Also:
-
closeAllExcept
Closes all streams and connections created by thisStorageConnectorexcept the given view. This method closes all objects created by thegetStorageAs(Class)method except the givenview. Ifviewisnull, then this method closes everything including the storage if it is closeable.This method is invoked when a suitable
DataStorehas been found - in which case the view used by the data store is given in argument to this method - or when no suitableDataStorehas been found - in which case theviewargument is null.This
StorageConnectorinstance shall not be used anymore after invocation of this method.- Parameters:
view- the view to leave open, ornullif none.- Throws:
DataStoreException- if an error occurred while closing the stream or database connection.- See Also:
-
unwrap
Returns the cause of given exception if it exists, or the exception itself otherwise. This method is invoked in thecatchblock of atryblock invokingImageIO.createImageInputStream(Object)orImageIO.createImageOutputStream(Object).Rational
As of Java 18, above-cited methods systematically catch allIOExceptions and wrap them in anIIOExceptionwith "Cannot create cache file!" error message. This is conform to Image I/O specification but misleading if the stream provider throws anIOExceptionfor another reason. Even when the failure is really caused by a problem with cache file, we want to propagate the original exception to user because its message may tell that there is no space left on device or no write permission.- See Also:
-
toString
Returns a string representation of thisStorageConnectorfor debugging purpose. This string representation is for diagnostic and may change in any future version.
-