sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1777838 - in /sis/branches/JDK8: ide-project/ ide-project/NetBeans/nbproject/ storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ storage/sis-storage/src/main/java/org/apache/sis/storage/ storage/sis-storage/src/test/java/or...
Date Sat, 07 Jan 2017 18:37:25 GMT
Author: desruisseaux
Date: Sat Jan  7 18:37:25 2017
New Revision: 1777838

URL: http://svn.apache.org/viewvc?rev=1777838&view=rev
Log:
Prepare storage module for better support of write operations.

Added:
    sis/branches/JDK8/ide-project/LicenseHeader.txt   (with props)
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/InputStreamAdapter.java
      - copied, changed from r1777837, sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/OutputStreamAdapter.java
      - copied, changed from r1777533, sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentReadException.java   (with props)
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentWriteException.java   (with props)
Removed:
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java
Modified:
    sis/branches/JDK8/ide-project/NetBeans/nbproject/project.properties
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ChannelFactory.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreException.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ForwardOnlyStorageException.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/UnsupportedStorageException.java
    sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/OutputType.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java

Added: sis/branches/JDK8/ide-project/LicenseHeader.txt
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/ide-project/LicenseHeader.txt?rev=1777838&view=auto
==============================================================================
--- sis/branches/JDK8/ide-project/LicenseHeader.txt (added)
+++ sis/branches/JDK8/ide-project/LicenseHeader.txt [UTF-8] Sat Jan  7 18:37:25 2017
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */

Propchange: sis/branches/JDK8/ide-project/LicenseHeader.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/ide-project/LicenseHeader.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/ide-project/NetBeans/nbproject/project.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/ide-project/NetBeans/nbproject/project.properties?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/ide-project/NetBeans/nbproject/project.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/ide-project/NetBeans/nbproject/project.properties [ISO-8859-1] Sat Jan  7 18:37:25 2017
@@ -32,6 +32,7 @@ excludes             =
 main.class           =
 manifest.file        = manifest.mf
 project.license      = apache20
+project.licensePath  = ../../ide-project/LicenseHeader.txt
 no.dependencies      = true
 source.encoding      = UTF-8
 javac.source         = 1.8

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ChannelFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ChannelFactory.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ChannelFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/ChannelFactory.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -23,7 +23,9 @@ import java.util.Collections;
 import java.util.Arrays;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URL;
@@ -35,8 +37,10 @@ import java.nio.file.InvalidPathExceptio
 import java.nio.file.FileSystemNotFoundException;
 import java.nio.file.OpenOption;
 import java.nio.file.StandardOpenOption;
+import java.nio.channels.Channel;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.system.Modules;
@@ -74,14 +78,17 @@ public abstract class ChannelFactory {
     }
 
     /**
-     * Returns a byte channel factory from the given input, or {@code null} if the input is of unknown type.
+     * Returns a byte channel factory from the given input or output,
+     * or {@code null} if the input is of unknown type.
      * More specifically:
      *
      * <ul>
-     *   <li>If the given input is {@code null}, then this method returns {@code null}.</li>
-     *   <li>If the given input is a {@link ReadableByteChannel} or an {@link InputStream},
+     *   <li>If the given storage is {@code null}, then this method returns {@code null}.</li>
+     *   <li>If the given storage is a {@link ReadableByteChannel} or an {@link InputStream},
      *       then the factory will return that input directly or indirectly as a wrapper.</li>
-     *   <li>If the given input if a {@link Path}, {@link File}, {@link URL}, {@link URI}
+     *   <li>If the given storage is a {@link WritableByteChannel} or an {@link OutputStream},
+     *       then the factory will return that output directly or indirectly as a wrapper.</li>
+     *   <li>If the given storage if a {@link Path}, {@link File}, {@link URL}, {@link URI}
      *       or {@link CharSequence}, then the factory will open new channels on demand.</li>
      * </ul>
      *
@@ -98,7 +105,7 @@ public abstract class ChannelFactory {
      * would alter significatively the channel behavior depending on whether we have been able to
      * honor the options or not.</p>
      *
-     * @param  input     the file to open, or {@code null}.
+     * @param  storage   the stream or the file to open, or {@code null}.
      * @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}.
@@ -106,7 +113,7 @@ public abstract class ChannelFactory {
      * @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 input, final String encoding, OpenOption... options) throws IOException {
+    public static ChannelFactory prepare(Object storage, final String encoding, OpenOption... options) throws IOException {
         /*
          * Unconditionally verify the options, even if we may not use them.
          */
@@ -127,18 +134,20 @@ public abstract class ChannelFactory {
          * to its getChannel() method, but only if the input stream type is exactly FileInputStream, not a subtype.
          * If Apache SIS defines its own FileInputStream subclass someday, we may need to add a special case here.
          */
-        if (input instanceof ReadableByteChannel) {
-            return new Stream((ReadableByteChannel) input);
-        } else if (input instanceof InputStream) {
-            return new Stream(Channels.newChannel((InputStream) input));
+        if (storage instanceof ReadableByteChannel || storage instanceof WritableByteChannel) {
+            return new Stream((Channel) storage);
+        } else if (storage instanceof InputStream) {
+            return new Stream(Channels.newChannel((InputStream) storage));
+//      } else if (storage instanceof OutputStream) {
+//          return new Stream(Channels.newChannel((OutputStream) storage));
         }
         /*
          * In the following cases, we will try hard to convert to Path objects before to fallback
          * on File, URL or URI, because only Path instances allow us to use the given OpenOptions.
          */
-        if (input instanceof URL) {
+        if (storage instanceof URL) {
             try {
-                input = IOUtilities.toPath((URL) input, encoding);
+                storage = IOUtilities.toPath((URL) storage, encoding);
             } catch (IOException e) {
                 /*
                  * This is normal if the URL uses HTTP or FTP protocol for instance. Log the exception at FINE
@@ -146,13 +155,13 @@ public abstract class ChannelFactory {
                  */
                 recoverableException(e);
             }
-        } else if (input instanceof URI) {
+        } else if (storage instanceof URI) {
             /*
              * If the user gave us a URI, try to convert to a Path before to fallback to URL, in order to be
              * able to use the given OpenOptions.  Note that the conversion to Path is likely to fail if the
              * URL uses HTTP or FTP protocols, because JDK7 does not provide file systems for them by default.
              */
-            final URI uri = (URI) input;
+            final URI uri = (URI) storage;
             if (!uri.isAbsolute()) {
                 /*
                  * All methods invoked in this block throws IllegalArgumentException if the URI has no scheme,
@@ -160,10 +169,10 @@ public abstract class ChannelFactory {
                  */
                 throw new IOException(Resources.format(Resources.Keys.MissingSchemeInURI_1, uri));
             } else try {
-                input = Paths.get(uri);
+                storage = Paths.get(uri);
             } catch (IllegalArgumentException | FileSystemNotFoundException e) {
                 try {
-                    input = uri.toURL();
+                    storage = uri.toURL();
                 } catch (MalformedURLException ioe) {
                     ioe.addSuppressed(e);
                     throw ioe;
@@ -176,18 +185,18 @@ public abstract class ChannelFactory {
                 recoverableException(e);
             }
         } else {
-            if (input instanceof CharSequence) {    // Needs to be before the check for File or URL.
-                input = IOUtilities.toFileOrURL(input.toString(), encoding);
+            if (storage instanceof CharSequence) {    // Needs to be before the check for File or URL.
+                storage = IOUtilities.toFileOrURL(storage.toString(), encoding);
             }
             /*
              * If the input is a File or a CharSequence that we have been able to convert to a File,
              * try to convert to a Path in order to be able to use the OpenOptions. Only if we fail
              * to convert to a Path (which is unlikely), we will use directly the File.
              */
-            if (input instanceof File) {
-                final File file = (File) input;
+            if (storage instanceof File) {
+                final File file = (File) storage;
                 try {
-                    input = file.toPath();
+                    storage = file.toPath();
                 } catch (final InvalidPathException e) {
                     /*
                      * Unlikely to happen. But if it happens anyway, try to open the channel in a
@@ -202,18 +211,24 @@ public abstract class ChannelFactory {
          * to convert it to a Path, or a URI, File or CharSequence input converted to URL. Do not
          * try to convert the URL to a Path, because this has already been tried before this point.
          */
-        if (input instanceof URL) {
-            final URL file = (URL) input;
+        if (storage instanceof URL) {
+            final URL file = (URL) storage;
             return new ChannelFactory() {
-                @Override public ReadableByteChannel reader() throws IOException {
+                @Override public ReadableByteChannel reader(String filename) throws IOException {
                     return Channels.newChannel(file.openStream());
                 }
+                @Override public WritableByteChannel writer(String filename) throws IOException {
+                    return Channels.newChannel(file.openConnection().getOutputStream());
+                }
             };
         }
-        if (input instanceof Path) {
-            final Path path = (Path) input;
+        if (storage instanceof Path) {
+            final Path path = (Path) storage;
             return new ChannelFactory() {
-                @Override public ReadableByteChannel reader() throws IOException {
+                @Override public ReadableByteChannel reader(String filename) throws IOException {
+                    return Files.newByteChannel(path, optionSet);
+                }
+                @Override public WritableByteChannel writer(String filename) throws IOException {
                     return Files.newByteChannel(path, optionSet);
                 }
             };
@@ -223,7 +238,7 @@ public abstract class ChannelFactory {
 
     /**
      * Returns {@code true} if this factory is capable to create another reader. This method returns {@code false}
-     * if this factory is capable to create only one channel and {@link #reader()} has already been invoked.
+     * if this factory is capable to create only one channel and {@link #reader(String)} has already been invoked.
      *
      * @return whether {@link #reader()} can be invoked.
      */
@@ -232,25 +247,50 @@ public abstract class ChannelFactory {
     }
 
     /**
-     * Returns the channel as an input stream. The returned stream is <strong>not</strong> buffered;
+     * Returns the readable channel as an input stream. The returned stream is <strong>not</strong> buffered;
      * it is caller's responsibility to wrap the stream in a {@link java.io.BufferedInputStream} if desired.
      *
+     * @param  filename  data store name to report in case of failure.
      * @return the input stream.
      * @throws IOException if the input stream or its underlying byte channel can not be created.
      */
-    public InputStream inputStream() throws IOException {
-        return Channels.newInputStream(reader());
+    public InputStream inputStream(final String filename) throws IOException {
+        return Channels.newInputStream(reader(filename));
+    }
+
+    /**
+     * Returns the writable channel as an output stream. The returned stream is <strong>not</strong> buffered;
+     * it is caller's responsibility to wrap the stream in a {@link java.io.BufferedOutputStream} if desired.
+     *
+     * @param  filename  data store name to report in case of failure.
+     * @return the output stream.
+     * @throws IOException if the output stream or its underlying byte channel can not be created.
+     */
+    public OutputStream outputStream(final String filename) throws IOException {
+        return Channels.newOutputStream(writer(filename));
     }
 
     /**
      * Returns a byte channel from the input given to the {@link #prepare prepare(…)} method.
      * If the channel has already been created and this method can not create it twice, then
-     * this method throw an exception.
+     * this method throws an exception.
      *
+     * @param  filename  data store name to report in case of failure.
      * @return the channel for the given input.
      * @throws IOException if an error occurred while opening the channel.
      */
-    public abstract ReadableByteChannel reader() throws IOException;
+    public abstract ReadableByteChannel reader(String filename) throws IOException;
+
+    /**
+     * Returns a byte channel from the output given to the {@link #prepare prepare(…)} method.
+     * If the channel has already been created and this method can not create it twice, then
+     * this method throws an exception.
+     *
+     * @param  filename  data store name to report in case of failure.
+     * @return the channel for the given output.
+     * @throws IOException if an error occurred while opening the channel.
+     */
+    public abstract WritableByteChannel writer(String filename) throws IOException;
 
     /**
      * A factory that returns an existing channel <cite>as-is</cite>.
@@ -260,35 +300,49 @@ public abstract class ChannelFactory {
         /**
          * The channel, or {@code null} if it has already been returned.
          */
-        private ReadableByteChannel input;
+        private Channel channel;
 
         /**
          * Creates a new factory for the given channel, which will be returned only once.
          */
-        Stream(final ReadableByteChannel input) {
-            this.input = input;
+        Stream(final Channel input) {
+            this.channel = input;
         }
 
         /**
-         * Returns whether {@link #reader()} can be invoked.
+         * Returns whether {@link #reader(String)} or {@link #writer(String)} can be invoked.
          */
         @Override
         public boolean canOpen() {
-            return input != null;
+            return channel != null;
+        }
+
+        /**
+         * Returns the readable channel on the first invocation or
+         * throws an exception on all subsequent invocations.
+         */
+        @Override
+        public ReadableByteChannel reader(final String filename) throws IOException {
+            final Channel in = channel;
+            if (in instanceof ReadableByteChannel) {
+                channel = null;
+                return (ReadableByteChannel) in;
+            }
+            throw new IOException(Resources.format(Resources.Keys.StreamIsReadOnce_1, filename));
         }
 
         /**
-         * Returns the channel on the first invocation or
+         * Returns the writable channel on the first invocation or
          * throws an exception on all subsequent invocations.
          */
         @Override
-        public ReadableByteChannel reader() throws IOException {
-            final ReadableByteChannel in = input;
-            if (in != null) {
-                input = null;
-                return in;
+        public WritableByteChannel writer(final String filename) throws IOException {
+            final Channel in = channel;
+            if (in instanceof WritableByteChannel) {
+                channel = null;
+                return (WritableByteChannel) in;
             }
-            throw new IOException(Resources.format(Resources.Keys.StreamIsReadOnce));
+            throw new IOException(Resources.format(Resources.Keys.StreamIsWriteOnce_1, filename));
         }
     }
 
@@ -326,7 +380,7 @@ public abstract class ChannelFactory {
          * {@link File} to a {@link Path}. On all subsequent invocations, the file is opened silently.</p>
          */
         @Override
-        public FileInputStream inputStream() throws IOException {
+        public FileInputStream inputStream(String filename) throws IOException {
             final FileInputStream in;
             try {
                 in = new FileInputStream(file);
@@ -342,19 +396,59 @@ public abstract class ChannelFactory {
              * But the exception was nevertheless unexpected, so log its stack trace in order
              * to allow the developer to check if there is something wrong.
              */
+            warning();
+            return in;
+        }
+
+        /**
+         * Opens a new output stream for the file given at construction time.
+         * The returned stream is <strong>not</strong> buffered.
+         *
+         * <p>On the first invocation, this method reports a warning about the failure to convert the
+         * {@link File} to a {@link Path}. On all subsequent invocations, the file is opened silently.</p>
+         */
+        @Override
+        public FileOutputStream outputStream(String filename) throws IOException {
+            final FileOutputStream out;
+            try {
+                out = new FileOutputStream(file);
+            } catch (IOException ioe) {
+                if (cause != null) {
+                    ioe.addSuppressed(cause);
+                    cause = null;
+                }
+                throw ioe;
+            }
+            warning();
+            return out;
+        }
+
+        /**
+         * Invoked when we have been able to create a channel, but maybe not with the given {@link OpenOption}s.
+         * Since the exception was nevertheless unexpected, log its stack trace in order to allow the developer
+         * to check if there is something wrong.
+         */
+        private void warning() {
             if (cause != null) {
                 Logging.unexpectedException(Logging.getLogger(Modules.STORAGE), ChannelFactory.class, "prepare", cause);
                 cause = null;
             }
-            return in;
         }
 
         /**
          * Opens a new channel for the file given at construction time.
          */
         @Override
-        public ReadableByteChannel reader() throws IOException {
-            return inputStream().getChannel();
+        public ReadableByteChannel reader(String filename) throws IOException {
+            return inputStream(filename).getChannel();
+        }
+
+        /**
+         * Opens a new channel for the file given at construction time.
+         */
+        @Override
+        public WritableByteChannel writer(String filename) throws IOException {
+            return outputStream(filename).getChannel();
         }
     }
 

Copied: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/InputStreamAdapter.java (from r1777837, sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/InputStreamAdapter.java?p2=sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/InputStreamAdapter.java&p1=sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java&r1=1777837&r2=1777838&rev=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/InputStreamAdapter.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -14,12 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.storage;
+package org.apache.sis.internal.storage;
 
 import java.io.InputStream;
 import java.io.IOException;
 import javax.imageio.stream.ImageInputStream;
-import org.apache.sis.internal.storage.Markable;
 
 
 /**
@@ -29,23 +28,30 @@ import org.apache.sis.internal.storage.M
  * @since   0.4
  * @version 0.8
  * @module
+ *
+ * @see OutputStreamAdapter
  */
-final class InputStreamAdapter extends InputStream implements Markable {
+public final class InputStreamAdapter extends InputStream implements Markable {
     /**
-     * The data input stream.
+     * The underlying data input stream. In principle, public access to this field breaks encapsulation.
+     * But since {@code InputStreamAdapter} does not hold any state and just forwards every method calls
+     * to that {@code ImageInputStream}, using on object or the other does not make a difference.
      */
-    final ImageInputStream input;
+    public final ImageInputStream input;
 
     /**
      * Constructs a new input stream.
+     *
+     * @param input  the stream to wrap.
      */
-    InputStreamAdapter(final ImageInputStream input) {
+    public InputStreamAdapter(final ImageInputStream input) {
         this.input = input;
     }
 
     /**
      * Reads the next byte of data from the input stream.
      *
+     * @return the next byte, or -1 if the end of the stream is reached.
      * @throws IOException if an I/O error occurs.
      */
     @Override
@@ -56,6 +62,7 @@ final class InputStreamAdapter extends I
     /**
      * Reads some number of bytes from the input stream.
      *
+     * @return total number of bytes read, or -1 if the end of the stream has been reached.
      * @throws IOException if an I/O error occurs.
      */
     @Override
@@ -66,6 +73,7 @@ final class InputStreamAdapter extends I
     /**
      * Reads up to {@code len} bytes of data from the input stream.
      *
+     * @return total number of bytes read, or -1 if the end of the stream has been reached.
      * @throws IOException if an I/O error occurs.
      */
     @Override
@@ -76,6 +84,7 @@ final class InputStreamAdapter extends I
     /**
      * Skips over and discards {@code n} bytes of data from this input stream.
      *
+     * @return total number of bytes skipped.
      * @throws IOException if an I/O error occurs.
      */
     @Override
@@ -86,7 +95,7 @@ final class InputStreamAdapter extends I
     /**
      * Returns always {@code true}, since marks support is mandatory in image input stream.
      *
-     * @throws IOException if an I/O error occurs.
+     * @return {@code true}.
      */
     @Override
     public boolean markSupported() {
@@ -97,7 +106,6 @@ final class InputStreamAdapter extends I
      * Marks the current position in this input stream.
      *
      * @param  readlimit ignored.
-     * @throws IOException if an I/O error occurs.
      */
     @Override
     public void mark(final int readlimit) {
@@ -106,8 +114,6 @@ final class InputStreamAdapter extends I
 
     /**
      * Marks the current position in this input stream.
-     *
-     * @throws IOException if an I/O error occurs.
      */
     @Override
     public void mark() {

Copied: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/OutputStreamAdapter.java (from r1777533, sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/OutputStreamAdapter.java?p2=sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/OutputStreamAdapter.java&p1=sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java&r1=1777533&r2=1777838&rev=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/InputStreamAdapter.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/OutputStreamAdapter.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -14,134 +14,98 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.sis.storage;
+package org.apache.sis.internal.storage;
 
-import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.IOException;
-import javax.imageio.stream.ImageInputStream;
-import org.apache.sis.internal.storage.Markable;
+import java.io.DataOutput;
+import java.io.Flushable;
+import java.io.Closeable;
 
 
 /**
- * Wraps an {@link ImageInputStream} as a standard {@link InputStream}.
+ * Wraps a {@link DataOutput} as a standard {@link OutputStream}.
  *
- * @author  Martin Desruisseaux (IRD)
- * @since   0.4
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
  * @version 0.8
  * @module
+ *
+ * @see InputStreamAdapter
  */
-final class InputStreamAdapter extends InputStream implements Markable {
-    /**
-     * 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);
-    }
-
+public final class OutputStreamAdapter extends OutputStream {
     /**
-     * Reads up to {@code len} bytes of data from the input stream.
-     *
-     * @throws IOException if an I/O error occurs.
+     * The underlying data output stream. In principle, public access to this field breaks encapsulation.
+     * But since {@code OutputStreamAdapter} does not hold any state and just forwards every method calls
+     * to that {@code DataOutput}, using on object or the other does not make a difference.
      */
-    @Override
-    public int read(final byte[] b, final int off, final int len) throws IOException {
-        return input.read(b, off, len);
-    }
+    public final DataOutput output;
 
     /**
-     * Skips over and discards {@code n} bytes of data from this input stream.
+     * Constructs a new output stream.
      *
-     * @throws IOException if an I/O error occurs.
+     * @param output  the stream to wrap.
      */
-    @Override
-    public long skip(final long n) throws IOException {
-        return input.skipBytes(n);
+    public OutputStreamAdapter(final DataOutput output) {
+        this.output = output;
     }
 
     /**
-     * Returns always {@code true}, since marks support is mandatory in image input stream.
+     * Writes the specified byte to the output stream.
      *
+     * @param  b  the byte to write.
      * @throws IOException if an I/O error occurs.
      */
     @Override
-    public boolean markSupported() {
-        return true;
+    public void write(final int b) throws IOException {
+        output.write(b);
     }
 
     /**
-     * Marks the current position in this input stream.
+     * Writes the specified bytes to the output stream.
      *
-     * @param  readlimit ignored.
+     * @param  b  the bytes to write.
      * @throws IOException if an I/O error occurs.
      */
     @Override
-    public void mark(final int readlimit) {
-        input.mark();
+    public void write(final byte[] b) throws IOException {
+        output.write(b);
     }
 
     /**
-     * Marks the current position in this input stream.
+     * Writes the specified sub-array to the output stream.
      *
+     * @param  b    the bytes to write.
+     * @param  off  the start offset in the data.
+     * @param  len  the number of bytes to write.
      * @throws IOException if an I/O error occurs.
      */
     @Override
-    public void mark() {
-        input.mark();
+    public void write(final byte[] b, final int off, final int len) throws IOException {
+        output.write(b, off, len);
     }
 
     /**
-     * Repositions this stream to the position at the time the {@code mark} method was last called.
+     * Forces any buffered output bytes to be written out.
      *
      * @throws IOException if an I/O error occurs.
      */
     @Override
-    public void reset() throws IOException {
-        input.reset();
-    }
-
-    /**
-     * Returns the current byte position of the stream.
-     *
-     * @return the position of the stream.
-     * @throws IOException if the position can not be obtained.
-     */
-    @Override
-    public long getStreamPosition() throws IOException {
-        return input.getStreamPosition();
+    public void flush() throws IOException {
+        if (output instanceof Flushable) {
+            ((Flushable) output).flush();
+        }
     }
 
     /**
-     * Closes this input stream.
+     * Releases any system resources associated with the output stream.
      *
      * @throws IOException if an I/O error occurs.
      */
     @Override
     public void close() throws IOException {
-        input.close();
+        if (output instanceof Closeable) {
+            ((Closeable) output).close();
+        }
     }
 }

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -92,6 +92,16 @@ public final class Resources extends Ind
         public static final short ClosedWriter_1 = 5;
 
         /**
+         * One or more read operations are in progress in the “{0}” data store.
+         */
+        public static final short ConcurrentRead_1 = 19;
+
+        /**
+         * A write operation is in progress in the “{0}” data store.
+         */
+        public static final short ConcurrentWrite_1 = 20;
+
+        /**
          * Character string in the “{0}” file is too long. The string has {2} characters while the
          * limit is {1}.
          */
@@ -144,9 +154,14 @@ public final class Resources extends Ind
         public static final short StreamIsForwardOnly_1 = 13;
 
         /**
-         * Stream can be read only once.
+         * The “{0}” data store can be read only once.
+         */
+        public static final short StreamIsReadOnce_1 = 18;
+
+        /**
+         * Can not modify previously written data in “{0}”.
          */
-        public static final short StreamIsReadOnce = 18;
+        public static final short StreamIsWriteOnce_1 = 21;
 
         /**
          * Format of “{0}” is not recognized.

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.properties [ISO-8859-1] Sat Jan  7 18:37:25 2017
@@ -25,6 +25,8 @@ CanNotReadFile_3                  = Can
 CanNotReadFile_4                  = Can not read line {2} (after column {3}) of \u201c{1}\u201d as part of a file in the {0} format.
 ClosedReader_1                    = This {0} reader is closed.
 ClosedWriter_1                    = This {0} writer is closed.
+ConcurrentRead_1                  = One or more read operations are in progress in the \u201c{0}\u201d data store.
+ConcurrentWrite_1                 = A write operation is in progress in the \u201c{0}\u201d data store.
 FeatureAlreadyPresent_2           = A feature named \u201c{1}\u201d is already present in the \u201c{0}\u201d data store.
 FeatureNotFound_2                 = Feature \u201c{1}\u201d has not been found in the \u201c{0}\u201d data store.
 ExcessiveStringSize_3             = Character string in the \u201c{0}\u201d file is too long. The string has {2} characters while the limit is {1}.
@@ -35,5 +37,6 @@ InconsistentNameComponents_2      = Comp
 MissingSchemeInURI_1              = Missing scheme in \u201c{0}\u201d URI.
 ProcessingExecutedOn_1            = Processing executed on {0}.
 StreamIsForwardOnly_1             = Can not move backward in the \u201c{0}\u201d stream.
-StreamIsReadOnce                  = Stream can be read only once.
+StreamIsReadOnce_1                = The \u201c{0}\u201d data store can be read only once.
+StreamIsWriteOnce_1               = Can not modify previously written data in \u201c{0}\u201d.
 UnknownFormatFor_1                = Format of \u201c{0}\u201d is not recognized.

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.properties [ISO-8859-1] Sat Jan  7 18:37:25 2017
@@ -30,6 +30,8 @@ CanNotReadFile_3                  = Ne p
 CanNotReadFile_4                  = Ne peut pas lire la ligne {2} (apr\u00e8s la colonne {3}) de \u00ab\u202f{1}\u202f\u00bb comme une partie d\u2019un fichier au format {0}.
 ClosedReader_1                    = Ce lecteur {0} est ferm\u00e9.
 ClosedWriter_1                    = Cet encodeur {0} est ferm\u00e9.
+ConcurrentRead_1                  = Une ou plusieurs op\u00e9rations de lecture sont en cours sur les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb.
+ConcurrentWrite_1                 = Une op\u00e9ration d\u2019\u00e9criture est en cours sur les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb.
 ExcessiveStringSize_3             = La cha\u00eene de caract\u00e8res dans le fichier \u00ab\u202f{0}\u202f\u00bb est trop longue. La cha\u00eene fait {2} caract\u00e8res alors que la limite est {1}.
 FeatureAlreadyPresent_2           = Une entit\u00e9 nomm\u00e9e \u00ab\u202f{1}\u202f\u00bb est d\u00e9j\u00e0 pr\u00e9sente dans les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb.
 FeatureNotFound_2                 = L\u2019entit\u00e9 \u00ab\u202f{1}\u202f\u00bb n\u2019est pas \u00e9t\u00e9 trouv\u00e9e dans les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb.
@@ -40,5 +42,6 @@ InconsistentNameComponents_2      = Les
 MissingSchemeInURI_1              = Il manque le sch\u00e9ma dans l\u2019URI \u00ab\u202f{0}\u202f\u00bb.
 ProcessingExecutedOn_1            = Traitement ex\u00e9cut\u00e9 sur {0}.
 StreamIsForwardOnly_1             = Ne peut pas reculer dans le flux de donn\u00e9es \u00ab\u202f{0}\u202f\u00bb.
-StreamIsReadOnce                  = Ce flux de donn\u00e9es ne peut \u00eatre lu qu\u2019une seule fois.
+StreamIsReadOnce_1                = Les donn\u00e9es de \u00ab\u202f{0}\u202f\u00bb ne peuvent \u00eatre lues qu\u2019une seule fois.
+StreamIsWriteOnce_1               = Ne peut pas revenir sur les donn\u00e9es d\u00e9j\u00e0 \u00e9crites dans \u00ab\u202f{0}\u202f\u00bb.
 UnknownFormatFor_1                = Le format de \u00ab\u202f{0}\u202f\u00bb n\u2019est pas reconnu.

Added: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentReadException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentReadException.java?rev=1777838&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentReadException.java (added)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentReadException.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -0,0 +1,76 @@
+/*
+ * 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.util.Locale;
+import org.apache.sis.internal.storage.Resources;
+
+
+/**
+ * Thrown when an operation can not be performed while a read operation is in progress.
+ * This exception is thrown for example if a write operation is attempted on a data store
+ * that does not support concurrent read and write operations.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ *
+ * @see ConcurrentWriteException
+ */
+public class ConcurrentReadException extends DataStoreException {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 3319444259890595458L;
+
+    /**
+     * Creates an exception with no cause and no details message.
+     */
+    public ConcurrentReadException() {
+    }
+
+    /**
+     * Creates an exception with the specified details message.
+     *
+     * @param message  the detail message.
+     */
+    public ConcurrentReadException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates an exception with the specified details message and cause.
+     *
+     * @param message  the detail message.
+     * @param cause    the cause for this exception.
+     */
+    public ConcurrentReadException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a localized exception for an operation that can not be executed while a read operation is in progress.
+     * Arguments given to this constructor are hints for building an error message.
+     *
+     * @param locale    the locale of the message to be returned by {@link #getLocalizedMessage()}, or {@code null}.
+     * @param filename  name of the file or data store where a read operation is in progress.
+     */
+    public ConcurrentReadException(final Locale locale, final String filename) {
+        super(locale, Resources.Keys.ConcurrentRead_1, filename);
+    }
+}

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

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

Added: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentWriteException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentWriteException.java?rev=1777838&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentWriteException.java (added)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ConcurrentWriteException.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -0,0 +1,76 @@
+/*
+ * 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.util.Locale;
+import org.apache.sis.internal.storage.Resources;
+
+
+/**
+ * Thrown when an operation can not be performed while a write operation is in progress.
+ * This exception is thrown for example if a read operation is attempted on a data store
+ * that does not support concurrent read and write operations.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ *
+ * @see ConcurrentReadException
+ */
+public class ConcurrentWriteException extends DataStoreException {
+    /**
+     * For cross-version compatibility.
+     */
+    private static final long serialVersionUID = 4005018924099696792L;
+
+    /**
+     * Creates an exception with no cause and no details message.
+     */
+    public ConcurrentWriteException() {
+    }
+
+    /**
+     * Creates an exception with the specified details message.
+     *
+     * @param message  the detail message.
+     */
+    public ConcurrentWriteException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates an exception with the specified details message and cause.
+     *
+     * @param message  the detail message.
+     * @param cause    the cause for this exception.
+     */
+    public ConcurrentWriteException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a localized exception for an operation that can not be executed while a write operation is in progress.
+     * Arguments given to this constructor are hints for building an error message.
+     *
+     * @param locale    the locale of the message to be returned by {@link #getLocalizedMessage()}, or {@code null}.
+     * @param filename  name of the file or data store where a write operation is in progress.
+     */
+    public ConcurrentWriteException(final Locale locale, final String filename) {
+        super(locale, Resources.Keys.ConcurrentWrite_1, filename);
+    }
+}

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

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

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreException.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreException.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStoreException.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -66,7 +66,6 @@ public class DataStoreException extends
      * Creates an exception with no cause and no details message.
      */
     public DataStoreException() {
-        super();
     }
 
     /**

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ForwardOnlyStorageException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ForwardOnlyStorageException.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ForwardOnlyStorageException.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/ForwardOnlyStorageException.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -17,7 +17,9 @@
 package org.apache.sis.storage;
 
 import java.util.Locale;
+import java.nio.file.OpenOption;
 import org.apache.sis.internal.storage.Resources;
+import org.apache.sis.internal.storage.IOUtilities;
 
 
 /**
@@ -44,7 +46,6 @@ public class ForwardOnlyStorageException
      * Creates an exception with no cause and no details message.
      */
     public ForwardOnlyStorageException() {
-        super();
     }
 
     /**
@@ -59,9 +60,14 @@ public class ForwardOnlyStorageException
     /**
      * Creates a localized exception with a default message saying that the stream is read-once.
      *
-     * @param locale   the locale of the message to be returned by {@link #getLocalizedMessage()}, or {@code null}.
+     * @param locale    the locale of the message to be returned by {@link #getLocalizedMessage()}, or {@code null}.
+     * @param filename  name of the file or data store where the error occurred.
+     * @param options   the option used for opening the file, or {@code null} or empty if unknown.
+     *                  This method looks in particular for {@link java.nio.file.StandardOpenOption#READ} and
+     *                  {@code WRITE} options for inferring if the data store was used as a reader or as a writer.
      */
-    public ForwardOnlyStorageException(final Locale locale) {
-        super(locale, Resources.Keys.StreamIsReadOnce);
+    public ForwardOnlyStorageException(final Locale locale, final String filename, final OpenOption... options) {
+        super(locale, IOUtilities.isWrite(options) ? Resources.Keys.StreamIsWriteOnce_1
+                                                   : Resources.Keys.StreamIsReadOnce_1, filename);
     }
 }

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/IllegalNameException.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -44,7 +44,6 @@ public class IllegalNameException extend
      * Creates an exception with no cause and no details message.
      */
     public IllegalNameException() {
-        super();
     }
 
     /**

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -45,6 +45,7 @@ import org.apache.sis.internal.storage.I
 import org.apache.sis.internal.storage.ChannelFactory;
 import org.apache.sis.internal.storage.ChannelDataInput;
 import org.apache.sis.internal.storage.ChannelImageInputStream;
+import org.apache.sis.internal.storage.InputStreamAdapter;
 import org.apache.sis.setup.OptionKey;
 
 
@@ -418,7 +419,7 @@ public class StorageConnector implements
         final Object value;
         try {
             value = createView(type);
-        } catch (RuntimeException e) {
+        } catch (RuntimeException | DataStoreException e) {
             throw e;
         } catch (Exception e) {
             throw new DataStoreException(Errors.format(Errors.Keys.CanNotOpen_1, getStorageName()), e);
@@ -467,7 +468,8 @@ public class StorageConnector implements
 
         ChannelDataInput asDataInput = null;
         if (factory != null) {
-            final ReadableByteChannel channel = factory.reader();
+            final String name = getStorageName();
+            final ReadableByteChannel channel = factory.reader(name);
             addViewToClose(channel, storage);
             ByteBuffer buffer = getOption(OptionKey.BYTE_BUFFER);
             if (buffer == null) {
@@ -475,7 +477,6 @@ public class StorageConnector implements
                 // TODO: we do not create direct buffer yet, but this is something
                 // we may want to consider in a future SIS version.
             }
-            final String name = getStorageName();
             if (asImageInputStream) {
                 asDataInput = new ChannelImageInputStream(name, channel, buffer, false);
             } else {

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/UnsupportedStorageException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/UnsupportedStorageException.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/UnsupportedStorageException.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/UnsupportedStorageException.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -43,7 +43,6 @@ public class UnsupportedStorageException
      * Creates an exception with no cause and no details message.
      */
     public UnsupportedStorageException() {
-        super();
     }
 
     /**

Modified: sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/test/java/org/apache/sis/storage/StorageConnectorTest.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -28,6 +28,7 @@ import java.sql.Connection;
 import org.apache.sis.setup.OptionKey;
 import org.apache.sis.internal.storage.ChannelDataInput;
 import org.apache.sis.internal.storage.ChannelImageInputStream;
+import org.apache.sis.internal.storage.InputStreamAdapter;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -300,7 +301,7 @@ public final strictfp class StorageConne
      * Tests the {@link StorageConnector#getStorageAs(Class)} method for the {@link Connection} type.
      *
      * @throws DataStoreException if an error occurred while using the storage connector.
-     * @throws IOException Should never happen.
+     * @throws IOException should never happen.
      */
     public void testGetAsConnection() throws DataStoreException, IOException {
         final StorageConnector connection = create(false);

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Reader.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -98,8 +98,9 @@ final class Reader extends StaxStreamRea
      * @throws DataStoreException if the input type is not recognized.
      * @throws XMLStreamException if an error occurred while opening the XML file.
      * @throws IOException if an error occurred while preparing the input stream.
+     * @throws Exception if another kind of error occurred while closing a previous stream.
      */
-    public Reader(final Store owner) throws DataStoreException, XMLStreamException, IOException {
+    public Reader(final Store owner) throws Exception {
         super(owner);
     }
 

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Store.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -16,10 +16,7 @@
  */
 package org.apache.sis.internal.gpx;
 
-import java.io.IOException;
 import java.net.URISyntaxException;
-import javax.xml.bind.JAXBException;
-import javax.xml.stream.XMLStreamException;
 import org.apache.sis.internal.xml.StaxDataStore;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
@@ -148,10 +145,12 @@ public final class Store extends StaxDat
             reader      = new Reader(this);
             version     = reader.initialize(true);
             metadata    = reader.getMetadata();
-        } catch (XMLStreamException | IOException | JAXBException e) {
-            throw new DataStoreException(e);
+        } catch (DataStoreException e) {
+            throw e;
         } catch (URISyntaxException | RuntimeException e) {
             throw new DataStoreContentException(e);
+        } catch (Exception e) {
+            throw new DataStoreException(e);
         }
         return metadata;
     }
@@ -182,10 +181,12 @@ public final class Store extends StaxDat
         if (r == null) try {
             r = new Reader(this);
             version = r.initialize(false);
-        } catch (XMLStreamException | IOException | JAXBException e) {
-            throw new DataStoreException(e);
+        } catch (DataStoreException e) {
+            throw e;
         } catch (URISyntaxException | RuntimeException e) {
             throw new DataStoreContentException(e);
+        } catch (Exception e) {
+            throw new DataStoreException(e);
         }
         final Stream<Feature> features = StreamSupport.stream(r, false);
         return features.onClose(r);

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/OutputType.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/OutputType.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/OutputType.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/OutputType.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -17,7 +17,14 @@
 package org.apache.sis.internal.xml;
 
 import java.io.Writer;
+import java.io.StringReader;
+import java.io.StringWriter;
 import java.io.OutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.nio.channels.WritableByteChannel;
 import javax.xml.stream.XMLEventWriter;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamWriter;
@@ -28,6 +35,10 @@ import javax.xml.transform.sax.SAXResult
 import javax.xml.transform.stax.StAXResult;
 import org.xml.sax.ContentHandler;
 import org.w3c.dom.Node;
+import org.apache.sis.internal.storage.ChannelDataInput;
+import org.apache.sis.internal.storage.ChannelImageOutputStream;
+import org.apache.sis.internal.storage.InputStreamAdapter;
+import org.apache.sis.internal.storage.OutputStreamAdapter;
 
 
 /**
@@ -46,7 +57,7 @@ enum OutputType {
      * The output is already an instance of {@link XMLStreamWriter}.
      * That output is returned directly.
      */
-    STAX(XMLStreamWriter.class) {
+    STAX(XMLStreamWriter.class, InputType.STAX) {
         @Override XMLStreamWriter create(StaxDataStore ds, Object s) {
             return (XMLStreamWriter) s;
         }
@@ -56,27 +67,39 @@ enum OutputType {
      * The output is an instance of Java I/O {@link OutputStream}.
      * Encoding depends on the {@linkplain StaxDataStore#encoding data store character encoding}.
      */
-    STREAM(OutputStream.class) {
+    STREAM(OutputStream.class, InputType.STREAM) {
         @Override XMLStreamWriter create(StaxDataStore ds, Object s) throws XMLStreamException {
             final XMLOutputFactory f = ds.outputFactory();
             return (ds.encoding != null) ? f.createXMLStreamWriter((OutputStream) s, ds.encoding.name())
                                          : f.createXMLStreamWriter((OutputStream) s);
         }
+        @Override Object toReader(final Object s) {
+            if (s instanceof ByteArrayOutputStream) {
+                return new ByteArrayInputStream(((ByteArrayOutputStream) s).toByteArray());
+            }
+            return super.toReader(s);
+        }
     },
 
     /**
      * The output is an instance of Java I/O {@link Writer}.
      */
-    CHARACTERS(Writer.class) {
+    CHARACTERS(Writer.class, InputType.CHARACTERS) {
         @Override XMLStreamWriter create(StaxDataStore ds, Object s) throws XMLStreamException {
             return ds.outputFactory().createXMLStreamWriter((Writer) s);
         }
+        @Override Object toReader(final Object s) {
+            if (s instanceof StringWriter) {
+                return new StringReader(s.toString());
+            }
+            return super.toReader(s);
+        }
     },
 
     /**
      * The output is an instance of XML {@link Result}, which is itself a wrapper around another kind of result.
      */
-    SOURCE(Result.class) {
+    RESULT(Result.class, InputType.SOURCE) {
         @Override XMLStreamWriter create(StaxDataStore ds, Object s) throws XMLStreamException {
             return ds.outputFactory().createXMLStreamWriter((Result) s);
         }
@@ -85,16 +108,19 @@ enum OutputType {
     /**
      * The output is an instance of DOM {@link Node}.
      */
-    NODE(Node.class) {
+    NODE(Node.class, InputType.NODE) {
         @Override XMLStreamWriter create(StaxDataStore ds, Object s) throws XMLStreamException {
             return ds.outputFactory().createXMLStreamWriter(new DOMResult((Node) s));
         }
+        @Override Object toReader(final Object s) {
+            return s;
+        }
     },
 
     /**
      * The output is an instance of SAX {@link ContentHandler}.
      */
-    SAX(ContentHandler.class) {
+    SAX(ContentHandler.class, InputType.SAX) {
         @Override XMLStreamWriter create(StaxDataStore ds, Object s) throws XMLStreamException {
             return ds.outputFactory().createXMLStreamWriter(new SAXResult((ContentHandler) s));
         }
@@ -103,7 +129,7 @@ enum OutputType {
     /**
      * The output is an instance of STAX {@link XMLEventWriter}.
      */
-    EVENT(XMLEventWriter.class) {
+    EVENT(XMLEventWriter.class, InputType.EVENT) {
         @Override XMLStreamWriter create(StaxDataStore ds, Object s) throws XMLStreamException {
             return ds.outputFactory().createXMLStreamWriter(new StAXResult((XMLEventWriter) s));
         }
@@ -115,9 +141,15 @@ enum OutputType {
     private final Class<?> outputType;
 
     /**
+     * The input type from the same framework (StAX, DOM, <i>etc</i>) than this output type.
+     */
+    final InputType inputType;
+
+    /**
      * Creates a new enumeration for the given type of output.
      */
-    private OutputType(final Class<?> outputType) {
+    private OutputType(final Class<?> outputType, final InputType inputType) {
+        this.inputType  = inputType;
         this.outputType = outputType;
     }
 
@@ -132,6 +164,38 @@ enum OutputType {
     abstract XMLStreamWriter create(StaxDataStore ds, Object s) throws XMLStreamException;
 
     /**
+     * Returns a reader for the data written by the given writer, or {@code null} if we can not read the data.
+     * The returned input can be used by {@link #inputType}.
+     *
+     * @param  s  the output from which to get the data that we wrote.
+     * @return the input for the data written by the given stream, or {@code null} if none.
+     */
+    Object toReader(final Object s) {
+        return null;
+    }
+
+    /**
+     * Converts the given stream, usually (but not necessarily) an input stream, to an output stream.
+     * It is caller's responsibility to reset the stream position to the beginning of file before to
+     * invoke this method.
+     */
+    static OutputStream fromInput(AutoCloseable stream) throws IOException {
+        if (stream instanceof OutputStream) {
+            return (OutputStream) stream;
+        }
+        if (stream instanceof InputStreamAdapter) {
+            stream = ((InputStreamAdapter) stream).input;
+        }
+        if (stream instanceof ChannelDataInput) {
+            final ChannelDataInput c = (ChannelDataInput) stream;
+            if (c.channel instanceof WritableByteChannel) {
+                stream = new ChannelImageOutputStream(c.filename, (WritableByteChannel) c.channel, c.buffer);
+            }
+        }
+        return (stream instanceof DataOutput) ? new OutputStreamAdapter((DataOutput) stream) : null;
+    }
+
+    /**
      * Returns a {@code WriterFactory} for the given output type. The {@code type} argument given to this method
      * shall be the class of the {@code s} argument to be given in {@link #create(StaxDataStore, Object)} calls.
      *

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -41,6 +41,8 @@ import org.apache.sis.internal.storage.C
 import org.apache.sis.internal.storage.FeatureStore;
 import org.apache.sis.internal.storage.Markable;
 import org.apache.sis.internal.util.AbstractMap;
+import org.apache.sis.storage.ConcurrentReadException;
+import org.apache.sis.storage.ConcurrentWriteException;
 import org.apache.sis.storage.DataStoreClosedException;
 import org.apache.sis.storage.ForwardOnlyStorageException;
 import org.apache.sis.storage.UnsupportedStorageException;
@@ -113,9 +115,12 @@ public abstract class StaxDataStore exte
      * For example if {@code storage} is a {@link java.nio.file.Path}, then {@code stream} will be some
      * stream or channel opened for that path.
      *
-     * <p>This reference should never be changed until the data store is closed. In particular, this field
-     * should <strong>not</strong> be set to the value of {@link ChannelFactory#inputStream()} because the
-     * later does not create the same kind of input stream than {@link StorageConnector}.</p>
+     * <p>We keep this reference as long as possible in order to use {@link #mark()} and {@link #reset()}
+     * instead than creating new streams for re-reading the data.  If we can not reset the stream but can
+     * create a new one, then this field will become a reference to the new stream. This change should be
+     * done only in last resort, when there is no way to reuse the existing stream.  This is because the
+     * streams created by {@link ChannelFactory#inputStream()} are not of the same kind than the streams
+     * created by {@link StorageConnector}.</p>
      *
      * @see #close()
      */
@@ -125,8 +130,11 @@ public abstract class StaxDataStore exte
      * Position of the first byte to read in the {@linkplain #stream}, or a negative value if unknown.
      * If the position is positive, then the stream should have been {@linkplain Markable#mark() marked}
      * at that position by the constructor.
+     *
+     * @see #mark()
+     * @see #reset()
      */
-    private final long streamPosition;
+    private long streamPosition;
 
     /**
      * The function in charge of producing a {@link XMLStreamReader} from the {@link #storage} or {@link #stream}.
@@ -161,15 +169,15 @@ public abstract class StaxDataStore exte
     private final ChannelFactory channelFactory;
 
     /**
-     * Whether the {@linkplain #stream} is currently in use by a {@link StaxStreamReader}.
-     * Value can be one of {@link #READY}, {@link #IN_USE} or {@link #FINISHED} constants.
+     * Whether the {@linkplain #stream} is currently in use by a {@link StaxStreamIO}. Value can be
+     * one of {@link #START}, {@link #READING}, {@link #WRITING} or {@link #FINISHED} constants.
      */
     private byte state;
 
     /**
      * Possible states for the {@link #state} field.
      */
-    private static final byte READY = 0, IN_USE = 1, FINISHED = 2;
+    private static final byte START = 0, READING = 1, WRITING = 2, FINISHED = 3;
 
     /**
      * Creates a new data store.
@@ -214,18 +222,50 @@ public abstract class StaxDataStore exte
          * other code will set their own mark (which could cause our reset() call to move to the wrong
          * position).
          */
-        if (stream instanceof Markable) try {
+        try {
+            mark();
+        } catch (IOException e) {
+            throw new DataStoreException(e);
+        }
+    }
+
+    /**
+     * Marks the current stream position. This method shall be invoked either at construction time,
+     * or after a new stream has been created.
+     */
+    private void mark() throws IOException {
+        streamPosition = -1;
+        if (stream instanceof Markable) {
             final Markable m = (Markable) stream;
             streamPosition = m.getStreamPosition();
             m.mark();
-        } catch (IOException e) {
-            throw new DataStoreException(e);
-        } else {
-            streamPosition = -1;
         }
     }
 
     /**
+     * Resets the stream position to the mark created at construction time, then marks again the stream
+     * for allowing future resets.
+     *
+     * @return {@code true} of success, or {@code false} if the stream can not be reset.
+     * @throws IOException if an error occurred while reseting the stream.
+     */
+    private boolean reset() throws IOException {
+        if (streamPosition >= 0) {
+            final Markable m = (Markable) stream;
+            long p;
+            do {
+                m.reset();
+                p = m.getStreamPosition();
+            } while (p > streamPosition);
+            if (p == streamPosition) {
+                m.mark();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Holds information that can be used for (un)marshallers configuration, and opportunistically
      * implement various listeners used by JAXB (actually the SIS wrappers) or StAX.
      */
@@ -356,11 +396,10 @@ public abstract class StaxDataStore exte
      * @throws DataStoreException if the input type is not recognized or the data store is closed.
      * @throws XMLStreamException if an error occurred while opening the XML file.
      * @throws IOException if an error occurred while preparing the input stream.
+     * @throws Exception if another kind of error occurred while closing a previous stream.
      */
     @SuppressWarnings("fallthrough")
-    final synchronized XMLStreamReader createReader(final StaxStreamReader target)
-            throws DataStoreException, XMLStreamException, IOException
-    {
+    final synchronized XMLStreamReader createReader(final StaxStreamReader target) throws Exception {
         Object input = storage;
         if (input == null) {
             throw new DataStoreClosedException(getLocale(), getFormatName(), StandardOpenOption.READ);
@@ -369,6 +408,8 @@ public abstract class StaxDataStore exte
          * If the storage given by the user was not one of InputStream, Reader or other type recognized
          * by InputType, then maybe that storage was a Path, File or URL, in which case the constructor
          * should have opened an InputStream for it. If not, then this was an unsupported storage type.
+         * Note that we may have a null 'storageToReader' but a non-null 'storageToWriter', which is why
+         * the UnsupportedStorageException has not been thrown at StaxDataStore construction time.
          */
         AutoCloseable opened = stream;
         InputType type = storageToReader;
@@ -385,41 +426,41 @@ public abstract class StaxDataStore exte
          * mark, then we can not re-read the data.
          */
         switch (state) {
-            default: throw new AssertionError(state);
-            case READY: break;                  // Stream already at the data start; nothing to do.
+            default:        throw new AssertionError(state);
+            case WRITING:   throw new ConcurrentWriteException(getLocale(), getDisplayName());
+            case START:     break;         // Stream already at the data start; nothing to do.
             case FINISHED: {
-                if (streamPosition >= 0) {
-                    final Markable m = (Markable) opened;
-                    long p;
-                    do {
-                        m.reset();
-                        p = m.getStreamPosition();
-                    } while (p > streamPosition);
-                    if (p == streamPosition) {
-                        m.mark();
-                        break;
-                    }
+                if (reset()) break;
+                if (opened != null) {
+                    stream = null;         // Cleared first in case of error during 'close()' call.
+                    opened.close();
+                    opened = null;
                 }
-                // Failed to reset the stream - fallthrough.
+                // Fall through
             }
-            /*
-             * If the input stream is in use, or if we finished to use it but were unable to reset its position,
-             * then we need to create a new input stream (except if the input was a DOM in memory, which we can
-             * share). The 'target' StaxStreamReader will be in charge of closing that stream.
-             */
-            case IN_USE: {
+            case READING: {
+                /*
+                 * If the input stream is in use, or if we finished to use it but were unable to reset its position,
+                 * then we need to create a new input stream (except if the input was a DOM in memory, which we can
+                 * share). The 'target' StaxStreamReader will be in charge of closing that stream.
+                 */
                 if (type == InputType.NODE) break;
+                final String name = getDisplayName();
                 if (channelFactory == null) {
-                    throw new ForwardOnlyStorageException(getLocale());
+                    throw new ForwardOnlyStorageException(getLocale(), name, StandardOpenOption.READ);
                 }
-                input = opened = channelFactory.inputStream();
                 type  = InputType.STREAM;
+                input = opened = channelFactory.inputStream(name);
+                if (stream == null) {
+                    stream = opened;
+                    mark();
+                }
                 break;
             }
         }
         final XMLStreamReader reader = type.create(this, input);
         target.stream = opened;
-        state = IN_USE;
+        state = READING;
         return reader;
     }
 
@@ -442,18 +483,36 @@ public abstract class StaxDataStore exte
         if (output == null) {
             throw new DataStoreClosedException(getLocale(), getFormatName(), StandardOpenOption.WRITE);
         }
+        switch (state) {
+            default:        throw new AssertionError(state);
+            case READING:   throw new ConcurrentReadException (getLocale(), getDisplayName());
+            case WRITING:   throw new ConcurrentWriteException(getLocale(), getDisplayName());
+            case START:     break;         // Stream already at the data start; nothing to do.
+            case FINISHED:  {
+                if (reset()) break;
+                throw new ForwardOnlyStorageException(getLocale(), getDisplayName(), StandardOpenOption.WRITE);
+            }
+        }
         /*
          * If the storage given by the user was not one of OutputStream, Writer or other type recognized
          * by OutputType, then maybe that storage was a Path, File or URL, in which case the constructor
-         * should have opened an InputStream for it. If not, then this was an unsupported storage type.
+         * should have opened an InputStream (not an OutputStream) for it.
          */
+        AutoCloseable opened = stream;
         OutputType type = storageToWriter;
         if (type == null) {
-            // TODO
-            throw new UnsupportedStorageException(getLocale(), getFormatName(), storage, StandardOpenOption.WRITE);
+            opened = OutputType.fromInput(opened);
+            if (opened == null) {
+                throw new UnsupportedStorageException(getLocale(), getFormatName(), output, StandardOpenOption.WRITE);
+            }
+            type = OutputType.STREAM;
+            output = opened;
+            stream = opened;
+            mark();
         }
         final XMLStreamWriter writer = type.create(this, output);
-        target.stream = stream;
+        target.stream = opened;
+        state = WRITING;
         return writer;
     }
 

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java?rev=1777838&r1=1777837&r2=1777838&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java [UTF-8] Sat Jan  7 18:37:25 2017
@@ -127,9 +127,10 @@ public abstract class StaxStreamReader e
      * @throws DataStoreException if the input type is not recognized or the data store is closed.
      * @throws XMLStreamException if an error occurred while opening the XML file.
      * @throws IOException if an error occurred while preparing the input stream.
+     * @throws Exception if another kind of error occurred while closing a previous stream.
      */
     @SuppressWarnings("ThisEscapedInObjectConstruction")
-    protected StaxStreamReader(final StaxDataStore owner) throws DataStoreException, XMLStreamException, IOException {
+    protected StaxStreamReader(final StaxDataStore owner) throws Exception {
         super(owner);
         reader = owner.createReader(this);      // Okay because will not store the 'this' reference.
     }



Mime
View raw message