sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1774642 - in /sis/branches/JDK8: core/sis-utility/src/main/java/org/apache/sis/internal/util/ core/sis-utility/src/main/java/org/apache/sis/setup/ core/sis-utility/src/main/java/org/apache/sis/util/logging/ core/sis-utility/src/main/java/o...
Date Fri, 16 Dec 2016 17:55:57 GMT
Author: desruisseaux
Date: Fri Dec 16 17:55:56 2016
New Revision: 1774642

URL: http://svn.apache.org/viewvc?rev=1774642&view=rev
Log:
GPX reader take Locale, TimeZone, WarningListeners and namespace in account.
Make other stores ready for the eventuality where DataStore constructor would take more information from the StorageConnector.
Specify the expected type when unmarshalling a document part with JAXB.

Modified:
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/UnmodifiableArrayList.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/util/logging/WarningListeners.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.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/XML.java
    sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
    sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
    sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java
    sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXStore.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStream.java
    sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/UnmodifiableArrayList.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/UnmodifiableArrayList.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/UnmodifiableArrayList.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/UnmodifiableArrayList.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -19,13 +19,12 @@ package org.apache.sis.internal.util;
 import java.io.Serializable;
 import java.util.AbstractList;
 import java.util.Arrays;
+import java.util.Objects;
+import java.util.RandomAccess;
 import java.lang.reflect.Array;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.collection.CheckedContainer;
 
-// Branch-dependent imports
-import java.util.Objects;
-
 
 /**
  * An unmodifiable view of an array. Invoking
@@ -55,14 +54,14 @@ import java.util.Objects;
  * <p>Note that the public API, {@link org.apache.sis.util.collection.Containers#unmodifiableList(Object[])},
  * returns {@code List<? extends E>}, which is okay.</p>
  *
- * @param <E> The type of elements in the list.
+ * @param  <E>  the type of elements in the list.
  *
  * @author  Martin Desruisseaux (IRD)
  * @since   0.3
  * @version 0.3
  * @module
  */
-public class UnmodifiableArrayList<E> extends AbstractList<E> implements CheckedContainer<E>, Serializable {
+public class UnmodifiableArrayList<E> extends AbstractList<E> implements RandomAccess, CheckedContainer<E>, Serializable {
     /**
      * For compatibility with different versions.
      */
@@ -89,7 +88,7 @@ public class UnmodifiableArrayList<E> ex
      * Callers <strong>must</strong> ensure that the type of array elements in exactly {@code E},
      * not a subtype of {@code E}. See class javadoc for more information.
      *
-     * @param array The array to wrap.
+     * @param array the array to wrap.
      */
     protected UnmodifiableArrayList(final E[] array) {                          // NOT "E..." - see javadoc.
         this.array = Objects.requireNonNull(array);
@@ -110,10 +109,9 @@ public class UnmodifiableArrayList<E> ex
      * the caller to instantiate the array explicitely, in order to make sure that the array type is
      * the intended one.</p>
      *
-     * @param  <E> The type of elements in the list.
-     * @param  array The array to wrap, or {@code null} if none.
-     * @return The given array wrapped in an unmodifiable list, or {@code null} if the given
-     *         array was null.
+     * @param  <E>    the type of elements in the list.
+     * @param  array  the array to wrap, or {@code null} if none.
+     * @return the given array wrapped in an unmodifiable list, or {@code null} if the given array was null.
      */
     public static <E> UnmodifiableArrayList<E> wrap(final E[] array) {          // NOT "E..." - see javadoc.
         return (array != null) ? new UnmodifiableArrayList<>(array) : null;
@@ -134,11 +132,11 @@ public class UnmodifiableArrayList<E> ex
      * should use {@link org.apache.sis.util.collection.Containers#unmodifiableList(Object[])} instead.
      * See class javadoc for more information.
      *
-     * @param  <E>   The type of elements in the list.
-     * @param  array The array to wrap.
-     * @param  lower Low endpoint (inclusive) of the sublist.
-     * @param  upper High endpoint (exclusive) of the sublist.
-     * @return The given array wrapped in an unmodifiable list.
+     * @param  <E>    the type of elements in the list.
+     * @param  array  the array to wrap.
+     * @param  lower  low endpoint (inclusive) of the sublist.
+     * @param  upper  high endpoint (exclusive) of the sublist.
+     * @return the given array wrapped in an unmodifiable list.
      */
     public static <E> UnmodifiableArrayList<E> wrap(final E[] array, final int lower, final int upper) {
         if (lower == 0 && upper == array.length) {
@@ -151,7 +149,7 @@ public class UnmodifiableArrayList<E> ex
      * Returns the element type of the wrapped array. The default implementation returns
      * <code>array.getClass().{@linkplain Class#getComponentType() getComponentType()}</code>.
      *
-     * @return The type of elements in the list.
+     * @return the type of elements in the list.
      */
     @Override
     public Class<E> getElementType() {
@@ -170,7 +168,7 @@ public class UnmodifiableArrayList<E> ex
     /**
      * Returns the list size.
      *
-     * @return The size of this list.
+     * @return the size of this list.
      */
     @Override
     public int size() {
@@ -188,7 +186,7 @@ public class UnmodifiableArrayList<E> ex
      * greater value is not necessarily more memory consuming, since the backing array
      * may be shared by many sublists.</p>
      *
-     * @return The length of the backing array.
+     * @return the length of the backing array.
      */
     public final int arraySize() {
         return array.length;
@@ -197,8 +195,8 @@ public class UnmodifiableArrayList<E> ex
     /**
      * Returns the element at the specified index.
      *
-     * @param  index The index of the element to get.
-     * @return The element at the given index.
+     * @param  index  the index of the element to get.
+     * @return the element at the given index.
      */
     @Override
     public E get(final int index) {
@@ -209,8 +207,8 @@ public class UnmodifiableArrayList<E> ex
      * Returns the index in this list of the first occurrence of the specified element,
      * or -1 if the list does not contain the element.
      *
-     * @param object The element to search for.
-     * @return The index of the first occurrence of the given object, or {@code -1}.
+     * @param  object  the element to search for.
+     * @return the index of the first occurrence of the given object, or {@code -1}.
      */
     @Override
     public int indexOf(final Object object) {
@@ -236,8 +234,8 @@ public class UnmodifiableArrayList<E> ex
      * Returns the index in this list of the last occurrence of the specified element,
      * or -1 if the list does not contain the element.
      *
-     * @param object The element to search for.
-     * @return The index of the last occurrence of the given object, or {@code -1}.
+     * @param  object  the element to search for.
+     * @return the index of the last occurrence of the given object, or {@code -1}.
      */
     @Override
     public int lastIndexOf(final Object object) {
@@ -262,7 +260,7 @@ public class UnmodifiableArrayList<E> ex
     /**
      * Returns {@code true} if this list contains the specified element.
      *
-     * @param object The element to check for existence.
+     * @param  object  the element to check for existence.
      * @return {@code true} if this collection contains the given element.
      */
     @Override
@@ -289,10 +287,10 @@ public class UnmodifiableArrayList<E> ex
      * Returns a view of the portion of this list between the specified
      * {@code lower}, inclusive, and {@code upper}, exclusive.
      *
-     * @param  lower Low endpoint (inclusive) of the sublist.
-     * @param  upper High endpoint (exclusive) of the sublist.
-     * @return A view of the specified range within this list.
-     * @throws IndexOutOfBoundsException If the lower or upper value are out of bounds.
+     * @param  lower  low endpoint (inclusive) of the sublist.
+     * @param  upper  high endpoint (exclusive) of the sublist.
+     * @return a view of the specified range within this list.
+     * @throws IndexOutOfBoundsException if the lower or upper value are out of bounds.
      *
      * @see #wrap(Object[], int, int)
      */
@@ -307,7 +305,7 @@ public class UnmodifiableArrayList<E> ex
     /**
      * A view over a portion of {@link UnmodifiableArrayList}.
      *
-     * @param <E> The type of elements in the list.
+     * @param  <E>  the type of elements in the list.
      *
      * @author  Martin Desruisseaux (Geomatys)
      * @since   0.3
@@ -377,7 +375,7 @@ public class UnmodifiableArrayList<E> ex
      * This is not what {@code ArrayList} does, but is not forbidden by {@link java.util.List#toArray()} javadoc
      * neither.
      *
-     * @return A copy of the wrapped array.
+     * @return a copy of the wrapped array.
      */
     @Override
     public E[] toArray() {
@@ -388,9 +386,9 @@ public class UnmodifiableArrayList<E> ex
      * Copies the backing array in the given one if the list fits in the given array.
      * If the list does not fit in the given array, returns the collection in a new array.
      *
-     * @param  <T>   The type of array element.
-     * @param  dest  The array where to copy the elements if the list can fits in the array.
-     * @return The given array, or a newly created array if this list is larger than the given array.
+     * @param  <T>   the type of array element.
+     * @param  dest  the array where to copy the elements if the list can fits in the array.
+     * @return the given array, or a newly created array if this list is larger than the given array.
      */
     @Override
     @SuppressWarnings("unchecked")
@@ -406,7 +404,7 @@ public class UnmodifiableArrayList<E> ex
                  */
                 dest = (T[]) Array.newInstance(dest.getClass().getComponentType(), size);
             } else {
-                dest[size] = null; // Required by Collection.toArray(T[]) javadoc.
+                dest[size] = null;              // Required by Collection.toArray(T[]) javadoc.
             }
         }
         System.arraycopy(array, lower(), dest, 0, size);
@@ -416,7 +414,7 @@ public class UnmodifiableArrayList<E> ex
     /**
      * Compares this list with the given object for equality.
      *
-     * @param  object The object to compare with this list.
+     * @param  object  the object to compare with this list.
      * @return {@code true} if the given object is equal to this list.
      */
     @Override

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=1774642&r1=1774641&r2=1774642&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] Fri Dec 16 17:55:56 2016
@@ -20,16 +20,16 @@ import java.util.Map;
 import java.util.HashMap;
 import java.nio.ByteBuffer;
 import java.nio.charset.Charset;
+import java.nio.file.OpenOption;
+import java.nio.file.StandardOpenOption;
 import java.io.Serializable;
 import java.io.ObjectStreamException;
+import java.util.Locale;
+import java.util.TimeZone;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.internal.system.Modules;
 
-// Branch-dependent imports
-import java.nio.file.OpenOption;
-import java.nio.file.StandardOpenOption;
-
 
 /**
  * Keys in a map of options for configuring various services
@@ -64,7 +64,7 @@ import java.nio.file.StandardOpenOption;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.4
+ * @version 0.8
  * @module
  */
 public class OptionKey<T> implements Serializable {
@@ -74,13 +74,44 @@ public class OptionKey<T> implements Ser
     private static final long serialVersionUID = -7580514229639750246L;
 
     /**
+     * The locale to use for locale-sensitive data. This option determines the language to use for writing
+     * {@link org.apache.sis.util.iso.AbstractInternationalString international strings} when the target
+     * storage support only one language. It may also control number and date patterns in some file formats
+     * like Comma Separated Values (CSV). However most data formats will ignore this locale.
+     *
+     * <p>This option is <strong>not</strong> for the locale of logging or warning messages. Messages
+     * locale is rather controlled by {@link org.apache.sis.storage.DataStore#setLocale(Locale)}.</p>
+     *
+     * @see org.apache.sis.xml.XML#LOCALE
+     *
+     * @since 0.8
+     */
+    public static final OptionKey<Locale> LOCALE = new OptionKey<>("LOCALE", Locale.class);
+
+    /**
+     * The timezone to use when parsing or formatting dates and times without explicit timezone.
+     * If this option is not provided, then the default value is format specific.
+     * That default is often, but not necessarily, the {@linkplain TimeZone#getDefault() platform default}.
+     *
+     * <div class="warning"><b>Upcoming API change — Java time API</b><br>
+     * The type may be changed to {@link java.time.ZoneId} when Apache SIS will target Java 8.
+     * This change may be applied in synchronization with GeoAPI 4.0.
+     * </div>
+     *
+     * @see org.apache.sis.xml.XML#TIMEZONE
+     *
+     * @since 0.8
+     */
+    public static final OptionKey<TimeZone> TIMEZONE = new OptionKey<>("TIMEZONE", TimeZone.class);
+
+    /**
      * The character encoding of document content.
      * This option can be used when the file to read does not describe itself its encoding.
      * For example this option can be used when reading plain text files, but is ignored when
      * reading XML files having a {@code <?xml version="1.0" encoding="…"?>} declaration.
      *
      * <p>If this option is not provided, then the default value is format specific.
-     * That default is often, but not necessarily, the {@link Charset#defaultCharset() platform default}.</p>
+     * That default is often, but not necessarily, the {@linkplain Charset#defaultCharset() platform default}.</p>
      *
      * @since 0.4
      */
@@ -273,7 +304,7 @@ public class OptionKey<T> implements Ser
      * Resolves this option key on deserialization. This method is invoked
      * only for instance of the exact {@code OptionKey} class, not subclasses.
      *
-     * @return  the unique {@code OptionKey} instance.
+     * @return the unique {@code OptionKey} instance.
      * @throws ObjectStreamException required by specification but should never be thrown.
      */
     private Object readResolve() throws ObjectStreamException {

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/logging/WarningListeners.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.util.logging;
 
+import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -25,6 +27,7 @@ import org.apache.sis.util.Localized;
 import org.apache.sis.util.Exceptions;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.util.UnmodifiableArrayList;
 
 
 /**
@@ -278,6 +281,22 @@ public class WarningListeners<S> impleme
     }
 
     /**
+     * Returns all registered warning listeners, or an empty list if none.
+     * This method returns an unmodifiable snapshot of the listener list at the time this method is invoked.
+     *
+     * @return immutable list of all registered warning listeners.
+     *
+     * @since 0.8
+     */
+    public List<WarningListener<? super S>> getListeners() {
+        final WarningListener<? super S>[] current;
+        synchronized (this) {
+            current = listeners;
+        }
+        return (current != null) ? UnmodifiableArrayList.wrap(current) : Collections.emptyList();
+    }
+
+    /**
      * Returns {@code true} if this object contains at least one listener.
      *
      * @return {@code true} if this object contains at least one listener, {@code false} otherwise.

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -55,20 +55,25 @@ public abstract class MarshalContext {
      * A {@code null} value means that the locale is unspecified. Callers are encouraged
      * to use the root locale as the default value, but some flexibility is allowed.
      *
-     * @return The locale for the XML fragment being (un)marshalled, or {@code null} is unspecified.
+     * @return the locale for the XML fragment being (un)marshalled, or {@code null} is unspecified.
      *
      * @see org.apache.sis.util.iso.DefaultInternationalString#toString(Locale)
      */
     public abstract Locale getLocale();
 
     /**
-     * Returns the timezone to use for (un)marshalling, or {@code null} if none were explicitely specified.
+     * Returns the timezone to use for (un)marshalling, or {@code null} if none was explicitely specified.
      *
      * <div class="section">Handling of <code>null</code> timezone</div>
      * A {@code null} value means that the timezone is unspecified. Callers are encouraged
      * to use the UTC timezone as the default value, but some flexibility is allowed.
      *
-     * @return The timezone for the XML fragment being (un)marshalled, or {@code null} if unspecified.
+     * <div class="warning"><b>Upcoming API change — Java time API</b><br>
+     * Return type may be changed to {@link java.time.ZoneId} when Apache SIS will target Java 8.
+     * This change may be applied in synchronization with GeoAPI 4.0.
+     * </div>
+     *
+     * @return the timezone for the XML fragment being (un)marshalled, or {@code null} if unspecified.
      */
     public abstract TimeZone getTimeZone();
 
@@ -88,8 +93,8 @@ public abstract class MarshalContext {
      *   </tr>
      * </table>
      *
-     * @param  prefix One of the above-cited prefix.
-     * @return The version for the given schema, or {@code null} if unknown.
+     * @param  prefix  one of the above-cited prefix.
+     * @return the version for the given schema, or {@code null} if unknown.
      */
     public abstract Version getVersion(final String prefix);
 }

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=1774642&r1=1774641&r2=1774642&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] Fri Dec 16 17:55:56 2016
@@ -371,6 +371,19 @@ public class MarshallerPool {
     }
 
     /**
+     * Acquires a unmarshaller and set the properties to the given value, if non-null.
+     */
+    final Unmarshaller acquireUnmarshaller(final Map<String,?> properties) throws JAXBException {
+        final Unmarshaller unmarshaller = acquireUnmarshaller();
+        if (properties != null) {
+            for (final Map.Entry<String,?> entry : properties.entrySet()) {
+                unmarshaller.setProperty(entry.getKey(), entry.getValue());
+            }
+        }
+        return unmarshaller;
+    }
+
+    /**
      * Declares a marshaller as available for reuse.
      * The caller should not use anymore the given marshaller after this method call,
      * since the marshaller may be re-used by another thread at any time after recycle.

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=1774642&r1=1774641&r2=1774642&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] Fri Dec 16 17:55:56 2016
@@ -183,7 +183,7 @@ abstract class Pooled {
      * Creates a {@link PooledMarshaller} or {@link PooledUnmarshaller}. The {@link #initialize(Pooled)}
      * method must be invoked after this constructor for completing the initialization.
      *
-     * @param template The {@link PooledTemplate} from which to get the initial values.
+     * @param template the {@link PooledTemplate} from which to get the initial values.
      */
     Pooled(final Pooled template) {
         initialProperties = new LinkedHashMap<>();
@@ -195,8 +195,8 @@ abstract class Pooled {
      * This method is not invoked in the {@link #Pooled(Pooled)} constructor in order to
      * give to subclasses a chance to complete their construction first.
      *
-     * @param  template The {@link PooledTemplate} from which to get the initial values.
-     * @throws JAXBException If an error occurred while setting a property.
+     * @param  template the {@link PooledTemplate} from which to get the initial values.
+     * @throws JAXBException if an error occurred while setting a property.
      */
     final void initialize(final Pooled template) throws JAXBException {
         reset(template); // Set the SIS properties first. JAXB properties are set below.
@@ -210,8 +210,8 @@ abstract class Pooled {
      * This method is invoked by {@link MarshallerPool} just before to push a
      * (un)marshaller in the pool after its usage.
      *
-     * @param  template The {@link PooledTemplate} from which to get the initial values.
-     * @throws JAXBException If an error occurred while restoring a property.
+     * @param  template  the {@link PooledTemplate} from which to get the initial values.
+     * @throws JAXBException if an error occurred while restoring a property.
      */
     public final void reset(final Pooled template) throws JAXBException {
         for (final Map.Entry<Object,Object> entry : initialProperties.entrySet()) {
@@ -240,9 +240,9 @@ abstract class Pooled {
      * {@code setProperty(key, value)} method. Otherwise the value shall be given to
      * {@code setFoo(value)} method where {@code "Foo"} is determined from the key.
      *
-     * @param  key   The property to reset.
-     * @param  value The initial value to give to the property.
-     * @throws JAXBException If an error occurred while restoring a property.
+     * @param  key    the property to reset.
+     * @param  value  the initial value to give to the property.
+     * @throws JAXBException if an error occurred while restoring a property.
      */
     protected abstract void reset(final Object key, final Object value) throws JAXBException;
 
@@ -291,8 +291,8 @@ abstract class Pooled {
      * modified for the first time, in order to allow {@link #reset(Pooled)} to restore
      * the (un)marshaller to its initial state.
      *
-     * @param type  The property to save.
-     * @param value The current value of the property.
+     * @param  type   the property to save.
+     * @param  value  the current value of the property.
      */
     final <E> void saveProperty(final Class<E> type, final E value) {
         if (initialProperties.put(type, value) != null) {
@@ -306,8 +306,8 @@ 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.
+     * @param  key  the JAXB property key.
+     * @return the property key to use.
      */
     private String convertPropertyKey(String key) {
         if (internal && key.startsWith(ENDORSED_PREFIX)) {
@@ -419,6 +419,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 {
         switch (name) {
             case XML.LOCALE:           return locale;

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=1774642&r1=1774641&r2=1774642&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] Fri Dec 16 17:55:56 2016
@@ -19,7 +19,7 @@ package org.apache.sis.xml;
 import java.util.Map;
 import java.util.Locale;
 import java.util.TimeZone;
-import java.util.logging.LogRecord; // For javadoc
+import java.util.logging.LogRecord;             // For javadoc
 import java.net.URL;
 import java.io.File;
 import java.io.IOException;
@@ -27,8 +27,12 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.JAXBElement;
 import javax.xml.bind.JAXBException;
 import javax.xml.transform.Source;
 import javax.xml.transform.Result;
@@ -36,6 +40,7 @@ import javax.xml.transform.stax.StAXSour
 import javax.xml.stream.XMLStreamReader;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Version;
+import org.apache.sis.util.Workaround;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.logging.WarningListener;
 import org.apache.sis.internal.system.Modules;
@@ -44,11 +49,6 @@ import org.apache.sis.internal.jaxb.Type
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
 
-// Branch-dependent imports
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-
 
 /**
  * Provides convenience methods for marshalling and unmarshalling SIS objects.
@@ -358,7 +358,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Marshall the given object into a string.
+     * Marshal the given object into a string.
      *
      * @param  object  the root of content tree to be marshalled.
      * @return the XML representation of the given object.
@@ -375,7 +375,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Marshall the given object into a stream.
+     * Marshal the given object into a stream.
      *
      * @param  object  the root of content tree to be marshalled.
      * @param  output  the stream where to write.
@@ -391,7 +391,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Marshall the given object into a file.
+     * Marshal the given object into a file.
      *
      * @param  object  the root of content tree to be marshalled.
      * @param  output  the file to be written.
@@ -407,7 +407,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Marshall the given object into a path.
+     * Marshal the given object into a path.
      *
      * @param  object  the root of content tree to be marshalled.
      * @param  output  the file to be written.
@@ -427,7 +427,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Marshall the given object to a stream, DOM or other destinations.
+     * Marshal the given object to a stream, DOM or other destinations.
      * This is the most flexible marshalling method provided in this {@code XML} class.
      * The destination is specified by the {@code output} argument implementation, for example
      * {@link javax.xml.transform.stream.StreamResult} for writing to a file or output stream.
@@ -457,7 +457,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Unmarshall an object from the given string.
+     * Unmarshal an object from the given string.
      * Note that the given argument is the XML document itself,
      * <strong>not</strong> a URL to a XML document.
      *
@@ -476,7 +476,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Unmarshall an object from the given stream.
+     * Unmarshal an object from the given stream.
      *
      * @param  input  the stream from which to read a XML representation.
      * @return the object unmarshalled from the given input.
@@ -492,7 +492,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Unmarshall an object from the given URL.
+     * Unmarshal an object from the given URL.
      *
      * @param  input  the URL from which to read a XML representation.
      * @return the object unmarshalled from the given input.
@@ -508,7 +508,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Unmarshall an object from the given file.
+     * Unmarshal an object from the given file.
      *
      * @param  input  the file from which to read a XML representation.
      * @return the object unmarshalled from the given input.
@@ -524,7 +524,7 @@ public final class XML extends Static {
     }
 
     /**
-     * Unmarshall an object from the given path.
+     * Unmarshal an object from the given path.
      *
      * @param  input  the path from which to read a XML representation.
      * @return the object unmarshalled from the given input.
@@ -545,8 +545,9 @@ public final class XML extends Static {
     }
 
     /**
-     * Unmarshall an object from the given stream, DOM or other sources.
-     * This is the most flexible unmarshalling method provided in this {@code XML} class.
+     * Unmarshal an object from the given stream, DOM or other sources.
+     * Together with the {@linkplain #unmarshal(Source, Class, Map) Unmarshal by Declared Type} variant,
+     * this is the most flexible unmarshalling method provided in this {@code XML} class.
      * The source is specified by the {@code input} argument implementation, for example
      * {@link javax.xml.transform.stream.StreamSource} for reading from a file or input stream.
      * The optional {@code properties} map can contain any key documented in this {@code XML} class,
@@ -563,21 +564,67 @@ public final class XML extends Static {
     public static Object unmarshal(final Source input, final Map<String,?> properties) throws JAXBException {
         ensureNonNull("input", input);
         final MarshallerPool pool = getPool();
-        final Unmarshaller unmarshaller = pool.acquireUnmarshaller();
-        if (properties != null) {
-            for (final Map.Entry<String,?> entry : properties.entrySet()) {
-                unmarshaller.setProperty(entry.getKey(), entry.getValue());
-            }
-        }
+        final Unmarshaller unmarshaller = pool.acquireUnmarshaller(properties);
         final Object object;
-        final XMLStreamReader reader;
-        if (input instanceof StAXSource && (reader = ((StAXSource) input).getXMLStreamReader()) != null) {
-            // As of JDK 8, XMLStreamReader is not handled by default unmarshal(Source) implementation.
-            object = unmarshaller.unmarshal(reader);
+        /*
+         * STAX sources are not handled by javax.xml.bind.helpers.AbstractUnmarshallerImpl implementation as of JDK 8.
+         * We have to handle those cases ourselves. This workaround should be removed if a future JDK version handles
+         * those cases.
+         */
+        if (input instanceof StAXSource) {
+            @Workaround(library = "JDK", version = "1.8")
+            final XMLStreamReader reader = ((StAXSource) input).getXMLStreamReader();
+            if (reader != null) {
+                object = unmarshaller.unmarshal(reader);
+            } else {
+                object = unmarshaller.unmarshal(((StAXSource) input).getXMLEventReader());
+            }
         } else {
             object = unmarshaller.unmarshal(input);
         }
         pool.recycle(unmarshaller);
         return object;
     }
+
+    /**
+     * Unmarshal an object from the given stream, DOM or other sources.
+     * Together with the {@linkplain #unmarshal(Source, Map) Unmarshal Global Root Element} variant,
+     * this is the most flexible unmarshalling method provided in this {@code XML} class.
+     * The source is specified by the {@code input} argument implementation, for example
+     * {@link javax.xml.transform.stream.StreamSource} for reading from a file or input stream.
+     * The optional {@code properties} map can contain any key documented in this {@code XML} class,
+     * together with the keys documented in the <cite>supported properties</cite> section of the the
+     * {@link Unmarshaller} class.
+     *
+     * @param  <T>           compile-time value of the {@code declaredType} argument.
+     * @param  input         the file from which to read a XML representation.
+     * @param  declaredType  the JAXB mapped class of the object to unmarshal.
+     * @param  properties    an optional map of properties to give to the unmarshaller, or {@code null} if none.
+     * @return the object unmarshalled from the given input, wrapped in a JAXB element.
+     * @throws JAXBException if a property has an illegal value, or if an error occurred during the unmarshalling.
+     *
+     * @since 0.8
+     */
+    public static <T> JAXBElement<T> unmarshal(final Source input, final Class<T> declaredType, final Map<String,?> properties)
+            throws JAXBException
+    {
+        ensureNonNull("input", input);
+        ensureNonNull("declaredType", declaredType);
+        final MarshallerPool pool = getPool();
+        final Unmarshaller unmarshaller = pool.acquireUnmarshaller(properties);
+        final JAXBElement<T> element;
+        if (input instanceof StAXSource) {                  // Same workaround than the one documented in above method.
+            @Workaround(library = "JDK", version = "1.8")
+            final XMLStreamReader reader = ((StAXSource) input).getXMLStreamReader();
+            if (reader != null) {
+                element = unmarshaller.unmarshal(reader, declaredType);
+            } else {
+                element = unmarshaller.unmarshal(((StAXSource) input).getXMLEventReader(), declaredType);
+            }
+        } else {
+            element = unmarshaller.unmarshal(input, declaredType);
+        }
+        pool.recycle(unmarshaller);
+        return element;
+    }
 }

Modified: sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -28,7 +28,6 @@ import org.apache.sis.storage.DataStoreR
 import org.apache.sis.storage.UnsupportedStorageException;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.Debug;
 
@@ -91,7 +90,7 @@ public class LandsatStore extends DataSt
      * @throws DataStoreException if an error occurred while opening the Landsat file.
      */
     public LandsatStore(final StorageConnector connector) throws DataStoreException {
-        ArgumentChecks.ensureNonNull("connector", connector);
+        super(connector);
         name = connector.getStorageName();
         source = connector.getStorageAs(Reader.class);
         connector.closeAllExcept(source);

Modified: sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -34,7 +34,6 @@ import org.apache.sis.internal.storage.C
 import org.apache.sis.internal.storage.MetadataBuilder;
 import org.apache.sis.metadata.sql.MetadataStoreException;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Classes;
 
 
@@ -75,7 +74,7 @@ public class GeoTiffStore extends DataSt
      * @throws DataStoreException if an error occurred while opening the GeoTIFF file.
      */
     public GeoTiffStore(final StorageConnector connector) throws DataStoreException {
-        ArgumentChecks.ensureNonNull("connector", connector);
+        super(connector);
         final Charset encoding = connector.getOption(OptionKey.ENCODING);
         this.encoding = (encoding != null) ? encoding : StandardCharsets.US_ASCII;
         final ChannelDataInput input = connector.getStorageAs(ChannelDataInput.class);

Modified: sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/NetcdfStore.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -20,7 +20,6 @@ import java.io.IOException;
 import org.opengis.metadata.Metadata;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
-import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
@@ -65,7 +64,7 @@ public class NetcdfStore extends DataSto
      * @throws DataStoreException if an error occurred while opening the NetCDF file.
      */
     public NetcdfStore(final StorageConnector connector) throws DataStoreException {
-        ArgumentChecks.ensureNonNull("connector", connector);
+        super(connector);
         try {
             decoder = NetcdfStoreProvider.decoder(listeners, connector);
         } catch (IOException e) {

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -181,6 +181,7 @@ public final class Store extends DataSto
      * @throws DataStoreException if an error occurred while opening the stream.
      */
     public Store(final StorageConnector connector) throws DataStoreException {
+        super(connector);
         filename = connector.getStorageName();
         final Reader r = connector.getStorageAs(Reader.class);
         connector.closeAllExcept(r);

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/wkt/Store.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -85,6 +85,7 @@ final class Store extends DataStore {
      * @throws DataStoreException if an error occurred while opening the stream.
      */
     public Store(final StorageConnector connector) throws DataStoreException {
+        super(connector);
         objects = new ArrayList<>();
         name    = connector.getStorageName();
         source  = connector.getStorageAs(Reader.class);

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/xml/Store.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -84,6 +84,7 @@ final class Store extends DataStore {
      * @throws DataStoreException if an error occurred while opening the stream.
      */
     public Store(final StorageConnector connector) throws DataStoreException {
+        super(connector);
         name = connector.getStorageName();
         final InputStream in = connector.getStorageAs(InputStream.class);
         if (in != null) {

Modified: sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-storage/src/main/java/org/apache/sis/storage/DataStore.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -35,7 +35,7 @@ import org.apache.sis.util.logging.Warni
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.8
  * @module
  *
  * @see DataStores#open(Object)
@@ -43,6 +43,7 @@ import org.apache.sis.util.logging.Warni
 public abstract class DataStore implements Localized, AutoCloseable {
     /**
      * The locale to use for formatting warnings.
+     * This is not the locale for formatting data in the storage.
      *
      * @see #getLocale()
      * @see #setLocale(Locale)
@@ -63,6 +64,25 @@ public abstract class DataStore implemen
     }
 
     /**
+     * Creates a new instance for the given storage (typically file or database).
+     *
+     * @param connector information about the storage (URL, stream, reader instance, <i>etc</i>).
+     *
+     * @since 0.8
+     */
+    protected DataStore(final StorageConnector connector) {
+        ArgumentChecks.ensureNonNull("connector", connector);
+        locale = Locale.getDefault(Locale.Category.DISPLAY);
+        listeners = new WarningListeners<>(this);
+        /*
+         * A future version could fetch some information from the StorageConnector.
+         * For now we do not, not even OptionKey.LOCALE because we are not talking
+         * about the same locale (the one in this DataStore is for warning messages,
+         * not for data).
+         */
+    }
+
+    /**
      * The locale to use for formatting warnings and other messages. This locale if for user interfaces
      * only - it has no effect on the data to be read or written from/to the data store.
      *

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXReader.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -18,11 +18,11 @@ package org.apache.sis.internal.gpx;
 
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.io.IOException;
 import java.io.EOFException;
 import java.net.URI;
 import java.net.URISyntaxException;
-import javax.xml.transform.stax.StAXSource;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.bind.JAXBException;
@@ -33,10 +33,10 @@ import org.apache.sis.storage.DataStoreC
 import org.apache.sis.internal.xml.StaxStreamReader;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.Version;
-import org.apache.sis.xml.XML;
 
 // Branch-dependent imports
 import org.opengis.feature.Feature;
+import java.time.format.DateTimeParseException;
 
 
 /**
@@ -65,16 +65,22 @@ public class GPXReader extends StaxStrea
     private final Types types;
 
     /**
+     * The namespace, which should be either {@link Tags#NAMESPACE_V10} or {@link Tags#NAMESPACE_V11}.
+     * We store this information for identifying the closing {@code <gpx>} tag.
+     */
+    private final String namespace;
+
+    /**
      * Version of the GPX file, or {@code null} if unspecified.
      * Can be {@link GPXStore#V1_0} or {@link GPXStore#V1_1}.
      */
-    private Version version;
+    private final Version version;
 
     /**
      * Convenience flag set to {@code true} if the {@link #version} field is {@link GPXStore#V1_0},
      * or {@code false} if the version is {@link GPXStore#V1_1}.
      */
-    private boolean isLegacy;
+    private final boolean isLegacy;
 
     /**
      * The metadata (ISO 19115 compatible), or {@code null} if none.
@@ -119,6 +125,8 @@ public class GPXReader extends StaxStrea
      * @throws XMLStreamException if an error occurred while opening the XML file.
      * @throws URISyntaxException if an error occurred while parsing URI in GPX 1.0 metadata.
      * @throws JAXBException if an error occurred while parsing GPX 1.1 metadata.
+     * @throws ClassCastException if an object unmarshalled by JAXB was not of the expected type.
+     * @throws DateTimeParseException if a text can not be parsed as a date.
      * @throws EOFException if the file seems to be truncated.
      */
     public GPXReader(final GPXStore owner, final StorageConnector connector)
@@ -130,25 +138,20 @@ public class GPXReader extends StaxStrea
          * Skip comments, characters, entity declarations, etc. until we find the root element.
          * If that root is anything other than <gpx>, we consider that this is not a GPX file.
          */
-        moveToRootElement(GPXReader::isNamespace, Tags.GPX);
+        moveToRootElement(GPXReader::isNamespaceGPX, Tags.GPX);
         /*
-         * If a version attribute is found on the <gpx> element, use that value for detecting
-         * the GPX version. Otherwise use the namespace URL.  If the version is not found, we
-         * leave the field to null (we do not assume any version). If a version is specified,
-         * we require major.minor version 1.0 or 1.1 but accept any bug-fix versions.
+         * If a version attribute is found on the <gpx> element, use that value for detecting the GPX version.
+         * If the version is not found, we leave the field to null (we do not assume any version). If a version
+         * is specified, we require major.minor version 1.0 or 1.1 but accept any bug-fix versions (e.g. 1.1.x).
          */
         final XMLStreamReader reader = getReader();
+        namespace = reader.getNamespaceURI();
         String ver = reader.getAttributeValue(null, Attributes.VERSION);
-        if (ver != null) {
-            version = new Version(ver);
+        if (ver == null) {
+            version  = null;
+            isLegacy = false;
         } else {
-            final String ns = reader.getNamespaceURI();
-            if (ns != null) switch (ns) {
-                case Tags.NAMESPACE_V10: version = GPXStore.V1_0; break;
-                case Tags.NAMESPACE_V11: version = GPXStore.V1_1; break;
-            }
-        }
-        if (version != null) {
+            version  = new Version(ver);
             isLegacy = version.compareTo(GPXStore.V1_0, 2) <= 0;
             if (version.compareTo(GPXStore.V1_1, 2) > 0) {
                 throw new DataStoreContentException(errors().getString(
@@ -168,27 +171,29 @@ public class GPXReader extends StaxStrea
         while (reader.hasNext()) {
             switch (reader.next()) {
                 case START_ELEMENT: {
-                    if (isNamespace(reader.getNamespaceURI())) {
+                    /*
+                     * GPX 1.0 and 1.1 metadata should not be mixed. However the following code will work even
+                     * if GPX 1.0 metadata like <name> or <author> appear after the GPX 1.1 <metadata> element.
+                     */
+                    if (isNamespaceGPX(reader.getNamespaceURI())) {
                         switch (reader.getLocalName()) {
                             case Tags.GPX: {
                                 throw new DataStoreContentException(errors().getString(
                                         Errors.Keys.NestedElementNotAllowed_1, Tags.GPX));
                             }
-                            case Tags.METADATA: {
-                                // GPX 1.1 metadata
-                                metadata = (Metadata) XML.unmarshal(new StAXSource(reader), null);
-                                break;
-                            }
+                            // GPX 1.1 metadata
+                            case Tags.METADATA:     metadata = unmarshal(Metadata.class); break;
+
                             // GPX 1.0 metadata
                             case Tags.NAME:         metadata().name        = getElementText();   break;
                             case Tags.DESCRIPTION:  metadata().description = getElementText();   break;
-                            case Tags.AUTHOR:       person()  .name        = getElementText();   break;
-                            case Tags.EMAIL:        person()  .email       = getElementText();   break;
+                            case Tags.AUTHOR:       author()  .name        = getElementText();   break;
+                            case Tags.EMAIL:        author()  .email       = getElementText();   break;
                             case Tags.URL:          link()    .uri         = getElementAsURI();  break;
                             case Tags.URL_NAME:     link()    .text        = getElementText();   break;
                             case Tags.TIME:         metadata().time        = getElementAsDate(); break;
                             case Tags.KEYWORDS:     metadata().keywords    = getElementAsList(); break;
-                            case Tags.BOUNDS:       metadata().bounds      = parseBound();       break;
+                            case Tags.BOUNDS:       metadata().bounds      = parseBound(reader); break;
                             case Tags.WAY_POINT:    // stop metadata parsing.
                             case Tags.TRACKS:
                             case Tags.ROUTES:       return;
@@ -197,8 +202,14 @@ public class GPXReader extends StaxStrea
                     break;
                 }
                 case END_ELEMENT: {
-                    if (isNamespace(reader.getNamespaceURI()) && Tags.GPX.equals(reader.getLocalName())) {
+                    /*
+                     * Reminder: END_ELEMENT events are already handled by XMLStreamReader.getElementText(),
+                     * Unmarshaller.unmarshal(XMLStreamReader, …) and our parseBound(…) methods. There is only
+                     * the enclosing <gpx> tag to check.
+                     */
+                    if (isEndGPX(reader)) {
                         finished = true;
+                        return;
                     }
                     break;
                 }
@@ -209,10 +220,22 @@ public class GPXReader extends StaxStrea
     /**
      * Returns {@code true} if the given namespace is a GPX namespace or is null.
      */
-    private static boolean isNamespace(final String ns) {
+    private static boolean isNamespaceGPX(final String ns) {
         return (ns == null) || ns.startsWith(Tags.NAMESPACE + "/GPX/");
     }
 
+    /**
+     * Returns {@code true} if the current position of the given reader is the closing {@code </gpx>} tag.
+     * The reader event should be {@link #END_DOCUMENT} before to invoke this method.
+     */
+    private boolean isEndGPX(final XMLStreamReader reader) {
+        return Tags.GPX.equals(reader.getLocalName()) && Objects.equals(namespace, reader.getNamespaceURI());
+    }
+
+    /**
+     * Returns the {@link #metadata} field, creating it if needed.
+     * This is a convenience method for GPX 1.0 metadata parsing.
+     */
     private Metadata metadata() {
         if (metadata == null) {
             metadata = new Metadata();
@@ -220,7 +243,11 @@ public class GPXReader extends StaxStrea
         return metadata;
     }
 
-    private Person person() {
+    /**
+     * Returns the {@link Metadata#author} field, creating all necessary objects if needed.
+     * This is a convenience method for GPX 1.0 metadata parsing.
+     */
+    private Person author() {
         final Metadata metadata = metadata();
         if (metadata.author == null) {
             metadata.author = new Person();
@@ -228,6 +255,10 @@ public class GPXReader extends StaxStrea
         return metadata.author;
     }
 
+    /**
+     * Returns the first element of the {@link Metadata#links} field, creating all necessary objects if needed.
+     * This is a convenience method for GPX 1.0 metadata parsing.
+     */
     private Link link() {
         final List<Link> links = metadata().links;
         final Link first;
@@ -241,39 +272,32 @@ public class GPXReader extends StaxStrea
     }
 
     /**
-     * Get GPX file version.
-     * This method will return a result only if called only after the input has been set.
+     * Returns the GPX file version, or {@code null} if unknown. If a {@code version} attribute
+     * was found on the root {@code <gpx>} element, then that version is returned.
+     * Otherwise this method tries to infer the version from the namespace URL.
      *
-     * @return Version or null if input is not set.
+     * @return GPX file version, or {@code null} if unknown.
      */
     public Version getVersion() {
+        if (version == null && namespace != null) {
+            switch (namespace) {
+                case Tags.NAMESPACE_V10: return GPXStore.V1_0;
+                case Tags.NAMESPACE_V11: return GPXStore.V1_1;
+            }
+        }
         return version;
     }
 
     /**
-     * Get GPX metadata.
-     * This method will return a result only if called only after the input has been set.
+     * Returns the metadata (ISO 19115 compatible), or {@code null} if none.
      *
-     * @return Metadata or null if input is not set.
+     * @return the metadata or {@code null} if none.
      */
     public Metadata getMetadata() {
         return metadata;
     }
 
     /**
-     * {@inheritDoc }
-     */
-    @Override
-    public void close() throws IOException, XMLStreamException {
-        super.close();
-        metadata = null;
-        current = null;
-        wayPointId = 0;
-        routeId = 0;
-        trackId = 0;
-    }
-
-    /**
      * Returns true if there is a next feature in the stream.
      *
      * @return true if there is next feature
@@ -371,8 +395,7 @@ public class GPXReader extends StaxStrea
      * Parse current Envelope element.
      * The stax reader must be placed to the start element.
      */
-    private Bounds parseBound() throws XMLStreamException, EOFException {
-        final XMLStreamReader reader = getReader();
+    private Bounds parseBound(final XMLStreamReader reader) throws XMLStreamException, EOFException {
         final String xmin = reader.getAttributeValue(null, Attributes.MIN_X);
         final String xmax = reader.getAttributeValue(null, Attributes.MAX_X);
         final String ymin = reader.getAttributeValue(null, Attributes.MIN_Y);
@@ -382,7 +405,7 @@ public class GPXReader extends StaxStrea
             throw new XMLStreamException("Error in xml file, metadata bounds not defined correctly");
         }
 
-        skipUntilEnd(Tags.BOUNDS);
+        skipUntilEnd(reader.getName());
         final Bounds bounds = new Bounds();
         bounds.westBoundLongitude = Double.parseDouble(xmin);
         bounds.eastBoundLongitude = Double.parseDouble(xmax);
@@ -632,4 +655,18 @@ public class GPXReader extends StaxStrea
         }
         throw new XMLStreamException("Error in xml file, "+Tags.TRACKS+" tag without end.");
     }
+
+    /**
+     * Closes the input stream and releases any resources used by this XML reader.
+     * This reader can not be used anymore after this method has been invoked.
+     *
+     * @throws IOException if an error occurred while closing the input stream.
+     * @throws XMLStreamException if an error occurred while releasing XML reader/writer resources.
+     */
+    @Override
+    public void close() throws IOException, XMLStreamException {
+        super.close();
+        current  = null;
+        finished = true;
+    }
 }

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXStore.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXStore.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/GPXStore.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -61,6 +61,7 @@ public class GPXStore extends StaxDataSt
      * @throws DataStoreException if an error occurred while opening the GPX file.
      */
     public GPXStore(final StorageConnector connector) throws DataStoreException {
+        super(connector);
         ArgumentChecks.ensureNonNull("connector", connector);
         final Charset encoding = connector.getOption(OptionKey.ENCODING);
         this.encoding = (encoding != null) ? encoding : StandardCharsets.UTF_8;

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/gpx/Metadata.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -26,7 +26,6 @@ import java.util.Objects;
 import java.io.IOException;
 import javax.xml.bind.annotation.XmlList;
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
 
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.DateType;
@@ -72,7 +71,6 @@ import org.apache.sis.metadata.iso.ident
  * @version 0.8
  * @module
  */
-@XmlRootElement(name = Tags.METADATA)
 public final class Metadata extends SimpleMetadata {
     /**
      * The name of the GPX file.

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxDataStore.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -16,9 +16,21 @@
  */
 package org.apache.sis.internal.xml;
 
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLReporter;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLOutputFactory;
+import org.apache.sis.xml.XML;
+import org.apache.sis.setup.OptionKey;
 import org.apache.sis.storage.DataStore;
+import org.apache.sis.storage.StorageConnector;
+import org.apache.sis.util.logging.WarningListeners;
 
 
 /**
@@ -30,7 +42,23 @@ import org.apache.sis.storage.DataStore;
  * @version 0.8
  * @module
  */
-public abstract class StaxDataStore extends DataStore {
+public abstract class StaxDataStore extends DataStore implements XMLReporter {
+    /**
+     * The locale to use for locale-sensitive data (<strong>not</strong> for logging or warning messages),
+     * or {@code null} if unspecified.
+     *
+     * @see OptionKey#LOCALE
+     */
+    private final Locale locale;
+
+    /**
+     * The timezone to use when parsing or formatting dates and times without explicit timezone,
+     * or {@code null} if unspecified.
+     *
+     * @see OptionKey#TIMEZONE
+     */
+    private final TimeZone timezone;
+
     /**
      * The STAX readers factory, created when first needed.
      *
@@ -47,8 +75,13 @@ public abstract class StaxDataStore exte
 
     /**
      * Creates a new data store.
+     *
+     * @param  connector  information about the storage (URL, stream, <i>etc</i>).
      */
-    protected StaxDataStore() {
+    protected StaxDataStore(final StorageConnector connector) {
+        super(connector);
+        locale   = connector.getOption(OptionKey.LOCALE);
+        timezone = connector.getOption(OptionKey.TIMEZONE);
     }
 
     /**
@@ -65,7 +98,7 @@ public abstract class StaxDataStore exte
     final synchronized XMLInputFactory inputFactory() {
         if (inputFactory == null) {
             inputFactory = XMLInputFactory.newInstance();
-            // TODO: register listeners here.
+            inputFactory.setXMLReporter(this);
         }
         return inputFactory;
     }
@@ -80,4 +113,40 @@ public abstract class StaxDataStore exte
         }
         return outputFactory;
     }
+
+    /**
+     * Returns the properties that can be used to JAXB (un)marshaller.
+     *
+     * @param  target  the object for which we are creating (un)marshaller configuration.
+     */
+    final Map<String,Object> configuration(final StaxStream target) {
+        final Map<String,Object> properties = new HashMap<>(4);
+        if (locale   != null) properties.put(XML.LOCALE,   locale);
+        if (timezone != null) properties.put(XML.TIMEZONE, timezone);
+        properties.put(XML.WARNING_LISTENER, target);
+        return properties;
+    }
+
+    /**
+     * Gives to {@link StaxStream} an access to the {@link #listeners} field.
+     */
+    final WarningListeners<DataStore> listeners() {
+        return listeners;
+    }
+
+    /**
+     * Forwards STAX warnings to {@link DataStore} listeners.
+     * This method is invoked by {@link javax.xml.stream.XMLStreamReader} when needed.
+     *
+     * @param message    the message to put in a logging record.
+     * @param errorType  ignored.
+     * @param info       ignored.
+     * @param location   ignored.
+     */
+    @Override
+    public void report(String message, String errorType, Object info, Location location) {
+        final LogRecord record = new LogRecord(Level.WARNING, message);
+        record.setSourceClassName(getClass().getCanonicalName());
+        listeners.warning(record);
+    }
 }

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStream.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStream.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStream.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStream.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -18,8 +18,10 @@ package org.apache.sis.internal.xml;
 
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.logging.LogRecord;
 import javax.xml.stream.XMLStreamException;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.logging.WarningListener;
 import org.apache.sis.util.resources.Errors;
 
 
@@ -40,7 +42,7 @@ import org.apache.sis.util.resources.Err
  * @version 0.8
  * @module
  */
-abstract class StaxStream implements AutoCloseable {
+abstract class StaxStream implements AutoCloseable, WarningListener<Object> {
     /**
      * The data store for which this reader or writer has been created.
      */
@@ -99,4 +101,24 @@ abstract class StaxStream implements Aut
     protected final Errors errors() {
         return Errors.getResources(owner.getLocale());
     }
+
+    /**
+     * Reports a warning represented by the given log record.
+     *
+     * @param source  ignored (typically a JAXB object being unmarshalled). Can be {@code null}.
+     * @param record  the warning as a log record.
+     */
+    @Override
+    public final void warningOccured(final Object source, final LogRecord warning) {
+        owner.listeners().warning(warning);
+    }
+
+    /**
+     * Returns the type of objects that emit warnings of interest for this listener.
+     * Fixed to {@code Object.class} as required by {@link org.apache.sis.xml.XML#WARNING_LISTENER} documentation.
+     */
+    @Override
+    public final Class<Object> getSourceClass() {
+        return Object.class;
+    }
 }

Modified: sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java?rev=1774642&r1=1774641&r2=1774642&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/xml/StaxStreamReader.java [UTF-8] Fri Dec 16 17:55:56 2016
@@ -28,6 +28,7 @@ import java.io.IOException;
 import java.io.EOFException;
 import java.net.URISyntaxException;
 import java.time.LocalDate;
+import javax.xml.namespace.QName;
 import javax.xml.stream.XMLEventReader;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamConstants;
@@ -38,8 +39,10 @@ import javax.xml.transform.Source;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.sax.SAXSource;
 import javax.xml.transform.stax.StAXSource;
+import javax.xml.bind.JAXBException;
 import org.xml.sax.InputSource;
 import org.w3c.dom.Node;
+import org.apache.sis.xml.XML;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.util.StandardDateFormat;
 import org.apache.sis.storage.DataStoreException;
@@ -165,7 +168,7 @@ public abstract class StaxStreamReader e
      * @return a reader over a portion of the stream.
      * @throws XMLStreamException if this XML reader has been closed.
      */
-    protected final XMLStreamReader getSubReader(final String tagName) throws XMLStreamException {
+    protected final XMLStreamReader getSubReader(final QName tagName) throws XMLStreamException {
         return new StreamReaderDelegate(getReader()) {
             /** Increased every time a nested element of the same name is found. */
             private int nested;
@@ -182,8 +185,8 @@ public abstract class StaxStreamReader e
                 }
                 final int t = super.next();
                 switch (t) {
-                    case START_ELEMENT: if (tagName.equals(getLocalName())) nested++; break;
-                    case END_ELEMENT:   if (tagName.equals(getLocalName())) nested--; break;
+                    case START_ELEMENT: if (tagName.equals(getName())) nested++; break;
+                    case END_ELEMENT:   if (tagName.equals(getName())) nested--; break;
                 }
                 return t;
             }
@@ -228,19 +231,19 @@ public abstract class StaxStreamReader e
      * @throws EOFException if end tag could not be found.
      * @throws XMLStreamException if an error occurred while reading the XML stream.
      */
-    protected final void skipUntilEnd(final String tagName) throws EOFException, XMLStreamException {
+    protected final void skipUntilEnd(final QName tagName) throws EOFException, XMLStreamException {
         final XMLStreamReader reader = getReader();
         int nested = 0;
         while (reader.hasNext()) {
             switch (reader.next()) {
                 case XMLStreamReader.START_ELEMENT: {
-                    if (tagName.equals(reader.getLocalName())) {
+                    if (tagName.equals(reader.getName())) {
                         nested++;
                     }
                     break;
                 }
                 case XMLStreamReader.END_ELEMENT: {
-                    if (tagName.equals(reader.getLocalName())) {
+                    if (tagName.equals(reader.getName())) {
                         if (--nested < 0) return;
                     }
                     break;
@@ -346,6 +349,22 @@ public abstract class StaxStreamReader e
     }
 
     /**
+     * Delegates to JAXB the unmarshalling of a part of XML document, starting from the current element (inclusive).
+     *
+     * @param  <T>   compile-time value of the {@code type} argument.
+     * @param  type  expected type of the object to unmarshal.
+     * @return the unmarshalled object, or {@code null} if none.
+     * @throws XMLStreamException if the XML stream is closed.
+     * @throws JAXBException if an error occurred during unmarshalling.
+     * @throws ClassCastException if the unmarshalling result is not of the expected type.
+     *
+     * @see javax.xml.bind.Unmarshaller#unmarshal(XMLStreamReader, Class)
+     */
+    protected final <T> T unmarshal(final Class<T> type) throws XMLStreamException, JAXBException {
+        return XML.unmarshal(new StAXSource(getReader()), type, owner.configuration(this)).getValue();
+    }
+
+    /**
      * Closes the input stream and releases any resources used by this XML reader.
      * This reader can not be used anymore after this method has been invoked.
      *



Mime
View raw message