sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1775004 [2/3] - in /sis/trunk: ./ core/sis-build-helper/ core/sis-feature/src/main/java/org/apache/sis/feature/ core/sis-feature/src/main/java/org/apache/sis/feature/builder/ core/sis-feature/src/main/java/org/apache/sis/internal/feature/ ...
Date Mon, 19 Dec 2016 08:23:45 GMT
Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Mon Dec 19 08:23:44 2016
@@ -44,6 +44,7 @@ CircularReference                 = Circ
 ClassNotFinal_1                   = Class \u2018{0}\u2019 is not final.
 CloneNotSupported_1               = Can not clone an object of type \u2018{0}\u2019.
 ClosedReader_1                    = This {0} reader is closed.
+ClosedWriter_1                    = This {0} writer is closed.
 DatabaseError_2                   = Database error while creating a \u2018{0}\u2019 object for the \u201c{1}\u201d identifier.
 DeadThread_1                      = Thread \u201c{0}\u201d is dead.
 DisposedInstanceOf_1              = This instance of \u2018{0}\u2019 has been disposed.
@@ -78,6 +79,7 @@ IllegalCRSType_1                  = Coor
 IllegalFormatPatternForClass_2    = The \u201c{1}\u201d pattern can not be applied to formating of objects of type \u2018{0}\u2019.
 IllegalIdentifierForCodespace_2   = \u201c{1}\u201d is not a valid identifier for the \u201c{0}\u201d code space.
 IllegalInputTypeForReader_2       = The {0} reader does not accept inputs of type \u2018{1}\u2019.
+IllegalOutputTypeForWriter_2      = The {0} writer does not accept outputs of type \u2018{1}\u2019.
 IllegalLanguageCode_1             = The \u201c{0}\u201d language is not recognized.
 IllegalMemberType_2               = Member \u201c{0}\u201d can not be associated to type \u201c{1}\u201d.
 IllegalOptionValue_2              = Option \u2018{0}\u2019 can not take the \u201c{1}\u201d value.
@@ -117,6 +119,7 @@ MissingValueInColumn_1            = Miss
 MutuallyExclusiveOptions_2        = Options \u201c{0}\u201d and \u201c{1}\u201d are mutually exclusive.
 NegativeArgument_2                = Argument \u2018{0}\u2019 shall not be negative. The given value was {1}.
 NegativeArrayLength_1             = Can not create a \u201c{0}\u201d array of negative length.
+NestedElementNotAllowed_1         = Nested \u201c{0}\u201d elements are not allowed.
 NodeChildOfItself_1               = Node \u201c{0}\u201d can not be a child of itself.
 NodeHasAnotherParent_1            = Node \u201c{0}\u201d already has another parent.
 NodeHasNoParent_1                 = Node \u201c{0}\u201d has no parent.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Mon Dec 19 08:23:44 2016
@@ -41,6 +41,7 @@ CircularReference                 = R\u0
 ClassNotFinal_1                   = La classe \u2018{0}\u2019 n\u2019est pas finale.
 CloneNotSupported_1               = Un objet de type \u2018{0}\u2019 ne peut pas \u00eatre clon\u00e9.
 ClosedReader_1                    = Ce lecteur {0} est ferm\u00e9.
+ClosedWriter_1                    = Cet encodeur {0} est ferm\u00e9.
 DatabaseError_2                   = Erreur de base de donn\u00e9es lors de la cr\u00e9ation d\u2019un objet \u2018{0}\u2019 pour l\u2019identifiant \u00ab\u202f{1}\u202f\u00bb.
 DeadThread_1                      = La t\u00e2che \u00ab\u202f{0}\u202f\u00bb est morte.
 DisposedInstanceOf_1              = Cette instance de \u2018{0}\u2019 a \u00e9t\u00e9 dispos\u00e9e.
@@ -75,6 +76,7 @@ IllegalCRSType_1                  = Le s
 IllegalFormatPatternForClass_2    = Le mod\u00e8le \u00ab\u202f{1}\u202f\u00bb ne peut pas \u00eatre appliqu\u00e9 au formatage d\u2019objets de type \u2018{0}\u2019.
 IllegalIdentifierForCodespace_2   = \u00ab\u202f{1}\u202f\u00bb n\u2019est pas un identifiant valide pour l\u2019espace de codes \u00ab\u202f{0}\u202f\u00bb.
 IllegalInputTypeForReader_2       = Le lecteur {0} n\u2019accepte pas des entr\u00e9s de type \u2018{1}\u2019.
+IllegalOutputTypeForWriter_2      = Le l\u2019encodeur {0} n\u2019accepte pas des sorties de type \u2018{1}\u2019.
 IllegalLanguageCode_1             = Le code de langue \u00ab\u202f{0}\u202f\u00bb n\u2019est pas reconnu.
 IllegalMemberType_2               = Le membre \u00ab\u202f{0}\u202f\u00bb ne peut pas \u00eatre associ\u00e9 au type \u00ab\u202f{1}\u202f\u00bb.
 IllegalOptionValue_2              = L\u2019option \u2018{0}\u2019 n\u2019accepte pas la valeur \u00ab\u202f{1}\u202f\u00bb.
@@ -114,6 +116,7 @@ MissingValueInColumn_1            = Il m
 MutuallyExclusiveOptions_2        = Les options \u00ab\u202f{0}\u202f\u00bb et \u00ab\u202f{1}\u202f\u00bb sont mutuellement exclusives.
 NegativeArgument_2                = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre n\u00e9gatif. La valeur donn\u00e9e \u00e9tait {1}.
 NegativeArrayLength_1             = Ne peut pas cr\u00e9er un tableau \u00ab\u202f{0}\u202f\u00bb de longueur n\u00e9gative.
+NestedElementNotAllowed_1         = L\u2019imbrication d\u2019\u00e9l\u00e9ments \u00ab\u202f{0}\u202f\u00bb n\u2019est pas autoris\u00e9e.
 NodeChildOfItself_1               = Le n\u0153ud \u00ab\u202f{0}\u202f\u00bb ne peut pas \u00eatre un enfant de lui-m\u00eame.
 NodeHasAnotherParent_1            = Le n\u0153ud \u00ab\u202f{0}\u202f\u00bb a d\u00e9j\u00e0 un autre parent.
 NodeHasNoParent_1                 = Le n\u0153ud \u00ab\u202f{0}\u202f\u00bb n\u2019a pas de parent.

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/MarshalContext.java [UTF-8] Mon Dec 19 08:23:44 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/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java [UTF-8] Mon Dec 19 08:23:44 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/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/Namespaces.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/Namespaces.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/Namespaces.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/Namespaces.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -222,12 +222,11 @@ public final class Namespaces extends St
     /**
      * Returns the preferred prefix for the given namespace URI.
      *
-     * @param  namespace    The namespace URI for which the prefix needs to be found.
-     *                      Can not be {@code null}.
-     * @param  defaultValue The default prefix to returned if the given {@code namespace}
-     *                      is not recognized, or {@code null}.
-     * @return The prefix inferred from the namespace URI, or {@code null} if the given namespace
-     *         is unrecognized and the {@code defaultValue} is null.
+     * @param  namespace     the namespace URI for which the prefix needs to be found. Can not be {@code null}.
+     * @param  defaultValue  the default prefix to returned if the given {@code namespace} is not recognized,
+     *                       or {@code null}.
+     * @return the prefix inferred from the namespace URI, or {@code null} if the given namespace is unrecognized
+     *         and the {@code defaultValue} is null.
      */
     public static String getPreferredPrefix(String namespace, final String defaultValue) {
         ArgumentChecks.ensureNonNull("namespace", namespace);

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/Pooled.java [UTF-8] Mon Dec 19 08:23:44 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/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/PooledMarshaller.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/PooledMarshaller.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/PooledMarshaller.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/PooledMarshaller.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -36,7 +36,6 @@ import javax.xml.validation.Schema;
 import org.xml.sax.ContentHandler;
 import org.w3c.dom.Node;
 import org.apache.sis.internal.jaxb.Context;
-import org.apache.sis.internal.system.XMLOutputFactory;
 
 
 /**
@@ -144,7 +143,7 @@ final class PooledMarshaller extends Poo
     public void marshal(final Object object, final Result output) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            marshal(object, XMLOutputFactory.createXMLStreamWriter(output), version);
+            marshal(object, OutputFactory.createXMLStreamWriter(output), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -165,7 +164,7 @@ final class PooledMarshaller extends Poo
     public void marshal(final Object object, final OutputStream output) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            marshal(object, XMLOutputFactory.createXMLStreamWriter(output, getEncoding()), version);
+            marshal(object, OutputFactory.createXMLStreamWriter(output, getEncoding()), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -187,7 +186,7 @@ final class PooledMarshaller extends Poo
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
             try (OutputStream s = new BufferedOutputStream(new FileOutputStream(output))) {
-                marshal(object, XMLOutputFactory.createXMLStreamWriter(s, getEncoding()), version);
+                marshal(object, OutputFactory.createXMLStreamWriter(s, getEncoding()), version);
             }
         } catch (IOException | XMLStreamException e) {
             throw new JAXBException(e);
@@ -209,7 +208,7 @@ final class PooledMarshaller extends Poo
     public void marshal(final Object object, final Writer output) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            marshal(object, XMLOutputFactory.createXMLStreamWriter(output), version);
+            marshal(object, OutputFactory.createXMLStreamWriter(output), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -230,7 +229,7 @@ final class PooledMarshaller extends Poo
     public void marshal(final Object object, final ContentHandler output) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            marshal(object, XMLOutputFactory.createXMLStreamWriter(output), version);
+            marshal(object, OutputFactory.createXMLStreamWriter(output), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -251,7 +250,7 @@ final class PooledMarshaller extends Poo
     public void marshal(final Object object, final Node output) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            marshal(object, XMLOutputFactory.createXMLStreamWriter(output), version);
+            marshal(object, OutputFactory.createXMLStreamWriter(output), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -289,7 +288,7 @@ final class PooledMarshaller extends Poo
     public void marshal(final Object object, final XMLEventWriter output) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            marshal(object, XMLOutputFactory.createXMLStreamWriter(output), version);
+            marshal(object, OutputFactory.createXMLStreamWriter(output), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/PooledUnmarshaller.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -39,7 +39,6 @@ import javax.xml.validation.Schema;
 import org.w3c.dom.Node;
 import org.xml.sax.InputSource;
 import org.apache.sis.internal.jaxb.Context;
-import org.apache.sis.internal.system.XMLInputFactory;
 
 
 /**
@@ -62,7 +61,7 @@ import org.apache.sis.internal.system.XM
  */
 final class PooledUnmarshaller extends Pooled implements Unmarshaller {
     /**
-     * The wrapper marshaller which does the real work.
+     * The wrapped marshaller which does the real work.
      */
     private final Unmarshaller unmarshaller;
 
@@ -70,9 +69,9 @@ final class PooledUnmarshaller extends P
      * Creates a pooled unmarshaller wrapping the given one.
      * Callers shall invoke {@link #reset(Pooled)} after construction for completing the initialization.
      *
-     * @param  unmarshaller The unmarshaller to use for the actual work.
-     * @param  template The {@link PooledTemplate} from which to get the initial values.
-     * @throws JAXBException If an error occurred while setting a property.
+     * @param  unmarshaller  the unmarshaller to use for the actual work.
+     * @param  template      the {@link PooledTemplate} from which to get the initial values.
+     * @throws JAXBException if an error occurred while setting a property.
      */
     PooledUnmarshaller(final Unmarshaller unmarshaller, final Pooled template) throws JAXBException {
         super(template);
@@ -84,9 +83,9 @@ final class PooledUnmarshaller extends P
      * Resets the given unmarshaller property to its initial state.
      * This method is invoked automatically by {@link #reset(Pooled)}.
      *
-     * @param  key   The property to reset.
-     * @param  value The saved 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 saved initial value to give to the property.
+     * @throws JAXBException if an error occurred while restoring a property.
      */
     @Override
     @SuppressWarnings({"unchecked","rawtypes","deprecation"})
@@ -114,8 +113,8 @@ final class PooledUnmarshaller extends P
      * than the one supported natively by SIS, i.e. when {@link #getFilterVersion()} returns a
      * non-null value.
      *
-     * @param  input   The reader created by SIS (<b>not</b> the reader given by the user).
-     * @param  version Identify the namespace substitutions to perform.
+     * @param  input    the reader created by SIS (<b>not</b> the reader given by the user).
+     * @param  version  identify the namespace substitutions to perform.
      * @return The unmarshalled object.
      */
     private Object unmarshal(XMLStreamReader input, final FilterVersion version)
@@ -129,7 +128,7 @@ final class PooledUnmarshaller extends P
         } finally {
             context.finish();
         }
-        input.close(); // Despite its name, this method does not close the underlying input stream.
+        input.close();              // Despite its name, this method does not close the underlying input stream.
         return object;
     }
 
@@ -148,7 +147,7 @@ final class PooledUnmarshaller extends P
         } finally {
             context.finish();
         }
-        input.close(); // Despite its name, this method does not close the underlying input stream.
+        input.close();              // Despite its name, this method does not close the underlying input stream.
         return object;
     }
 
@@ -159,7 +158,7 @@ final class PooledUnmarshaller extends P
     public Object unmarshal(final InputStream input) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -180,7 +179,7 @@ final class PooledUnmarshaller extends P
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
             try (final InputStream s = input.openStream()) {
-                return unmarshal(XMLInputFactory.createXMLStreamReader(s), version);
+                return unmarshal(InputFactory.createXMLStreamReader(s), version);
             }
         } catch (IOException | XMLStreamException e) {
             throw new JAXBException(e);
@@ -202,7 +201,7 @@ final class PooledUnmarshaller extends P
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
             try (final InputStream s = new BufferedInputStream(new FileInputStream(input))) {
-                return unmarshal(XMLInputFactory.createXMLStreamReader(s), version);
+                return unmarshal(InputFactory.createXMLStreamReader(s), version);
             }
         } catch (IOException | XMLStreamException e) {
             throw new JAXBException(e);
@@ -223,7 +222,7 @@ final class PooledUnmarshaller extends P
     public Object unmarshal(final Reader input) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -243,7 +242,7 @@ final class PooledUnmarshaller extends P
     public Object unmarshal(final InputSource input) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -263,7 +262,7 @@ final class PooledUnmarshaller extends P
     public Object unmarshal(final Node input) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -283,7 +282,7 @@ final class PooledUnmarshaller extends P
     public <T> JAXBElement<T> unmarshal(final Node input, final Class<T> declaredType) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version, declaredType);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version, declaredType);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -303,7 +302,7 @@ final class PooledUnmarshaller extends P
     public Object unmarshal(final Source input) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -323,7 +322,7 @@ final class PooledUnmarshaller extends P
     public <T> JAXBElement<T> unmarshal(final Source input, final Class<T> declaredType) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version, declaredType);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version, declaredType);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -377,7 +376,7 @@ final class PooledUnmarshaller extends P
     public Object unmarshal(final XMLEventReader input) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {
@@ -397,7 +396,7 @@ final class PooledUnmarshaller extends P
     public <T> JAXBElement<T> unmarshal(final XMLEventReader input, final Class<T> declaredType) throws JAXBException {
         final FilterVersion version = getFilterVersion();
         if (version != null) try {
-            return unmarshal(XMLInputFactory.createXMLStreamReader(input), version, declaredType);
+            return unmarshal(InputFactory.createXMLStreamReader(input), version, declaredType);
         } catch (XMLStreamException e) {
             throw new JAXBException(e);
         } else {

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/xml/XML.java [UTF-8] Mon Dec 19 08:23:44 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,13 +27,20 @@ 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;
+import javax.xml.transform.stax.StAXSource;
+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;
@@ -42,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.
@@ -356,10 +358,10 @@ 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.
+     * @param  object  the root of content tree to be marshalled.
+     * @return the XML representation of the given object.
      * @throws JAXBException if an error occurred during the marshalling.
      */
     public static String marshal(final Object object) throws JAXBException {
@@ -373,10 +375,10 @@ 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.
+     * @param  object  the root of content tree to be marshalled.
+     * @param  output  the stream where to write.
      * @throws JAXBException if an error occurred during the marshalling.
      */
     public static void marshal(final Object object, final OutputStream output) throws JAXBException {
@@ -389,10 +391,10 @@ 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.
+     * @param  object  the root of content tree to be marshalled.
+     * @param  output  the file to be written.
      * @throws JAXBException if an error occurred during the marshalling.
      */
     public static void marshal(final Object object, final File output) throws JAXBException {
@@ -405,10 +407,10 @@ 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.
+     * @param  object  the root of content tree to be marshalled.
+     * @param  output  the file to be written.
      * @throws JAXBException if an error occurred during the marshalling.
      */
     public static void marshal(final Object object, final Path output) throws JAXBException {
@@ -425,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.
@@ -433,9 +435,9 @@ public final class XML extends Static {
      * together with the keys documented in the <cite>supported properties</cite> section of the the
      * {@link Marshaller} class.
      *
-     * @param  object The root of content tree to be marshalled.
-     * @param  output The file to be written.
-     * @param  properties An optional map of properties to give to the marshaller, or {@code null} if none.
+     * @param  object      the root of content tree to be marshalled.
+     * @param  output      the file to be written.
+     * @param  properties  an optional map of properties to give to the marshaller, or {@code null} if none.
      * @throws JAXBException if a property has an illegal value, or if an error occurred during the marshalling.
      *
      * @since 0.4
@@ -455,12 +457,12 @@ 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.
      *
-     * @param  xml The XML representation of an object.
-     * @return The object unmarshalled from the given input.
+     * @param  xml  the XML representation of an object.
+     * @return the object unmarshalled from the given input.
      * @throws JAXBException if an error occurred during the unmarshalling.
      */
     public static Object unmarshal(final String xml) throws JAXBException {
@@ -474,10 +476,10 @@ 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.
+     * @param  input  the stream from which to read a XML representation.
+     * @return the object unmarshalled from the given input.
      * @throws JAXBException if an error occurred during the unmarshalling.
      */
     public static Object unmarshal(final InputStream input) throws JAXBException {
@@ -490,10 +492,10 @@ 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.
+     * @param  input  the URL from which to read a XML representation.
+     * @return the object unmarshalled from the given input.
      * @throws JAXBException if an error occurred during the unmarshalling.
      */
     public static Object unmarshal(final URL input) throws JAXBException {
@@ -506,10 +508,10 @@ 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.
+     * @param  input  the file from which to read a XML representation.
+     * @return the object unmarshalled from the given input.
      * @throws JAXBException if an error occurred during the unmarshalling.
      */
     public static Object unmarshal(final File input) throws JAXBException {
@@ -522,10 +524,10 @@ 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.
+     * @param  input  the path from which to read a XML representation.
+     * @return the object unmarshalled from the given input.
      * @throws JAXBException if an error occurred during the unmarshalling.
      */
     public static Object unmarshal(final Path input) throws JAXBException {
@@ -543,17 +545,18 @@ 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,
      * together with the keys documented in the <cite>supported properties</cite> section of the the
      * {@link Unmarshaller} class.
      *
-     * @param  input The file from which to read a XML representation.
-     * @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.
+     * @param  input       the file from which to read a XML representation.
+     * @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.
      * @throws JAXBException if a property has an illegal value, or if an error occurred during the unmarshalling.
      *
      * @since 0.4
@@ -561,14 +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;
+        /*
+         * 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);
         }
-        final Object 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/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -142,6 +142,7 @@ import org.junit.BeforeClass;
     org.apache.sis.internal.converter.NumberConverterTest.class,        // Shall be after SystemRegistryTest.
 
     // XML most basic types.
+    org.apache.sis.xml.NamespacesTest.class,
     org.apache.sis.xml.XLinkTest.class,
     org.apache.sis.xml.NilReasonTest.class,
     org.apache.sis.xml.LegacyCodesTest.class,

Modified: sis/trunk/ide-project/NetBeans/nbproject/cfg_hints.xml
URL: http://svn.apache.org/viewvc/sis/trunk/ide-project/NetBeans/nbproject/cfg_hints.xml?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/ide-project/NetBeans/nbproject/cfg_hints.xml (original)
+++ sis/trunk/ide-project/NetBeans/nbproject/cfg_hints.xml Mon Dec 19 08:23:44 2016
@@ -142,5 +142,13 @@
         <node name="org.netbeans.modules.java.hints.jdk.ThrowableInitCause">
             <attribute name="strict" value="false"/>
         </node>
+        <node name="org.netbeans.modules.java.hints.suggestions.ConstantNameHint">
+            <attribute name="immutableClasses" value=""/>
+            <attribute name="namePattern" value="[A-Z]([A-Z\d_]*[A-Z\d])?"/>
+            <attribute name="minLength" value="0"/>
+            <attribute name="onlyCheckImmutables" value="true"/>
+            <attribute name="maxLength" value="35"/>
+            <attribute name="enabled" value="false"/>
+        </node>
     </tool>
 </configuration>

Modified: sis/trunk/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java [UTF-8] (original)
+++ sis/trunk/storage/sis-earth-observation/src/main/java/org/apache/sis/storage/earthobservation/LandsatStore.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -25,9 +25,10 @@ import org.opengis.util.FactoryException
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreReferencingException;
+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;
 
 
@@ -89,12 +90,13 @@ 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);
         if (source == null) {
-            throw new DataStoreException(Errors.format(Errors.Keys.CanNotOpen_1, name));
+            throw new UnsupportedStorageException(errors().getString(Errors.Keys.IllegalInputTypeForReader_2,
+                    "Landsat", Classes.getClass(connector.getStorage())));
         }
     }
 
@@ -134,6 +136,14 @@ public class LandsatStore extends DataSt
     }
 
     /**
+     * Returns the error resources in the current locale.
+     */
+    private Errors errors() {
+        // Must use "super" because LandsatStore construction may not be finished.
+        return Errors.getResources(super.getLocale());
+    }
+
+    /**
      * Returns a string representation of this Landsat store for debugging purpose.
      * The content of the string returned by this method may change in any future SIS version.
      *

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -88,9 +88,9 @@ public final class Resources extends Ind
         public static final short DitheringOrHalftoningApplied_2 = 3;
 
         /**
-         * The “{0}” GeoTIFF key has been ignored.
+         * The following GeoTIFF keys have been ignored: {0}
          */
-        public static final short IgnoredGeoKey_1 = 16;
+        public static final short IgnoredGeoKeys_1 = 19;
 
         /**
          * The “{0}” TIFF tag has been ignored.
@@ -129,8 +129,8 @@ public final class Resources extends Ind
         public static final short MissingValue_2 = 7;
 
         /**
-         * The file defines “{2}” with a value of {3}{4}, but that value should be {1}{4} according
-         * parent definition ({0}).
+         * The file defines “{2}” with value {3}{4}, but that value should be {1}{4} according parent
+         * definition ({0}).
          */
         public static final short NotTheEpsgValue_5 = 17;
 
@@ -145,6 +145,11 @@ public final class Resources extends Ind
         public static final short UnexpectedListOfValues_2 = 15;
 
         /**
+         * The “{1}” parameter was not expected for the “{0}” projection method.
+         */
+        public static final short UnexpectedParameter_2 = 20;
+
+        /**
          * Found {2} tiles or strips in the “{0}” file while {1} were expected.
          */
         public static final short UnexpectedTileCount_3 = 10;
@@ -158,6 +163,11 @@ public final class Resources extends Ind
          * Version {0} of GeoTIFF key directory is not supported.
          */
         public static final short UnsupportedGeoKeyDirectory_1 = 13;
+
+        /**
+         * Unsupported storage location for the “{0}” GeoTIFF value.
+         */
+        public static final short UnsupportedGeoKeyStorage_1 = 16;
     }
 
     /**

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties [ISO-8859-1] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.properties [ISO-8859-1] Mon Dec 19 08:23:44 2016
@@ -25,16 +25,18 @@ ComputedValueForAttribute_2       = No v
 DefaultValueForAttribute_2        = No value specified for the \u201c{0}\u201d TIFF tag. The {1} default value will be used.
 DitheringOrHalftoningApplied_2    = An ordered dither or halftone technique has been applied to the image data. The dithering or halftoning matrix size is {0}\u00d7{1}.
 IgnoredTag_1                      = The \u201c{0}\u201d TIFF tag has been ignored.
-IgnoredGeoKey_1                   = The \u201c{0}\u201d GeoTIFF key has been ignored.
+IgnoredGeoKeys_1                  = The following GeoTIFF keys have been ignored: {0}
 InconsistentTileStrip_1           = TIFF image \u201c{0}\u201d shall be either tiled or organized into strips.
 InvalidGeoValue_2                 = \u201c{1}\u201d is not a valid value for the \u201c{0}\u201d GeoTIFF key.
 ListTooShort_3                    = TIFF tag \u201c{0}\u201d shall contain at least {1} values but found only {2}.
 MismatchedLength_4                = TIFF tags \u201c{0}\u201d and \u201c{1}\u201d have values of different lengths. Found \u201c{2}\u201d and \u201c{3}\u201d elements respectively.
 MissingGeoValue_1                 = No value has been found for the \u201c{0}\u201d GeoTIFF key.
 MissingValue_2                    = Can not read TIFF image from \u201c{0}\u201d because the \u201c{1}\u201d tag is missing.
-NotTheEpsgValue_5                 = The file defines \u201c{2}\u201d with a value of {3}{4}, but that value should be {1}{4} according parent definition ({0}).
+NotTheEpsgValue_5                 = The file defines \u201c{2}\u201d with value {3}{4}, but that value should be {1}{4} according parent definition ({0}).
 RandomizedProcessApplied          = A randomized process such as error diffusion has been applied to the image data.
 UnexpectedListOfValues_2          = A single value was expected for the \u201c{0}\u201d key but {1} values have been found.
+UnexpectedParameter_2             = The \u201c{1}\u201d parameter was not expected for the \u201c{0}\u201d projection method.
 UnexpectedTileCount_3             = Found {2} tiles or strips in the \u201c{0}\u201d file while {1} were expected.
 UnsupportedCoordinateSystemKind_1 = Coordinate system kind {0} is unsupported.
 UnsupportedGeoKeyDirectory_1      = Version {0}\u00a0of GeoTIFF key directory is not supported.
+UnsupportedGeoKeyStorage_1        = Unsupported storage location for the \u201c{0}\u201d GeoTIFF value.

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.properties [ISO-8859-1] Mon Dec 19 08:23:44 2016
@@ -30,7 +30,7 @@ ComputedValueForAttribute_2       = Aucu
 DefaultValueForAttribute_2        = Aucune valeur n\u2019a \u00e9t\u00e9 sp\u00e9cifi\u00e9e pour le tag TIFF \u00ab\u202f{0}\u202f\u00bb. La valeur par d\u00e9faut sera {1}.
 DitheringOrHalftoningApplied_2    = Un tramage ordonn\u00e9 ou une technique en demi-teinte a \u00e9t\u00e9 appliqu\u00e9. La taille de la matrice de tramage est {0}\u00d7{1}.
 IgnoredTag_1                      = Le tag TIFF \u00ab\u202f{0}\u202f\u00bb a \u00e9t\u00e9 ignor\u00e9.
-IgnoredGeoKey_1                   = La cl\u00e9 GeoTIFF \u00ab\u202f{0}\u202f\u00bb a \u00e9t\u00e9 ignor\u00e9e.
+IgnoredGeoKeys_1                  = Les cl\u00e9s GeoTIFF suivantes ont \u00e9t\u00e9 ignor\u00e9es\u2008: {0}
 InconsistentTileStrip_1           = L\u2019image TIFF \u00ab\u202f{0}\u202f\u00bb doit \u00eatre soit tuil\u00e9e, soit organis\u00e9e par bandes.
 InvalidGeoValue_2                 = La valeur \u00ab\u202f{1}\u202f\u00bb n\u2019est pas valide pour la cl\u00e9 GeoTIFF \u00ab\u202f{0}\u202f\u00bb.
 ListTooShort_3                    = Le tag TIFF \u00ab\u202f{0}\u202f\u00bb devrait contenir au moins {1} valeurs alors qu\u2019on n\u2019en a trouv\u00e9 que {2}.
@@ -40,6 +40,8 @@ MissingValue_2                    = Ne p
 NotTheEpsgValue_5                 = Le fichier d\u00e9finit \u00ab\u202f{2}\u202f\u00bb avec la valeur {3}{4}, mais cette valeur devrait \u00eatre {1}{4} pour \u00eatre en accord avec la d\u00e9finition du parent {0}.
 RandomizedProcessApplied          = Un processus randomis\u00e9 comme la diffusion d\u2019erreur a \u00e9t\u00e9 appliqu\u00e9.
 UnexpectedListOfValues_2          = Une seule valeur \u00e9tait attendue pour la cl\u00e9 \u00ab\u202f{0}\u202f\u00bb, mais on en a trouv\u00e9es {1}.
+UnexpectedParameter_2             = Le param\u00e8tre \u00ab\u202f{1}\u202f\u00bb est inattendu pour la m\u00e9thode de projection \u00ab\u202f{0}\u202f\u00bb.
 UnexpectedTileCount_3             = {2} tuiles ont \u00e9t\u00e9 trouv\u00e9es dans le fichier \u00ab\u202f{0}\u202f\u00bb alors qu\u2019on en attendait {1}.
 UnsupportedCoordinateSystemKind_1 = Le type de syst\u00e8me de coordonn\u00e9es {0} n\u2019est pas support\u00e9.
 UnsupportedGeoKeyDirectory_1      = La version {0} du r\u00e9pertoire de cl\u00e9s GeoTIFF n\u2019est pas support\u00e9e.
+UnsupportedGeoKeyStorage_1        = La valeur GeoTIFF \u00ab\u202f{0}\u202f\u00bb utilise un mode de stockage non-support\u00e9.

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/CRSBuilder.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.storage.geotiff;
 
+import java.util.Arrays;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -35,16 +36,21 @@ import org.opengis.metadata.Identifier;
 import org.opengis.metadata.spatial.CellGeometry;
 import org.opengis.metadata.spatial.PixelOrientation;
 import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.crs.CRSFactory;
+import org.opengis.referencing.crs.GeocentricCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.ProjectedCRS;
+import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.cs.EllipsoidalCS;
+import org.opengis.referencing.cs.VerticalCS;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.datum.PrimeMeridian;
+import org.opengis.referencing.datum.VerticalDatum;
 import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.OperationMethod;
@@ -63,6 +69,7 @@ import org.apache.sis.internal.util.Util
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.math.Vector;
 import org.apache.sis.measure.Units;
+import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.CommonCRS;
@@ -79,7 +86,6 @@ import org.apache.sis.util.Characters;
 import org.apache.sis.util.Debug;
 
 import static org.apache.sis.util.Utilities.equalsIgnoreMetadata;
-import org.apache.sis.util.iso.DefaultNameSpace;
 
 
 /**
@@ -191,6 +197,9 @@ final class CRSBuilder {
 
     /**
      * All values found in the {@code GeoKeyDirectory} after the header.
+     * Each value shall be used at most once. This allow us to remove value after usage,
+     * so we can easily detect at the end of the parsing process which GeoTIFF keys were
+     * unrecognized or ignored.
      */
     private final Map<Short,Object> geoKeys = new HashMap<>();
 
@@ -526,9 +535,14 @@ final class CRSBuilder {
     }
 
 
-    // ---------------------------- geokeys parsing -----------------------------
 
 
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                                 GeoKeys parsing                                  ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
     /**
      * Decodes all the given GeoTIFF keys, then creates a coordinate reference system.
      * An overview of the key directory structure is given in {@linkplain CRSBuilder class javadoc}.
@@ -674,29 +688,39 @@ final class CRSBuilder {
                  * it would have be stored in one of the standard GeoTIFF tags.
                  */
                 default: {
-                    warning(Resources.Keys.IgnoredGeoKey_1, GeoKeys.name(key));
+                    warning(Resources.Keys.UnsupportedGeoKeyStorage_1, GeoKeys.name(key));
                     continue;
                 }
             }
             geoKeys.put(key, value);
         }
         /*
-         * At this point we finished copying all GeoTIFF keys in CRSBuilder.geoKeys map.
+         * At this point we finished copying all GeoTIFF keys in 'CRSBuilder.geoKeys' map.
+         * First create the main coordinate reference system, as determined by 'ModelType'.
+         * Then if a vertical CRS exists and the main CRS is not geocentric (in which case
+         * adding a vertical CRS would make no sense), create a three-dimensional compound CRS.
          */
+        CoordinateReferenceSystem crs;
         final int crsType = getAsInteger(GeoKeys.ModelType);
         switch (crsType) {
             case GeoCodes.undefined:           return null;
-            case GeoCodes.ModelTypeProjected:  return createProjectedCRS();
+            case GeoCodes.ModelTypeProjected:  crs = createProjectedCRS(); break;
+            case GeoCodes.ModelTypeGeocentric: return createGeocentricCRS();        // Ignore vertical CRS.
             case GeoCodes.ModelTypeGeographic: {
-                return createGeographicCRS(true,
+                crs = createGeographicCRS(true,
                         createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE));
+                break;
             }
-            case GeoCodes.ModelTypeGeocentric: // TODO
             default: {
                 warning(Resources.Keys.UnsupportedCoordinateSystemKind_1, crsType);
                 return null;
             }
         }
+        final VerticalCRS vertical = createVerticalCRS();
+        if (vertical != null) {
+            crs = objectFactory().createCompoundCRS(Collections.singletonMap(IdentifiedObject.NAME_KEY, crs.getName()), crs, vertical);
+        }
+        return crs;
     }
 
     /**
@@ -709,6 +733,8 @@ final class CRSBuilder {
      *   <li>{@link ImageFileDirectory} must have filled its part of metadata before to invoke this method.</li>
      * </ul>
      *
+     * After execution, this method emits a warning for unprocessed GeoTIFF tags.
+     *
      * @param  metadata  the helper class where to write metadata values.
      * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
      */
@@ -739,12 +765,39 @@ final class CRSBuilder {
         }
         metadata.setCellGeometry(cg);
         metadata.setPointInPixel(po);
+        /*
+         * Build a list of remaining GeoKeys.
+         */
+        if (!geoKeys.isEmpty()) {
+            final StringBuilder joiner = new StringBuilder();
+            for (final short key : remainingKeys()) {
+                if (joiner.length() != 0) {
+                    joiner.append(", ");
+                }
+                joiner.append(GeoKeys.name(key));
+            }
+            warning(Resources.Keys.IgnoredGeoKeys_1, joiner.toString());
+        }
+    }
+
+    /**
+     * Returns all remaining keys, sorted in increasing order.
+     */
+    private Short[] remainingKeys() {
+        final Short[] keys = geoKeys.keySet().toArray(new Short[geoKeys.size()]);
+        Arrays.sort(keys);
+        return keys;
     }
 
 
-    // -------------------------- geodetic components ---------------------------
 
 
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                   Geodetic components (datum, ellipsoid, etc.)                   ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
     /**
      * Returns a coordinate system (CS) with the same axis directions than the given CS but potentially different units.
      * If a coordinate system exists in the EPSG database with the requested characteristics, that CS will be returned
@@ -853,7 +906,9 @@ final class CRSBuilder {
     private PrimeMeridian createPrimeMeridian(final String[] names, final Unit<Angle> unit) throws FactoryException {
         final int epsg = getAsInteger(GeoKeys.PrimeMeridian);
         switch (epsg) {
-            case GeoCodes.undefined: break;         // If not specified, default to Greenwich.
+            case GeoCodes.undefined: {
+                break;                      // If not specified, default to Greenwich.
+            }
             case GeoCodes.userDefined: {
                 final double longitude = getAsDouble(GeoKeys.PrimeMeridianLong);
                 if (Double.isNaN(longitude)) {
@@ -867,7 +922,7 @@ final class CRSBuilder {
                      */
                     return objectFactory().createPrimeMeridian(properties(names[PRIMEM]), longitude, unit);
                 }
-                break;              // Default to Greenwich.
+                break;                      // Default to Greenwich.
             }
             default: {
                 /*
@@ -1066,9 +1121,14 @@ final class CRSBuilder {
     }
 
 
-    // ----------------------------- geographic CRS -----------------------------
 
 
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                     Geodetic CRS (geographic and geocentric)                     ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
     /**
      * Splits the {@link GeoKeys#GeogCitation} value into its prime meridian, ellipsoid, datum and CRS name components.
      * This method is intended to parse geographic CRS names written like below:
@@ -1218,9 +1278,80 @@ final class CRSBuilder {
         verify(datum, angularUnit, linearUnit);
     }
 
+    /**
+     * Creates a geocentric CRS from user-defined parameters.
+     * The GeoTIFF values used by this method are the same than the ones used by {@code createGeographicCRS(…)}.
+     *
+     * @throws NoSuchElementException if a mandatory value is missing.
+     * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
+     * @throws ClassCastException if an object defined by an EPSG code is not of the expected type.
+     * @throws FactoryException if an error occurred during objects creation with the factories.
+     *
+     * @see #createGeodeticDatum(String, Unit, Unit)
+     */
+    private GeocentricCRS createGeocentricCRS() throws FactoryException {
+        final int epsg = getAsInteger(GeoKeys.GeographicType);
+        switch (epsg) {
+            case GeoCodes.undefined: {
+                throw new NoSuchElementException(missingValue(GeoKeys.GeographicType));
+            }
+            case GeoCodes.userDefined: {
+                /*
+                 * Creates the geodetic datum, then a geocentric CRS. We use the coordinate system of
+                 * the WGS84 geocentric CRS as a template and modify its unit of measurement if needed.
+                 */
+                final String[] names = splitName(getAsString(GeoKeys.GeogCitation));
+                final Unit<Length> linearUnit = createUnit(GeoKeys.GeogLinearUnits, GeoKeys.GeogLinearUnitSize, Length.class, Units.METRE);
+                final Unit<Angle> angularUnit = createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE);
+                final GeodeticDatum datum = createGeodeticDatum(names, angularUnit, linearUnit);
+                CartesianCS cs = (CartesianCS) CommonCRS.WGS84.geocentric().getCoordinateSystem();
+                if (!Units.METRE.equals(linearUnit)) {
+                    cs = replaceLinearUnit(cs, linearUnit);
+                }
+                final GeocentricCRS crs = objectFactory().createGeocentricCRS(properties(getOrDefault(names, GCRS)), datum, cs);
+                lastName = crs.getName();
+                return crs;
+            }
+            default: {
+                /*
+                 * Geocentric CRS defined by an EPSG code. In principle we should just use the EPSG code.
+                 * But if the file also defines the components, verify that those components are consistent
+                 * with what we would expect for a CRS of the given EPSG code.
+                 */
+                final GeocentricCRS crs = epsgFactory().createGeocentricCRS(String.valueOf(epsg));
+                verify(crs);
+                return crs;
+            }
+        }
+    }
+
+    /**
+     * Verifies if the user-defined CRS created from GeoTIFF values
+     * matches the given CRS created from the EPSG geodetic dataset.
+     * This method does not verify the EPSG code of the given CRS.
+     *
+     * @param  crs  the CRS created from the EPSG geodetic dataset.
+     */
+    private void verify(final GeocentricCRS crs) throws FactoryException {
+        /*
+         * Note: current createUnit(…) implementation does not allow us to distinguish whether METRE ou DEGREE units
+         * were specified in the GeoTIFF file or if we got the default values. We do not compare units of that reason.
+         */
+        final Unit<Length> linearUnit = createUnit(GeoKeys.GeogLinearUnits, GeoKeys.GeogLinearUnitSize, Length.class, Units.METRE);
+        final Unit<Angle> angularUnit = createUnit(GeoKeys.AngularUnits, GeoKeys.AngularUnitSize, Angle.class, Units.DEGREE);
+        final GeodeticDatum datum = crs.getDatum();
+        verifyIdentifier(crs, datum, GeoKeys.GeodeticDatum);
+        verify(datum, angularUnit, linearUnit);
+    }
+
+
 
-    // ----------------------------- projected CRS ------------------------------
 
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                                  Projected CRS                                   ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
 
     /**
      * Creates a projected CRS from an EPSG code or from user-defined parameters.
@@ -1332,17 +1463,17 @@ final class CRSBuilder {
                 while (it.hasNext()) {
                     final Unit<?> unit;
                     final Map.Entry<Short,?> entry = it.next();
-                    final short code = entry.getKey();
-                    switch (GeoKeys.unitOf(code)) {
-                        case GeoKeys.RATIO:     unit = Units.UNITY; break;
-                        case GeoKeys.LINEAR:    unit = linearUnit;  break;
-                        case GeoKeys.ANGULAR:   unit = angularUnit; break;
-                        case GeoKeys.AZIMUTH:   unit = azimuthUnit; break;
+                    final short key = entry.getKey();
+                    switch (GeoKeys.unitOf(key)) {
+                        case GeoKeys.RATIO:   unit = Units.UNITY; break;
+                        case GeoKeys.LINEAR:  unit = linearUnit;  break;
+                        case GeoKeys.ANGULAR: unit = angularUnit; break;
+                        case GeoKeys.AZIMUTH: unit = azimuthUnit; break;
                         default: continue;
                     }
                     final double value = ((Number) entry.getValue()).doubleValue();
                     it.remove();
-                    parameters.parameter("GeoTIFF" + code).setValue(value, unit);
+                    parameters.parameter("GeoTIFF:" + key).setValue(value, unit);
                 }
                 final Conversion c = operationFactory().createDefiningConversion(properties(name), method, parameters);
                 lastName = c.getName();
@@ -1366,7 +1497,108 @@ final class CRSBuilder {
     private void verify(final Conversion projection, final Unit<Angle> angularUnit, final Unit<Length> linearUnit)
             throws FactoryException
     {
-        // TODO
+        final Unit<Angle> azimuthUnit = createUnit(GeoKeys.AzimuthUnits, (short) 0, Angle.class, Units.DEGREE);
+        final String type = getAsString(GeoKeys.CoordTrans);
+        if (type != null) {
+            /*
+             * Compare the name of the map projection declared in the GeoTIFF file with the name
+             * of the projection used by the EPSG geodetic dataset.
+             */
+            final OperationMethod method = projection.getMethod();
+            if (!IdentifiedObjects.isHeuristicMatchForName(method, type)) {
+                Identifier expected = IdentifiedObjects.getIdentifier(method, Citations.GEOTIFF);
+                if (expected == null) {
+                    expected = IdentifiedObjects.getIdentifier(method, null);
+                }
+                warning(Resources.Keys.NotTheEpsgValue_5, IdentifiedObjects.getIdentifierOrName(projection),
+                        expected.getCode(), GeoKeys.name(GeoKeys.CoordTrans), type, "");
+            }
+            /*
+             * Compare the parameter values with the ones declared in the EPSG geodetic dataset.
+             */
+            final ParameterValueGroup parameters = projection.getParameterValues();
+            for (final short key : remainingKeys()) {
+                final Unit<?> unit;
+                switch (GeoKeys.unitOf(key)) {
+                    case GeoKeys.RATIO:   unit = Units.UNITY; break;
+                    case GeoKeys.LINEAR:  unit = linearUnit;  break;
+                    case GeoKeys.ANGULAR: unit = angularUnit; break;
+                    case GeoKeys.AZIMUTH: unit = azimuthUnit; break;
+                    default: continue;
+                }
+                try {
+                    verify(projection, parameters.parameter("GeoTIFF:" + key).doubleValue(unit), key, unit);
+                } catch (ParameterNotFoundException e) {
+                    warning(Resources.Keys.UnexpectedParameter_2, type, GeoKeys.name(key));
+                }
+            }
+        }
+    }
+
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                                   Vertical CRS                                   ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Creates a vertical datum.
+     */
+    private VerticalDatum createVerticalDatum() throws FactoryException {
+        final int epsg = getAsInteger(GeoKeys.VerticalDatum);
+        switch (epsg) {
+            case GeoCodes.undefined:
+            case GeoCodes.userDefined: {
+                throw new NoSuchElementException(missingValue(GeoKeys.VerticalDatum));
+            }
+            default: {
+                return epsgFactory().createVerticalDatum(String.valueOf(epsg));
+            }
+        }
+    }
+
+    /**
+     * Creates an optional vertical CRS, or returns {@code null} if no vertical CRS definition is found.
+     * This method is different from the other {@code createFooCRS()} methods in that the vertical CRS
+     * may be defined <em>in addition</em> of another CRS. Some GeoTIFF values used by this method are:
+     *
+     * <ul>
+     *   <li>A code given by {@link GeoKeys#VerticalCSType}.</li>
+     *   <li>If above code is {@link GeoCodes#userDefined}, then:<ul>
+     *     <li>a name given by {@link GeoKeys#VerticalCitation},</li>
+     *     <li>a {@link VerticalDatum} given by {@link GeoKeys#VerticalDatum}.</li>
+     *   </ul></li>
+     *   <li>A unit code given by {@link GeoKeys#VerticalUnits} (optional).</li>
+     * </ul>
+     *
+     * @throws NoSuchElementException if a mandatory value is missing.
+     * @throws NumberFormatException if a numeric value was stored as a string and can not be parsed.
+     * @throws ClassCastException if an object defined by an EPSG code is not of the expected type.
+     * @throws FactoryException if an error occurred during objects creation with the factories.
+     */
+    private VerticalCRS createVerticalCRS() throws FactoryException {
+        final int epsg = getAsInteger(GeoKeys.VerticalCSType);
+        switch (epsg) {
+            case GeoCodes.undefined: {
+                return null;
+            }
+            case GeoCodes.userDefined: {
+                final String name = getAsString(GeoKeys.VerticalCitation);
+                final VerticalDatum datum = createVerticalDatum();
+                final Unit<Length> unit = createUnit(GeoKeys.VerticalUnits, (short) 0, Length.class, Units.METRE);
+                VerticalCS cs = CommonCRS.Vertical.MEAN_SEA_LEVEL.crs().getCoordinateSystem();
+                if (!Units.METRE.equals(unit)) {
+                    cs = (VerticalCS) CoordinateSystems.replaceLinearUnit(cs, unit);
+                }
+                return objectFactory().createVerticalCRS(properties(name), datum, cs);
+            }
+            default: {
+                return epsgFactory().createVerticalCRS(String.valueOf(epsg));
+            }
+        }
     }
 
     /**

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStore.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -29,11 +29,11 @@ import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreContentException;
+import org.apache.sis.storage.UnsupportedStorageException;
 import org.apache.sis.internal.storage.ChannelDataInput;
 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;
 
 
@@ -70,19 +70,19 @@ public class GeoTiffStore extends DataSt
      * This constructor invokes {@link StorageConnector#closeAllExcept(Object)},
      * keeping open only the needed resource.
      *
-     * @param  storage  information about the storage (URL, stream, <i>etc</i>).
+     * @param  connector  information about the storage (URL, stream, <i>etc</i>).
      * @throws DataStoreException if an error occurred while opening the GeoTIFF file.
      */
-    public GeoTiffStore(final StorageConnector storage) throws DataStoreException {
-        ArgumentChecks.ensureNonNull("storage", storage);
-        final Charset encoding = storage.getOption(OptionKey.ENCODING);
+    public GeoTiffStore(final StorageConnector connector) throws DataStoreException {
+        super(connector);
+        final Charset encoding = connector.getOption(OptionKey.ENCODING);
         this.encoding = (encoding != null) ? encoding : StandardCharsets.US_ASCII;
-        final ChannelDataInput input = storage.getStorageAs(ChannelDataInput.class);
+        final ChannelDataInput input = connector.getStorageAs(ChannelDataInput.class);
         if (input == null) {
-            throw new DataStoreException(Errors.format(Errors.Keys.IllegalInputTypeForReader_2,
-                    "TIFF", Classes.getClass(storage.getStorage())));
+            throw new UnsupportedStorageException(errors().getString(Errors.Keys.IllegalInputTypeForReader_2,
+                    "TIFF", Classes.getClass(connector.getStorage())));
         }
-        storage.closeAllExcept(input);
+        connector.closeAllExcept(input);
         try {
             reader = new Reader(this, input);
         } catch (IOException e) {
@@ -118,7 +118,7 @@ public class GeoTiffStore extends DataSt
                 }
                 metadata = builder.build(true);
             } catch (IOException e) {
-                throw new DataStoreException(reader.errors().getString(Errors.Keys.CanNotRead_1, reader.input.filename), e);
+                throw new DataStoreException(errors().getString(Errors.Keys.CanNotRead_1, reader.input.filename), e);
             } catch (FactoryException | ArithmeticException e) {
                 throw new DataStoreContentException(reader.canNotDecode(), e);
             }
@@ -143,6 +143,14 @@ public class GeoTiffStore extends DataSt
     }
 
     /**
+     * Returns the error resources in the current locale.
+     */
+    final Errors errors() {
+        // Must use "super" because GeoTiffStore construction may not be finished.
+        return Errors.getResources(super.getLocale());
+    }
+
+    /**
      * Reports a warning represented by the given message and exception.
      * At least one of {@code message} and {@code exception} shall be non-null.
      *

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -18,6 +18,7 @@ package org.apache.sis.storage.geotiff;
 
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
+import org.apache.sis.util.Version;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.DataStoreProvider;
@@ -47,6 +48,11 @@ public class GeoTiffStoreProvider extend
     private static final String MIME_TYPE = "image/tiff";
 
     /**
+     * The TIFF version.
+     */
+    private static final Version VERSION = new Version("6.0");
+
+    /**
      * Creates a new provider.
      */
     public GeoTiffStoreProvider() {
@@ -78,7 +84,7 @@ public class GeoTiffStoreProvider extend
                     buffer.order(isBigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
                     switch (buffer.getShort(p + (Short.SIZE / Byte.SIZE))) {
                         case GeoTIFF.CLASSIC:
-                        case GeoTIFF.BIG_TIFF: return new ProbeResult(true, MIME_TYPE, null);
+                        case GeoTIFF.BIG_TIFF: return new ProbeResult(true, MIME_TYPE, VERSION);
                     }
                 } finally {
                     buffer.order(old);

Modified: sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java [UTF-8] (original)
+++ sis/trunk/storage/sis-geotiff/src/main/java/org/apache/sis/storage/geotiff/Reader.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -181,8 +181,8 @@ final class Reader extends GeoTIFF {
                 }
             }
         }
-        // Do not invoke errors() yet because GeoTiffStore construction may not be finished.
-        throw new DataStoreContentException(Errors.format(Errors.Keys.UnexpectedFileFormat_2, "TIFF", input.filename));
+        // Do not invoke this.errors() yet because GeoTiffStore construction may not be finished. Owner.error() is okay.
+        throw new DataStoreContentException(owner.errors().getString(Errors.Keys.UnexpectedFileFormat_2, "TIFF", input.filename));
     }
 
     /**

Modified: sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java
URL: http://svn.apache.org/viewvc/sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java?rev=1775004&r1=1775003&r2=1775004&view=diff
==============================================================================
--- sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java [UTF-8] (original)
+++ sis/trunk/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Decoder.java [UTF-8] Mon Dec 19 08:23:44 2016
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.netcdf;
 
 import java.util.Date;
+import java.util.Objects;
 import java.io.Closeable;
 import java.io.IOException;
 import javax.measure.Unit;
@@ -25,9 +26,6 @@ import org.apache.sis.measure.Units;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.util.logging.WarningListeners;
 
-// Branch-dependent imports
-import java.util.Objects;
-
 
 /**
  * The API used internally by Apache SIS for fetching variables and attribute values from a NetCDF file.



Mime
View raw message