sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1640591 - in /sis/branches/JDK7: ./ core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/ core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/ core/sis-metadata/src/test/java/org/apache/sis/metadata/ core/sis-met...
Date Wed, 19 Nov 2014 16:33:10 GMT
Author: desruisseaux
Date: Wed Nov 19 16:33:09 2014
New Revision: 1640591

URL: http://svn.apache.org/r1640591
Log:
Merge from the JDK8 branch: ISO-19115 TopicCategory and PixelOrientation shall be Enum, not CodeList.
http://jira.codehaus.org/browse/GEO-199

Added:
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/EnumMarshallingTest.java
      - copied unchanged from r1640590, sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/EnumMarshallingTest.java
Modified:
    sis/branches/JDK7/   (props changed)
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_ParameterDirection.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java
    sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
    sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ObjectToString.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemRegistry.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/CodeListAdapter.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/CodeListFilter.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/SystemRegistryTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/collection/CodeListSetTest.java
    sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
    sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java

Propchange: sis/branches/JDK7/
------------------------------------------------------------------------------
  Merged /sis/branches/JDK8:r1640394-1640590

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -18,8 +18,7 @@ package org.apache.sis.internal.jaxb.cod
 
 import javax.xml.bind.annotation.XmlElement;
 import org.opengis.metadata.spatial.PixelOrientation;
-import org.apache.sis.internal.jaxb.gmd.CodeListAdapter;
-import org.apache.sis.internal.jaxb.gmd.CodeListProxy;
+import org.apache.sis.internal.jaxb.gmd.EnumAdapter;
 
 
 /**
@@ -29,70 +28,46 @@ import org.apache.sis.internal.jaxb.gmd.
  *
  * @author  Cédric Briançon (Geomatys)
  * @since   0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.5
  * @module
  */
-public final class MD_PixelOrientationCode
-        extends CodeListAdapter<MD_PixelOrientationCode, PixelOrientation>
-{
+public final class MD_PixelOrientationCode extends EnumAdapter<MD_PixelOrientationCode, PixelOrientation> {
     /**
-     * Empty constructor for JAXB only.
+     * The enumeration value.
      */
-    public MD_PixelOrientationCode() {
-    }
+    @XmlElement(name = "MD_PixelOrientationCode")
+    private String value;
 
     /**
-     * Creates a new adapter for the given proxy.
+     * Empty constructor for JAXB only.
      */
-    private MD_PixelOrientationCode(final CodeListProxy proxy) {
-        super(proxy);
+    public MD_PixelOrientationCode() {
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the wrapped value.
      *
-     * @return The wrapper for the code list value.
+     * @param wrapper The wrapper.
+     * @return The wrapped value.
      */
     @Override
-    protected MD_PixelOrientationCode wrap(CodeListProxy proxy) {
-        return new MD_PixelOrientationCode(proxy);
+    public final PixelOrientation unmarshal(final MD_PixelOrientationCode wrapper) {
+        return PixelOrientation.valueOf(name(wrapper.value));
     }
 
     /**
-     * {@inheritDoc}
+     * Wraps the given value.
      *
-     * @return The code list class.
+     * @param  e The value to wrap.
+     * @return The wrapped value.
      */
     @Override
-    protected Class<PixelOrientation> getCodeListClass() {
-        return PixelOrientation.class;
-    }
-
-    /**
-     * Returns {@code true} since this code list is actually an enum.
-     */
-    @Override
-    protected boolean isEnum() {
-        return true;
-    }
-
-    /**
-     * Invoked by JAXB on marshalling.
-     *
-     * @return The value to be marshalled.
-     */
-    @Override
-    @XmlElement(name = "MD_PixelOrientationCode")
-    public CodeListProxy getElement() {
-        return proxy;
-    }
-
-    /**
-     * Invoked by JAXB on unmarshalling.
-     *
-     * @param proxy The unmarshalled value.
-     */
-    public void setElement(final CodeListProxy proxy) {
-        this.proxy = proxy;
+    public final MD_PixelOrientationCode marshal(final PixelOrientation e) {
+        if (e == null) {
+            return null;
+        }
+        final MD_PixelOrientationCode wrapper = new MD_PixelOrientationCode();
+        wrapper.value = value(e);
+        return wrapper;
     }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -18,8 +18,7 @@ package org.apache.sis.internal.jaxb.cod
 
 import javax.xml.bind.annotation.XmlElement;
 import org.opengis.metadata.identification.TopicCategory;
-import org.apache.sis.internal.jaxb.gmd.CodeListAdapter;
-import org.apache.sis.internal.jaxb.gmd.CodeListProxy;
+import org.apache.sis.internal.jaxb.gmd.EnumAdapter;
 
 
 /**
@@ -31,68 +30,46 @@ import org.apache.sis.internal.jaxb.gmd.
  * @author  Guihem Legal (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.5
  * @module
  */
-public final class MD_TopicCategoryCode extends CodeListAdapter<MD_TopicCategoryCode, TopicCategory> {
+public final class MD_TopicCategoryCode extends EnumAdapter<MD_TopicCategoryCode, TopicCategory> {
     /**
-     * Empty constructor for JAXB only.
+     * The enumeration value.
      */
-    public MD_TopicCategoryCode() {
-    }
+    @XmlElement(name = "MD_TopicCategoryCode")
+    private String value;
 
     /**
-     * Creates a new adapter for the given proxy.
+     * Empty constructor for JAXB only.
      */
-    private MD_TopicCategoryCode(final CodeListProxy proxy) {
-        super(proxy);
+    public MD_TopicCategoryCode() {
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the wrapped value.
      *
-     * @return The wrapper for the code list value.
+     * @param wrapper The wrapper.
+     * @return The wrapped value.
      */
     @Override
-    protected MD_TopicCategoryCode wrap(CodeListProxy proxy) {
-        return new MD_TopicCategoryCode(proxy);
+    public final TopicCategory unmarshal(final MD_TopicCategoryCode wrapper) {
+        return TopicCategory.valueOf(name(wrapper.value));
     }
 
     /**
-     * {@inheritDoc}
+     * Wraps the given value.
      *
-     * @return The code list class.
+     * @param  e The value to wrap.
+     * @return The wrapped value.
      */
     @Override
-    protected Class<TopicCategory> getCodeListClass() {
-        return TopicCategory.class;
-    }
-
-    /**
-     * Returns {@code true} since this code list is actually an enum.
-     */
-    @Override
-    protected boolean isEnum() {
-        return true;
-    }
-
-    /**
-     * Invoked by JAXB on marshalling.
-     *
-     * @return The value to be marshalled.
-     */
-    @Override
-    @XmlElement(name = "MD_TopicCategoryCode")
-    public CodeListProxy getElement() {
-        return proxy;
-    }
-
-    /**
-     * Invoked by JAXB on unmarshalling.
-     *
-     * @param proxy The unmarshalled value.
-     */
-    public void setElement(final CodeListProxy proxy) {
-        this.proxy = proxy;
+    public final MD_TopicCategoryCode marshal(final TopicCategory e) {
+        if (e == null) {
+            return null;
+        }
+        final MD_TopicCategoryCode wrapper = new MD_TopicCategoryCode();
+        wrapper.value = value(e);
+        return wrapper;
     }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_ParameterDirection.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_ParameterDirection.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_ParameterDirection.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/SV_ParameterDirection.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -40,6 +40,12 @@ public final class SV_ParameterDirection
     private String value;
 
     /**
+     * Empty constructor for JAXB only.
+     */
+    public SV_ParameterDirection() {
+    }
+
+    /**
      * Returns the wrapped value.
      *
      * @param wrapper The wrapper.

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/code/CodeListMarshallingTest.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -25,13 +25,12 @@ import org.opengis.metadata.citation.Rol
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.Responsibility;
-import org.opengis.metadata.identification.TopicCategory;
-import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
+import org.opengis.metadata.citation.PresentationForm;
+import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.internal.jaxb.Schemas;
 import org.apache.sis.xml.XML;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.xml.MarshallerPool;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.test.XMLTestCase;
 import org.junit.Test;
 
@@ -44,7 +43,7 @@ import static org.apache.sis.test.Assert
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Guilhem Legal (Geomatys)
  * @since   0.3 (derived from geotk-3.17)
- * @version 0.4
+ * @version 0.5
  * @module
  *
  * @see <a href="http://jira.geotoolkit.org/browse/GEOTK-121">GEOTK-121</a>
@@ -154,17 +153,23 @@ public final strictfp class CodeListMars
      */
     @Test
     public void testExtraCodes() throws JAXBException {
-        final DefaultDataIdentification id = new DefaultDataIdentification();
-        id.setTopicCategories(Arrays.asList(
-                TopicCategory.valueOf("oceans"), // New code
-                TopicCategory.valueOf("OCEANS"), // Existing code with UML id="oceans"
-                TopicCategory.valueOf("test"))); // New code
+        final DefaultCitation id = new DefaultCitation();
+        id.setPresentationForms(Arrays.asList(
+                PresentationForm.valueOf("IMAGE_DIGITAL"), // Existing code with UML id="imageDigital"
+                PresentationForm.valueOf("test")));        // New code
 
         final String xml = marshal(id);
 
-        // "OCEANS" is marshalled as "oceans" because is contains a UML id, which is lower-case.
-        assertEquals(2, CharSequences.count(xml, "<gmd:MD_TopicCategoryCode>oceans</gmd:MD_TopicCategoryCode>"));
-        assertEquals(0, CharSequences.count(xml, "<gmd:MD_TopicCategoryCode>OCEANS</gmd:MD_TopicCategoryCode>"));
-        assertEquals(1, CharSequences.count(xml, "<gmd:MD_TopicCategoryCode>test</gmd:MD_TopicCategoryCode>"));
+        // "IMAGE_DIGITAL" is marshalled as "imageDigital" because is contains a UML id, which is lower-case.
+        assertXmlEquals(
+                "<gmd:CI_Citation xmlns:gmd=\"" + Namespaces.GMD + "\">\n" +
+                "  <gmd:presentationForm>\n" +
+                "    <gmd:CI_PresentationFormCode codeListValue=\"imageDigital\">Image digital</gmd:CI_PresentationFormCode>\n" +
+                "  </gmd:presentationForm>\n" +
+                "  <gmd:presentationForm>\n" +
+                "    <gmd:CI_PresentationFormCode codeListValue=\"test\">Test</gmd:CI_PresentationFormCode>\n" +
+                "  </gmd:presentationForm>\n" +
+                "</gmd:CI_Citation>\n",
+                xml, "xmlns:*", "codeList", "codeSpace");
     }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/MetadataTestCase.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -21,6 +21,7 @@ import java.util.Locale;
 import java.util.Random;
 import java.util.Collection;
 import org.opengis.util.CodeList;
+import org.opengis.util.Enumerated;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.collection.CheckedContainer;
@@ -64,7 +65,7 @@ public abstract strictfp class MetadataT
      * Creates a new test suite for the given types.
      *
      * @param standard The standard implemented by the metadata objects to test.
-     * @param types The GeoAPI interfaces or {@link CodeList} types to test.
+     * @param types The GeoAPI interfaces, {@link CodeList} or {@link Enum} types to test.
      */
     protected MetadataTestCase(final MetadataStandard standard, final Class<?>... types) {
         super(types);
@@ -78,7 +79,7 @@ public abstract strictfp class MetadataT
      */
     @Override
     protected <T> Class<? extends T> getImplementation(final Class<T> type) {
-        assertTrue(standard.isMetadata(type));
+        assertTrue(type.getName(), standard.isMetadata(type));
         final Class<? extends T> impl = standard.getImplementation(type);
         assertNotNull(type.getName(), impl);
         return impl;
@@ -101,8 +102,8 @@ public abstract strictfp class MetadataT
 
     /**
      * Returns a dummy value of the given type. The default implementation returns values for
-     * {@link CharSequence}, {@link Number}, {@link Date}, {@link Locale}, {@link CodeList}
-     * and types in the {@link #types} list.
+     * {@link CharSequence}, {@link Number}, {@link Date}, {@link Locale}, {@link CodeList},
+     * {@link Enum} and types in the {@link #types} list.
      *
      * <p>The returned value may be of an other type than the given one if the
      * {@code PropertyAccessor} converter method know how to convert that type.</p>
@@ -127,11 +128,11 @@ public abstract strictfp class MetadataT
         if (Date.class.isAssignableFrom(type)) {
             return new Date(random.nextInt() * 1000L);
         }
-        if (CodeList.class.isAssignableFrom(type)) try {
+        if (Enumerated.class.isAssignableFrom(type)) try {
             if (type == CodeList.class) {
                 return null;
             }
-            final CodeList<?>[] codes = (CodeList<?>[]) type.getMethod("values", (Class[]) null).invoke(null, (Object[]) null);
+            final Enumerated[] codes = (Enumerated[]) type.getMethod("values", (Class[]) null).invoke(null, (Object[]) null);
             return codes[random.nextInt(codes.length)];
         } catch (ReflectiveOperationException e) {
             fail(e.toString());
@@ -184,7 +185,7 @@ public abstract strictfp class MetadataT
     public void testPropertyValues() {
         random = TestUtilities.createRandomNumberGenerator();
         for (final Class<?> type : types) {
-            if (!CodeList.class.isAssignableFrom(type)) {
+            if (!Enumerated.class.isAssignableFrom(type)) {
                 final Class<?> impl = getImplementation(type);
                 if (impl != null) {
                     assertTrue(type.isAssignableFrom(impl));

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -17,11 +17,9 @@
 package org.apache.sis.metadata;
 
 import java.util.Arrays;
-import java.util.Collections;
 import javax.measure.unit.SI;
 import org.opengis.metadata.citation.Role;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.identification.TopicCategory;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.collection.TableColumn;
 import org.apache.sis.util.collection.TreeTableFormat;
@@ -32,7 +30,6 @@ import org.apache.sis.metadata.iso.citat
 import org.apache.sis.metadata.iso.citation.DefaultIndividual;
 import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.metadata.iso.content.DefaultAttributeGroup;
-import org.apache.sis.metadata.iso.identification.DefaultKeywords;
 import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
 import org.apache.sis.metadata.iso.lineage.DefaultProcessing;
 import org.apache.sis.test.DependsOn;
@@ -180,34 +177,29 @@ public final strictfp class TreeTableFor
 
     /**
      * Tests the formatting of a {@link DefaultDataIdentification} object with custom code list elements
-     * Note that adding enumeration values is normally not allowed, so a future version of this test may
-     * need to change the code type.
      */
     @Test
     public void testTreeWithCustomElements() {
-        final DefaultKeywords keywords = new DefaultKeywords();
-        keywords.setKeywords(Arrays.asList(
+        final DefaultCitation citation = new DefaultCitation();
+        citation.setAlternateTitles(Arrays.asList(
                 new SimpleInternationalString("Apple"),
                 new SimpleInternationalString("Orange"),
                 new SimpleInternationalString("Kiwi")));
 
-        final DefaultDataIdentification identification = new DefaultDataIdentification();
-        identification.setDescriptiveKeywords(Collections.singleton(keywords));
-        identification.setTopicCategories(Arrays.asList(
-                TopicCategory.HEALTH,
-                TopicCategory.valueOf("OCEANS"), // Existing category
-                TopicCategory.valueOf("test"))); // Custom category
+        citation.setPresentationForms(Arrays.asList(
+                PresentationForm.IMAGE_DIGITAL,
+                PresentationForm.valueOf("AUDIO_DIGITAL"),  // Existing form
+                PresentationForm.valueOf("test")));         // Custom form
 
-        final String text = format.format(identification.asTreeTable());
+        final String text = format.format(citation.asTreeTable());
         assertMultilinesEquals(
-            "Data identification\n" +
-            "  ├─Descriptive keywords\n" +
-            "  │   ├─Keyword (1 of 3)…………… Apple\n" +
-            "  │   ├─Keyword (2 of 3)…………… Orange\n" +
-            "  │   └─Keyword (3 of 3)…………… Kiwi\n" +
-            "  ├─Topic category (1 of 3)…… Health\n" +
-            "  ├─Topic category (2 of 3)…… Oceans\n" +
-            "  └─Topic category (3 of 3)…… Test\n",
+            "Citation\n" +
+            "  ├─Alternate title (1 of 3)………… Apple\n" +
+            "  ├─Alternate title (2 of 3)………… Orange\n" +
+            "  ├─Alternate title (3 of 3)………… Kiwi\n" +
+            "  ├─Presentation form (1 of 3)…… Image digital\n" +
+            "  ├─Presentation form (2 of 3)…… Audio digital\n" +
+            "  └─Presentation form (3 of 3)…… Test\n",
             text);
     }
 }

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/AllMetadataTest.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -17,7 +17,7 @@
 package org.apache.sis.metadata.iso;
 
 import java.lang.reflect.Modifier;
-import org.opengis.util.CodeList;
+import org.opengis.util.Enumerated;
 import org.opengis.annotation.UML;
 import org.opengis.annotation.Specification;
 import org.opengis.metadata.content.FeatureCatalogueDescription;
@@ -332,7 +332,7 @@ public final strictfp class AllMetadataT
             return null;
         }
         final String classname = "org.apache.sis.internal.jaxb." +
-              (CodeList.class.isAssignableFrom(type) ? "code" : "metadata") +
+              (Enumerated.class.isAssignableFrom(type) ? "code" : "metadata") +
               '.' + type.getAnnotation(UML.class).identifier();
         final Class<?> wrapper = Class.forName(classname);
         assertTrue("Expected a final class for " + wrapper.getName(), Modifier.isFinal(wrapper.getModifiers()));

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -51,6 +51,7 @@ import org.junit.BeforeClass;
     org.apache.sis.metadata.AbstractMetadataTest.class,
 
     // XML marshalling.
+    org.apache.sis.internal.jaxb.code.EnumMarshallingTest.class,
     org.apache.sis.internal.jaxb.code.CodeListMarshallingTest.class,
     org.apache.sis.internal.jaxb.code.PT_LocaleTest.class,
     org.apache.sis.xml.FreeTextMarshallingTest.class,

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -872,7 +872,8 @@ public class AbstractIdentifiedObject ex
                 return implementsSameInterface(object);
             }
             default: {
-                throw new IllegalArgumentException(Errors.format(Errors.Keys.UnknownEnumValue_1, mode));
+                throw new IllegalArgumentException(Errors.format(
+                        Errors.Keys.UnknownEnumValue_2, ComparisonMode.class, mode));
             }
         }
     }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/matrix/Matrices.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -849,7 +849,8 @@ public final class Matrices extends Stat
             case IGNORE_METADATA: return equals(m1, m2, 0, false);
             case DEBUG:           // Fall through
             case APPROXIMATIVE:   return equals(m1, m2, Numerics.COMPARISON_THRESHOLD, true);
-            default: throw new IllegalArgumentException(Errors.format(Errors.Keys.UnknownEnumValue_1, mode));
+            default: throw new IllegalArgumentException(Errors.format(
+                    Errors.Keys.UnknownEnumValue_2, ComparisonMode.class, mode));
         }
     }
 

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ObjectToString.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ObjectToString.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ObjectToString.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ObjectToString.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -125,4 +125,31 @@ class ObjectToString<S> extends SystemCo
             return (source != null) ? source.name() : null;
         }
     }
+
+
+    /**
+     * Specialized instance for {@link java.lang.Enum}.
+     * This class invokes {@link java.lang.Enum#name()} instead than {@code toString()}.
+     *
+     * @see org.apache.sis.internal.converter.StringConverter.Enum
+     */
+    static final class Enum<S extends java.lang.Enum<S>> extends ObjectToString<S> {
+        private static final long serialVersionUID = 5391817175838307542L;
+
+        /** Creates a new converter from the given type of enum to strings. */
+        Enum(final Class<S> sourceClass, final SystemConverter<String, S> inverse) {
+            super(sourceClass, inverse);
+        }
+
+        /** Function is bijective, because no duplicated enum name shall exist. */
+        @Override public Set<FunctionProperty> properties() {
+            return EnumSet.of(FunctionProperty.INJECTIVE, FunctionProperty.SURJECTIVE,
+                    FunctionProperty.INVERTIBLE);
+        }
+
+        /** Returns the name of the given code list element. */
+        @Override public String apply(final S source) {
+            return (source != null) ? source.name() : null;
+        }
+    }
 }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -352,7 +352,7 @@ abstract class StringConverter<T> extend
         }
 
         /** Converts the given string to the target type of this converter. */
-        @Override T doConvert(String source) {
+        @Override T doConvert(final String source) {
             final T code = Types.forCodeName(targetClass, source, false);
             if (code == null) {
                 throw new UnconvertibleObjectException(formatErrorMessage(source));
@@ -365,4 +365,36 @@ abstract class StringConverter<T> extend
             return new ObjectToString.CodeList<>(targetClass, this);
         }
     }
+
+    /**
+     * Converter from {@link String} to {@link java.lang.Enum}.
+     * This converter is particular in that it requires the target class in argument
+     * to the constructor.
+     *
+     * <p>Instances of this class are created by
+     * {@link SystemRegistry#createConverter(Class, Class)}.</p>
+     */
+    static final class Enum<T extends java.lang.Enum<T>> extends StringConverter<T> {
+        /** For cross-version compatibility on serialization. */
+        private static final long serialVersionUID = -4124617013044304640L;
+
+        /** Creates a new converter for the given enumeration. */
+        Enum(final Class<T> targetClass) {
+            super(targetClass);
+        }
+
+        /** Converts the given string to the target type of this converter. */
+        @Override T doConvert(final String source) {
+            final T code = Types.forEnumName(targetClass, source);
+            if (code == null) {
+                throw new UnconvertibleObjectException(formatErrorMessage(source));
+            }
+            return code;
+        }
+
+        /** Invoked by the constructor for creating the inverse converter. */
+        @Override ObjectConverter<T, String> createInverse() {
+            return new ObjectToString.Enum<>(targetClass, this);
+        }
+    }
 }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemRegistry.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemRegistry.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemRegistry.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/converter/SystemRegistry.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -140,6 +140,9 @@ public final class SystemRegistry extend
      *       We do not register every code lists in advance because there is too
      *       many of them, and a generic code is available for all of them.</li>
      * </ul>
+     *
+     * @return A newly generated converter from the specified source class to the target class,
+     *         or {@code null} if none.
      */
     @Override
     @SuppressWarnings({"unchecked","rawtypes"})
@@ -181,13 +184,17 @@ public final class SystemRegistry extend
                     targetClass, find(String.class, targetClass));
         }
         /*
-         * From String to CodeList.
+         * From String to CodeList or Enum.
          */
         if (sourceClass == String.class) {
             if (CodeList.class.isAssignableFrom(targetClass)) {
                 return (ObjectConverter<S,T>) new StringConverter.CodeList<>(
                         targetClass.asSubclass(CodeList.class));
             }
+            if (targetClass.isEnum()) {
+                return (ObjectConverter<S,T>) new StringConverter.Enum<>(
+                        targetClass.asSubclass(Enum.class));
+            }
         }
         /*
          * From Number to other kinds of Number.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gmd/CodeListAdapter.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -44,7 +44,7 @@ import org.apache.sis.internal.jaxb.Cont
  * @author  Cédric Briançon (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.5)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 public abstract class CodeListAdapter<ValueType extends CodeListAdapter<ValueType,BoundType>,
@@ -96,17 +96,14 @@ public abstract class CodeListAdapter<Va
 
     /**
      * Substitutes the adapter value read from an XML stream by the object which will
-     * contains the value. JAXB calls automatically this method at unmarshalling time.
+     * contain the value. JAXB calls automatically this method at unmarshalling time.
      *
      * @param  adapter The adapter for this metadata value.
      * @return A code list which represents the metadata value.
      */
     @Override
     public final BoundType unmarshal(final ValueType adapter) {
-        if (adapter == null) {
-            return null;
-        }
-        return Types.forCodeName(getCodeListClass(), adapter.proxy.identifier(), true);
+        return (adapter != null) ? Types.forCodeName(getCodeListClass(), adapter.proxy.identifier(), true) : null;
     }
 
     /**
@@ -118,33 +115,7 @@ public abstract class CodeListAdapter<Va
      */
     @Override
     public final ValueType marshal(final BoundType value) {
-        if (value == null) {
-            return null;
-        }
-        final CodeListProxy p;
-        if (isEnum()) {
-            // To be removed after GEO-199 resolution.
-            p = new CodeListProxy();
-            p.value = Types.getCodeName(value);
-        } else {
-            p = new CodeListProxy(Context.current(), value);
-        }
-        return wrap(p);
-    }
-
-    /**
-     * Returns {@code true} if this code list is actually an enum. The default implementation
-     * returns {@code false} in every cases, since there is very few enums in ISO 19115.
-     *
-     * @return {@code true} if this code list is actually an enum.
-     *
-     * @todo Remove this method after we refactored enum wrappers as {@link EnumAdapter} subclasses
-     *       instead of {@code CodeListAdapter}. This requires the resolution of GEO-199 first.
-     *
-     * @see <a href="http://jira.codehaus.org/browse/GEO-199">GEO-199</a>
-     */
-    protected boolean isEnum() {
-        return false;
+        return (value != null) ? wrap(new CodeListProxy(Context.current(), value)) : null;
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/CodeListAdapter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/CodeListAdapter.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/CodeListAdapter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/gml/CodeListAdapter.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -59,7 +59,7 @@ public abstract class CodeListAdapter<Bo
 
     /**
      * Substitutes the adapter value read from an XML stream by the object which will
-     * contains the value. JAXB calls automatically this method at unmarshalling time.
+     * contain the value. JAXB calls automatically this method at unmarshalling time.
      *
      * @param  proxy The proxy for the GML value.
      * @return A code list which represents the GML value.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/CodeListFilter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/CodeListFilter.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/CodeListFilter.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/CodeListFilter.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -61,11 +61,20 @@ final class CodeListFilter implements Co
      */
     @Override
     public boolean accept(final CodeList<?> code) {
-        for (final String name : code.names()) {
-            if (CharSequences.equalsFiltered(name, codename, Filter.LETTERS_AND_DIGITS, true)) {
+        for (final String candidate : code.names()) {
+            if (accept(candidate, codename)) {
                 return true;
             }
         }
         return false;
     }
+
+    /**
+     * Returns {@code true} if the given names matches the name we are looking for.
+     * This is defined in a separated method in order to ensure that all code paths
+     * use the same criterion.
+     */
+    static boolean accept(final String candidate, final String codename) {
+        return CharSequences.equalsFiltered(candidate, codename, Filter.LETTERS_AND_DIGITS, true);
+    }
 }

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/iso/Types.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -512,10 +512,9 @@ public final class Types extends Static 
     }
 
     /**
-     * Returns the code of the given type that matches the given name, or optionally returns a new
-     * one if none match it. This method performs the same work than the GeoAPI {@code valueOf(…)}
-     * method, except that this method is more tolerant on string comparisons when looking for an
-     * existing code:
+     * Returns the enumeration value of the given type that matches the given name, or {@code null} if none.
+     * This method is similar to the standard {@code Enum.valueOf(…)} method, except that this method is more
+     * tolerant on string comparisons:
      *
      * <ul>
      *   <li>Name comparisons are case-insensitive.</li>
@@ -523,8 +522,64 @@ public final class Types extends Static 
      *       Spaces and punctuation characters like {@code '_'} and {@code '-'} are ignored.</li>
      * </ul>
      *
-     * If no match is found, then a new code is created only if the {@code canCreate} argument is
-     * {@code true}. Otherwise this method returns {@code null}.
+     * If there is no match, this method returns {@code null} — it does not thrown an exception,
+     * unless the given class is not an enumeration.
+     *
+     * @param <T>      The compile-time type given as the {@code enumType} parameter.
+     * @param enumType The type of enumeration.
+     * @param name     The name of the enumeration value to obtain, or {@code null}.
+     * @return A value matching the given name, or {@code null} if the name is null
+     *         or if no matching enumeration is found.
+     *
+     * @see Enum#valueOf(Class, String)
+     *
+     * @since 0.5
+     */
+    public static <T extends Enum<T>> T forEnumName(final Class<T> enumType, String name) {
+        name = CharSequences.trimWhitespaces(name);
+        if (name != null && !name.isEmpty()) try {
+            return Enum.valueOf(enumType, name);
+        } catch (IllegalArgumentException e) {
+            final Enum<?>[] values;
+            try {
+                values = (Enum<?>[]) enumType.getMethod("values", (Class[]) null).invoke((Object[]) null);
+            } catch (ReflectiveOperationException | ClassCastException r) {
+                // Should never happen, except if 'enumType' is not an Enum.
+                e.addSuppressed(r);
+                throw e;
+            }
+            if (values instanceof Enumerated[]) {
+                for (final Enumerated code : (Enumerated[]) values) {
+                    for (final String candidate : code.names()) {
+                        if (CodeListFilter.accept(candidate, name)) {
+                            return enumType.cast(code);
+                        }
+                    }
+                }
+            } else {
+                for (final Enum<?> code : values) {
+                    if (CodeListFilter.accept(code.name(), name)) {
+                        return enumType.cast(code);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the code of the given type that matches the given name, or optionally returns a new one if none
+     * match the name. This method performs the same work than the GeoAPI {@code CodeList.valueOf(…)} method,
+     * except that this method is more tolerant on string comparisons when looking for an existing code:
+     *
+     * <ul>
+     *   <li>Name comparisons are case-insensitive.</li>
+     *   <li>Only {@linkplain Character#isLetterOrDigit(int) letter and digit} characters are compared.
+     *       Spaces and punctuation characters like {@code '_'} and {@code '-'} are ignored.</li>
+     * </ul>
+     *
+     * If no match is found, then a new code is created only if the {@code canCreate} argument is {@code true}.
+     * Otherwise this method returns {@code null}.
      *
      * @param <T>        The compile-time type given as the {@code codeType} parameter.
      * @param codeType   The type of code list.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -804,9 +804,9 @@ public final class Errors extends Indexe
         public static final short UnknownCommand_1 = 113;
 
         /**
-         * Unknown enumeration value: {0}.
+         * “{1}” is not a known or supported value for the ‘{0}’ enumeration.
          */
-        public static final short UnknownEnumValue_1 = 114;
+        public static final short UnknownEnumValue_2 = 114;
 
         /**
          * Format of “{0}” is not recognized.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Wed Nov 19 16:33:09 2014
@@ -172,7 +172,7 @@ UnitlessParameter_1               = Para
 UnknownAuthority_1                = Authority \u201c{0}\u201d is unknown.
 UnknownAxisDirection_1            = Axis direction \u201c{0}\u201d is unknown.
 UnknownCommand_1                  = Command \u201c{0}\u201d is not recognized.
-UnknownEnumValue_1                = Unknown enumeration value: {0}.
+UnknownEnumValue_2                = \u201c{1}\u201d is not a known or supported value for the \u2018{0}\u2019 enumeration.
 UnknownFormatFor_1                = Format of \u201c{0}\u201d is not recognized.
 UnknownOption_1                   = Option \u201c{0}\u201d is not recognized.
 UnknownType_1                     = Type \u2018{0}\u2019 is unknown in this context.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Wed Nov 19 16:33:09 2014
@@ -161,7 +161,7 @@ UnitlessParameter_1               = Le p
 UnknownAuthority_1                = L\u2019autorit\u00e9 \u00ab\u202f{0}\u202f\u00bb n\u2019est pas reconnue.
 UnknownAxisDirection_1            = La direction d\u2019axe \u00ab\u202f{0}\u202f\u00bb n\u2019est pas reconnue.
 UnknownCommand_1                  = La commande \u00ab\u202f{0}\u202f\u00bb n\u2019est pas reconnue.
-UnknownEnumValue_1                = Valeur d\u2019\u00e9num\u00e9ration inconnue: {0}.
+UnknownEnumValue_2                = \u00ab\u202f{1}\u202f\u00bb n\u2019est pas une valeur connue ou support\u00e9e pour l\u2019\u00e9num\u00e9ration \u2018{0}\u2019.
 UnknownFormatFor_1                = Le format de \u00ab\u202f{0}\u202f\u00bb n\u2019est pas reconnu.
 UnknownOption_1                   = L\u2019option \u00ab\u202f{0}\u202f\u00bb n\u2019est pas reconnue.
 UnknownType_1                     = Le type \u2018{0}\u2019 n\u2019est pas reconnu dans ce contexte.

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/StringConverterTest.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -25,10 +25,11 @@ import java.net.URL;
 import java.net.URISyntaxException;
 import java.net.MalformedURLException;
 import java.nio.charset.Charset;
+import java.lang.annotation.ElementType;
 import javax.measure.unit.SI;
 import javax.measure.unit.Unit;
 import org.opengis.util.InternationalString;
-import org.opengis.metadata.spatial.PixelOrientation;
+import org.opengis.metadata.citation.OnLineFunction;
 import org.apache.sis.measure.Angle;
 import org.apache.sis.math.FunctionProperty;
 import org.apache.sis.util.ObjectConverter;
@@ -51,7 +52,7 @@ import java.nio.charset.StandardCharsets
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-2.4)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @DependsOn(org.apache.sis.measure.AngleTest.class)
@@ -308,8 +309,21 @@ public final strictfp class StringConver
      */
     @Test
     public void testCodeList() {
-        final ObjectConverter<String, PixelOrientation> c = new StringConverter.CodeList<>(PixelOrientation.class);
-        runInvertibleConversion(c, "LOWER_RIGHT", PixelOrientation.LOWER_RIGHT);
+        final ObjectConverter<String, OnLineFunction> c = new StringConverter.CodeList<>(OnLineFunction.class);
+        runInvertibleConversion(c, "OFFLINE_ACCESS", OnLineFunction.OFFLINE_ACCESS);
+        tryUnconvertibleValue(c);
+        assertSerializedEquals(c);
+    }
+
+    /**
+     * Tests conversions to {@link java.lang.Enum}.
+     *
+     * @since 0.5
+     */
+    @Test
+    public void testEnum() {
+        final ObjectConverter<String, ElementType> c = new StringConverter.Enum<>(ElementType.class);
+        runInvertibleConversion(c, "PACKAGE", ElementType.PACKAGE);
         tryUnconvertibleValue(c);
         assertSerializedEquals(c);
     }

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/SystemRegistryTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/SystemRegistryTest.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/SystemRegistryTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/internal/converter/SystemRegistryTest.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -21,7 +21,8 @@ import java.net.URI;
 import java.util.Date;
 import java.util.List;
 import java.util.Collection;
-import org.opengis.metadata.spatial.PixelOrientation;
+import java.lang.annotation.ElementType;
+import org.opengis.metadata.citation.OnLineFunction;
 import org.apache.sis.measure.Angle;
 import org.apache.sis.util.ObjectConverter;
 import org.apache.sis.test.DependsOn;
@@ -39,7 +40,7 @@ import static org.apache.sis.internal.co
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.00)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 @DependsOn(ConverterRegistryTest.class)
@@ -64,10 +65,27 @@ public final strictfp class SystemRegist
      */
     @Test
     public void testStringCodeList() {
-        final ObjectConverter<String, PixelOrientation> c1 = INSTANCE.findExact(String.class, PixelOrientation.class);
-        final ObjectConverter<PixelOrientation, String> c2 = INSTANCE.findExact(PixelOrientation.class, String.class);
-        assertInstanceOf("PixelOrientation ← String", StringConverter.CodeList.class, c1);
-        assertInstanceOf("String ← PixelOrientation", ObjectToString.CodeList.class,  c2);
+        final ObjectConverter<String, OnLineFunction> c1 = INSTANCE.findExact(String.class, OnLineFunction.class);
+        final ObjectConverter<OnLineFunction, String> c2 = INSTANCE.findExact(OnLineFunction.class, String.class);
+        assertInstanceOf("OnLineFunction ← String", StringConverter.CodeList.class, c1);
+        assertInstanceOf("String ← OnLineFunction", ObjectToString.CodeList.class,  c2);
+        assertSame("inverse()", c2, c1.inverse());
+        assertSame("inverse()", c1, c2.inverse());
+        assertSame(c1, assertSerializedEquals(c1));
+        assertSame(c2, assertSerializedEquals(c2));
+    }
+
+    /**
+     * Tests the creation of an enum converter.
+     *
+     * @since 0.5
+     */
+    @Test
+    public void testStringEnum() {
+        final ObjectConverter<String, ElementType> c1 = INSTANCE.findExact(String.class, ElementType.class);
+        final ObjectConverter<ElementType, String> c2 = INSTANCE.findExact(ElementType.class, String.class);
+        assertInstanceOf("ElementType ← String", StringConverter.Enum.class, c1);
+        assertInstanceOf("String ← ElementType", ObjectToString.Enum.class,  c2);
         assertSame("inverse()", c2, c1.inverse());
         assertSame("inverse()", c1, c2.inverse());
         assertSame(c1, assertSerializedEquals(c1));

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/test/AnnotationsTestCase.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -18,6 +18,7 @@ package org.apache.sis.test;
 
 import java.util.Set;
 import java.util.HashSet;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import javax.xml.bind.annotation.XmlNs;
 import javax.xml.bind.annotation.XmlType;
@@ -26,6 +27,7 @@ import javax.xml.bind.annotation.XmlElem
 import javax.xml.bind.annotation.XmlElementRef;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.CodeList;
+import org.opengis.util.Enumerated;
 import org.opengis.annotation.UML;
 import org.opengis.annotation.Obligation;
 import org.opengis.annotation.Specification;
@@ -71,7 +73,7 @@ public abstract strictfp class Annotatio
     private static final String DEFAULT = "##default";
 
     /**
-     * The GeoAPI interfaces or {@link CodeList} types to test.
+     * The GeoAPI interfaces, {@link CodeList} or {@link Enum} types to test.
      */
     protected final Class<?>[] types;
 
@@ -92,7 +94,7 @@ public abstract strictfp class Annotatio
     /**
      * Creates a new test suite for the given types.
      *
-     * @param types The GeoAPI interfaces or {@link CodeList} types to test.
+     * @param types The GeoAPI interfaces, {@link CodeList} or {@link Enum} types to test.
      */
     protected AnnotationsTestCase(final Class<?>... types) {
         this.types = types;
@@ -104,7 +106,7 @@ public abstract strictfp class Annotatio
      * interface is the {@link org.apache.sis.metadata.iso.citation.DefaultCitation} class.
      *
      * @param  <T>  The type represented by the {@code type} argument.
-     * @param  type The GeoAPI interface (never a {@link CodeList} type).
+     * @param  type The GeoAPI interface (never a {@link CodeList} or {@link Enum} type).
      * @return The SIS implementation for the given interface.
      */
     protected abstract <T> Class<? extends T> getImplementation(Class<T> type);
@@ -143,7 +145,7 @@ public abstract strictfp class Annotatio
      * <p>In SIS implementation, most wrappers are also {@link javax.xml.bind.annotation.adapters.XmlAdapter}.
      * But this is not a requirement.</p>
      *
-     * @param  type The GeoAPI interface or {@link CodeList} type.
+     * @param  type The GeoAPI interface, {@link CodeList} or {@link Enum} type.
      * @return The wrapper for the given type, or {@code null} if none.
      * @throws ClassNotFoundException If a wrapper was expected but not found.
      */
@@ -167,7 +169,7 @@ public abstract strictfp class Annotatio
      * Returns the value of {@link #getWrapperFor(Class)} for the given class, or for a parent
      * of the given class if {@code getWrapperFor(Class)} threw {@code ClassNotFoundException}.
      *
-     * @param  type The GeoAPI interface or {@link CodeList} type.
+     * @param  type The GeoAPI interface, {@link CodeList} or {@link Enum} type.
      * @return The wrapper for the given type. {@link WrapperClass#type} is {@code null} if
      *         no wrapper has been found.
      * @throws ClassNotFoundException If a wrapper was expected but not found in the
@@ -217,7 +219,7 @@ public abstract strictfp class Annotatio
      * <p>The prefix for the given namespace will be fetched by
      * {@link Namespaces#getPreferredPrefix(String, String)}.</p>
      *
-     * @param  impl The implementation class or {@link CodeList} type.
+     * @param  impl The implementation class, {@link CodeList} or {@link Enum} type.
      * @param  specification The specification that define the type, or {@code null} if unspecified.
      * @return The expected namespace.
      * @throws IllegalArgumentException If the given specification is unknown to this method.
@@ -400,7 +402,7 @@ public abstract strictfp class Annotatio
             testingClass = type.getCanonicalName();
             UML uml = type.getAnnotation(UML.class);
             assertNotNull("Missing @UML annotation.", uml);
-            if (!CodeList.class.isAssignableFrom(type)) {
+            if (!Enumerated.class.isAssignableFrom(type)) {
                 for (final Method method : type.getDeclaredMethods()) {
                     testingMethod = method.getName();
                     if (!isIgnored(method)) {
@@ -428,7 +430,7 @@ public abstract strictfp class Annotatio
     public void testPackageAnnotations() {
         final Set<Package> packages = new HashSet<>();
         for (final Class<?> type : types) {
-            if (!CodeList.class.isAssignableFrom(type)) {
+            if (!Enumerated.class.isAssignableFrom(type)) {
                 testingClass = type.getCanonicalName();
                 final Class<?> impl = getImplementation(type);
                 if (impl != null) {
@@ -469,7 +471,7 @@ public abstract strictfp class Annotatio
     @DependsOnMethod("testInterfaceAnnotations")
     public void testImplementationAnnotations() {
         for (final Class<?> type : types) {
-            if (CodeList.class.isAssignableFrom(type)) {
+            if (Enumerated.class.isAssignableFrom(type)) {
                 // Skip code lists, since they are not the purpose of this test.
                 continue;
             }
@@ -528,7 +530,7 @@ public abstract strictfp class Annotatio
     @DependsOnMethod("testImplementationAnnotations")
     public void testMethodAnnotations() {
         for (final Class<?> type : types) {
-            if (CodeList.class.isAssignableFrom(type)) {
+            if (Enumerated.class.isAssignableFrom(type)) {
                 // Skip code lists, since they are not the purpose of this test.
                 continue;
             }
@@ -616,22 +618,34 @@ public abstract strictfp class Annotatio
              * and verify that exactly one of @XmlElement or @XmlElementRef annotation is declared.
              */
             testingClass = wrapper.type.getCanonicalName();
-            final Method getter, setter;
-            try {
-                getter = wrapper.type.getMethod("getElement", (Class<?>[]) null);
-                setter = wrapper.type.getMethod("setElement", getter.getReturnType());
-            } catch (NoSuchMethodException e) {
-                fail(e.toString());
-                continue;
+            final XmlElement element;
+            if (type.isEnum()) {
+                final Field field;
+                try {
+                    field = wrapper.type.getDeclaredField("value");
+                } catch (NoSuchFieldException e) {
+                    fail(e.toString());
+                    continue;
+                }
+                element = field.getAnnotation(XmlElement.class);
+            } else {
+                final Method getter, setter;
+                try {
+                    getter = wrapper.type.getMethod("getElement", (Class<?>[]) null);
+                    setter = wrapper.type.getMethod("setElement", getter.getReturnType());
+                } catch (NoSuchMethodException e) {
+                    fail(e.toString());
+                    continue;
+                }
+                assertEquals("The setter method must be declared in the same class than the " +
+                             "getter method - not in a parent class, to avoid issues with JAXB.",
+                             getter.getDeclaringClass(), setter.getDeclaringClass());
+                assertEquals("The setter parameter type shall be the same than the getter return type.",
+                             getter.getReturnType(), getSingleton(setter.getParameterTypes()));
+                element = getter.getAnnotation(XmlElement.class);
+                assertEquals("Expected @XmlElement XOR @XmlElementRef.", (element == null),
+                             getter.isAnnotationPresent(XmlElementRef.class));
             }
-            assertEquals("The setter method must be declared in the same class than the " +
-                         "getter method - not in a parent class, to avoid issues with JAXB.",
-                         getter.getDeclaringClass(), setter.getDeclaringClass());
-            assertEquals("The setter parameter type shall be the same than the getter return type.",
-                         getter.getReturnType(), getSingleton(setter.getParameterTypes()));
-            final XmlElement element = getter.getAnnotation(XmlElement.class);
-            assertEquals("Expected @XmlElement XOR @XmlElementRef.", (element == null),
-                         getter.isAnnotationPresent(XmlElementRef.class));
             /*
              * If the annotation is @XmlElement, ensure that XmlElement.name() is equals to
              * the UML identifier. Then verify that the
@@ -643,7 +657,7 @@ public abstract strictfp class Annotatio
                     assertEquals("Wrong @XmlElement.", uml.identifier(), element.name());
                 }
                 final String namespace = assertExpectedNamespace(element.namespace(), wrapper.type, uml);
-                if (!CodeList.class.isAssignableFrom(type)) {
+                if (!Enumerated.class.isAssignableFrom(type)) {
                     final String expected = getNamespace(getImplementation(type));
                     if (expected != null) { // 'assertNotNull' is 'testImplementationAnnotations()' job.
                         assertEquals("Inconsistent @XmlRootElement namespace.", expected, namespace);

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/collection/CodeListSetTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/collection/CodeListSetTest.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/collection/CodeListSetTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/collection/CodeListSetTest.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -23,7 +23,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Random;
 import org.opengis.referencing.cs.AxisDirection;
-import org.opengis.metadata.spatial.PixelOrientation;
+import org.opengis.metadata.citation.OnLineFunction;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.util.iso.LargeCodeList;
@@ -69,11 +69,11 @@ public final strictfp class CodeListSetT
      * the same ordinal value than {@link AxisDirection#NORTH}, so we can detect if the
      * {@code SortedSet} confuses the code list types.
      */
-    private CodeListSet<PixelOrientation> createOtherKind() {
+    private CodeListSet<OnLineFunction> createOtherKind() {
         // For the validity of the tests, ordinal value must be the same.
-        assertEquals(NORTH.ordinal(), PixelOrientation.LOWER_LEFT.ordinal());
-        final CodeListSet<PixelOrientation> c = new CodeListSet<>(PixelOrientation.class);
-        assertTrue(c.add(PixelOrientation.LOWER_LEFT));
+        assertEquals(NORTH.ordinal(), OnLineFunction.INFORMATION.ordinal());
+        final CodeListSet<OnLineFunction> c = new CodeListSet<>(OnLineFunction.class);
+        assertTrue(c.add(OnLineFunction.INFORMATION));
         return c;
     }
 
@@ -115,7 +115,7 @@ public final strictfp class CodeListSetT
 
         assertFalse("Should be null-safe.", c.contains(null));
         assertFalse("Code list of other kind should not be included.",
-                c.contains(PixelOrientation.LOWER_LEFT));
+                c.contains(OnLineFunction.INFORMATION));
     }
 
     /**
@@ -127,7 +127,7 @@ public final strictfp class CodeListSetT
         final CodeListSet<AxisDirection> c = create(4);
         assertFalse("Should be null-safe.", c.remove(null));
         assertFalse("Code list of other kind should not be included.",
-                c.remove(PixelOrientation.LOWER_LEFT));
+                c.remove(OnLineFunction.INFORMATION));
 
         assertTrue ("NORTH",  c.remove  (NORTH));
         assertFalse("SOUTH",  c.remove  (SOUTH));

Modified: sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/test/java/org/apache/sis/util/iso/TypesTest.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -21,14 +21,15 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.TreeMap;
 import java.util.Locale;
+import java.lang.annotation.ElementType;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Address;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.OnLineFunction;
 import org.opengis.metadata.content.ImagingCondition;
-import org.opengis.parameter.ParameterDirection;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.parameter.ParameterDirection;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -105,6 +106,36 @@ public final strictfp class TypesTest ex
     }
 
     /**
+     * Tests the {@link Types#forEnumName(Class, String)} method with an enumeration from the JDK.
+     * Such enumerations do not implement the {@link org.opengis.util.Enumerated} interface.
+     *
+     * @since 0.5
+     */
+    @Test
+    public void testForStandardEnumName() {
+        assertSame(ElementType.LOCAL_VARIABLE, Types.forEnumName(ElementType.class, "LOCAL_VARIABLE"));
+        assertSame(ElementType.LOCAL_VARIABLE, Types.forEnumName(ElementType.class, "LOCALVARIABLE"));
+        assertSame(ElementType.LOCAL_VARIABLE, Types.forEnumName(ElementType.class, "local variable"));
+        assertSame(ElementType.LOCAL_VARIABLE, Types.forEnumName(ElementType.class, "local-variable"));
+        assertNull(Types.forEnumName(ElementType.class, "variable"));
+    }
+
+    /**
+     * Tests the {@link Types#forEnumName(Class, String)} method with an enumeration from GeoAPI.
+     * Such enumerations implement the {@link org.opengis.util.Enumerated} interface.
+     *
+     * @since 0.5
+     */
+    @Test
+    public void testForGeoapiEnumName() {
+        assertSame(ParameterDirection.IN_OUT, Types.forEnumName(ParameterDirection.class, "IN_OUT"));
+        assertSame(ParameterDirection.IN_OUT, Types.forEnumName(ParameterDirection.class, "INOUT"));
+        assertSame(ParameterDirection.IN_OUT, Types.forEnumName(ParameterDirection.class, "in out"));
+        assertSame(ParameterDirection.IN_OUT, Types.forEnumName(ParameterDirection.class, "in/out"));
+        assertNull(Types.forEnumName(ParameterDirection.class, "out/in"));
+    }
+
+    /**
      * Tests the {@link Types#forCodeName(Class, String, boolean)} method.
      */
     @Test

Modified: sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java?rev=1640591&r1=1640590&r2=1640591&view=diff
==============================================================================
--- sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java [UTF-8] (original)
+++ sis/branches/JDK7/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java [UTF-8] Wed Nov 19 16:33:09 2014
@@ -47,6 +47,7 @@ import org.opengis.metadata.maintenance.
 import org.opengis.metadata.constraint.Restriction;
 import org.opengis.referencing.crs.VerticalCRS;
 
+import org.opengis.util.CodeList;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.metadata.iso.DefaultMetadata;
@@ -67,6 +68,7 @@ import org.apache.sis.internal.netcdf.Va
 import org.apache.sis.internal.netcdf.GridGeometry;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.metadata.Standards;
+import org.apache.sis.util.resources.Errors;
 
 // The following dependency is used only for static final String constants.
 // Consequently the compiled class files should not have this dependency.
@@ -103,7 +105,7 @@ import static org.apache.sis.storage.net
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.20)
- * @version 0.3
+ * @version 0.5
  * @module
  */
 final class MetadataReader {
@@ -185,13 +187,66 @@ final class MetadataReader {
     }
 
     /**
+     * Invoked when a non-fatal exception occurred while reading metadata.
+     * This method will send a record to the registered listeners if any,
+     * or will log the record otherwise.
+     */
+    private void warning(final Exception e) {
+        decoder.listeners.warning(null, e);
+    }
+
+    /**
+     * Reads the attribute value for the given name, then trims the leading and trailing spaces.
+     * If the value is null, empty or contains only spaces, then this method returns {@code null}.
+     */
+    private String stringValue(final String name) throws IOException {
+        String value = decoder.stringValue(name);
+        if (value != null) {
+            value = value.trim();
+            if (value.isEmpty()) {
+                value = null;
+            }
+        }
+        return value;
+    }
+
+    /**
      * Returns the given string as an {@code InternationalString} if non-null, or {@code null} otherwise.
+     * This method does not trim leading or trailing spaces, since this is often already done by the caller.
      */
     private static InternationalString toInternationalString(final String value) {
         return (value != null) ? new SimpleInternationalString(value) : null;
     }
 
     /**
+     * Returns the enumeration constant for the given name, or {@code null} if the given name is not recognized.
+     * In the later case, this method emits a warning.
+     */
+    private <T extends Enum<T>> T forEnumName(final Class<T> enumType, final String name) {
+        final T code = Types.forEnumName(enumType, name);
+        if (code == null && name != null) {
+            decoder.listeners.warning(Errors.format(Errors.Keys.UnknownEnumValue_2, enumType, name), null);
+        }
+        return code;
+    }
+
+    /**
+     * Returns the code value for the given name, or {@code null} if the given name is not recognized.
+     * In the later case, this method emits a warning.
+     */
+    private <T extends CodeList<T>> T forCodeName(final Class<T> codeType, final String name) {
+        final T code = Types.forCodeName(codeType, name, false);
+        if (code == null && name != null) {
+            /*
+             * CodeLists are not enums, but using the error message for enums is not completly wrong since
+             * if we did not allowed CodeList to create new elements, then we are using it like an enum.
+             */
+            decoder.listeners.warning(Errors.format(Errors.Keys.UnknownEnumValue_2, codeType, name), null);
+        }
+        return code;
+    }
+
+    /**
      * Returns the first element of the given collection.
      */
     private static <T> T first(final Collection<T> collection) {
@@ -285,7 +340,7 @@ final class MetadataReader {
             resource.setFunction(OnLineFunction.INFORMATION);
             return resource;
         } catch (URISyntaxException e) {
-            decoder.listeners.warning(null, e);
+            warning(e);
         }
         return null;
     }
@@ -335,14 +390,14 @@ final class MetadataReader {
     private Responsibility createResponsibleParty(final Responsible keys, final boolean isPointOfContact)
             throws IOException
     {
-        final String individualName   = decoder.stringValue(keys.NAME);
-        final String organisationName = decoder.stringValue(keys.INSTITUTION);
-        final String email            = decoder.stringValue(keys.EMAIL);
-        final String url              = decoder.stringValue(keys.URL);
+        final String individualName   = stringValue(keys.NAME);
+        final String organisationName = stringValue(keys.INSTITUTION);
+        final String email            = stringValue(keys.EMAIL);
+        final String url              = stringValue(keys.URL);
         if (individualName == null && organisationName == null && email == null && url == null) {
             return null;
         }
-        Role role = Types.forCodeName(Role.class, decoder.stringValue(keys.ROLE), true);
+        Role role = forCodeName(Role.class, stringValue(keys.ROLE));
         if (role == null) {
             role = isPointOfContact ? Role.POINT_OF_CONTACT : keys.DEFAULT_ROLE;
         }
@@ -417,11 +472,11 @@ final class MetadataReader {
      * @throws IOException If an I/O operation was necessary but failed.
      */
     private Citation createCitation(final Identifier identifier) throws IOException {
-        String title = decoder.stringValue(TITLE);
+        String title = stringValue(TITLE);
         if (title == null) {
-            title = decoder.stringValue("full_name"); // THREDDS attribute documented in TITLE javadoc.
+            title = stringValue("full_name"); // THREDDS attribute documented in TITLE javadoc.
             if (title == null) {
-                title = decoder.stringValue("name"); // THREDDS attribute documented in TITLE javadoc.
+                title = stringValue("name"); // THREDDS attribute documented in TITLE javadoc.
                 if (title == null) {
                     title = decoder.getTitle();
                 }
@@ -430,7 +485,7 @@ final class MetadataReader {
         final Date   creation   = decoder.dateValue(DATE_CREATED);
         final Date   modified   = decoder.dateValue(DATE_MODIFIED);
         final Date   issued     = decoder.dateValue(DATE_ISSUED);
-        final String references = decoder.stringValue(REFERENCES);
+        final String references =       stringValue(REFERENCES);
         final DefaultCitation citation = new DefaultCitation(title);
         if (identifier != null) {
             citation.setIdentifiers(singleton(identifier));
@@ -453,7 +508,7 @@ final class MetadataReader {
         }
         decoder.setSearchPath(searchPath);
         if (references != null) {
-            citation.setOtherCitationDetails(singleton(toInternationalString(references)));
+            citation.setOtherCitationDetails(singleton(new SimpleInternationalString(references)));
         }
         return citation.isEmpty() ? null : citation;
     }
@@ -477,21 +532,21 @@ final class MetadataReader {
             decoder.setSearchPath(path);
             final Keywords standard = createKeywords(KeywordType.THEME, true);
             final Keywords keywords = createKeywords(KeywordType.THEME, false);
-            final String   topic    = decoder.stringValue(TOPIC_CATEGORY);
-            final String   type     = decoder.stringValue(DATA_TYPE);
-            final String   credits  = decoder.stringValue(ACKNOWLEDGMENT);
-            final String   license  = decoder.stringValue(LICENSE);
-            final String   access   = decoder.stringValue(ACCESS_CONSTRAINT);
+            final String   topic    = stringValue(TOPIC_CATEGORY);
+            final String   type     = stringValue(DATA_TYPE);
+            final String   credits  = stringValue(ACKNOWLEDGMENT);
+            final String   license  = stringValue(LICENSE);
+            final String   access   = stringValue(ACCESS_CONSTRAINT);
             final Extent   extent   = hasExtent ? null : createExtent();
             if (standard!=null || keywords!=null || topic != null || type!=null || credits!=null || license!=null || access!= null || extent!=null) {
                 if (identification == null) {
                     identification = new DefaultDataIdentification();
                 }
-                if (topic    != null) addIfAbsent(identification.getTopicCategories(), Types.forCodeName(TopicCategory.class, topic, true));
-                if (type     != null) addIfAbsent(identification.getSpatialRepresentationTypes(), Types.forCodeName(SpatialRepresentationType.class, type, true));
+                if (topic    != null) addIfAbsent(identification.getTopicCategories(), forEnumName(TopicCategory.class, topic));
+                if (type     != null) addIfAbsent(identification.getSpatialRepresentationTypes(), forCodeName(SpatialRepresentationType.class, type));
                 if (standard != null) addIfAbsent(identification.getDescriptiveKeywords(), standard);
                 if (keywords != null) addIfAbsent(identification.getDescriptiveKeywords(), keywords);
-                if (credits  != null) addIfAbsent(identification.getCredits(), Types.toInternationalString(credits));
+                if (credits  != null) addIfAbsent(identification.getCredits(), new SimpleInternationalString(credits));
                 if (license  != null) addIfAbsent(identification.getResourceConstraints(), constraints = new DefaultLegalConstraints(license));
                 if (access   != null) {
                     for (String keyword : access.split(KEYWORD_SEPARATOR)) {
@@ -500,7 +555,7 @@ final class MetadataReader {
                             if (constraints == null) {
                                 identification.getResourceConstraints().add(constraints = new DefaultLegalConstraints());
                             }
-                            addIfAbsent(constraints.getAccessConstraints(), Types.forCodeName(Restriction.class, keyword, true));
+                            addIfAbsent(constraints.getAccessConstraints(), forCodeName(Restriction.class, keyword));
                         }
                     }
                 }
@@ -512,12 +567,12 @@ final class MetadataReader {
                     hasExtent = true;
                 }
             }
-            project = addIfNonNull(project, toInternationalString(decoder.stringValue(PROJECT)));
+            project = addIfNonNull(project, toInternationalString(stringValue(PROJECT)));
         }
         decoder.setSearchPath(searchPath);
         final Citation citation = createCitation(identifier);
-        final String   summary  = decoder.stringValue(SUMMARY);
-        final String   purpose  = decoder.stringValue(PURPOSE);
+        final String   summary  = stringValue(SUMMARY);
+        final String   purpose  = stringValue(PURPOSE);
         if (identification == null) {
             if (citation==null && summary==null && purpose==null && project==null && publisher==null && pointOfContact==null) {
                 return null;
@@ -530,22 +585,22 @@ final class MetadataReader {
         if (pointOfContact != null) {
             identification.setPointOfContacts(singleton(pointOfContact));
         }
-        addKeywords(identification, project,   "project"); // Not necessarily the same string than PROJECT.
-        addKeywords(identification, publisher, "dataCenter");
-        identification.setSupplementalInformation(toInternationalString(decoder.stringValue(COMMENT)));
+        addKeywords(identification, project,   KeywordType.PROJECT);
+        addKeywords(identification, publisher, KeywordType.DATACENTRE);
+        identification.setSupplementalInformation(toInternationalString(stringValue(COMMENT)));
         return identification;
     }
 
     /**
      * Adds the given keywords to the given identification info if the given set is non-null.
      */
-    private static void addKeywords(final DefaultDataIdentification addTo,
-            final Set<InternationalString> words, final String type)
+    private void addKeywords(final DefaultDataIdentification addTo,
+            final Set<InternationalString> words, final KeywordType type)
     {
         if (words != null) {
             final DefaultKeywords keywords = new DefaultKeywords();
             keywords.setKeywords(words);
-            keywords.setType(Types.forCodeName(KeywordType.class, type, true));
+            keywords.setType(type);
             addTo.getDescriptiveKeywords().add(keywords);
         }
     }
@@ -558,7 +613,7 @@ final class MetadataReader {
      * @throws IOException If an I/O operation was necessary but failed.
      */
     private Keywords createKeywords(final KeywordType type, final boolean standard) throws IOException {
-        final String list = decoder.stringValue(standard ? STANDARD_NAME : KEYWORDS);
+        final String list = stringValue(standard ? STANDARD_NAME : KEYWORDS);
         DefaultKeywords keywords = null;
         if (list != null) {
             final Set<InternationalString> words = new LinkedHashSet<>();
@@ -572,7 +627,7 @@ final class MetadataReader {
                 keywords = new DefaultKeywords();
                 keywords.setKeywords(words);
                 keywords.setType(type);
-                final String vocabulary = decoder.stringValue(standard ? STANDARD_NAME_VOCABULARY : VOCABULARY);
+                final String vocabulary = stringValue(standard ? STANDARD_NAME_VOCABULARY : VOCABULARY);
                 if (vocabulary != null) {
                     keywords.setThesaurusName(new DefaultCitation(vocabulary));
                 }
@@ -642,7 +697,7 @@ final class MetadataReader {
             final UnitConverter c = getConverterTo(decoder.unitValue(VERTICAL.UNITS), SI.METRE);
             double min = valueOf(zmin, c);
             double max = valueOf(zmax, c);
-            if (CF.POSITIVE_DOWN.equals(decoder.stringValue(VERTICAL.POSITIVE))) {
+            if (CF.POSITIVE_DOWN.equals(stringValue(VERTICAL.POSITIVE))) {
                 final double tmp = min;
                 min = -max;
                 max = -tmp;
@@ -662,7 +717,7 @@ final class MetadataReader {
             final Number tmin = decoder.numericValue(TIME.MINIMUM);
             final Number tmax = decoder.numericValue(TIME.MAXIMUM);
             if (tmin != null || tmax != null) {
-                final String symbol = decoder.stringValue(TIME.UNITS);
+                final String symbol = stringValue(TIME.UNITS);
                 if (symbol != null) {
                     final Date[] dates = decoder.numberToDate(symbol, tmin, tmax);
                     startTime = dates[0];
@@ -683,12 +738,12 @@ final class MetadataReader {
             }
             extent.setTemporalElements(singleton(t));
         } catch (UnsupportedOperationException e) {
-            decoder.listeners.warning(null, e);
+            warning(e);
         }
         /*
          * Add the geographic identifier, if present.
          */
-        final String identifier = decoder.stringValue(GEOGRAPHIC_IDENTIFIER);
+        final String identifier = stringValue(GEOGRAPHIC_IDENTIFIER);
         if (identifier != null) {
             if (extent == null) {
                 extent = new DefaultExtent();
@@ -706,7 +761,7 @@ final class MetadataReader {
         if (source != null) try {
             return source.getConverterToAny(target);
         } catch (ConversionException e) {
-            decoder.listeners.warning(null, e);
+            warning(e);
         }
         return null;
     }
@@ -734,7 +789,7 @@ final class MetadataReader {
      */
     private Collection<DefaultCoverageDescription> createContentInfo() throws IOException {
         final Map<List<String>, DefaultCoverageDescription> contents = new HashMap<>(4);
-        final String processingLevel = decoder.stringValue(PROCESSING_LEVEL);
+        final String processingLevel = stringValue(PROCESSING_LEVEL);
         for (final Variable variable : decoder.getVariables()) {
             if (!variable.isCoverage(2)) {
                 continue;
@@ -805,7 +860,7 @@ final class MetadataReader {
         }
         String description = variable.getDescription();
         if (description != null && !(description = description.trim()).isEmpty() && !description.equals(name)) {
-            band.setDescription(toInternationalString(description));
+            band.setDescription(new SimpleInternationalString(description));
         }
 //TODO: Can't store the units, because the Band interface restricts it to length.
 //      We need the SampleDimension interface proposed in ISO 19115 revision draft.
@@ -832,8 +887,8 @@ final class MetadataReader {
     {
         if (name != null && meaning != null) {
             final DefaultRangeElementDescription element = new DefaultRangeElementDescription();
-            element.setName(toInternationalString(name));
-            element.setDefinition(toInternationalString(meaning));
+            element.setName(new SimpleInternationalString(name));
+            element.setDefinition(new SimpleInternationalString(meaning));
             // TODO: create a record from values (and possibly from the masks).
             //       if (pixel & mask == value) then we have that range element.
             return element;
@@ -854,14 +909,14 @@ final class MetadataReader {
      * @throws IOException If an I/O operation was necessary but failed.
      */
     private Identifier getFileIdentifier() throws IOException {
-        String identifier = decoder.stringValue(IDENTIFIER);
+        String identifier = stringValue(IDENTIFIER);
         if (identifier == null) {
             identifier = decoder.getId();
             if (identifier == null) {
                 return null;
             }
         }
-        final String namespace  = decoder.stringValue(NAMING_AUTHORITY);
+        final String namespace = stringValue(NAMING_AUTHORITY);
         return new DefaultIdentifier((namespace != null) ? new DefaultCitation(namespace) : null, identifier);
     }
 
@@ -882,7 +937,7 @@ final class MetadataReader {
         }
         metadata.setMetadataScopes(singleton(new DefaultMetadataScope(ScopeCode.DATASET, null)));
         for (final String service : SERVICES) {
-            final String name = decoder.stringValue(service);
+            final String name = stringValue(service);
             if (name != null) {
                 addIfAbsent(metadata.getMetadataScopes(), new DefaultMetadataScope(ScopeCode.SERVICE, name));
             }
@@ -924,7 +979,7 @@ final class MetadataReader {
                 }
             }
             // Also add history.
-            final String history = decoder.stringValue(HISTORY);
+            final String history = stringValue(HISTORY);
             if (history != null) {
                 final DefaultDataQuality quality = new DefaultDataQuality();
                 final DefaultLineage lineage = new DefaultLineage();



Mime
View raw message