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 696dfafa870b352593dba3dd6e5449294e799cd5 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Wed Aug 17 18:02:41 2022 +0200 Allow `ChannelImageInputStream` to wrap an array of `byte[]` containing all data. --- .../sis/internal/storage/io/ChannelData.java | 25 ++++++- .../sis/internal/storage/io/ChannelDataInput.java | 15 ++++- .../storage/io/ChannelImageInputStream.java | 14 +++- .../sis/internal/storage/io/NullChannel.java | 77 ++++++++++++++++++++++ .../sis/internal/storage/io/package-info.java | 2 +- .../org/apache/sis/storage/StorageConnector.java | 11 +++- 6 files changed, 137 insertions(+), 7 deletions(-) diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelData.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelData.java index 19b2c50287..e45ca2fcdf 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelData.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelData.java @@ -32,7 +32,7 @@ import static org.apache.sis.util.ArgumentChecks.ensureBetween; * querying or modifying the stream position. This class does not define any read or write operations. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.3 * @since 0.3 * @module */ @@ -125,6 +125,21 @@ public abstract class ChannelData implements Markable { this.channelOffset = (channel instanceof SeekableByteChannel) ? ((SeekableByteChannel) channel).position() : 0; } + /** + * Creates a new instance for a buffer filled with the bytes to use. + * This constructor uses an independent, read-only view of the given buffer. + * No reference to the given buffer will be retained. + * + * @param filename a short identifier (typically a filename without path) used for formatting error message. + * @param data the buffer filled with all bytes to read. + */ + ChannelData(final String filename, final ByteBuffer data) { + this.filename = filename; + buffer = data.asReadOnlyBuffer(); + buffer.order(data.order()); + channelOffset = 0; + } + /** * Implementation of {@link ChannelDataInput#readBit()} provided here for performance reasons. * It is caller responsibility to ensure that the {@link #buffer} contains at least one byte. @@ -245,9 +260,10 @@ public abstract class ChannelData implements Markable { /** * Discards the initial portion of the stream prior to the indicated position. * Attempting to {@linkplain #seek(long) seek} to an offset within the flushed - * portion of the stream will result in an {@link IndexOutOfBoundsException}. + * portion of the stream may result in an {@link IndexOutOfBoundsException}. * - * <p>This method moves the data starting at the given position to the beginning of the {@link #buffer}, + * <p>If the {@link #buffer} is read-only, then this method does nothing. Otherwise + * this method moves the data starting at the given position to the beginning of the {@link #buffer}, * thus making more room for new data before the data at the given position is discarded.</p> * * @param position the length of the stream prefix that may be flushed. @@ -259,6 +275,9 @@ public abstract class ChannelData implements Markable { throw new IndexOutOfBoundsException(Errors.format(Errors.Keys.ValueOutOfRange_4, "position", bufferOffset, currentPosition, position)); } + if (buffer.isReadOnly()) { + return; + } final int n = (int) Math.max(position - bufferOffset, 0); final int p = buffer.position() - n; final int r = buffer.limit() - n; 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 335667359b..389716e584 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 @@ -60,7 +60,7 @@ import static org.apache.sis.util.ArgumentChecks.ensureBetween; * {@link javax.imageio} is needed. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.3 * @since 0.3 * @module */ @@ -106,6 +106,19 @@ public class ChannelDataInput extends ChannelData { } } + /** + * Creates a new instance for a buffer filled with the bytes to use. + * This constructor uses an independent, read-only view of the given buffer. + * No reference to the given buffer will be retained. + * + * @param filename a short identifier (typically a filename without path) used for formatting error message. + * @param data the buffer filled with all bytes to read. + */ + public ChannelDataInput(final String filename, final ByteBuffer data) { + super(filename, data); + channel = new NullChannel(); + } + /** * Returns the length of the stream (in bytes), or -1 if unknown. * The length is relative to the channel position at {@linkplain #ChannelDataInput construction time}. 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 9a8a3c0186..3b875bfe29 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 @@ -42,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 1.2 + * @version 1.3 * * @see javax.imageio.stream.FileImageInputStream * @see javax.imageio.ImageIO#createImageInputStream(Object) @@ -68,6 +68,18 @@ public class ChannelImageInputStream extends ChannelDataInput implements ImageIn super(filename, channel, buffer, filled); } + /** + * Creates a new instance for a buffer filled with the bytes to use. + * This constructor uses an independent, read-only view of the given buffer. + * No reference to the given buffer will be retained. + * + * @param filename a short identifier (typically a filename without path) used for formatting error message. + * @param data the buffer filled with all bytes to read. + */ + public ChannelImageInputStream(final String filename, final ByteBuffer data) { + super(filename, data); + } + /** * Creates a new input stream from the given {@code ChannelDataInput}. * This constructor is invoked when we need to change the implementation class diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/NullChannel.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/NullChannel.java new file mode 100644 index 0000000000..2486e11828 --- /dev/null +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/NullChannel.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.internal.storage.io; + +import java.util.Objects; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.ClosedChannelException; + + +/** + * A channel which read no values. This class behaves as if the channel already reached the end of file. + * + * @author Martin Desruisseaux (Geomatys) + * @version 1.3 + * @since 1.3 + * @module + */ +final class NullChannel implements ReadableByteChannel { + /** + * Whether this channel has been closed. + */ + private volatile boolean closed; + + /** + * Creates an initially open channel. + */ + NullChannel() { + } + + /** + * Pretends to read a sequence of bytes and indicates that the channel reached the end of file. + * Read-only buffers are accepted (this is required for {@link ChannelImageInputStream}). + * + * @param dst ignored except for non-null check. + * @return always -1. + * @throws ClosedChannelException if this channel has been closed. + */ + @Override + public int read(ByteBuffer dst) throws ClosedChannelException { + Objects.requireNonNull(dst); + if (closed) { + throw new ClosedChannelException(); + } + return -1; + } + + /** + * Returns whether this channel is still open. + */ + @Override + public boolean isOpen() { + return !closed; + } + + /** + * Closes this channel. If this channel is already closed, then this method does nothing. + */ + @Override + public void close() { + closed = true; + } +} diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/package-info.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/package-info.java index e2932d1265..de0e699a69 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/package-info.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/package-info.java @@ -24,7 +24,7 @@ * may change in incompatible ways in any future version without notice. * * @author Martin Desruisseaux (Geomatys) - * @version 1.2 + * @version 1.3 * @since 0.3 * @module */ diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java index 2f2fab45f3..5560158acd 100644 --- a/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java +++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java @@ -99,7 +99,7 @@ import org.apache.sis.setup.OptionKey; * * @author Martin Desruisseaux (Geomatys) * @author Alexis Manin (Geomatys) - * @version 1.2 + * @version 1.3 * @since 0.3 * @module */ @@ -711,6 +711,10 @@ public class StorageConnector implements Serializable { * (including the {@link ImageInputStream} and {@link javax.imageio.stream.ImageOutputStream} types), * then it is returned unchanged.</li> * + * <li>Otherwise if the input is an instance of {@link ByteBuffer}, then an {@link 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.</li> + * * <li>Otherwise if the input is an instance of {@link java.nio.file.Path}, {@link java.io.File}, * {@link java.net.URI}, {@link java.net.URL}, {@link CharSequence}, {@link InputStream} or * {@link java.nio.channels.ReadableByteChannel}, then an {@link ImageInputStream} backed by a @@ -953,6 +957,11 @@ public class StorageConnector implements Serializable { if (storage instanceof InputStream) { ((InputStream) storage).mark(DEFAULT_BUFFER_SIZE); } + if (storage instanceof ByteBuffer) { + final ChannelDataInput asDataInput = new ChannelImageInputStream(getStorageName(), (ByteBuffer) storage); + addView(ChannelDataInput.class, asDataInput); + return asDataInput; + } /* * Following method call recognizes ReadableByteChannel, InputStream (with optimization for FileInputStream), * URL, URI, File, Path or other types that may be added in future Apache SIS versions.