This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit b025d4b61f453344f463688695ecb19a2d9079e8 Author: Martin Desruisseaux <[email protected]> AuthorDate: Wed Apr 6 20:07:33 2022 +0200 Refactor existing code in preparation for addition of `WritableGridCoverageResource` implementations. --- .../java/org/apache/sis/image/ImageCombiner.java | 6 ++-- .../apache/sis/internal/storage/PRJDataStore.java | 4 ++- .../apache/sis/internal/storage/URIDataStore.java | 5 ++- .../apache/sis/internal/storage/ascii/Store.java | 19 +++++++++-- .../sis/internal/storage/io/ChannelDataInput.java | 13 ++++++++ .../storage/io/ChannelImageInputStream.java | 17 +--------- .../sis/storage/ReadOnlyStorageException.java | 2 +- ...on.java => ResourceAlreadyExistsException.java} | 37 +++++++--------------- .../sis/storage/WritableGridCoverageResource.java | 34 ++++++++++++++------ 9 files changed, 76 insertions(+), 61 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/ImageCombiner.java b/core/sis-feature/src/main/java/org/apache/sis/image/ImageCombiner.java index 533d3acb0f..1ee69e78b9 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/ImageCombiner.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/ImageCombiner.java @@ -36,7 +36,7 @@ import org.apache.sis.measure.Units; /** * Combines an arbitrary amount of images into a single one. - * The combined mages may use different coordinate systems if a resampling operation is specified. + * The combined images may use different coordinate systems if a resampling operation is specified. * The workflow is as below: * * <ol> @@ -70,8 +70,8 @@ public class ImageCombiner implements Consumer<RenderedImage> { /** * Creates an image combiner which will write in the given image. That image is not cleared; - * pixels that are not overwritten by another image given to {@code ImageCombiner} methods - * will be left unchanged. + * pixels that are not overwritten by calls to the {@code accept(…)} or {@code resample(…)} + * methods will be left unchanged. * * @param destination the image where to combine images. */ diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java index 4c04ec072a..82f8f6556e 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java @@ -98,8 +98,10 @@ public abstract class PRJDataStore extends URIDataStore { protected CoordinateReferenceSystem crs; /** - * Creates a new data store. The following options are recognized: + * Creates a new data store. This constructor does not open the file, + * so subclass constructors can decide whether to open in read-only or read/write mode. * + * <p>The following options are recognized:</p> * <ul> * <li>{@link DataOptionKey#DEFAULT_CRS}: default CRS if no auxiliary {@code "*.prj"} file is found.</li> * <li>{@link DataOptionKey#ENCODING}: encoding of the {@code "*.prj"} file. Default is the JVM default.</li> diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java index 1f6a701159..8aef150aaa 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/URIDataStore.java @@ -77,7 +77,10 @@ public abstract class URIDataStore extends DataStore implements StoreResource, R private final boolean locationIsPath; /** - * Creates a new data store. + * Creates a new data store. This constructor does not open the file, + * so subclass constructors can decide whether to open in read-only or read/write mode. + * It is caller's responsibility to ensure that the {@link java.nio.file.OpenOption} + * are compatible with whether this data store is read-only or read/write. * * @param provider the factory that created this {@code URIDataStore} instance, or {@code null} if unspecified. * @param connector information about the storage (URL, stream, reader instance, <i>etc</i>). diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ascii/Store.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ascii/Store.java index 411490d10b..0c485df201 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ascii/Store.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ascii/Store.java @@ -75,7 +75,7 @@ import org.apache.sis.util.resources.Errors; * @since 1.2 * @module */ -final class Store extends PRJDataStore implements GridCoverageResource { +class Store extends PRJDataStore implements GridCoverageResource { /** * Keys of elements expected in the header. Must be in upper-case letters. */ @@ -151,6 +151,9 @@ final class Store extends PRJDataStore implements GridCoverageResource { /** * Creates a new ASCII Grid store from the given file, URL or stream. + * This constructor opens the file, possibly creating it if the {@code connector} contains an + * option like {@link java.nio.file.StandardOpenOption#CREATE}, but does not try to read it now. + * It is possible to open an empty file and have {@link WritableStore} to write in it later. * * @param provider the factory that created this {@code DataStore} instance, or {@code null} if unspecified. * @param connector information about the storage (URL, stream, <i>etc</i>). @@ -449,10 +452,20 @@ cellsize: if (value != null) { return coverage; } + /** + * Replaces all data by the given coverage. + * This is used for write operations only. + */ + final void setCoverage(final GridCoverage replacement) { + gridGeometry = replacement.getGridGeometry(); + coverage = replacement; + metadata = null; + } + /** * Returns the input if it has not been closed. */ - private CharactersView input() throws DataStoreException { + final CharactersView input() throws DataStoreException { final CharactersView in = input; if (in == null) { throw new DataStoreClosedException(getLocale(), StoreProvider.NAME, StandardOpenOption.READ); @@ -482,7 +495,7 @@ cellsize: if (value != null) { * Closes this data store after an unrecoverable error occurred. * The caller is expected to throw the given exception after this method call. */ - private void closeOnError(final Throwable e) { + final void closeOnError(final Throwable e) { try { close(); } catch (Throwable s) { diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataInput.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataInput.java index 1a3d63bba1..19d918af63 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataInput.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataInput.java @@ -106,6 +106,19 @@ public class ChannelDataInput extends ChannelData { } } + /** + * Returns the length of the stream (in bytes), or -1 if unknown. + * + * @return the length of the stream (in bytes), or -1 if unknown. + * @throws IOException if an error occurred while fetching the stream length. + */ + public final long length() throws IOException { // Method signature must match ImageInputStream.length(). + if (channel instanceof SeekableByteChannel) { + return ((SeekableByteChannel) channel).size(); + } + return -1; + } + /** * Tries to read more bytes from the channel without changing the buffer position. * This method returns a negative number if the buffer is already full or if the channel reached the diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelImageInputStream.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelImageInputStream.java index fa63a556dd..679128b80e 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelImageInputStream.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelImageInputStream.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.ReadableByteChannel; -import java.nio.channels.SeekableByteChannel; import javax.imageio.stream.IIOByteBuffer; import javax.imageio.stream.ImageInputStream; @@ -43,7 +42,7 @@ import javax.imageio.stream.ImageInputStream; * <p>This class is used when compatibility with {@link javax.imageio.ImageReader} is needed.</p> * * @author Martin Desruisseaux (Geomatys) - * @version 0.5 + * @version 1.2 * * @see javax.imageio.stream.FileImageInputStream * @see javax.imageio.ImageIO#createImageInputStream(Object) @@ -103,20 +102,6 @@ public class ChannelImageInputStream extends ChannelDataInput implements ImageIn return buffer.order(); } - /** - * Returns the length of the stream (in bytes), or -1 if unknown. - * - * @return the length of the stream (in bytes), or -1 if unknown. - * @throws IOException if an error occurred while fetching the stream length. - */ - @Override - public final long length() throws IOException { - if (channel instanceof SeekableByteChannel) { - return ((SeekableByteChannel) channel).size(); - } - return -1; - } - /** * Reads a byte from the stream and returns a {@code true} if it is nonzero, {@code false} otherwise. * The implementation is as below: diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/ReadOnlyStorageException.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/ReadOnlyStorageException.java index e6b1c38c1c..f05f9c3e80 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/storage/ReadOnlyStorageException.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/ReadOnlyStorageException.java @@ -18,7 +18,7 @@ package org.apache.sis.storage; /** - * Thrown when a {@code DataStore} can not perform a write operations. + * Thrown when a {@code DataStore} can not perform a write operation. * If a data store does not support any write operation, then it should not implement * {@link WritableAggregate} or {@link WritableFeatureSet} interface. * But in some situations, a data store may implement a {@code Writable*} interface diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/ReadOnlyStorageException.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/ResourceAlreadyExistsException.java similarity index 54% copy from storage/sis-storage/src/main/java/org/apache/sis/storage/ReadOnlyStorageException.java copy to storage/sis-storage/src/main/java/org/apache/sis/storage/ResourceAlreadyExistsException.java index e6b1c38c1c..4830f66d53 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/storage/ReadOnlyStorageException.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/ResourceAlreadyExistsException.java @@ -18,31 +18,25 @@ package org.apache.sis.storage; /** - * Thrown when a {@code DataStore} can not perform a write operations. - * If a data store does not support any write operation, then it should not implement - * {@link WritableAggregate} or {@link WritableFeatureSet} interface. - * But in some situations, a data store may implement a {@code Writable*} interface - * and nevertheless be unable to perform a write operation, for example because the - * underlying {@link java.nio.channels.Channel} is read-only or part of the file is - * locked by another process. + * Thrown when a write operation can not be performed because it would cause the replacement of an existing resource. + * Replacements can be performed only if an option such as {@link WritableGridCoverageResource.CommonOption#REPLACE} + * has been specified. * - * @author Johann Sorel (Geomatys) - * @version 0.8 - * @since 0.8 + * @author Martin Desruisseaux (Geomatys) + * @version 1.2 + * @since 1.2 * @module - * - * @see ForwardOnlyStorageException */ -public class ReadOnlyStorageException extends DataStoreException { +public class ResourceAlreadyExistsException extends DataStoreException { /** * For cross-version compatibility. */ - private static final long serialVersionUID = 5710116172772560023L; + private static final long serialVersionUID = 3854120553618596031L; /** * Creates an exception with no cause and no details message. */ - public ReadOnlyStorageException() { + public ResourceAlreadyExistsException() { } /** @@ -50,26 +44,17 @@ public class ReadOnlyStorageException extends DataStoreException { * * @param message the detail message. */ - public ReadOnlyStorageException(final String message) { + public ResourceAlreadyExistsException(String message) { super(message); } - /** - * Creates an exception with the specified cause and no details message. - * - * @param cause the cause for this exception. - */ - public ReadOnlyStorageException(final Throwable cause) { - super(cause); - } - /** * Creates an exception with the specified details message and cause. * * @param message the detail message. * @param cause the cause for this exception. */ - public ReadOnlyStorageException(final String message, final Throwable cause) { + public ResourceAlreadyExistsException(String message, Throwable cause) { super(message, cause); } } diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/WritableGridCoverageResource.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/WritableGridCoverageResource.java index 50248ad92c..254884b6e3 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/storage/WritableGridCoverageResource.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/WritableGridCoverageResource.java @@ -35,7 +35,7 @@ public interface WritableGridCoverageResource extends GridCoverageResource { * Configuration of the process of writing a coverage in a data store. * By default, the {@linkplain #write write operation} is conservative: no operation is executed * if it would result in data lost. {@code Option} allows to modify this behavior for example by - * allowing the {@linkplain CommonOption#TRUNCATE replacement} of previous data. + * allowing the {@link CommonOption#REPLACE replacement} of previous data. * Options can also configure other aspects like compression, version or encryption. * * <p>Some options may be {@link DataStore}-specific. @@ -71,21 +71,29 @@ public interface WritableGridCoverageResource extends GridCoverageResource { * <li>If there are no existing coverages in the {@link GridCoverageResource}, * then the new coverage will be inserted as if this option was not provided.</li> * </ul> + * + * This option is mutually exclusive with {@link #UPDATE}. */ - TRUNCATE, + REPLACE, /** * Updates or appends existing coverage with new data. - * If a coverage already exists when the {@linkplain #write write operation} is executed with this option, then: + * If this option is specified, then there is a choice: * * <ul> - * <li>Areas of the provided {@link GridCoverage} that are within the existing {@link GridGeometry} - * will overwrite the existing data.</li> - * <li>Areas outside the existing {@link GridGeometry} will result in expanding the grid geometry - * with the new data.</li> + * <li>If a coverage already exists in the {@link GridCoverageResource}, then: + * <ul> + * <li>Areas of the provided {@link GridCoverage} that are within the existing {@link GridGeometry} + * will overwrite the existing data.</li> + * <li>Areas outside the existing {@link GridGeometry} will result in expanding the grid geometry + * with the new data.</li> + * </ul> + * </li> + * <li>If there are no existing coverages in the {@link GridCoverageResource}, + * then the new coverage is inserted as if this option was not provided.</li> * </ul> * - * If there are no previous coverages, then the new coverage is inserted as if this option was not provided. + * This option is mutually exclusive with {@link #REPLACE}. */ UPDATE } @@ -94,13 +102,19 @@ public interface WritableGridCoverageResource extends GridCoverageResource { * Writes a new coverage in the data store for this resource. If a coverage already exists for this resource, * then the behavior of this method is determined by the given options. If no option is specified, the default * behavior is to fail if writing a coverage would cause an existing coverage to be overwritten. - * This behavior can be modified by requesting the {@linkplain CommonOption#TRUNCATE replacement} + * This behavior can be modified by requesting the {@link CommonOption#REPLACE replacement} * or {@linkplain CommonOption#UPDATE update} of existing coverages. * * @param coverage new data to write in the data store for this resource. * @param options configuration of the write operation. May be {@link DataStore}-specific options * (e.g. for compression, encryption, <i>etc</i>). - * @throws DataStoreException if an error occurred while writing data in the underlying data store. + * @throws IllegalArgumentException if mutually exclusive options are specified. + * @throws ReadOnlyStorageException if the resource is (possibly temporarily) read-only. + * @throws ResourceAlreadyExistsException if a coverage already exists in this resource + * and no {@code REPLACE} or {@code UPDATE} option have been specified. + * @throws IncompatibleResourceException if the given resource can not be written, + * for example because its grid geometry is unsupported by this resource. + * @throws DataStoreException if another error occurred while writing data in the underlying data store. */ void write(GridCoverage coverage, Option... options) throws DataStoreException; }
