sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1511393 - in /sis/branches/JDK7/storage/sis-storage/src: main/java/org/apache/sis/storage/ test/java/org/apache/sis/storage/
Date Wed, 07 Aug 2013 16:54:59 GMT
Author: desruisseaux
Date: Wed Aug  7 16:54:59 2013
New Revision: 1511393

URL: http://svn.apache.org/r1511393
Log:
StorageConnector needs to be also able to provide InputStream and Reader objects.
This support complicates a bit the task of closing the stream, in part because
AutoCloseable is not guaranteed to be idempotent (ImageInputStream in not).

Added:
    sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
  (with props)
Modified:
    sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
    sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
    sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
    sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java

Modified: sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java?rev=1511393&r1=1511392&r2=1511393&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
[UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreRegistry.java
[UTF-8] Wed Aug  7 16:54:59 2013
@@ -73,7 +73,7 @@ final class DataStoreRegistry {
      *   <li>A {@link java.nio.file.Path} or a {@link java.io.File} for a file or a
directory.</li>
      *   <li>A {@link java.net.URI} or a {@link java.net.URL} to a distant resource.</li>
      *   <li>A {@link java.lang.CharSequence} interpreted as a filename or a URL.</li>
-     *   <li>A {@link java.nio.channels.Channel} or a {@link java.io.DataInput}.</li>
+     *   <li>A {@link java.nio.channels.Channel}, {@link java.io.DataInput}, {@link
java.io.InputStream} or {@link java.io.Reader}.</li>
      *   <li>A {@link javax.sql.DataSource} or a {@link java.sql.Connection} to a JDBC
database.</li>
      *   <li>Any other {@code DataStore}-specific object, for example {@link ucar.nc2.NetcdfFile}.</li>
      *   <li>An existing {@link StorageConnector} instance.</li>

Modified: sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java?rev=1511393&r1=1511392&r2=1511393&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
[UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStores.java
[UTF-8] Wed Aug  7 16:54:59 2013
@@ -69,7 +69,7 @@ public final class DataStores extends St
      *   <li>A {@link java.nio.file.Path} or a {@link java.io.File} for a file or a
directory.</li>
      *   <li>A {@link java.net.URI} or a {@link java.net.URL} to a distant resource.</li>
      *   <li>A {@link java.lang.CharSequence} interpreted as a filename or a URL.</li>
-     *   <li>A {@link java.nio.channels.Channel} or a {@link java.io.DataInput}.</li>
+     *   <li>A {@link java.nio.channels.Channel}, {@link java.io.DataInput}, {@link
java.io.InputStream} or {@link java.io.Reader}.</li>
      *   <li>A {@link javax.sql.DataSource} or a {@link java.sql.Connection} to a JDBC
database.</li>
      *   <li>Any other {@code DataStore}-specific object, for example {@link ucar.nc2.NetcdfFile}.</li>
      *   <li>An existing {@link StorageConnector} instance.</li>

Added: sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java?rev=1511393&view=auto
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
(added)
+++ sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
[UTF-8] Wed Aug  7 16:54:59 2013
@@ -0,0 +1,124 @@
+/*
+ * 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.storage;
+
+import java.io.InputStream;
+import java.io.IOException;
+import javax.imageio.stream.ImageInputStream;
+
+
+/**
+ * Wraps a {@link ImageInputStream} as a standard {@link InputStream}.
+ *
+ * @author  Martin Desruisseaux (IRD)
+ * @since   0.4 (derived from geotk-1.2)
+ * @version 0.4
+ * @module
+ */
+final class InputStreamAdapter extends InputStream {
+    /**
+     * The data input stream.
+     */
+    final ImageInputStream input;
+
+    /**
+     * Constructs a new input stream.
+     */
+    InputStreamAdapter(final ImageInputStream input) {
+        this.input = input;
+    }
+
+    /**
+     * Reads the next byte of data from the input stream.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public int read() throws IOException {
+        return input.read();
+    }
+
+    /**
+     * Reads some number of bytes from the input stream.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public int read(final byte[] b) throws IOException {
+        return input.read(b);
+    }
+
+    /**
+     * Reads up to {@code len} bytes of data from the input stream.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public int read(final byte[] b, final int off, final int len) throws IOException {
+        return input.read(b, off, len);
+    }
+
+    /**
+     * Skips over and discards {@code n} bytes of data from this input stream.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public long skip(final long n) throws IOException {
+        return input.skipBytes(n);
+    }
+
+    /**
+     * Returns always {@code true}, since marks support is mandatory in image input stream.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public boolean markSupported() {
+        return true;
+    }
+
+    /**
+     * Marks the current position in this input stream.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public void mark(final int readlimit) {
+        input.mark();
+    }
+
+    /**
+     * Repositions this stream to the position at the time the {@code mark} method was last
called.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public void reset() throws IOException {
+        input.reset();
+    }
+
+    /**
+     * Closes this input stream.
+     *
+     * @throws IOException if an I/O error occurs.
+     */
+    @Override
+    public void close() throws IOException {
+        input.close();
+    }
+}

Propchange: sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java?rev=1511393&r1=1511392&r2=1511393&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
[UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
[UTF-8] Wed Aug  7 16:54:59 2013
@@ -17,13 +17,20 @@
 package org.apache.sis.storage;
 
 import java.util.Map;
+import java.util.Queue;
+import java.util.Iterator;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.IdentityHashMap;
 import java.util.ConcurrentModificationException;
+import java.io.Reader;
 import java.io.DataInput;
+import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.Serializable;
 import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
 import java.nio.channels.ReadableByteChannel;
 import javax.imageio.ImageIO;
 import javax.imageio.stream.ImageInputStream;
@@ -47,7 +54,7 @@ import org.apache.sis.setup.OptionKey;
  *   <li>A {@link java.nio.file.Path} or a {@link java.io.File} for a file or a directory.</li>
  *   <li>A {@link java.net.URI} or a {@link java.net.URL} to a distant resource.</li>
  *   <li>A {@link CharSequence} interpreted as a filename or a URL.</li>
- *   <li>A {@link java.nio.channels.Channel} or a {@link DataInput}.</li>
+ *   <li>A {@link java.nio.channels.Channel}, {@link DataInput}, {@link InputStream}
or {@link Reader}.</li>
  *   <li>A {@link DataSource} or a {@link Connection} to a JDBC database.</li>
  *   <li>Any other {@code DataStore}-specific object, for example {@link ucar.nc2.NetcdfFile}.</li>
  * </ul>
@@ -84,7 +91,7 @@ public class StorageConnector implements
      * The minimal size of the {@link ByteBuffer} to be created. This size is used only
      * for temporary buffers that are unlikely to be used for the actual reading process.
      */
-    private static final int MINIMAL_BUFFER_SIZE = 256;
+    static final int MINIMAL_BUFFER_SIZE = 256;
 
     /**
      * The input/output object given at construction time.
@@ -121,6 +128,12 @@ public class StorageConnector implements
      *   <li>{@link ImageInputStream}:
      *       Same as {@code DataInput} if it can be casted, or {@code null} otherwise.</li>
      *
+     *   <li>{@link InputStream}:
+     *       If not explicitely provided, this is a wrapper around the above {@link ImageInputStream}.</li>
+     *
+     *   <li>{@link Reader}:
+     *       If not explicitely provided, this is a wrapper around the above {@link InputStream}.</li>
+     *
      *   <li>{@link Connection}:
      *       The storage object as a JDBC connection.</li>
      * </ul>
@@ -134,6 +147,17 @@ public class StorageConnector implements
     private transient Map<Class<?>, Object> views;
 
     /**
+     * Objects which will need to be closed by the {@link #closeAllExcept(Object)} method.
+     * For each (<var>key</var>, <var>value</var>) entry, if the
object to close (the key)
+     * is a wrapper around an other object (e.g. an {@link InputStreamReader} wrapping an
+     * {@link InputStream}), then the value is the other object.
+     *
+     * @see #addViewToClose(Object, Object)
+     * @see #closeAllExcept(Object)
+     */
+    private transient Map<Object, Object> viewsToClose;
+
+    /**
      * The options, created only when first needed.
      *
      * @see #getOption(OptionKey)
@@ -165,12 +189,13 @@ public class StorageConnector implements
     }
 
     /**
-     * Sets the option value for the given key. The default implementation recognizes the
given options:
+     * Sets the option value for the given key. The default implementation recognizes the
following options:
      *
      * <ul>
+     *   <li>{@link OptionKey#ENCODING}     for decoding characters in an input stream,
if needed.</li>
      *   <li>{@link OptionKey#URL_ENCODING} for converting URL to URI or filename,
if needed.</li>
      *   <li>{@link OptionKey#OPEN_OPTIONS} for specifying whether the data store shall
be read only or read/write.</li>
-     *   <li>{@link OptionKey#BYTE_BUFFER} for allowing users to control the byte buffer
to be created.</li>
+     *   <li>{@link OptionKey#BYTE_BUFFER}  for allowing users to control the byte
buffer to be created.</li>
      * </ul>
      *
      * @param <T>   The type of option value.
@@ -265,12 +290,12 @@ public class StorageConnector implements
      *   </li>
      *   <li>{@link DataInput}:
      *     <ul>
-     *       <li>If the {@linkplain #getStorage() storage} object is already an instance
of {@link DataInput}
+     *       <li>If the {@linkplain #getStorage() storage} object is already an instance
of {@code DataInput}
      *           (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 java.nio.file.Path},
{@link java.io.File},
-     *           {@link java.net.URI}, {@link java.net.URL}, {@link CharSequence}, {@link
java.io.InputStream} or
+     *           {@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
      *           {@link ByteBuffer} is created when first needed and returned.</li>
      *
@@ -282,7 +307,30 @@ public class StorageConnector implements
      *   </li>
      *   <li>{@link ImageInputStream}:
      *     <ul>
-     *       <li>If the {@code DataInput} computed above can be casted to {@code null},
returns it.</li>
+     *       <li>If the above {@code DataInput} can be created and casted to {@code
ImageInputStream}, returns it.</li>
+     *
+     *       <li>Otherwise this method returns {@code null}.</li>
+     *     </ul>
+     *   </li>
+     *   <li>{@link InputStream}:
+     *     <ul>
+     *       <li>If the {@linkplain #getStorage() storage} object is already an instance
of {@link InputStream},
+     *           then it is returned unchanged.</li>
+     *
+     *       <li>Otherwise if the above {@code ImageInputStream} can be created,
+     *           returns a wrapper around that stream.</li>
+     *
+     *       <li>Otherwise this method returns {@code null}.</li>
+     *     </ul>
+     *   </li>
+     *   <li>{@link Reader}:
+     *     <ul>
+     *       <li>If the {@linkplain #getStorage() storage} object is already an instance
of {@link Reader},
+     *           then it is returned unchanged.</li>
+     *
+     *       <li>Otherwise if the above {@code InputStream} can be created, returns
an {@link InputStreamReader}
+     *           using the encoding specified by {@link OptionKey#ENCODING} if any, or using
the system default
+     *           encoding otherwise.</li>
      *
      *       <li>Otherwise this method returns {@code null}.</li>
      *     </ul>
@@ -379,6 +427,7 @@ public class StorageConnector implements
                 getOption(OptionKey.URL_ENCODING), getOption(OptionKey.OPEN_OPTIONS));
         ChannelDataInput asDataInput = null;
         if (channel != null) {
+            addViewToClose(channel, storage);
             ByteBuffer buffer = getOption(OptionKey.BYTE_BUFFER);
             if (buffer == null) {
                 buffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
@@ -391,6 +440,7 @@ public class StorageConnector implements
             } else {
                 asDataInput = new ChannelDataInput(name, channel, buffer, false);
             }
+            addViewToClose(asDataInput, channel);
         }
         addView(ChannelDataInput.class, asDataInput);
     }
@@ -419,13 +469,16 @@ public class StorageConnector implements
             final ChannelDataInput c = getView(ChannelDataInput.class);
             if (c == null) {
                 asDataInput = ImageIO.createImageInputStream(storage);
+                addViewToClose(asDataInput, storage);
             } else if (c instanceof DataInput) {
                 asDataInput = (DataInput) c;
+                // No call to 'addViewToClose' because the instance already exists.
             } else {
                 asDataInput = new ChannelImageInputStream(c);
-                if (views.put(ChannelDataInput.class, asDataInput) != c) {
+                if (views.put(ChannelDataInput.class, asDataInput) != c) { // Replace the
previous instance.
                     throw new ConcurrentModificationException();
                 }
+                addViewToClose(asDataInput, c.channel);
             }
         }
         addView(DataInput.class, asDataInput);
@@ -532,13 +585,42 @@ public class StorageConnector implements
             if (storage instanceof Connection) {
                 return storage;
             } else if (storage instanceof DataSource) {
-                return ((DataSource) storage).getConnection();
+                final Connection c = ((DataSource) storage).getConnection();
+                addViewToClose(c, storage);
+                return c;
             }
         }
         if (type == ImageInputStream.class) {
             final DataInput input = getStorageAs(DataInput.class);
             return (input instanceof ImageInputStream) ? input : null;
         }
+        if (type == InputStream.class) {
+            if (storage instanceof InputStream) {
+                return storage;
+            }
+            final DataInput input = getStorageAs(DataInput.class);
+            if (input instanceof InputStream) {
+                return (InputStream) input;
+            }
+            if (input instanceof ImageInputStream) {
+                final InputStream c = new InputStreamAdapter((ImageInputStream) input);
+                addViewToClose(c, input);
+                return c;
+            }
+        }
+        if (type == Reader.class) {
+            if (storage instanceof Reader) {
+                return storage;
+            }
+            final InputStream input = getStorageAs(InputStream.class);
+            if (input != null) {
+                final Charset encoding = getOption(OptionKey.ENCODING);
+                final Reader c = (encoding != null) ? new InputStreamReader(input, encoding)
+                                                    : new InputStreamReader(input);
+                addViewToClose(c, input);
+                return c;
+            }
+        }
         throw new IllegalArgumentException(Errors.format(Errors.Keys.UnknownType_1, type));
     }
 
@@ -568,6 +650,23 @@ public class StorageConnector implements
     }
 
     /**
+     * Declares that the given {@code input} will need to be closed by the {@link #closeAllExcept(Object)}
method.
+     * The {@code input} argument is always a new instance wrapping, directly or indirectly,
the {@link #storage}.
+     * Callers must specify the wrapped object in the {@code delegate} argument.
+     *
+     * @param input    The newly created object which will need to be closed.
+     * @param delegate The object wrapped by the given {@code input}.
+     */
+    private void addViewToClose(final Object input, final Object delegate) {
+        if (viewsToClose == null) {
+            viewsToClose = new IdentityHashMap<>(4);
+        }
+        if (viewsToClose.put(input, delegate) != null) {
+            throw new AssertionError(input);
+        }
+    }
+
+    /**
      * Closes all streams and connections created by this {@code StorageConnector} except
the given view.
      * This method closes all objects created by the {@link #getStorageAs(Class)} method
except the given {@code view}.
      * If {@code view} is {@code null}, then this method closes everything including the
{@linkplain #getStorage()
@@ -586,37 +685,86 @@ public class StorageConnector implements
      * @see DataStoreProvider#open(StorageConnector)
      */
     public void closeAllExcept(final Object view) throws DataStoreException {
+        final Map<Object,Object> toClose = viewsToClose;
+        viewsToClose = Collections.emptyMap();
+        views        = Collections.emptyMap();
+        if (toClose == null) {
+            if (storage != view && storage instanceof AutoCloseable) try {
+                ((AutoCloseable) storage).close();
+            } catch (Exception e) {
+                throw new DataStoreException(e);
+            }
+            return;
+        }
         /*
-         * Need a set of objects to close without duplicated values. In particular, the value
for
-         * DataInput and ImageInputStream are often the same instance. We must avoid duplicated
-         * values because ImageInputStream.close() is not indempotent.
+         * The "AutoCloseable.close() is not indempotent" problem
+         * ------------------------------------------------------
+         * We will need a set of objects to close without duplicated values. For example
the values associated to the
+         * 'ImageInputStream.class' and 'DataInput.class' keys are often the same instance.
 We must avoid duplicated
+         * values because 'ImageInputStream.close()' is not indempotent,  i.e.  invoking
their 'close()' method twice
+         * will thrown an IOException.
+         *
+         * Generally speaking, all AutoCloseable instances are not guaranteed to be indempotent
because this is not
+         * required by the interface contract. Consequently we must be careful to not invoke
the close() method on
+         * the same instance twice (indirectly or indirectly).
+         *
+         * The set of objects to close will be the keys of the 'viewsToClose' map. It can
not be the values of the
+         * 'views' map.
          */
-        final Map<AutoCloseable,Object> toClose = new IdentityHashMap<>(4);
-        for (final Object value : views.values()) {
-            if (value instanceof AutoCloseable) {
-                toClose.put((AutoCloseable) value, null);
-            }
+        toClose.put(storage, null);
+        if (view != null) {
+            /*
+             * If there is a view to not close, search for all views that are wrapper for
the given view.
+             * Those wrappers shall not be closed. For example if the caller does not want
to close the
+             * InputStream view, then we shall not close the InputStreamReader wrapper neither.
+             */
+            final Queue<Object> deferred = new LinkedList<>();
+            Object doNotClose = view;
+            do {
+                final Iterator<Map.Entry<Object,Object>> it = toClose.entrySet().iterator();
+                while (it.hasNext()) {
+                    final Map.Entry<Object,Object> entry = it.next();
+                    if (entry.getValue() == doNotClose) {
+                        deferred.add(entry.getKey());
+                        it.remove();
+                    }
+                }
+                doNotClose = deferred.poll();
+            } while (doNotClose != null);
         }
-        toClose.remove(view);
-        toClose.remove(storage);
-        try {
-            if (!toClose.isEmpty()) {
-                for (final AutoCloseable value : toClose.keySet()) {
-                    value.close();
+        /*
+         * Remove the view to not close. If that view is a wrapper for an other object, do
not close the
+         * wrapped object neither. Proceed the dependency chain up to the original 'storage'
object.
+         */
+        for (Object doNotClose = view; doNotClose != null;) {
+            doNotClose = toClose.remove(doNotClose);
+        }
+        /*
+         * Remove all wrapped objects. After this loop, only the "top level" objects should
remain
+         * (typically only one object). This block is needed because of the "AutoCloseable.close()
+         * is not idempotent" issue, otherwise we could have omitted it.
+         */
+        for (final Object delegate : toClose.values().toArray()) { // 'toArray()' is for
avoiding ConcurrentModificationException.
+            toClose.remove(delegate);
+        }
+        /*
+         * Now close all remaining items. If an exception occurs, we will propagate it only
after we are
+         * done closing all items.
+         */
+        DataStoreException failure = null;
+        for (final Object c : toClose.keySet()) {
+            if (c instanceof AutoCloseable) try {
+                ((AutoCloseable) c).close();
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = new DataStoreException(e);
+                } else {
+                    failure.addSuppressed(e);
                 }
-            } else if (view == null && storage instanceof AutoCloseable) {
-                /*
-                 * Close only if we didn't closed a view because closing an input stream
view
-                 * automatically close the 'storage' if the former is a wrapper for the later.
-                 * Since AutoCloseable.close() is not guaranteed to be indempotent, we should
-                 * avoid to call it (indirectly) twice.
-                 */
-                ((AutoCloseable) storage).close();
             }
-        } catch (Exception e) {
-            throw new DataStoreException(e);
-        } finally {
-            views = Collections.emptyMap();
+        }
+        if (failure != null) {
+            throw failure;
         }
     }
 

Modified: sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java?rev=1511393&r1=1511392&r2=1511393&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java
[UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java
[UTF-8] Wed Aug  7 16:54:59 2013
@@ -17,6 +17,8 @@
 package org.apache.sis.storage;
 
 import java.io.DataInput;
+import java.io.InputStream;
+import java.io.Reader;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadableByteChannel;
@@ -37,7 +39,7 @@ import static org.opengis.test.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.4
  * @module
  */
 @DependsOn(org.apache.sis.internal.storage.ChannelImageInputStreamTest.class)
@@ -149,6 +151,50 @@ public final strictfp class StorageConne
     }
 
     /**
+     * Tests the {@link StorageConnector#getStorageAs(Class)} method for the {@link InputStream}
type.
+     *
+     * @throws DataStoreException Should never happen.
+     * @throws IOException If an error occurred while reading the test file.
+     */
+    @Test
+    @DependsOnMethod("testGetAsImageInputStream")
+    public void testGetAsInputStream() throws DataStoreException, IOException {
+        StorageConnector connection = create(true);
+        InputStream in = connection.getStorageAs(InputStream.class);
+        assertSame(connection.getStorage(), in);
+        connection.closeAllExcept(null);
+
+        connection = create(false);
+        in = connection.getStorageAs(InputStream.class);
+        assertNotSame(connection.getStorage(), in);
+        assertSame("Expected cached value.", in, connection.getStorageAs(InputStream.class));
+        assertInstanceOf("Expected Channel backend", InputStreamAdapter.class, in);
+        assertInstanceOf("Expected Channel backend", ChannelImageInputStream.class, ((InputStreamAdapter)
in).input);
+        assertSame(((InputStreamAdapter) in).input, connection.getStorageAs(DataInput.class));
+        assertSame(((InputStreamAdapter) in).input, connection.getStorageAs(ImageInputStream.class));
+
+        final ReadableByteChannel channel = ((ChannelImageInputStream) ((InputStreamAdapter)
in).input).channel;
+        assertTrue(channel.isOpen());
+        connection.closeAllExcept(null);
+        assertFalse(channel.isOpen());
+    }
+
+    /**
+     * Tests the {@link StorageConnector#getStorageAs(Class)} method for the {@link Reader}
type.
+     *
+     * @throws DataStoreException Should never happen.
+     * @throws IOException If an error occurred while reading the test file.
+     */
+    @Test
+    @DependsOnMethod("testGetAsInputStream")
+    public void testGetAsReader() throws DataStoreException, IOException {
+        StorageConnector connection = create(true);
+        final Reader in = connection.getStorageAs(Reader.class);
+        assertSame("Expected cached value.", in, connection.getStorageAs(Reader.class));
+        connection.closeAllExcept(null);
+    }
+
+    /**
      * Tests the {@link StorageConnector#getStorageAs(Class)} method for the {@link ChannelDataInput}
type.
      * The initial value should not be an instance of {@link ChannelImageInputStream} in
order to avoid initializing
      * the Image I/O classes. However after a call to {@code getStorageAt(ChannelImageInputStream.class)},
the type
@@ -213,7 +259,7 @@ public final strictfp class StorageConne
 
         final ByteBuffer buffer = connection.getStorageAs(ByteBuffer.class);
         assertNotNull("getStorageAs(ByteBuffer.class)", buffer);
-        assertTrue(buffer.capacity() < StorageConnector.DEFAULT_BUFFER_SIZE);
+        assertEquals(StorageConnector.MINIMAL_BUFFER_SIZE, buffer.capacity());
         assertEquals(MAGIC_NUMBER, buffer.getInt());
         connection.closeAllExcept(null);
     }



Mime
View raw message