sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1780633 - in /sis/branches/JDK8: core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-referencing/src/test/java/org/apache/sis/referencing/report/ core/sis-utility/src/main/java/org/apache/sis/internal/util/ core/sis-utility/src...
Date Sat, 28 Jan 2017 04:48:31 GMT
Author: desruisseaux
Date: Sat Jan 28 04:48:30 2017
New Revision: 1780633

URL: http://svn.apache.org/viewvc?rev=1780633&view=rev
Log:
Allow formatted XML output when using XMLStreamWriter. This apply to GPX format.

Added:
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Implementation.java   (with props)
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/FormattedWriter.java   (with props)
Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/PooledTemplate.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java
    sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java
    sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.properties
    sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_fr.properties
    sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxStreamWriter.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/FormattableObject.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -23,6 +23,7 @@ import javax.xml.bind.annotation.XmlTran
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.internal.util.X364;
+import org.apache.sis.internal.util.Constants;
 
 
 /**
@@ -186,7 +187,7 @@ public abstract class FormattableObject
         formatter.configure(convention, null, colorize ? Colors.DEFAULT : null,
                 convention.toUpperCase           ? (byte) +1 : 0,
                 (convention.majorVersion() == 1) ? (byte) -1 : 0,
-                WKTFormat.DEFAULT_INDENTATION);
+                Constants.DEFAULT_INDENTATION);
         if (!strict) {
             formatter.transliterator = Transliterator.IDENTITY;
         }

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -320,7 +320,7 @@ public class Formatter implements Locali
      * Creates a new formatter instance with the default configuration.
      */
     public Formatter() {
-        this(Convention.DEFAULT, Symbols.getDefault(), WKTFormat.DEFAULT_INDENTATION);
+        this(Convention.DEFAULT, Symbols.getDefault(), Constants.DEFAULT_INDENTATION);
     }
 
     /**
@@ -363,7 +363,7 @@ public class Formatter implements Locali
         this.authority     = Convention.DEFAULT.getNameAuthority();
         this.symbols       = symbols;
         this.lineSeparator = this.symbols.lineSeparator();
-        this.indentation   = WKTFormat.DEFAULT_INDENTATION;
+        this.indentation   = Constants.DEFAULT_INDENTATION;
         this.numberFormat  = numberFormat;                      // No clone needed.
         this.dateFormat    = dateFormat;
         this.unitFormat    = unitFormat;

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -44,6 +44,7 @@ import org.apache.sis.measure.UnitFormat
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.StandardDateFormat;
 
 
@@ -121,15 +122,14 @@ public class WKTFormat extends CompoundF
     /**
      * The indentation value to give to the {@link #setIndentation(int)}
      * method for formatting the complete object on a single line.
+     *
+     * @see #getIndentation()
+     * @see #setIndentation(int)
+     * @see org.apache.sis.setup.OptionKey#INDENTATION
      */
     public static final int SINGLE_LINE = -1;
 
     /**
-     * The default indentation value.
-     */
-    static final byte DEFAULT_INDENTATION = 2;
-
-    /**
      * The symbols to use for this formatter.
      * The same object is also referenced in the {@linkplain #parser} and {@linkplain #formatter}.
      * It appears here for serialization purpose.
@@ -240,7 +240,7 @@ public class WKTFormat extends CompoundF
         symbols      = Symbols.getDefault();
         keywordCase  = KeywordCase.DEFAULT;
         keywordStyle = KeywordStyle.DEFAULT;
-        indentation  = DEFAULT_INDENTATION;
+        indentation  = Constants.DEFAULT_INDENTATION;
     }
 
     /**
@@ -537,6 +537,8 @@ public class WKTFormat extends CompoundF
      * The {@value #SINGLE_LINE} value means that the whole WKT is to be formatted on a single line.
      *
      * @param  indentation  the new indentation to use.
+     *
+     * @see org.apache.sis.setup.OptionKey#INDENTATION
      */
     public void setIndentation(final int indentation) {
         ArgumentChecks.ensureBetween("indentation", SINGLE_LINE, Byte.MAX_VALUE, indentation);

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -26,6 +26,7 @@ import java.io.BufferedWriter;
 import java.io.OutputStreamWriter;
 import java.io.Closeable;
 import org.opengis.util.InternationalString;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Deprecable;
 
@@ -59,7 +60,7 @@ abstract strictfp class HTMLGenerator im
      * The number of space to add or remove in the {@linkplain #margin}
      * when new HTML elements are opened or closed.
      */
-    private static final int INDENTATION = 2;
+    private static final int INDENTATION = Constants.DEFAULT_INDENTATION;
 
     /**
      * Where to write the HTML page.

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -37,6 +37,14 @@ import org.apache.sis.util.Static;
  */
 public final class Constants extends Static {
     /**
+     * The default indentation value to use in various text formats (both WKT and XML).
+     * We use a small value (2 instead of 4) because OGC's XML are very verbose.
+     *
+     * @see org.apache.sis.setup.OptionKey#INDENTATION
+     */
+    public static final byte DEFAULT_INDENTATION = 2;
+
+    /**
      * The {@value} code space.
      */
     public static final String EPSG = "EPSG";

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -72,20 +72,20 @@ public class StreamWriterDelegate implem
 
     /** Forwards the call verbatim. */
     @Override
-    public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
-        out.writeEmptyElement(namespaceURI, localName);
+    public void writeEmptyElement(String localName) throws XMLStreamException {
+        out.writeEmptyElement(localName);
     }
 
     /** Forwards the call verbatim. */
     @Override
-    public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
-        out.writeEmptyElement(prefix, localName, namespaceURI);
+    public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
+        out.writeEmptyElement(namespaceURI, localName);
     }
 
     /** Forwards the call verbatim. */
     @Override
-    public void writeEmptyElement(String localName) throws XMLStreamException {
-        out.writeEmptyElement(localName);
+    public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+        out.writeEmptyElement(prefix, localName, namespaceURI);
     }
 
     /** Forwards the call verbatim. */

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -191,8 +191,10 @@ public final class Utilities extends Sta
         if (precision >= 0) {
             for (int i=0,n=0; i<length; i += n) {
                 if (--precision < 0) {
-                    // Found the amount of characters to keep. The 'n' variable can be
-                    // zero only if precision == 0, in which case the string is empty.
+                    /*
+                     * Found the amount of characters to keep. The 'n' variable can be
+                     * zero only if precision == 0, in which case the string is empty.
+                     */
                     if (n == 0) {
                         value = "";
                     } else {

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/setup/OptionKey.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -113,6 +113,8 @@ public class OptionKey<T> implements Ser
      * <p>If this option is not provided, then the default value is format specific.
      * That default is often, but not necessarily, the {@linkplain Charset#defaultCharset() platform default}.</p>
      *
+     * @see javax.xml.bind.Marshaller#JAXB_ENCODING
+     *
      * @since 0.4
      */
     public static final OptionKey<Charset> ENCODING = new OptionKey<>("ENCODING", Charset.class);
@@ -179,6 +181,27 @@ public class OptionKey<T> implements Ser
     public static final OptionKey<ByteBuffer> BYTE_BUFFER = new OptionKey<>("BYTE_BUFFER", ByteBuffer.class);
 
     /**
+     * The number of spaces to use for indentation when formatting text files in WKT or XML formats.
+     * A value of {@value org.apache.sis.io.wkt.WKTFormat#SINGLE_LINE} means to format the whole WKT
+     * or XML document on a single line without line feeds or indentation.
+     *
+     * <p>If this option is not provided, then the most typical default value used in Apache SIS is 2.
+     * Such small indentation value is used because XML documents defined by OGC standards tend to be
+     * verbose.</p>
+     *
+     * @see org.apache.sis.io.wkt.WKTFormat#SINGLE_LINE
+     * @see javax.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT
+     *
+     * @since 0.8
+     */
+    public static final OptionKey<Integer> INDENTATION = new OptionKey<>("INDENTATION", Integer.class);
+
+    /*
+     * Note: we do not provide a LINE_SEPARATOR option for now because we can not control the line separator
+     * in JDK's JAXB implementation, and Apache SIS provides an org.apache.sis.io.LineAppender alternative.
+     */
+
+    /**
      * The name of this key. For {@code OptionKey} instances, it shall be the name of the static constants.
      * For subclasses of {@code OptionKey}, there is no restriction.
      */

Added: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Implementation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Implementation.java?rev=1780633&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Implementation.java (added)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Implementation.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -0,0 +1,145 @@
+/*
+ * 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.xml;
+
+import javax.xml.bind.JAXBContext;
+
+
+/**
+ * Known JAXB implementations.
+ * This enumeration allows to set vendor-specific marshaller properties.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+enum Implementation {
+    /**
+     * JAXB implementation bundled in the JDK.
+     */
+    INTERNAL("com.sun.xml.internal.bind.indentString",
+             "com.sun.xml.internal.bind.namespacePrefixMapper",
+             "org.apache.sis.xml.OGCNamespacePrefixMapper"),
+
+    /**
+     * JAXB implementation provided in a separated JAR, used for instance by Glassfish.
+     */
+    ENDORSED("com.sun.xml.bind.indentString",
+             "com.sun.xml.bind.namespacePrefixMapper",
+             "org.apache.sis.xml.OGCNamespacePrefixMapper_Endorsed"),
+
+    /**
+     * Unrecognized implementation.
+     */
+    OTHER(null, null, null);
+
+    /**
+     * The prefix of property names which are provided in external (endorsed) implementation of JAXB.
+     * This is slightly different than the prefix used by the implementation bundled with the JDK 6,
+     * which is {@code "com.sun.xml.internal.bind"}.
+     */
+    private static final String ENDORSED_PREFIX = "com.sun.xml.bind.";
+
+    /**
+     * The prefix of property names which are provided in internal implementation of JAXB
+     * (the one bundled with the JDK 6).
+     */
+    private static final String INTERNAL_PREFIX = "com.sun.xml.internal.bind.";
+
+    /**
+     * The JAXB property for setting the indentation string, or {@code null} if none.
+     */
+    final String indentKey;
+
+    /**
+     * The JAXB property for setting the namespace prefix mapper, or {@code null} if none.
+     */
+    final String mapperKey;
+
+    /**
+     * The JAXB property for setting the namespace prefix mapper, or {@code null} if none.
+     */
+    final String mapper;
+
+    /**
+     * Creates a new enumeration value for a JAXB implementation.
+     */
+    private Implementation(final String indentKey, final String mapperKey, final String mapper) {
+        this.indentKey = indentKey;
+        this.mapperKey = mapperKey;
+        this.mapper    = mapper;
+    }
+
+    /**
+     * Detects if we are using the endorsed JAXB implementation (the one provided in separated JAR files)
+     * or the one bundled in JDK. We use the JAXB context package name as a criterion:
+     *
+     * <ul>
+     *   <li>JAXB endorsed JAR uses    {@code "com.sun.xml.bind.*"}</li>
+     *   <li>JAXB bundled in JDK uses  {@code "com.sun.xml.internal.bind.*"}</li>
+     * </ul>
+     *
+     * @param  context  the JAXB context for which to detect the implementation.
+     * @return the implementation, or {@code OTHER} if unknown.
+     */
+    public static Implementation detect(final JAXBContext context) {
+        if (context != null) {
+            final String classname = context.getClass().getName();
+            if (classname.startsWith(INTERNAL_PREFIX)) {
+                return INTERNAL;
+            } else if (classname.startsWith(ENDORSED_PREFIX)) {
+                return ENDORSED;
+            }
+        }
+        return OTHER;
+    }
+
+    /**
+     * Returns {@code false} if the given (un)marshaller property should be silently ignored.
+     * A value of {@code true} does not necessarily mean that the given property is supported,
+     * but that the caller should either support the property or throw an exception.
+     *
+     * <p>This method excludes the {@code "com.sun.xml.bind.*"} properties if the implementation
+     * is not {@link #ENDORSED} or {@link #INTERNAL}. We do not distinguish between the endorsed
+     * and internal namespaces since Apache SIS use only the endorsed namespace and let
+     * {@code org.apache.sis.xml.Pooled} do the conversion to internal namespace if needed.</p>
+     *
+     * @param  key  the property key to test.
+     * @return {@code false} if the given property should be silently ignored.
+     */
+    boolean filterProperty(final String key) {
+        // We user 'mapper' as a sentinel value for identifying INTERNAL and ENDORSED cases.
+        return (mapper != null) || !key.startsWith(ENDORSED_PREFIX);
+    }
+
+    /**
+     * Converts the given key from {@code "com.sun.xml.bind.*"} to {@code "com.sun.xml.internal.bind.*"} namespace.
+     * This method is invoked when the JAXB implementation is known to be the {@link #INTERNAL} one. We perform this
+     * conversion for allowing Apache SIS to ignore the difference between internal and endorsed JAXB.
+     *
+     * @param  key  the key that may potentially a endorsed JAXB key.
+     * @return the key as an internal JAXB key, or the given key unchanged if it is not an endorsed JAXB key.
+     */
+    static String toInternal(String key) {
+        if (key.startsWith(ENDORSED_PREFIX)) {
+            final StringBuilder buffer = new StringBuilder(key.length() + 10);
+            key = buffer.append(INTERNAL_PREFIX).append(key, ENDORSED_PREFIX.length(), key.length()).toString();
+        }
+        return key;
+    }
+}

Propchange: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Implementation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Implementation.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -32,7 +32,9 @@ import org.apache.sis.internal.system.De
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.jaxb.AdapterReplacement;
 import org.apache.sis.internal.jaxb.TypeRegistration;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.CharSequences;
 
 
 /**
@@ -66,11 +68,6 @@ import org.apache.sis.util.ArgumentCheck
  */
 public class MarshallerPool {
     /**
-     * The indentation string, fixed to 2 spaces instead of 4 because ISO/OGC XML are very verbose.
-     */
-    private static final String INDENTATION = "  ";
-
-    /**
      * Amount of nanoseconds to wait before to remove unused (un)marshallers.
      * This is a very approximative value: actual timeout will not be shorter,
      * but may be twice longer.
@@ -78,21 +75,19 @@ public class MarshallerPool {
     private static final long TIMEOUT = 15000000000L;           // 15 seconds.
 
     /**
-     * Kind of JAXB implementations.
-     */
-    private static final byte INTERNAL = 0, ENDORSED = 1, OTHER = 2;
-
-    /**
      * The JAXB context to use for creating marshaller and unmarshaller.
+     *
+     * @see #createMarshaller()
+     * @see #createUnmarshaller()
      */
-    private final JAXBContext context;
+    protected final JAXBContext context;
 
     /**
-     * {@link #INTERNAL} if the JAXB implementation is the one bundled in the JDK,
-     * {@link #ENDORSED} if the TAXB implementation is the endorsed JAXB (Glassfish), or
-     * {@link #OTHER} if unknown.
+     * {@code INTERNAL} if the JAXB implementation is the one bundled in the JDK,
+     * {@code ENDORSED} if the TAXB implementation is the endorsed JAXB (Glassfish), or
+     * {@code null} if unknown.
      */
-    private final byte implementation;
+    private final Implementation implementation;
 
     /**
      * The mapper between namespaces and prefix.
@@ -191,30 +186,12 @@ public class MarshallerPool {
         ArgumentChecks.ensureNonNull("context", context);
         this.context = context;
         replacements = DefaultFactories.createServiceLoader(AdapterReplacement.class);
-        /*
-         * Detects if we are using the endorsed JAXB implementation (i.e. the one provided in
-         * separated JAR files) or the one bundled in JDK 6. We use the JAXB context package
-         * name as a criterion:
-         *
-         *   JAXB endorsed JAR uses    "com.sun.xml.bind"
-         *   JAXB bundled in JDK uses  "com.sun.xml.internal.bind"
-         */
-        String classname = context.getClass().getName();
-        if (classname.startsWith("com.sun.xml.internal.bind.")) {
-            classname = "org.apache.sis.xml.OGCNamespacePrefixMapper";
-            implementation = INTERNAL;
-        } else if (classname.startsWith(Pooled.ENDORSED_PREFIX)) {
-            classname = "org.apache.sis.xml.OGCNamespacePrefixMapper_Endorsed";
-            implementation = ENDORSED;
-        } else {
-            classname = null;
-            implementation = OTHER;
-        }
+        implementation = Implementation.detect(context);
         /*
          * Prepares a copy of the property map (if any), then removes the
          * properties which are handled especially by this constructor.
          */
-        template = new PooledTemplate(properties, implementation == INTERNAL);
+        template = new PooledTemplate(properties, implementation);
         final Object rootNamespace = template.remove(XML.DEFAULT_NAMESPACE, "");
         /*
          * Instantiates the OGCNamespacePrefixMapper appropriate for the implementation
@@ -222,6 +199,7 @@ public class MarshallerPool {
          * usual ClassNotFoundException if the class was found but its parent class has
          * not been found.
          */
+        final String classname = implementation.mapper;
         if (classname == null) {
             mapper = null;
         } else try {
@@ -445,23 +423,23 @@ public class MarshallerPool {
      *
      * @return a new marshaller configured for formatting OGC/ISO XML.
      * @throws JAXBException if an error occurred while creating and configuring the marshaller.
+     *
+     * @see #context
+     * @see #acquireMarshaller()
      */
     protected Marshaller createMarshaller() throws JAXBException {
         final Marshaller marshaller = context.createMarshaller();
         marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
-        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
-        switch (implementation) {
-            case INTERNAL: {
-                marshaller.setProperty("com.sun.xml.internal.bind.namespacePrefixMapper", mapper);
-                marshaller.setProperty("com.sun.xml.internal.bind.indentString", INDENTATION);
-                break;
-            }
-            case ENDORSED: {
-                marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper);
-                marshaller.setProperty("com.sun.xml.bind.indentString", INDENTATION);
-                break;
-            }
-            // Do nothing for the OTHER case.
+        /*
+         * Note: we do not set the Marshaller.JAXB_ENCODING property because specification
+         * said that the default value is "UTF-8", which is what we want.
+         */
+        String key;
+        if ((key = implementation.mapperKey) != null) {
+            marshaller.setProperty(key, mapper);
+        }
+        if ((key = implementation.indentKey) != null) {
+            marshaller.setProperty(key, CharSequences.spaces(Constants.DEFAULT_INDENTATION));
         }
         synchronized (replacements) {
             for (final AdapterReplacement adapter : replacements) {
@@ -478,6 +456,9 @@ public class MarshallerPool {
      *
      * @return a new unmarshaller configured for parsing OGC/ISO XML.
      * @throws JAXBException if an error occurred while creating and configuring the unmarshaller.
+     *
+     * @see #context
+     * @see #acquireUnmarshaller()
      */
     protected Unmarshaller createUnmarshaller() throws JAXBException {
         final Unmarshaller unmarshaller = context.createUnmarshaller();

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -50,7 +50,7 @@ import org.apache.sis.internal.jaxb.Type
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.8
  * @module
  */
 abstract class Pooled {
@@ -61,21 +61,12 @@ abstract class Pooled {
     private static final String[] SCHEMA_KEYS = {"gmd"};
 
     /**
-     * The prefix of property names which are provided in external (endorsed) implementation of JAXB.
-     * This is slightly different than the prefix used by the implementation bundled with the JDK 6,
-     * which is {@code "com.sun.xml.internal.bind"}.
-     *
-     * @see #convertPropertyKey(String)
-     */
-    static final String ENDORSED_PREFIX = "com.sun.xml.bind.";
-
-    /**
      * {@code true} if the JAXB implementation is the one bundled in JDK 6, or {@code false}
      * if this is the external implementation provided as a JAR file in the endorsed directory.
      * If {@code true}, then an additional {@code "internal"} package name needs to be inserted
      * in the property keys.
      *
-     * @see #convertPropertyKey(String)
+     * @see Implementation#toInternal(String)
      */
     private final boolean internal;
 
@@ -179,7 +170,7 @@ abstract class Pooled {
     /**
      * Creates a {@link PooledTemplate}.
      *
-     * @param internal {@code true} if the JAXB implementation is the one bundled in JDK 6,
+     * @param internal  {@code true} if the JAXB implementation is the one bundled in JDK 6,
      *        or {@code false} if this is the external implementation provided as a JAR file
      *        in the endorsed directory.
      */
@@ -313,22 +304,6 @@ abstract class Pooled {
     }
 
     /**
-     * Converts a property key from the JAXB name to the underlying implementation name.
-     * This applies only to property keys in the {@code "com.sun.xml.bind"} namespace.
-     *
-     * @param  key  the JAXB property key.
-     * @return the property key to use.
-     */
-    private String convertPropertyKey(String key) {
-        if (internal && key.startsWith(ENDORSED_PREFIX)) {
-            final StringBuilder buffer = new StringBuilder(key.length() + 10);
-            key = buffer.append("com.sun.xml.internal.bind.")
-                    .append(key, ENDORSED_PREFIX.length(), key.length()).toString();
-        }
-        return key;
-    }
-
-    /**
      * A method which is common to both {@code Marshaller} and {@code Unmarshaller}.
      * It saves the initial state if it was not already done, but subclasses will
      * need to complete the work.
@@ -421,7 +396,9 @@ abstract class Pooled {
          * If we reach this point, the given name is not a SIS property. Try to handle
          * it as a (un)marshaller-specific property, after saving the previous value.
          */
-        name = convertPropertyKey(name);
+        if (internal) {
+            name = Implementation.toInternal(name);
+        }
         if (!initialProperties.containsKey(name)) {
             if (initialProperties.put(name, getStandardProperty(name)) != null) {
                 // Should never happen, unless on concurrent changes in a backgroung thread.
@@ -435,7 +412,7 @@ abstract class Pooled {
      * A method which is common to both {@code Marshaller} and {@code Unmarshaller}.
      */
     @SuppressWarnings("ReturnOfCollectionOrArrayField")     // Because unmodifiable.
-    public final Object getProperty(final String name) throws PropertyException {
+    public final Object getProperty(String name) throws PropertyException {
         switch (name) {
             case XML.LOCALE:           return locale;
             case XML.TIMEZONE:         return timezone;
@@ -462,7 +439,10 @@ abstract class Pooled {
             }
             case TypeRegistration.ROOT_ADAPTERS: return (rootAdapters != null) ? rootAdapters.clone() : null;
             default: {
-                return getStandardProperty(convertPropertyKey(name));
+                if (internal) {
+                    name = Implementation.toInternal(name);
+                }
+                return getStandardProperty(name);
             }
         }
     }

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/PooledTemplate.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/PooledTemplate.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/PooledTemplate.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/PooledTemplate.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -44,11 +44,14 @@ final class PooledTemplate extends Poole
      *                    {@code false} if this is the external implementation provided as a JAR file
      *                    in the endorsed directory.
      */
-    PooledTemplate(final Map<String,?> properties, final boolean internal) throws PropertyException {
-        super(internal);
+    PooledTemplate(final Map<String,?> properties, final Implementation implementation) throws PropertyException {
+        super(implementation == Implementation.INTERNAL);
         if (properties != null) {
             for (final Map.Entry<String,?> entry : properties.entrySet()) {
-                setProperty(entry.getKey(), entry.getValue());
+                final String key = entry.getKey();
+                if (implementation.filterProperty(key)) {
+                    setProperty(key, entry.getValue());
+                }
             }
         }
     }

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -102,6 +102,7 @@ public final class XML extends Static {
      * {@link org.apache.sis.metadata.iso.DefaultMetadata#setLanguage(Locale) setLanguage(Locale)}
      * method will have precedence over this property. This behavior is compliant with INSPIRE rules.
      *
+     * @see org.apache.sis.setup.OptionKey#LOCALE
      * @see Marshaller#setProperty(String, Object)
      * @see org.apache.sis.metadata.iso.DefaultMetadata#setLanguage(Locale)
      */
@@ -115,6 +116,8 @@ public final class XML extends Static {
      * <div class="section">Default behavior</div>
      * If this property is never set, then (un)marshalling will use the
      * {@linkplain TimeZone#getDefault() default timezone}.
+     *
+     * @see org.apache.sis.setup.OptionKey#TIMEZONE
      */
     public static final String TIMEZONE = "org.apache.sis.xml.timezone";
 

Modified: sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -59,6 +59,11 @@ public final class Resources extends Ind
         }
 
         /**
+         * Can not use UCAR library for NetCDF format. Fallback on Apache SIS implementation.
+         */
+        public static final short CanNotUseUCAR = 4;
+
+        /**
          * Dimension “{2}” declared by attribute “{1}” is not found in the “{0}” file.
          */
         public static final short DimensionNotFound_3 = 1;

Modified: sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.properties?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.properties [ISO-8859-1] Sat Jan 28 04:48:30 2017
@@ -19,6 +19,7 @@
 # Resources in this file are for "sis-netcdf" usage only and should not be used by any other module.
 # For resources shared by all modules in the Apache SIS project, see "org.apache.sis.util.resources" package.
 #
+CanNotUseUCAR                     = Can not use UCAR library for NetCDF format. Fallback on Apache SIS implementation.
 DimensionNotFound_3               = Dimension \u201c{2}\u201d declared by attribute \u201c{1}\u201d is not found in the \u201c{0}\u201d file.
 UnexpectedDimensionForVariable_4  = Variable \u201c{1}\u201d in file \u201c{0}\u201d has a dimension \u201c{3}\u201d while we expected \u201c{2}\u201d.
 VariableNotFound_2                = Variable \u201c{1}\u201d is not found in the \u201c{0}\u201d file.

Modified: sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_fr.properties?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_fr.properties [ISO-8859-1] Sat Jan 28 04:48:30 2017
@@ -24,6 +24,7 @@
 #   U+202F NARROW NO-BREAK SPACE  before  ; ! and ?
 #   U+00A0 NO-BREAK SPACE         before  :
 #
+CanNotUseUCAR                     = Ne peut pas utiliser la biblioth\u00e8que de l\u2019UCAR pour le format NetCDF. L\u2019impl\u00e9mentation de Apache SIS sera utilis\u00e9e \u00e0 la place.
 DimensionNotFound_3               = La dimension \u00ab\u202f{2}\u202f\u00bb d\u00e9clar\u00e9e par l\u2019attribut \u00ab\u202f{1}\u202f\u00bb n\u2019a pas \u00e9t\u00e9 trouv\u00e9e dans le fichier \u00ab\u202f{0}\u202f\u00bb.
 UnexpectedDimensionForVariable_4  = La variable \u00ab\u202f{1}\u202f\u00bb dans le fichier \u00ab\u202f{0}\u202f\u00bb a une dimension \u00ab\u202f{3}\u202f\u00bb alors qu\u2019on attendait \u00ab\u202f{2}\u202f\u00bb.
 VariableNotFound_2                = La variable \u00ab\u202f{1}\u202f\u00bb n\u2019a pas \u00e9t\u00e9 trouv\u00e9e dans le fichier \u00ab\u202f{0}\u202f\u00bb.

Modified: sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStoreProvider.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.storage.netcdf;
 
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
@@ -25,6 +27,7 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.UndeclaredThrowableException;
 import org.apache.sis.internal.netcdf.Decoder;
+import org.apache.sis.internal.netcdf.Resources;
 import org.apache.sis.internal.netcdf.impl.ChannelDecoder;
 import org.apache.sis.internal.netcdf.ucar.DecoderWrapper;
 import org.apache.sis.internal.storage.io.ChannelDataInput;
@@ -136,7 +139,7 @@ public class NetcdfStoreProvider extends
      * @throws DataStoreException if an I/O error occurred.
      */
     @Override
-    public ProbeResult probeContent(StorageConnector connector) throws DataStoreException {
+    public ProbeResult probeContent(final StorageConnector connector) throws DataStoreException {
         int     version     = 0;
         boolean hasVersion  = false;
         boolean isSupported = false;
@@ -164,7 +167,7 @@ public class NetcdfStoreProvider extends
         if (!isSupported) {
             final String path = connector.getStorageAs(String.class);
             if (path != null) {
-                ensureInitialized();
+                ensureInitialized(false);
                 final Method method = canOpenFromPath;
                 if (method != null) try {
                     isSupported = (Boolean) method.invoke(null, path);
@@ -275,7 +278,7 @@ public class NetcdfStoreProvider extends
     private static Decoder createByReflection(final WarningListeners<?> listeners, final Object input, final boolean isUCAR)
             throws IOException, DataStoreException
     {
-        ensureInitialized();
+        ensureInitialized(true);
         /*
          * Get the appropriate constructor for the isUCAR argument. This constructor will be null
          * if the above code failed to load the UCAR library. Otherwise, instantiate the wrapper.
@@ -300,17 +303,23 @@ public class NetcdfStoreProvider extends
             if (cause instanceof DataStoreException) throw (DataStoreException) cause;
             if (cause instanceof RuntimeException)   throw (RuntimeException)   cause;
             if (cause instanceof Error)              throw (Error)              cause;
-            throw new UndeclaredThrowableException(cause); // Should never happen actually.
+            throw new UndeclaredThrowableException(cause);  // Should never happen actually.
         } catch (ReflectiveOperationException e) {
-            throw new AssertionError(e); // Should never happen (shall be verified by the JUnit tests).
+            throw new AssertionError(e);                    // Should never happen (shall be verified by the JUnit tests).
         }
     }
 
     /**
      * Gets the {@link java.lang.Class} that represent the {@link ucar.nc2.NetcdfFile type}.
+     *
+     * @param  open  {@code true} if this method is invoked (indirectly) from the {@link #open(StorageConnector)}
+     *               method, or {@code false} if invoked from the {@link #probeContent(StorageConnector)} method.
+     *               This is used only for logging message.
      */
-    private static void ensureInitialized() {
+    private static void ensureInitialized(final boolean open) {
         if (netcdfFileClass == null) {
+            Level  severity = null;                             // Logging level to use in case of failure.
+            Throwable cause = null;                             // Cause of the failure (may stay null).
             synchronized (NetcdfStoreProvider.class) {
                 /*
                  * No double-check because it is not a big deal if the constructors are fetched twice.
@@ -318,29 +327,50 @@ public class NetcdfStoreProvider extends
                  */
                 try {
                     netcdfFileClass = Class.forName(UCAR_CLASSNAME);
+                    canOpenFromPath = netcdfFileClass.getMethod("canOpen", String.class);
+                    if (canOpenFromPath.getReturnType() == Boolean.TYPE) {
+                        /*
+                         * At this point we found the class and method from UCAR API. Now get the Apache SIS wrapper
+                         * using reflection for avoiding "hard" dependency from this provider to the UCAR library.
+                         */
+                        final Class<? extends Decoder> wrapper =
+                                Class.forName("org.apache.sis.internal.netcdf.ucar.DecoderWrapper").asSubclass(Decoder.class);
+                        final Class<?>[] parameterTypes = new Class<?>[] {WarningListeners.class, netcdfFileClass};
+                        createFromUCAR = wrapper.getConstructor(parameterTypes);
+                        parameterTypes[1] = String.class;
+                        createFromPath = wrapper.getConstructor(parameterTypes);
+                        return;                                                                         // Success
+                    }
                 } catch (ClassNotFoundException e) {
-                    netcdfFileClass = Void.TYPE;
-                    return;
-                }
-                try {
                     /*
-                     * UCAR API.
+                     * Happen if the UCAR library is not on the classpath. Log at the configuration level without
+                     * reporting the exception (for avoiding scaring logs) because this is a typical use case.
                      */
-                    canOpenFromPath = netcdfFileClass.getMethod("canOpen", String.class);
-                    assert canOpenFromPath.getReturnType() == Boolean.TYPE;
+                    severity = Level.CONFIG;
+                } catch (NoClassDefFoundError | ReflectiveOperationException e) {
                     /*
-                     * SIS Wrapper API.
+                     * NoClassDefFoundError may happen if the UCAR class has been found but one of its dependencies
+                     * is missing (for example SLF4J). Log at the warning level because the user probably wanted to
+                     * use the UCAR library.
+                     *
+                     * ReflectiveOperationException should never happen because API compatibility shall be verified
+                     * by the JUnit tests. If it happen anyway  (for example because the user puts on his classpath
+                     * a different version of the NetCDF library than the one we tested), report a warning.
                      */
-                    final Class<? extends Decoder> wrapper =
-                            Class.forName("org.apache.sis.internal.netcdf.ucar.DecoderWrapper").asSubclass(Decoder.class);
-                    final Class<?>[] parameterTypes = new Class<?>[] {WarningListeners.class, netcdfFileClass};
-                    createFromUCAR = wrapper.getConstructor(parameterTypes);
-                    parameterTypes[1] = String.class;
-                    createFromPath = wrapper.getConstructor(parameterTypes);
-                } catch (ReflectiveOperationException e) {
-                    throw new AssertionError(e);        // Should never happen (shall be verified by the JUnit tests).
+                    severity = Level.WARNING;
+                    cause = e;
                 }
+                /*
+                 * At this point we failed to use the UCAR library. Remember that failure while we are still in the
+                 * synchronized block, then log a message outside the synchronized block.
+                 */
+                reset();
+                netcdfFileClass = Void.TYPE;
             }
+            final LogRecord record = Resources.forLocale(null).getLogRecord(severity, Resources.Keys.CanNotUseUCAR);
+            record.setThrown(cause);
+            record.setLoggerName(Modules.NETCDF);
+            Logging.log(NetcdfStoreProvider.class, open ? "open" : "probeContent", record);
         }
     }
 

Added: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/FormattedWriter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/FormattedWriter.java?rev=1780633&view=auto
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/FormattedWriter.java (added)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/FormattedWriter.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.storage.xml.stream;
+
+import java.util.Arrays;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.stream.XMLStreamException;
+import org.apache.sis.internal.util.StreamWriterDelegate;
+
+
+/**
+ * Adds indentation to a XML output.
+ *
+ * <div class="note"><b>Design note:</b>
+ * an alternative approach would have been to provide {@code startIdentation()} and {@code endIndentation()}
+ * convenience methods in {@link StaxStreamWriter}, and let subclasses perform their own formatting. It would
+ * reduce the need to try to guess some formatting aspects (e.g. whether to format on a single line or not).
+ * However that approach does not integrate very well with JAXB; the {@code Marshaller.JAXB_FORMATTED_OUTPUT}
+ * property seems to be ignored when marshalling a fragment using {@code XMLStreamWriter}. Even if that property
+ * was supported, there is no standard way as of JDK8 to tell to JAXB to begin the indentation at some level
+ * (for taking in account the indentation of the elements containing the fragment to marshal with JAXB).</div>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ */
+final class FormattedWriter extends StreamWriterDelegate {
+    /**
+     * A predefined amount of spaces, used by {@link #indent()} for writing a greater amount of
+     * spaces in one call to {@link XMLStreamWriter#writeCharacters(char[], int, int)} methods.
+     */
+    private static final char[] SPACES = new char[12];
+    static {
+        Arrays.fill(SPACES, ' ');
+    }
+
+    /**
+     * The line separator to use.
+     */
+    private final String lineSeparator;
+
+    /**
+     * Number of spaces to add for each new indentation level.
+     */
+    private final int indentation;
+
+    /**
+     * The number of spaces to write before next XML start tags. This value is incremented or decremented
+     * by the {@link #indentation} value every time a XML start element or end element is encountered.
+     */
+    private int margin;
+
+    /**
+     * {@code true} if the last {@code writeStartElement(…)} method invocation has not yet been followed by a
+     * {@code writeEndElement(…)} method invocation. In such case, the start and end tags can be written on
+     * the same line.
+     */
+    private boolean inline;
+
+    /**
+     * Creates a new XML writer with indentation.
+     *
+     * @param  out  where to write the XML.
+     */
+    FormattedWriter(final XMLStreamWriter out, final int indentation) throws XMLStreamException {
+        super(out);
+        this.indentation = indentation;
+        lineSeparator = System.lineSeparator();
+    }
+
+    /**
+     * Writes a line separator, then the given amount of spaces.
+     */
+    private void indent() throws XMLStreamException {
+        int n = margin;
+        out.writeCharacters(lineSeparator);
+        final int length = SPACES.length;
+        while (n > length) {
+            out.writeCharacters(SPACES, 0, length);
+            n -= length;
+        }
+        out.writeCharacters(SPACES, 0, n);
+    }
+
+    /**
+     * Appends indentation before an empty tag.
+     */
+    private void emptyIndent() throws XMLStreamException {
+        indent();
+        inline = false;
+    }
+
+    /**
+     * Increases the indentation level and appends indentation before a start tag.
+     */
+    final void startIndent() throws XMLStreamException {
+        indent();
+        inline = true;
+        margin += indentation;
+    }
+
+    /**
+     * Appends indentation, then forwards the call verbatim.
+     */
+    @Override
+    public void writeStartElement(String localName) throws XMLStreamException {
+        startIndent();
+        out.writeStartElement(localName);
+    }
+
+    /**
+     * Appends indentation, then forwards the call verbatim.
+     */
+    @Override
+    public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
+        startIndent();
+        out.writeStartElement(namespaceURI, localName);
+    }
+
+    /**
+     * Appends indentation, then forwards the call verbatim.
+     */
+    @Override
+    public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+        startIndent();
+        out.writeStartElement(prefix, localName, namespaceURI);
+    }
+
+    /**
+     * Appends indentation, then forwards the call verbatim.
+     */
+    @Override
+    public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
+        emptyIndent();
+        out.writeEmptyElement(namespaceURI, localName);
+    }
+
+    /**
+     * Appends indentation, then forwards the call verbatim.
+     */
+    @Override
+    public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+        emptyIndent();
+        out.writeEmptyElement(prefix, localName, namespaceURI);
+    }
+
+    /**
+     * Appends indentation, then forwards the call verbatim.
+     */
+    @Override
+    public void writeEmptyElement(String localName) throws XMLStreamException {
+        emptyIndent();
+        out.writeEmptyElement(localName);
+    }
+
+    /**
+     * Appends indentation if the value is not inline, then forwards the call verbatim.
+     */
+    @Override
+    public void writeEndElement() throws XMLStreamException {
+        margin -= indentation;
+        if (!inline) indent();
+        inline = false;
+        out.writeEndElement();
+    }
+
+    /**
+     * Appends a new line after the document.
+     */
+    @Override
+    public void writeEndDocument() throws XMLStreamException {
+        out.writeCharacters(lineSeparator);
+        out.writeEndDocument();
+        out.writeCharacters(lineSeparator);
+    }
+}

Propchange: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/FormattedWriter.java
------------------------------------------------------------------------------
    svn:eol-style = native

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

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxDataStore.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -43,12 +43,16 @@ import org.apache.sis.internal.storage.i
 import org.apache.sis.internal.storage.io.IOUtilities;
 import org.apache.sis.internal.storage.io.Markable;
 import org.apache.sis.internal.util.AbstractMap;
+import org.apache.sis.internal.util.Constants;
+import org.apache.sis.internal.util.Utilities;
+import org.apache.sis.io.wkt.WKTFormat;
 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;
 import org.apache.sis.util.logging.WarningListener;
+import org.apache.sis.util.Debug;
 
 
 /**
@@ -171,6 +175,12 @@ public abstract class StaxDataStore exte
     private final ChannelFactory channelFactory;
 
     /**
+     * The number of spaces to use in indentations, or -1 if the XML output should not be formatted.
+     * This is ignored at reading time.
+     */
+    private final byte indentation;
+
+    /**
      * 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.
      */
@@ -191,10 +201,14 @@ public abstract class StaxDataStore exte
      */
     protected StaxDataStore(final StaxDataStoreProvider provider, final StorageConnector connector) throws DataStoreException {
         super(provider, connector);
+        final Integer indent;
         storage         = connector.getStorage();
         locale          = connector.getOption(OptionKey.LOCALE);
         timezone        = connector.getOption(OptionKey.TIMEZONE);
         encoding        = connector.getOption(OptionKey.ENCODING);
+        indent          = connector.getOption(OptionKey.INDENTATION);
+        indentation     = (indent == null) ? Constants.DEFAULT_INDENTATION
+                                           : (byte) Math.max(WKTFormat.SINGLE_LINE, Math.min(120, indent));
         configuration   = new Config();
         storageToWriter = OutputType.forType(storage.getClass());
         storageToReader = InputType.forType(storage.getClass());
@@ -341,6 +355,15 @@ public abstract class StaxDataStore exte
         public final Class<Object> getSourceClass() {
             return Object.class;
         }
+
+        /**
+         * Do not format all properties for avoiding a never-ending loop.
+         */
+        @Debug
+        @Override
+        public String toString() {
+            return Utilities.toString(getClass(), "locale", locale, "timezone", timezone);
+        }
     }
 
     /**
@@ -544,7 +567,10 @@ public abstract class StaxDataStore exte
                 mark();
             }
         }
-        final XMLStreamWriter writer = type.create(this, outputOrFile);
+        XMLStreamWriter writer = type.create(this, outputOrFile);
+        if (indentation >= 0) {
+            writer = new FormattedWriter(writer, indentation);
+        }
         target.stream = output;
         state = WRITING;
         return writer;

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxStreamWriter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxStreamWriter.java?rev=1780633&r1=1780632&r2=1780633&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxStreamWriter.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/xml/stream/StaxStreamWriter.java [UTF-8] Sat Jan 28 04:48:30 2017
@@ -144,7 +144,7 @@ public abstract class StaxStreamWriter e
     public void writeStartDocument() throws Exception {
         final Charset encoding = owner.encoding;
         if (encoding != null) {
-            writer.writeStartDocument(encoding.name());
+            writer.writeStartDocument(encoding.name(), null);
         } else {
             writer.writeStartDocument();
         }
@@ -293,6 +293,11 @@ public abstract class StaxStreamWriter e
         if (m == null) {
             m = getMarshallerPool().acquireMarshaller();
             m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
+            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);     // Formatting will be done by FormattedWriter.
+            final Charset encoding = owner.encoding;
+            if (encoding != null) {
+                m.setProperty(Marshaller.JAXB_ENCODING, encoding.name());
+            }
             for (final Map.Entry<String,?> entry : ((Map<String,?>) owner.configuration).entrySet()) {
                 m.setProperty(entry.getKey(), entry.getValue());
             }
@@ -307,7 +312,7 @@ public abstract class StaxStreamWriter e
         }
         marshaller = null;
         m.marshal(new JAXBElement<>(qn, type, object), out);
-        marshaller = m;                 // Allow reuse or recycling only on success.
+        marshaller = m;                                                   // Allow reuse or recycling only on success.
     }
 
     /**



Mime
View raw message