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 ef25f4058f3c6d872847aeab3d0d0f5f657d96e1
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Fri Oct 29 15:58:26 2021 +0200

    Add the possibility to listen to read or write operations.
---
 .../sis/internal/geotiff/SchemaModifier.java       |  4 +-
 .../sis/internal/sql/feature/SchemaModifier.java   |  4 +-
 .../sis/internal/storage/io/ChannelFactory.java    | 39 ++++++++++++---
 .../sis/internal/storage/io/InternalOptionKey.java | 56 ++++++++++++++++++++++
 .../sis/internal/storage/io/package-info.java      |  2 +-
 .../org/apache/sis/storage/StorageConnector.java   |  9 ++--
 6 files changed, 100 insertions(+), 14 deletions(-)

diff --git 
a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/SchemaModifier.java
 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/SchemaModifier.java
index 781defc..11e1650 100644
--- 
a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/SchemaModifier.java
+++ 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/SchemaModifier.java
@@ -21,6 +21,7 @@ import org.apache.sis.coverage.SampleDimension;
 import org.apache.sis.measure.NumberRange;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.setup.OptionKey;
+import org.apache.sis.internal.storage.io.InternalOptionKey;
 import org.apache.sis.storage.DataStoreException;
 import org.opengis.metadata.Metadata;
 import org.opengis.util.GenericName;
@@ -123,8 +124,7 @@ public interface SchemaModifier {
      * @todo if we move this key in public API in the future, then it would be 
a
      *       value in existing {@link org.apache.sis.storage.DataOptionKey} 
class.
      */
-    OptionKey<SchemaModifier> OPTION = new 
OptionKey<SchemaModifier>("SCHEMA_MODIFIER", SchemaModifier.class) {
-    };
+    OptionKey<SchemaModifier> OPTION = new 
InternalOptionKey<SchemaModifier>("SCHEMA_MODIFIER", SchemaModifier.class);
 
     /**
      * The default instance which performs no modification.
diff --git 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SchemaModifier.java
 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SchemaModifier.java
index 8a960ba..14c6917 100644
--- 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SchemaModifier.java
+++ 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SchemaModifier.java
@@ -18,6 +18,7 @@ package org.apache.sis.internal.sql.feature;
 
 import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.internal.storage.io.InternalOptionKey;
 import org.apache.sis.setup.OptionKey;
 
 // Branch-dependent imports
@@ -73,6 +74,5 @@ public interface SchemaModifier {
      * @todo if we move this key in public API in the future, then it would be 
a
      *       value in existing {@link org.apache.sis.storage.DataOptionKey} 
class.
      */
-    OptionKey<SchemaModifier> OPTION = new 
OptionKey<SchemaModifier>("SCHEMA_MODIFIER", SchemaModifier.class) {
-    };
+    OptionKey<SchemaModifier> OPTION = new 
InternalOptionKey<SchemaModifier>("SCHEMA_MODIFIER", SchemaModifier.class);
 }
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java
index 3bab9a5..9755cfb 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.Arrays;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
+import java.util.function.UnaryOperator;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -56,7 +57,7 @@ import org.apache.sis.storage.event.StoreListeners;
 /**
  * Opens a readable channel for a given input object (URL, input stream, 
<i>etc</i>).
  * The {@link #prepare prepare(…)} method analyzes the given input {@link 
Object} and tries to return a factory instance
- * capable to open at least one {@link ReadableByteChannel} for that input. 
For some kinds of input like {@link Path} or
+ * capable to open at least a {@link ReadableByteChannel} for that input. For 
some kinds of input like {@link Path} or
  * {@link URL}, the {@link #readable readable(…)} method can be invoked an 
arbitrary amount of times for creating as many
  * channels as needed. But for other kinds of input like {@link InputStream}, 
only one channel can be returned.
  * In such case, only the first {@link #readable readable(…)} method 
invocation will succeed and all subsequent ones
@@ -68,13 +69,13 @@ import org.apache.sis.storage.event.StoreListeners;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.0
+ * @version 1.2
  * @since   0.8
  * @module
  */
 public abstract class ChannelFactory {
     /**
-     * Options to be rejected by {@link #prepare(Object, String, boolean, 
OpenOption...)} for safety reasons.
+     * Options to be rejected by {@link #prepare(Object, boolean, String, 
OpenOption[])} for safety reasons.
      */
     private static final Set<StandardOpenOption> ILLEGAL_OPTIONS = EnumSet.of(
             StandardOpenOption.APPEND, StandardOpenOption.TRUNCATE_EXISTING, 
StandardOpenOption.DELETE_ON_CLOSE);
@@ -82,7 +83,7 @@ public abstract class ChannelFactory {
     /**
      * For subclass constructors.
      */
-    ChannelFactory() {
+    protected ChannelFactory() {
     }
 
     /**
@@ -117,16 +118,42 @@ public abstract class ChannelFactory {
      * honor the options or not.</p>
      *
      * @param  storage         the stream or the file to open, or {@code null}.
+     * @param  allowWriteOnly  whether to allow wrapping {@link 
WritableByteChannel} and {@link OutputStream}.
      * @param  encoding        if the input is an encoded URL, the character 
encoding (normally {@code "UTF-8"}).
      *                         If the URL is not encoded, then {@code null}. 
This argument is ignored if the given
      *                         input does not need to be converted from URL to 
{@code File}.
+     * @param  options         the options to use for creating a new byte 
channel. Can be null or empty for read-only.
+     * @param  wrapper         a function for creating wrapper around the 
factory, or {@code null} if none.
+     *                         It can be used for installing listener or for 
transforming data on the fly.
+     * @return the channel factory for the given input, or {@code null} if the 
given input is of unknown type.
+     * @throws IOException if an error occurred while processing the given 
input.
+     */
+    public static ChannelFactory prepare(
+            final Object storage, final boolean allowWriteOnly,
+            final String encoding, final OpenOption[] options,
+            final UnaryOperator<ChannelFactory> wrapper) throws IOException
+    {
+        ChannelFactory factory = prepare(storage, allowWriteOnly, encoding, 
options);
+        if (factory != null && wrapper != null) {
+            factory = wrapper.apply(factory);
+        }
+        return factory;
+    }
+
+    /**
+     * Returns a byte channel factory without wrappers, or {@code null} if 
unsupported.
+     * This method performs the same work than {@linkplain #prepare(Object, 
boolean, String,
+     * OpenOption[], UnaryOperator, UnaryOperator) above method}, but without 
wrappers.
+     *
+     * @param  storage         the stream or the file to open, or {@code null}.
      * @param  allowWriteOnly  whether to allow wrapping {@link 
WritableByteChannel} and {@link OutputStream}.
+     * @param  encoding        if the input is an encoded URL, the character 
encoding (normally {@code "UTF-8"}).
      * @param  options         the options to use for creating a new byte 
channel. Can be null or empty for read-only.
      * @return the channel factory for the given input, or {@code null} if the 
given input is of unknown type.
      * @throws IOException if an error occurred while processing the given 
input.
      */
-    public static ChannelFactory prepare(Object storage, final String encoding,
-            final boolean allowWriteOnly, OpenOption... options) throws 
IOException
+    private static ChannelFactory prepare(Object storage, final boolean 
allowWriteOnly,
+            final String encoding, OpenOption[] options) throws IOException
     {
         /*
          * Unconditionally verify the options (unless 'allowWriteOnly' is 
true),
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/InternalOptionKey.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/InternalOptionKey.java
new file mode 100644
index 0000000..6789d21
--- /dev/null
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/InternalOptionKey.java
@@ -0,0 +1,56 @@
+/*
+ * 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.function.UnaryOperator;
+import org.apache.sis.setup.OptionKey;
+import org.apache.sis.storage.StorageConnector;
+
+
+/**
+ * {@link StorageConnector} options not part of public API.
+ * Some of those options may move to public API in the future if useful.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.2
+ *
+ * @param  <T>  the type of option values.
+ *
+ * @since 1.2
+ * @module
+ */
+public final class InternalOptionKey<T> extends OptionKey<T> {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 1786137598411493790L;
+
+    /**
+     * Wraps readable or writable channels on creation. Wrappers can be used 
for example
+     * in order to listen to read events or for transforming bytes on the fly.
+     */
+    @SuppressWarnings("unchecked")
+    public static final InternalOptionKey<UnaryOperator<ChannelFactory>> 
CHANNEL_FACTORY_WRAPPER =
+            (InternalOptionKey) new 
InternalOptionKey<>("READ_CHANNEL_WRAPPER", UnaryOperator.class);
+
+    /**
+     * Creates a new key of the given name.
+     */
+    public InternalOptionKey(final String name, final Class<T> type) {
+        super(name, type);
+    }
+}
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 ea669bd..e2932d1 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.1
+ * @version 1.2
  * @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 d22cd81..6e77e1f 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
@@ -56,6 +56,7 @@ import org.apache.sis.internal.storage.io.ChannelDataInput;
 import org.apache.sis.internal.storage.io.ChannelImageInputStream;
 import org.apache.sis.internal.storage.io.InputStreamAdapter;
 import org.apache.sis.internal.storage.io.RewindableLineReader;
+import org.apache.sis.internal.storage.io.InternalOptionKey;
 import org.apache.sis.internal.util.Strings;
 import org.apache.sis.io.InvalidSeekException;
 import org.apache.sis.setup.OptionKey;
@@ -86,7 +87,7 @@ import org.apache.sis.setup.OptionKey;
  * is serializable.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.1
+ * @version 1.2
  * @since   0.3
  * @module
  */
@@ -923,8 +924,10 @@ public class StorageConnector implements Serializable {
          * URL, URI, File, Path or other types that may be added in future 
Apache SIS versions.
          * If the given storage is already a ReadableByteChannel, then the 
factory will return it as-is.
          */
-        final ChannelFactory factory = ChannelFactory.prepare(storage,
-                getOption(OptionKey.URL_ENCODING), false, 
getOption(OptionKey.OPEN_OPTIONS));
+        final ChannelFactory factory = ChannelFactory.prepare(storage, false,
+                getOption(OptionKey.URL_ENCODING),
+                getOption(OptionKey.OPEN_OPTIONS),
+                getOption(InternalOptionKey.CHANNEL_FACTORY_WRAPPER));
         if (factory == null) {
             return null;
         }

Reply via email to