This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 3993e51cac43dd500436aef187319231c2f59268
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Jan 10 16:44:36 2020 +0100

    Documentation updates and minor code adjustments.
    Some import statements were restored to their original order to reducing 
conflicts when we will merge to master
    (the use of automatic tools for managing import statements is a question to 
be revisited later).
---
 .../main/java/org/apache/sis/feature/Features.java | 100 +++++++++++++--------
 .../sis/internal/metadata/sql/SQLBuilder.java      |   2 +-
 .../sis/internal/metadata/sql/package-info.java    |   2 +-
 .../java/org/apache/sis/test/sql/TestDatabase.java |  58 ++++++------
 .../java/org/apache/sis/test/sql/package-info.java |   3 +-
 .../org/apache/sis/internal/map/GridCanvas.java    |   8 +-
 .../java/org/apache/sis/internal/map/MapItem.java  |   5 +-
 .../java/org/apache/sis/internal/map/MapLayer.java |   4 +-
 .../org/apache/sis/internal/map/MapLayers.java     |   4 +-
 .../org/apache/sis/internal/map/Presentation.java  |   1 +
 .../apache/sis/internal/map/RenderException.java   |   2 +
 .../org/apache/sis/internal/map/package-info.java  |   4 +-
 .../apache/sis/storage/shapefile/cpg/CpgFiles.java |  66 ++++++--------
 .../apache/sis/internal/sql/feature/Features.java  |   1 +
 .../apache/sis/internal/storage/SubsetAdapter.java |   3 +-
 .../sis/internal/storage/csv/StoreProvider.java    |   2 +-
 .../storage/folder/FolderStoreProvider.java        |   8 +-
 .../sis/internal/storage/query/SimpleQuery.java    |  25 +++---
 .../java/org/apache/sis/storage/FeatureNaming.java |   6 +-
 .../sis/internal/storage/gpx/StoreProvider.java    |   2 +-
 20 files changed, 164 insertions(+), 142 deletions(-)

diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java 
b/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
index 11f9e05..b818a22 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/Features.java
@@ -16,32 +16,32 @@
  */
 package org.apache.sis.feature;
 
+import java.util.Map;
 import java.util.Optional;
-
-import org.opengis.feature.Attribute;
-import org.opengis.feature.AttributeType;
-import org.opengis.feature.Feature;
-import org.opengis.feature.FeatureAssociationRole;
-import org.opengis.feature.FeatureType;
-import org.opengis.feature.IdentifiedType;
-import org.opengis.feature.InvalidPropertyValueException;
-import org.opengis.feature.Operation;
-import org.opengis.feature.PropertyType;
+import java.util.IdentityHashMap;
+import org.opengis.util.GenericName;
+import org.opengis.util.NameFactory;
+import org.opengis.util.InternationalString;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.metadata.quality.ConformanceResult;
 import org.opengis.metadata.quality.DataQuality;
 import org.opengis.metadata.quality.Element;
 import org.opengis.metadata.quality.Result;
-import org.opengis.util.GenericName;
-import org.opengis.util.InternationalString;
-import org.opengis.util.NameFactory;
-
-import org.apache.sis.internal.feature.Resources;
-import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.iso.DefaultNameFactory;
+import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.feature.Resources;
 
 // Branch-dependent imports
+import org.opengis.feature.Attribute;
+import org.opengis.feature.AttributeType;
+import org.opengis.feature.Feature;
+import org.opengis.feature.FeatureType;
+import org.opengis.feature.FeatureAssociationRole;
+import org.opengis.feature.IdentifiedType;
+import org.opengis.feature.InvalidPropertyValueException;
+import org.opengis.feature.Operation;
+import org.opengis.feature.PropertyType;
 
 
 /**
@@ -49,7 +49,8 @@ import org.apache.sis.util.iso.DefaultNameFactory;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.0
+ * @author  Alexis Manin (Geomatys)
+ * @version 1.1
  * @since   0.5
  * @module
  */
@@ -123,6 +124,49 @@ public final class Features extends Static {
     }
 
     /**
+     * Returns the given type as an {@link AttributeType} by casting if 
possible, or by getting the result type
+     * of an operation. More specifically this method returns the first of the 
following types which apply:
+     *
+     * <ul>
+     *   <li>If the given type is an instance of {@link AttributeType}, then 
it is returned as-is.</li>
+     *   <li>If the given type is an instance of {@link Operation} and the 
{@linkplain Operation#getResult()
+     *       result type} is an {@link AttributeType}, then that result type 
is returned.</li>
+     *   <li>If the given type is an instance of {@link Operation} and the 
{@linkplain Operation#getResult()
+     *       result type} is another operation, then the above check is 
performed recursively.</li>
+     * </ul>
+     *
+     * @param  type  the data type to express as an attribute type.
+     * @return the attribute type, or empty if this method cannot find any.
+     *
+     * @since 1.1
+     */
+    public static Optional<AttributeType<?>> castOrUnwrap(IdentifiedType type) 
{
+        if (!(type instanceof AttributeType<?>)) {
+            if (!(type instanceof Operation)) {
+                return Optional.empty();
+            }
+            type = ((Operation) type).getResult();
+            if (!(type instanceof AttributeType<?>)) {
+                if (!(type instanceof Operation)) {
+                    return Optional.empty();
+                }
+                /*
+                 * Operation returns another operation. This case should be 
rare and should never
+                 * contain a cycle. However given that the consequence of an 
infinite cycle here
+                 * would be thread freeze, we check as a safety.
+                 */
+                final Map<IdentifiedType,Boolean> done = new 
IdentityHashMap<>(4);
+                while (!((type = ((Operation) type).getResult()) instanceof 
AttributeType<?>)) {
+                    if (!(type instanceof Operation) || done.put(type, 
Boolean.TRUE) != null) {
+                        return Optional.empty();
+                    }
+                }
+            }
+        }
+        return Optional.of((AttributeType<?>) type);
+    }
+
+    /**
      * Finds a feature type common to all given types, or returns {@code null} 
if none is found.
      * The return value is either one of the given types, or a parent common 
to all types.
      * A feature <var>F</var> is considered a common parent if <code>F.{@link 
DefaultFeatureType#isAssignableFrom
@@ -262,26 +306,4 @@ public final class Features extends Static {
             }
         }
     }
-
-
-    /**
-     * Test if given property type is an attribute as defined by {@link 
AttributeType}, or if it produces one as an
-     * {@link Operation#getResult() operation result}. It it is, we return the 
found attribute.
-     *
-     * @param input the data type to unravel the attribute from.
-     * @return The found attribute or an empty shell if we cannot find any.
-     */
-    public static Optional<AttributeType<?>> castOrUnwrap(IdentifiedType 
input) {
-        // In case an operation also implements attribute type, we check it 
first.
-        // TODO : cycle detection ?
-        while (!(input instanceof AttributeType) && input instanceof 
Operation) {
-            input = ((Operation) input).getResult();
-        }
-
-        if (input instanceof AttributeType) {
-            return Optional.of((AttributeType) input);
-        }
-
-        return Optional.empty();
-    }
 }
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/SQLBuilder.java
 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/SQLBuilder.java
index 1cb7e8a..ed4a804 100644
--- 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/SQLBuilder.java
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/SQLBuilder.java
@@ -29,7 +29,7 @@ import org.apache.sis.internal.metadata.ReferencingServices;
  * This class is for internal purpose only and may change or be removed in any 
future SIS version.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.1
  * @since   0.8
  * @module
  */
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/package-info.java
 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/package-info.java
index 8e3fe15..f2470d8 100644
--- 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/package-info.java
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/package-info.java
@@ -72,7 +72,7 @@
  * </ol>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.1
  * @since   0.7
  * @module
  */
diff --git 
a/core/sis-metadata/src/test/java/org/apache/sis/test/sql/TestDatabase.java 
b/core/sis-metadata/src/test/java/org/apache/sis/test/sql/TestDatabase.java
index 6a427fa..625817f 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/sql/TestDatabase.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/sql/TestDatabase.java
@@ -17,25 +17,22 @@
 package org.apache.sis.test.sql;
 
 import java.io.IOException;
+import javax.sql.DataSource;
 import java.sql.Connection;
+import java.sql.Statement;
 import java.sql.ResultSet;
-import java.sql.SQLDataException;
 import java.sql.SQLException;
-import java.sql.Statement;
-import javax.sql.DataSource;
-
+import java.sql.SQLDataException;
+import org.postgresql.PGProperty;
+import org.postgresql.ds.PGSimpleDataSource;
+import org.hsqldb.jdbc.JDBCDataSource;
+import org.hsqldb.jdbc.JDBCPool;
+import org.apache.derby.jdbc.EmbeddedDataSource;
 import org.apache.sis.internal.metadata.sql.Initializer;
 import org.apache.sis.internal.metadata.sql.ScriptRunner;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.util.Debug;
 
-import org.apache.derby.jdbc.EmbeddedDataSource;
-
-import org.hsqldb.jdbc.JDBCDataSource;
-import org.hsqldb.jdbc.JDBCPool;
-import org.postgresql.PGProperty;
-import org.postgresql.ds.PGSimpleDataSource;
-
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
@@ -68,7 +65,8 @@ import static org.junit.Assume.assumeTrue;
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @author  Alexis Manin (Geomatys)
+ * @version 1.1
  * @since   0.7
  * @module
  */
@@ -209,35 +207,39 @@ public strictfp class TestDatabase implements 
AutoCloseable {
         ds.setCurrentSchema(schema);
         ds.setProperty(PGProperty.LOGGER_LEVEL, "OFF");   // For avoiding 
warning when no PostgreSQL server is running.
         /*
-         * Current version does not use pooling on the assumption
-         * that connections to local host are fast enough.
+         * Current version does not use pooling on the assumption that 
connections to local host are fast enough.
+         * We verify that the schema does not exist, even if the `create` 
argument is `false`, because we assume
+         * that the test is going to create the schema soon (see the contract 
documented in method javadoc).
+         * This is also a safety for avoiding to delete a schema that was not 
created by the test case.
          */
-        if (create) {
-            try (Connection c = ds.getConnection()) {
-                try (ResultSet reflect = c.getMetaData().getSchemas(null, 
schema)) {
-                    if (reflect.next()) {
-                        throw new SQLDataException("Schema \"" + schema + "\" 
already exists in \"" + NAME + "\".");
-                    }
+        try (Connection c = ds.getConnection()) {
+            try (ResultSet reflect = c.getMetaData().getSchemas(null, schema)) 
{
+                if (reflect.next()) {
+                    throw new SQLDataException("Schema \"" + schema + "\" 
already exists in \"" + NAME + "\".");
                 }
+            }
+            if (create) {
                 try (Statement s = c.createStatement()) {
                     s.execute("CREATE SCHEMA \"" + schema + '"');
                 }
-
-            } catch (SQLException e) {
-                final String state = e.getSQLState();
-                assumeFalse("This test needs a PostgreSQL server running on 
the local host.", "08001".equals(state));
-                assumeFalse("This test needs a PostgreSQL database named \"" + 
NAME + "\".", "3D000".equals(state));
-                throw e;
             }
+        } catch (SQLException e) {
+            final String state = e.getSQLState();
+            assumeFalse("This test needs a PostgreSQL server running on the 
local host.", "08001".equals(state));
+            assumeFalse("This test needs a PostgreSQL database named \"" + 
NAME + "\".", "3D000".equals(state));
+            throw e;
         }
         return new TestDatabase(ds) {
             @Override public void close() throws SQLException {
                 final PGSimpleDataSource ds = (PGSimpleDataSource) source;
                 try (Connection c = ds.getConnection()) {
                     try (Statement s = c.createStatement()) {
-                        // Prevents test to hang indefinitely if connections 
are not properly released in test cases.
+                        /*
+                         * Prevents test to hang indefinitely if connections 
are not properly released in test cases.
+                         * If the limit (in seconds) is exceeded, an 
SQLTimeoutException is thrown and test fails.
+                         */
                         s.setQueryTimeout(10);
-                        s.execute("DROP SCHEMA \"" + ds.getCurrentSchema() + 
"\" CASCADE;");
+                        s.execute("DROP SCHEMA \"" + ds.getCurrentSchema() + 
"\" CASCADE");
                     }
                 }
             }
diff --git 
a/core/sis-metadata/src/test/java/org/apache/sis/test/sql/package-info.java 
b/core/sis-metadata/src/test/java/org/apache/sis/test/sql/package-info.java
index c7302a5..82d76d1 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/sql/package-info.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/sql/package-info.java
@@ -22,7 +22,8 @@
  * in any future version without notice.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @author  Alexis Manin (Geomatys)
+ * @version 1.1
  * @since   1.0
  * @module
  */
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/GridCanvas.java 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/GridCanvas.java
index e655ae2..38c40c5 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/GridCanvas.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/GridCanvas.java
@@ -27,7 +27,6 @@ import org.apache.sis.geometry.GeneralEnvelope;
 import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
 import org.apache.sis.internal.referencing.provider.Affine;
 import org.apache.sis.referencing.CRS;
-import static org.apache.sis.referencing.CRS.getSingleComponents;
 import org.apache.sis.referencing.CommonCRS;
 import org.apache.sis.referencing.crs.DefaultDerivedCRS;
 import org.apache.sis.referencing.operation.DefaultConversion;
@@ -43,7 +42,10 @@ import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.util.FactoryException;
 
+
 /**
+ * Area when an grid coverage is displayed.
+ *
  * <p>
  * NOTE: this class is a first draft subject to modifications.
  * </p>
@@ -319,8 +321,8 @@ public abstract class GridCanvas {
         final GeneralEnvelope result = new GeneralEnvelope(targetCRS);
 
         //decompose crs
-        final List<SingleCRS> sourceParts = getSingleComponents(sourceCRS);
-        final List<SingleCRS> targetParts = getSingleComponents(targetCRS);
+        final List<SingleCRS> sourceParts = CRS.getSingleComponents(sourceCRS);
+        final List<SingleCRS> targetParts = CRS.getSingleComponents(targetCRS);
 
         int sourceAxeIndex=0;
         sourceLoop:
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapItem.java 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapItem.java
index 4c50463..7d45f4d 100644
--- a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapItem.java
+++ b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapItem.java
@@ -21,6 +21,7 @@ import java.beans.PropertyChangeListener;
 import java.util.Objects;
 import javax.swing.event.EventListenerList;
 
+
 /**
  * Parent class of all map elements.
  *
@@ -29,8 +30,8 @@ import javax.swing.event.EventListenerList;
  * </p>
  *
  * @author  Johann Sorel (Geomatys)
- * @version 1.0
- * @since   1.0
+ * @version 2.0
+ * @since   2.0
  * @module
  */
 public abstract class MapItem {
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapLayer.java 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapLayer.java
index 25be50e..08a3990 100644
--- a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapLayer.java
+++ b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapLayer.java
@@ -37,8 +37,8 @@ import org.opengis.style.Style;
  * </p>
  *
  * @author  Johann Sorel (Geomatys)
- * @version 1.0
- * @since   1.0
+ * @version 2.0
+ * @since   2.0
  * @module
  */
 public class MapLayer extends MapItem {
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapLayers.java 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapLayers.java
index 03dc544..0f218e1 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapLayers.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/MapLayers.java
@@ -40,8 +40,8 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
  * </p>
  *
  * @author  Johann Sorel (Geomatys)
- * @version 1.0
- * @since   1.0
+ * @version 2.0
+ * @since   2.0
  * @module
  */
 public class MapLayers extends MapItem {
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/Presentation.java
 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/Presentation.java
index 0b13ec6..0673be1 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/Presentation.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/Presentation.java
@@ -18,6 +18,7 @@ package org.apache.sis.internal.map;
 
 import org.opengis.feature.Feature;
 
+
 /**
  * When rendering resources, the first step is to generate the visual aspect
  * of each feature or coverage, we call each one a Presentation.
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/RenderException.java
 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/RenderException.java
index c65ba63..36b3edd 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/RenderException.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/RenderException.java
@@ -18,7 +18,9 @@ package org.apache.sis.internal.map;
 
 import org.apache.sis.util.ArgumentChecks;
 
+
 /**
+ * Thrown when a map rendering process failed.
  *
  * <p>
  * NOTE: this class is a first draft subject to modifications.
diff --git 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/package-info.java
 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/package-info.java
index 24003d3..4fcaf00 100644
--- 
a/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/package-info.java
+++ 
b/core/sis-portrayal/src/main/java/org/apache/sis/internal/map/package-info.java
@@ -27,8 +27,8 @@
  * @todo Since everything is about maps in this package, should we omit the 
{@code Map} prefix in class names?
  *
  * @author  Johann Sorel (Geomatys)
- * @version 1.0
- * @since   1.0
+ * @version 2.0
+ * @since   2.0
  * @module
  */
 package org.apache.sis.internal.map;
diff --git 
a/storage/sis-shapefile/src/main/java/org/apache/sis/storage/shapefile/cpg/CpgFiles.java
 
b/storage/sis-shapefile/src/main/java/org/apache/sis/storage/shapefile/cpg/CpgFiles.java
index 4eec64a..5dfec95 100644
--- 
a/storage/sis-shapefile/src/main/java/org/apache/sis/storage/shapefile/cpg/CpgFiles.java
+++ 
b/storage/sis-shapefile/src/main/java/org/apache/sis/storage/shapefile/cpg/CpgFiles.java
@@ -19,69 +19,61 @@ package org.apache.sis.storage.shapefile.cpg;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import org.apache.sis.util.Static;
+
 
 /**
  * CPG files utilities.
- * *.cpg files contains a single word for the name of the dbf character 
encoding.
+ * {@code *.cpg} files contains a single word for the name of the DBF 
character encoding.
  *
- * @author Johann Sorel (Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @version 2.0
  * @since   2.0
  * @module
  */
-public final class CpgFiles {
-
-    private CpgFiles(){}
-
+public final class CpgFiles extends Static {
     /**
-     * Read charset from given stream.
-     *
-     * @param in input channel
-     * @return CharSet
-     * @throws IOException
+     * Do not allow instantiation of this class.
      */
-    public static Charset read(ReadableByteChannel in) throws IOException {
-        final String str = 
toString(Channels.newInputStream(in),Charset.forName("UTF-8")).trim();
-        return Charset.forName(str);
-    }
+    private CpgFiles(){}
 
     /**
-     * Write charset to given file.
+     * Reads the character set from given stream.
+     * If the file is empty, then the default character set is returned.
      *
-     * @param cs charset to write.
-     * @param file output file.
-     * @throws IOException
+     * @param  in input channel from which to read the character set.
+     * @return the character set from the given stream.
+     * @throws IOException if the file does not exist or cannot be read.
      */
-    public static void write(Charset cs, Path file) throws IOException {
-        try (BufferedWriter cpgWriter = Files.newBufferedWriter(file, 
Charset.defaultCharset())) {
-            cpgWriter.write(cs.name());
+    public static Charset read(final ReadableByteChannel in) throws 
IOException {
+        try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(Channels.newInputStream(in), StandardCharsets.UTF_8))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                if ((line = line.trim()).isEmpty()) {
+                    return Charset.forName(line);
+                }
+            }
         }
+        return Charset.defaultCharset();
     }
 
     /**
-     * Read the contents of a stream into String with specified encoding and 
close the Stream.
+     * Writes the character set to given file.
      *
-     * @param stream input steam
-     * @return The file contents as string
-     * @throws IOException if the file does not exist or cannot be read.
+     * @param  cs    charset to write.
+     * @param  file  output file.
+     * @throws IOException if an error occurred while writing the file.
      */
-    private static String toString(final InputStream stream, final Charset 
encoding) throws IOException {
-        final StringBuilder sb  = new StringBuilder();
-        try (BufferedReader br = new BufferedReader(new 
InputStreamReader(stream, encoding))) {
-            String line;
-            while ((line = br.readLine()) != null) {
-                sb.append(line).append('\n');
-            }
-        } finally {
-            stream.close();
+    public static void write(final Charset cs, final Path file) throws 
IOException {
+        try (BufferedWriter writer = Files.newBufferedWriter(file, 
StandardCharsets.UTF_8)) {
+            writer.write(cs.name());
         }
-        return sb.toString();
     }
 }
diff --git 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Features.java
 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Features.java
index 0e4e29e..d903395 100644
--- 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Features.java
+++ 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Features.java
@@ -584,6 +584,7 @@ final class Features implements Spliterator<Feature> {
         }
 
         Builder setColumns(final ColumnRef... columns) {
+            // TODO: empty array is not the same than null array.
             if (columns == null || columns.length < 1) this.columns = null;
             else this.columns = Arrays.copyOf(columns, columns.length);
             return this;
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/SubsetAdapter.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/SubsetAdapter.java
index 600919a..3c3e244 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/SubsetAdapter.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/SubsetAdapter.java
@@ -62,7 +62,8 @@ public final class SubsetAdapter {
         if (sortRequired(query) && !driver.sort(query.getSortBy())) 
remaining.setSortBy(query.getSortBy());
 
         if (!allColumnsIncluded(query) && !driver.select(query.getColumns())) {
-            remaining.setColumns(query.getColumns().toArray(new 
SimpleQuery.Column[0]));
+            List<SimpleQuery.Column> columns = query.getColumns();
+            remaining.setColumns(columns != null ? columns.toArray(new 
SimpleQuery.Column[columns.size()]) : null);
         }
 
         final FeatureSet driverSubset = driver.build().orElse(source);
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
index 8a1e3de..a36bdef 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/StoreProvider.java
@@ -26,13 +26,13 @@ import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataOptionKey;
 import org.apache.sis.storage.ProbeResult;
 import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.feature.FoliationRepresentation;
 import org.apache.sis.internal.storage.Resources;
 import org.apache.sis.internal.storage.Capability;
 import org.apache.sis.internal.storage.StoreMetadata;
 import org.apache.sis.internal.storage.URIDataStore;
 import org.apache.sis.internal.storage.wkt.FirstKeywordPeek;
-import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.util.ArgumentChecks;
 
 
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java
index 969fd42..461bf17 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/folder/FolderStoreProvider.java
@@ -38,6 +38,9 @@ import org.apache.sis.storage.DataStoreProvider;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.ProbeResult;
+import org.apache.sis.storage.Aggregate;
+import org.apache.sis.storage.FeatureSet;
+import org.apache.sis.storage.GridCoverageResource;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.internal.system.Modules;
@@ -47,9 +50,6 @@ import org.apache.sis.internal.storage.Capability;
 import org.apache.sis.internal.storage.StoreMetadata;
 import org.apache.sis.internal.storage.StoreUtilities;
 import org.apache.sis.setup.OptionKey;
-import org.apache.sis.storage.Aggregate;
-import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.storage.GridCoverageResource;
 
 
 /**
@@ -73,7 +73,7 @@ public final class FolderStoreProvider extends 
DataStoreProvider {
     static final String NAME = "folder";
 
     /**
-     * Description of the parameter for formating conventions of dates and 
numbers.
+     * Description of the parameter for formatting conventions of dates and 
numbers.
      */
     private static final ParameterDescriptor<Locale> LOCALE;
 
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
index b1af455..5b327cd 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/query/SimpleQuery.java
@@ -17,23 +17,17 @@
 package org.apache.sis.internal.storage.query;
 
 import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
+import java.util.List;
+import java.util.LinkedHashMap;
 import java.util.Objects;
-
-import org.opengis.feature.FeatureType;
-import org.opengis.filter.Filter;
-import org.opengis.filter.expression.Expression;
-import org.opengis.filter.sort.SortBy;
 import org.opengis.util.GenericName;
-
+import org.apache.sis.filter.InvalidExpressionException;
 import org.apache.sis.feature.builder.FeatureTypeBuilder;
 import org.apache.sis.feature.builder.PropertyTypeBuilder;
-import org.apache.sis.filter.InvalidExpressionException;
 import org.apache.sis.internal.feature.FeatureExpression;
-import org.apache.sis.internal.storage.Resources;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
+import org.apache.sis.internal.storage.Resources;
 import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.storage.Query;
 import org.apache.sis.util.ArgumentChecks;
@@ -42,6 +36,10 @@ import org.apache.sis.util.collection.Containers;
 import org.apache.sis.util.iso.Names;
 
 // Branch-dependent imports
+import org.opengis.feature.FeatureType;
+import org.opengis.filter.Filter;
+import org.opengis.filter.expression.Expression;
+import org.opengis.filter.sort.SortBy;
 
 
 /**
@@ -125,9 +123,8 @@ public class SimpleQuery extends Query implements Cloneable 
{
      */
     @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter")
     public void setColumns(Column... columns) {
-        if (columns == null || columns.length < 1) {
-            this.columns = null;
-        } else {
+        if (columns != null) {
+            ArgumentChecks.ensureNonEmpty("columns", columns);
             columns = columns.clone();
             final Map<Object,Integer> uniques = new 
LinkedHashMap<>(Containers.hashMapCapacity(columns.length));
             for (int i=0; i<columns.length; i++) {
@@ -139,8 +136,8 @@ public class SimpleQuery extends Query implements Cloneable 
{
                     throw new 
IllegalArgumentException(Resources.format(Resources.Keys.DuplicatedQueryProperty_3,
 key, p, i));
                 }
             }
-            this.columns = columns;
         }
+        this.columns = columns;
     }
 
     /**
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/FeatureNaming.java 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/FeatureNaming.java
index 0ca48cd..8389d2a 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/FeatureNaming.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/FeatureNaming.java
@@ -36,8 +36,8 @@ import org.apache.sis.internal.storage.Resources;
  * actually puts no restriction on the kind of object associated to {@code 
GenericName}s;
  * {@link DataStore} implementations are free to choose their internal object.
  * Those objects can be stored and fetched using the {@code String} 
representation of their name
- * as given by {@link GenericName#toString()}, or a shortened name when there 
is no ambiguity. Note that search is
- * case sensitive.
+ * as given by {@link GenericName#toString()}, or a shortened name when there 
is no ambiguity.
+ * Note that search is case sensitive.
  *
  * <div class="note"><b>Example:</b>
  * a data store may contain a {@code FeatureType} named {@code "foo:bar"}.
@@ -147,7 +147,7 @@ public class FeatureNaming<E> {
     }
 
     /**
-     * Returns the value associated to the given name. Case sensitive.
+     * Returns the value associated to the given name (case sensitive).
      *
      * @param  store  the data store for which to get a value, or {@code null} 
if unknown.
      * @param  name   the name for which to get a value.
diff --git 
a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/StoreProvider.java
 
b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/StoreProvider.java
index 322a161..98b0cab 100644
--- 
a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/StoreProvider.java
+++ 
b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/StoreProvider.java
@@ -21,11 +21,11 @@ import javax.xml.bind.JAXBException;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.internal.storage.Capability;
 import org.apache.sis.internal.storage.StoreMetadata;
 import org.apache.sis.internal.storage.xml.stream.StaxDataStoreProvider;
 import org.apache.sis.measure.Range;
-import org.apache.sis.storage.FeatureSet;
 import org.apache.sis.util.Version;
 
 

Reply via email to