You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2017/05/06 12:09:41 UTC

svn commit: r1794136 [2/4] - in /sis/branches/JDK7: ./ core/sis-build-helper/src/main/java/org/apache/sis/internal/taglet/ core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-metadata/src/main/java/org/apache/sis/metadata/ core/sis-metadata...

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java [UTF-8] Sat May  6 12:09:41 2017
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.metadata;
 
+import java.util.Arrays;
 import java.util.Locale;
 import org.opengis.metadata.citation.Address;
 import org.opengis.metadata.citation.Contact;
@@ -65,11 +66,11 @@ public final strictfp class TreeNodeTest
      *     ├─Alternate title (2 of 2)………………………………………… Second alternate title
      *     ├─Edition……………………………………………………………………………………… Some edition
      *     ├─Cited responsible party (1 of 2)
-     *     │   └─Party (Organisation)
+     *     │   └─Organisation
      *     │      ├─Name…………………………………………………………………………… Some organisation
      *     │      └─Role…………………………………………………………………………… Distributor
      *     ├─Cited responsible party (2 of 2)
-     *     │   └─Party (Individual)
+     *     │   └─Individual
      *     │      ├─Name…………………………………………………………………………… Some person of contact
      *     │      ├─Contact info
      *     │      │   └─Address
@@ -98,11 +99,14 @@ public final strictfp class TreeNodeTest
     }
 
     /**
+     * The policy to be given to {@link TreeTableView} constructor.
+     */
+    private ValueExistencePolicy valuePolicy = ValueExistencePolicy.NON_EMPTY;
+
+    /**
      * Creates a node to be tested for the given metadata object and value policy.
      */
-    private static <T extends AbstractMetadata> TreeNode create(final T metadata,
-            final Class<? super T> baseType, final ValueExistencePolicy valuePolicy)
-    {
+    private <T extends AbstractMetadata> TreeNode create(final T metadata, final Class<? super T> baseType) {
         final MetadataStandard  standard = MetadataStandard.ISO_19115;
         final TreeTableView table = new TreeTableView(standard, metadata, baseType, valuePolicy);
         return (TreeNode) table.getRoot();
@@ -114,7 +118,7 @@ public final strictfp class TreeNodeTest
     @Test
     public void testRootNode() {
         final DefaultCitation citation = TreeNodeChildrenTest.metadataWithoutCollections();
-        final TreeNode node = create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY);
+        final TreeNode node = create(citation, Citation.class);
         assertEquals("getName()",        "Citation",     node.getName());
         assertEquals("getIdentifier()",  "CI_Citation",  node.getIdentifier());
         assertEquals("baseType",         Citation.class, node.baseType);
@@ -124,9 +128,10 @@ public final strictfp class TreeNodeTest
         assertFalse ("isLeaf()",                         node.isLeaf());
 
         final TreeNodeChildren children = (TreeNodeChildren) node.getChildren();
-        assertSame ("children.metadata", citation, children.metadata);
-        assertFalse("children.isEmpty()", node.getChildren().isEmpty());
-        assertSame ("children.parent", node, children.iterator().next().getParent());
+        assertEquals("children.titleProperty", -1, children.titleProperty);
+        assertSame  ("children.metadata", citation, children.metadata);
+        assertFalse ("children.isEmpty()", node.getChildren().isEmpty());
+        assertSame  ("children.parent", node, children.iterator().next().getParent());
     }
 
     /**
@@ -137,7 +142,7 @@ public final strictfp class TreeNodeTest
     @DependsOnMethod("testRootNode")            // Because tested more basic methods than 'getValue(TableColumn)'.
     public void testGetNameForSingleton() {
         final DefaultCitation citation = TreeNodeChildrenTest.metadataWithSingletonInCollections();
-        assertColumnContentEquals(create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
+        assertColumnContentEquals(create(citation, Citation.class), TableColumn.NAME,
             "Citation",
               "Title",
               "Alternate title",
@@ -154,7 +159,7 @@ public final strictfp class TreeNodeTest
     @DependsOnMethod("testGetNameForSingleton")
     public void testGetNameForMultiOccurrences() {
         final DefaultCitation citation = TreeNodeChildrenTest.metadataWithMultiOccurrences();
-        assertColumnContentEquals(create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
+        assertColumnContentEquals(create(citation, Citation.class), TableColumn.NAME,
             "Citation",
               "Title",
               "Alternate title (1 of 2)",
@@ -166,25 +171,50 @@ public final strictfp class TreeNodeTest
     }
 
     /**
+     * Compares the result of the given getter method invoked on all nodes of {@link #metadataWithHierarchy()}.
+     * In the particular case of the {@link TableColumn#NAME}, international strings are replaced by unlocalized
+     * strings before comparisons.
+     *
+     * <p>If {@link #valuePolicy} is {@link ValueExistencePolicy#COMPACT}, then this method removes the elements at
+     * indices 0, 6 and 10 (if {@code offset} = 0) or 1, 7 and 11 (if {@code offset} = 1) from the {@code expected}
+     * array before to perform the comparison.</p>
+     *
+     * @param  offset    0 if compact mode excludes the parent, or 1 if compact mode exclude the first child.
+     * @param  column    the column from which to get a value.
+     * @param  expected  the expected values. The first value is the result of the getter method
+     *                   applied on the given node, and all other values are the result of the
+     *                   getter method applied on the children, in iteration order.
+     */
+    private void assertCitationContentEquals(final int offset, final TableColumn<?> column, final Object... expected) {
+        if (valuePolicy == ValueExistencePolicy.COMPACT) {
+            assertEquals(19, expected.length);
+            System.arraycopy(expected, 11+offset, expected, 10+offset,  8-offset);    // Compact the "Individual" element.
+            System.arraycopy(expected,  7+offset, expected,  6+offset, 11-offset);    // Compact the "Organisation" element.
+            System.arraycopy(expected,  1+offset, expected,    offset, 16-offset);    // Compact the "Title" element.
+            Arrays.fill(expected, 16, 19, null);
+        }
+        assertColumnContentEquals(create(metadataWithHierarchy(), Citation.class), column, expected);
+    }
+
+    /**
      * Tests {@link TreeNode#getName()} on a metadata with a deeper hierarchy.
      */
     @Test
     @DependsOnMethod("testGetNameForMultiOccurrences")
     public void testGetNameForHierarchy() {
-        final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnContentEquals(create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY), TableColumn.NAME,
+        assertCitationContentEquals(1, TableColumn.NAME,
             "Citation",
               "Title",
               "Alternate title (1 of 2)",
               "Alternate title (2 of 2)",
               "Edition",
               "Cited responsible party (1 of 2)",
-                "Party",
-                  "Name",
+                "Organisation",                         // A Party subtype
+                  "Name",                               // In COMPACT mode, this value is associated to "Organisation" node.
                 "Role",
               "Cited responsible party (2 of 2)",
-                "Party",
-                  "Name",
+                "Individual",                           // A Party subtype
+                  "Name",                               // In COMPACT mode, this value is associated to "Individual" node.
                   "Contact info",
                     "Address",
                       "Electronic mail address",
@@ -203,8 +233,7 @@ public final strictfp class TreeNodeTest
     @Test
     @DependsOnMethod("testGetNameForMultiOccurrences")     // Because similar to names, which were tested progressively.
     public void testGetIdentifier() {
-        final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnContentEquals(create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY), TableColumn.IDENTIFIER,
+        assertCitationContentEquals(1, TableColumn.IDENTIFIER,
             "CI_Citation",
               "title",
               "alternateTitle",
@@ -212,11 +241,11 @@ public final strictfp class TreeNodeTest
               "edition",
               "citedResponsibleParty",
                 "party",
-                  "name",
+                  "name",                               // In COMPACT mode, this value is associated to "party" node.
                 "role",
               "citedResponsibleParty",
                 "party",
-                  "name",
+                  "name",                               // In COMPACT mode, this value is associated to "party" node.
                   "contactInfo",
                     "address",
                       "electronicMailAddress",
@@ -234,8 +263,7 @@ public final strictfp class TreeNodeTest
     public void testGetIndex() {
         final Integer ZERO = 0;
         final Integer ONE  = 1;
-        final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnContentEquals(create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY), TableColumn.INDEX,
+        assertCitationContentEquals(1, TableColumn.INDEX,
             null,           // CI_Citation
               null,         // title
               ZERO,         // alternateTitle
@@ -243,11 +271,11 @@ public final strictfp class TreeNodeTest
               null,         // edition
               ZERO,         // citedResponsibleParty
                 ZERO,       // party (organisation)
-                  null,     // name
+                  null,     // name                         — in COMPACT mode, this value is associated to "party" node.
                 null,       // role
               ONE,          // citedResponsibleParty
                 ZERO,       // party (individual)
-                  null,     // name
+                  null,     // name                         — in COMPACT mode, this value is associated to "party" node.
                   ZERO,     // contactInfo
                     ZERO,   // address
                       ZERO, // electronicMailAddress
@@ -263,20 +291,19 @@ public final strictfp class TreeNodeTest
     @Test
     @DependsOnMethod("testGetIdentifier")       // Because if identifiers are wrong, we are looking at wrong properties.
     public void testGetElementType() {
-        final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnContentEquals(create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY), TableColumn.TYPE,
+        assertCitationContentEquals(0, TableColumn.TYPE,
             Citation.class,
               InternationalString.class,
               InternationalString.class,
               InternationalString.class,
               InternationalString.class,
               Responsibility.class,
-                Party.class,
-                  InternationalString.class,
+                Party.class,                            // In COMPACT mode, value with be the one of "name" node instead.
+                  InternationalString.class,            // Name
                 Role.class,
               Responsibility.class,
-                Party.class,
-                  InternationalString.class,
+                Party.class,                            // In COMPACT mode, value with be the one of "name" node instead.
+                  InternationalString.class,            // Name
                   Contact.class,
                     Address.class,
                       String.class,
@@ -292,22 +319,21 @@ public final strictfp class TreeNodeTest
     @Test
     @DependsOnMethod("testGetIdentifier")       // Because if identifiers are wrong, we are looking at wrong properties.
     public void testGetValue() {
-        final DefaultCitation citation = metadataWithHierarchy();
-        assertColumnContentEquals(create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY), TableColumn.VALUE,
-            null, // Citation
+        assertCitationContentEquals(0, TableColumn.VALUE,
+            null,                               // Citation
               "Some title",
               "First alternate title",
               "Second alternate title",
               "Some edition",
-              null, // ResponsibleParty
-                null, // Party (organisation)
+              null,                             // ResponsibleParty
+                null,                           // Party (organisation)
                   "Some organisation",
                 Role.DISTRIBUTOR,
-              null, // ResponsibleParty
-                null, // Party (individual)
+              null,                             // ResponsibleParty
+                null,                           // Party (individual)
                   "Some person of contact",
-                  null, // Contact
-                    null, // Address
+                  null,                         // Contact
+                    null,                       // Address
                       "Some email",
                 Role.POINT_OF_CONTACT,
               PresentationForm.MAP_DIGITAL,
@@ -322,7 +348,7 @@ public final strictfp class TreeNodeTest
     @DependsOnMethod("testGetValue")
     public void testNewChild() {
         final DefaultCitation citation = metadataWithHierarchy();
-        final TreeNode node = create(citation, Citation.class, ValueExistencePolicy.NON_EMPTY);
+        final TreeNode node = create(citation, Citation.class);
         /*
          * Ensure that we can not overwrite existing nodes.
          */
@@ -359,35 +385,57 @@ public final strictfp class TreeNodeTest
      * on all children of that given. In the particular case of the {@link TableColumn#NAME},
      * international strings are replaced by unlocalized strings before comparisons.
      *
-     * @param  node     the node for which to test the children.
-     * @param  column   the column from which to get a value.
-     * @param  values   the expected values. The first value is the result of the getter method
-     *                  applied on the given node, and all other values are the result of the
-     *                  getter method applied on the children, in iteration order.
+     * @param  node      the node for which to test the children.
+     * @param  column    the column from which to get a value.
+     * @param  expected  the expected values. The first value is the result of the getter method
+     *                   applied on the given node, and all other values are the result of the
+     *                   getter method applied on the children, in iteration order.
      */
-    private static void assertColumnContentEquals(final TreeNode node,
-            final TableColumn<?> column, final Object... values)
+    private void assertColumnContentEquals(final TreeNode node,
+            final TableColumn<?> column, final Object... expected)
     {
-        assertEquals("Missing values in the tested metadata.", values.length,
-                assertColumnContentEquals(node, column, values, 0));
+        int count = expected.length;
+        if (valuePolicy == ValueExistencePolicy.COMPACT) {
+            while (expected[count-1] == null) count--;
+        }
+        assertEquals("Missing values in the tested metadata.", count,
+                assertColumnContentEquals(node, column, expected, 0));
     }
 
     /**
      * Implementation of the above {@code assertGetterReturns}, to be invoked recursively.
+     *
+     * @return number of nodes found in the given metadata tree.
      */
     private static int assertColumnContentEquals(final TreeTable.Node node, final TableColumn<?> column,
-            final Object[] values, int index)
+            final Object[] expected, int index)
     {
         final Object actual = node.getValue(column);
         Object unlocalized = actual;
         if (unlocalized instanceof InternationalString) {
             unlocalized = ((InternationalString) unlocalized).toString(Locale.ROOT);
         }
-        assertEquals("values[" + index + ']', values[index++], unlocalized);
+        assertEquals("values[" + index + ']', expected[index++], unlocalized);
         for (final TreeTable.Node child : node.getChildren()) {
-            index = assertColumnContentEquals(child, column, values, index);
+            index = assertColumnContentEquals(child, column, expected, index);
         }
         assertSame("Value shall be stable.", actual, node.getValue(column));
         return index;
     }
+
+    /**
+     * Same tests but using {@link ValueExistencePolicy#COMPACT}.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-298">SIS-298</a>
+     */
+    @Test
+    @DependsOnMethod({"testGetNameForHierarchy", "testGetIdentifier", "testGetIndex", "testGetElementType", "testGetValue"})
+    public void testCompactPolicy() {
+        valuePolicy = ValueExistencePolicy.COMPACT;
+        testGetNameForHierarchy();
+        testGetIdentifier();
+        testGetIndex();
+        testGetElementType();
+        testGetValue();
+    }
 }

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=1794136&r1=1794135&r2=1794136&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] Sat May  6 12:09:41 2017
@@ -44,7 +44,7 @@ import static org.apache.sis.test.Assert
  * Tests the {@link TreeTableFormat} applied to the formatting of metadata tree.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.5
+ * @version 0.8
  * @since   0.3
  * @module
  */
@@ -76,31 +76,27 @@ public final strictfp class TreeTableFor
 
     /**
      * Tests the formatting of a {@link DefaultCitation} object.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-298">SIS-298</a>
      */
     @Test
     public void testCitation() {
         final DefaultCitation citation = DefaultCitationTest.create();
         final String text = format.format(citation.asTreeTable());
         assertMultilinesEquals(
-            "Citation\n" +
-            "  ├─Title…………………………………………………………………………… Undercurrent\n" +
+            "Citation……………………………………………………………………………… Undercurrent\n" +
             "  ├─Alternate title………………………………………………… Andākarento\n" +
-            "  ├─Identifier\n" +
-            "  │   ├─Authority\n" +
-            "  │   │   ├─Title……………………………………………………… International Standard Book Number\n" +
+            "  ├─Identifier……………………………………………………………… 9782505004509\n" +
+            "  │   ├─Authority……………………………………………………… International Standard Book Number\n" +
             "  │   │   └─Alternate title…………………………… ISBN\n" +
-            "  │   ├─Code…………………………………………………………………… 9782505004509\n" +
             "  │   └─Code space…………………………………………………… ISBN\n"+
             "  ├─Cited responsible party (1 of 2)\n" +
-            "  │   ├─Party\n" +
-            "  │   │   └─Name………………………………………………………… Testsuya Toyoda\n" +
+            "  │   ├─Individual…………………………………………………… Testsuya Toyoda\n" +
             "  │   └─Role…………………………………………………………………… Author\n" +
             "  ├─Cited responsible party (2 of 2)\n" +
-            "  │   ├─Party\n" +
-            "  │   │   └─Name………………………………………………………… Kōdansha\n" +
+            "  │   ├─Organisation……………………………………………… Kōdansha\n" +
             "  │   ├─Role…………………………………………………………………… Editor\n" +
-            "  │   └─Extent\n" +
-            "  │       ├─Description……………………………………… World\n" +
+            "  │   └─Extent……………………………………………………………… World\n" +
             "  │       └─Geographic element\n" +
             "  │           ├─West bound longitude…… 180°W\n" +
             "  │           ├─East bound longitude…… 180°E\n" +
@@ -128,8 +124,7 @@ public final strictfp class TreeTableFor
         final String text = format.format(processing.asTreeTable());
         assertMultilinesEquals(
             "Processing\n" +
-            "  ├─Documentation (1 of 3)\n" +
-            "  │   ├─Title……………………………………………… Some specification\n" +
+            "  ├─Documentation (1 of 3)…………… Some specification\n" +
             "  │   └─Presentation form……………… Document hardcopy\n" +
             "  ├─Documentation (2 of 3)\n" +
             "  │   └─Presentation form……………… Image hardcopy\n" +

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java [UTF-8] Sat May  6 12:09:41 2017
@@ -54,18 +54,15 @@ public final strictfp class TreeTableVie
      * with {@link ValueExistencePolicy#NON_EMPTY}.
      */
     private static final String EXPECTED =
-            "Citation\n" +
-            "  ├─Title……………………………………………………………………………………………… Some title\n" +
+            "Citation………………………………………………………………………………………………… Some title\n" +
             "  ├─Alternate title (1 of 2)…………………………………………… First alternate title\n" +
             "  ├─Alternate title (2 of 2)…………………………………………… Second alternate title\n" +
             "  ├─Edition………………………………………………………………………………………… Some edition\n" +
             "  ├─Cited responsible party (1 of 2)\n" +
-            "  │   ├─Party\n" +
-            "  │   │   └─Name…………………………………………………………………………… Some organisation\n" +
+            "  │   ├─Organisation………………………………………………………………… Some organisation\n" +
             "  │   └─Role……………………………………………………………………………………… Distributor\n" +
             "  ├─Cited responsible party (2 of 2)\n" +
-            "  │   ├─Party\n" +
-            "  │   │   ├─Name…………………………………………………………………………… Some person of contact\n" +
+            "  │   ├─Individual……………………………………………………………………… Some person of contact\n" +
             "  │   │   └─Contact info\n" +
             "  │   │       └─Address\n" +
             "  │   │           └─Electronic mail address…… Some email\n" +
@@ -81,9 +78,9 @@ public final strictfp class TreeTableVie
      */
     @Test
     public void testToString() {
-        final TreeTableView metadata = create(ValueExistencePolicy.NON_EMPTY);
-        assertMultilinesEquals(EXPECTED, formatNameAndValue(metadata)); // Locale-independent
-        assertArrayEquals(toTreeStructure(EXPECTED), toTreeStructure(metadata.toString())); // Locale-dependent.
+        final TreeTableView metadata = create(ValueExistencePolicy.COMPACT);
+        assertMultilinesEquals(EXPECTED, formatNameAndValue(metadata));                         // Locale-independent
+        assertArrayEquals(toTreeStructure(EXPECTED), toTreeStructure(metadata.toString()));     // Locale-dependent.
     }
 
     /**
@@ -94,7 +91,7 @@ public final strictfp class TreeTableVie
     @Test
     @DependsOnMethod("testToString")
     public void testSerialization() throws Exception {
-        final Object original = create(ValueExistencePolicy.NON_EMPTY);
+        final Object original = create(ValueExistencePolicy.COMPACT);
         final Object deserialized;
         final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
         try (ObjectOutputStream out = new ObjectOutputStream(buffer)) {

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=1794136&r1=1794135&r2=1794136&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] Sat May  6 12:09:41 2017
@@ -236,8 +236,8 @@ public final strictfp class AllMetadataT
     protected String getExpectedXmlElementName(final Class<?> enclosing, final UML uml) {
         String name = super.getExpectedXmlElementName(enclosing, uml);
         switch (name) {
-            case "MD_Scope": {      // ISO 19115:2014
-                name = "DQ_Scope";  // ISO 19115:2003
+            case "MD_Scope": {                  // ISO 19115:2014
+                name = "DQ_Scope";              // ISO 19115:2003
                 break;
             }
             case "distributedComputingPlatform": {

Modified: sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java [UTF-8] Sat May  6 12:09:41 2017
@@ -135,27 +135,22 @@ public final strictfp class DefaultDataI
     public void testToString() {
         assertMultilinesEquals(
                 "Data identification\n" +
-                "  ├─Citation\n" +
-                "  │   ├─Title……………………………………………………… Sea Surface Temperature Analysis Model\n" +
-                "  │   ├─Date\n" +
-                "  │   │   ├─Date……………………………………………… 2005-09-22 00:00:00\n" +
+                "  ├─Citation………………………………………………………… Sea Surface Temperature Analysis Model\n" +
+                "  │   ├─Date………………………………………………………… 2005-09-22 00:00:00\n" +
                 "  │   │   └─Date type………………………………… Creation\n" +
-                "  │   └─Identifier\n" +
-                "  │       └─Code……………………………………………… SST_Global.nc\n" +
+                "  │   └─Identifier………………………………………… SST_Global.nc\n" +
                 "  ├─Abstract………………………………………………………… NCEP SST Global 5.0 x 2.5 degree model data\n" +
                 "  ├─Descriptive keywords\n" +
                 "  │   ├─Keyword………………………………………………… EARTH SCIENCE > Oceans > Ocean Temperature > Sea Surface Temperature\n" +
                 "  │   ├─Type………………………………………………………… Theme\n" +
-                "  │   └─Thesaurus name\n" +
-                "  │       └─Title…………………………………………… GCMD Science Keywords\n" +
+                "  │   └─Thesaurus name……………………………… GCMD Science Keywords\n" +
                 "  ├─Resource constraints\n" +
                 "  │   └─Use limitation……………………………… Freely available\n" +
                 "  ├─Spatial representation type……… Grid\n" +
                 "  ├─Language (1 of 2)………………………………… en_US\n" +
                 "  ├─Language (2 of 2)………………………………… en\n" +
                 "  ├─Character set…………………………………………… US-ASCII\n" +
-                "  └─Extent\n" +
-                "      ├─Description……………………………………… World\n" +
+                "  └─Extent……………………………………………………………… World\n" +
                 "      └─Geographic element\n" +
                 "          ├─West bound longitude…… 180°W\n" +
                 "          ├─East bound longitude…… 180°E\n" +

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] Sat May  6 12:09:41 2017
@@ -730,6 +730,9 @@ public abstract class AbstractEnvelope i
 
     /**
      * Returns {@code true} if this envelope completely encloses the specified envelope.
+     * The default implementation delegates to:
+     *
+     * <blockquote><pre>{@linkplain #contains(Envelope, boolean) contains}(envelope, <b>true</b>)</pre></blockquote>
      *
      * <div class="section">Pre-conditions</div>
      * This method assumes that the specified envelope uses the same CRS than this envelope.
@@ -764,10 +767,6 @@ public abstract class AbstractEnvelope i
      * <p>This method is subject to the same pre-conditions than {@link #contains(Envelope)},
      * and handles envelopes spanning the anti-meridian in the same way.</p>
      *
-     * <div class="warning"><b>Warning:</b> This method may change or be removed in a future SIS version.
-     * For API stability, use the {@link #contains(Envelope)} method instead.
-     * See <a href="http://issues.apache.org/jira/browse/SIS-172">SIS-172</a> for more information.</div>
-     *
      * @param  envelope        the envelope to test for inclusion.
      * @param  edgesInclusive  {@code true} if this envelope edges are inclusive.
      * @return {@code true} if this envelope completely encloses the specified one.
@@ -848,6 +847,11 @@ public abstract class AbstractEnvelope i
 
     /**
      * Returns {@code true} if this envelope intersects the specified envelope.
+     * This method returns {@code true} if two envelope <em>interiors</em> have at least one point in common
+     * (in other words, their intersection is non-{@linkplain #isEmpty() empty}).
+     * The default implementation delegates to:
+     *
+     * <blockquote><pre>{@linkplain #intersects(Envelope, boolean) intersects}(envelope, <b>false</b>)</pre></blockquote>
      *
      * <div class="section">Pre-conditions</div>
      * This method assumes that the specified envelope uses the same CRS than this envelope.
@@ -867,31 +871,36 @@ public abstract class AbstractEnvelope i
      * @since 0.4
      */
     public boolean intersects(final Envelope envelope) throws MismatchedDimensionException {
-        return intersects(envelope, true);
+        return intersects(envelope, false);
     }
 
     /**
-     * Returns {@code true} if this envelope intersects the specified envelope.
-     * If one or more edges from the specified envelope coincide with an edge from this envelope,
-     * then this method returns {@code true} only if {@code edgesInclusive} is {@code true}.
-     *
-     * <p>This method is subject to the same pre-conditions than {@link #intersects(Envelope)},
-     * and handles envelopes spanning the anti-meridian in the same way.</p>
+     * Returns {@code true} if this envelope intersects or (optionally) touches the specified envelope.
+     * The {@code touch} argument controls the value to return if only the envelope boundaries
+     * (not the interiors) have a point in common:
+     *
+     * <ul>
+     *   <li>If {@code false}, this method returns {@code true} if the intersection between the two envelopes
+     *       is non-{@linkplain #isEmpty() empty} (i.e. the envelope <em>interiors</em> have points in common).
+     *       This is the usual definition of {@code intersects} operation.</li>
+     *   <li>If {@code true}, this method returns {@code true} if the two envelopes intersect each other
+     *       <em>or</em> touch each other.</li>
+     * </ul>
      *
-     * <div class="warning"><b>Warning:</b> This method may change or be removed in a future SIS version.
-     * For API stability, use the {@link #intersects(Envelope)} method instead.
-     * See <a href="http://issues.apache.org/jira/browse/SIS-172">SIS-172</a> for more information.</div>
+     * This method is subject to the same pre-conditions than {@link #intersects(Envelope)},
+     * and handles envelopes spanning the anti-meridian in the same way.
      *
-     * @param  envelope        the envelope to test for intersection.
-     * @param  edgesInclusive  {@code true} if this envelope edges are inclusive.
-     * @return {@code true} if this envelope intersects the specified one.
-     * @throws MismatchedDimensionException if the specified envelope doesn't have the expected dimension.
+     * @param  envelope  the envelope to test for intersection.
+     * @param  touch     the value to return if the two envelopes touch each other.
+     * @return {@code true} if this envelope intersects the specified envelope, or
+     *         {@code touch} if this envelope touches the specified envelope, or {@code false} otherwise.
+     * @throws MismatchedDimensionException if the specified envelope does not have the expected dimension.
      * @throws AssertionError if assertions are enabled and the envelopes have mismatched CRS.
      *
      * @see #contains(Envelope, boolean)
      * @see #equals(Envelope, double, boolean)
      */
-    public boolean intersects(final Envelope envelope, final boolean edgesInclusive) throws MismatchedDimensionException {
+    public boolean intersects(final Envelope envelope, final boolean touch) throws MismatchedDimensionException {
         ensureNonNull("envelope", envelope);
         final int dimension = getDimension();
         ensureDimensionMatches("envelope", dimension, envelope);
@@ -905,7 +914,7 @@ public abstract class AbstractEnvelope i
             final double lower1 = lowerCorner.getOrdinate(i);
             final double upper1 = upperCorner.getOrdinate(i);
             final boolean lowerCondition, upperCondition;
-            if (edgesInclusive) {
+            if (touch) {
                 lowerCondition = (lower1 <= upper0);
                 upperCondition = (upper1 >= lower0);
             } else {
@@ -937,7 +946,7 @@ public abstract class AbstractEnvelope i
             }
             // The check for ArrayEnvelope.class is for avoiding never-ending callbacks.
             assert envelope.getClass() == ArrayEnvelope.class || hasNaN(envelope) ||
-                    !contains(new ArrayEnvelope(envelope), edgesInclusive) : envelope;
+                    !contains(new ArrayEnvelope(envelope), touch) : envelope;
             return false;
         }
         return true;

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/geometry/Envelope2D.java [UTF-8] Sat May  6 12:09:41 2017
@@ -834,9 +834,10 @@ public class Envelope2D extends Rectangl
             }
             /*
              * See AbstractEnvelope.intersects(Envelope) for an illustration of the algorithm applied here.
+             * We use < operator, not <=, for consistency with the standard "intersects" definition.
              */
-            final boolean minCondition = (min1 <= min0 + span0);
-            final boolean maxCondition = (min1 + span1 >= min0);
+            final boolean minCondition = (min1 < min0 + span0);
+            final boolean maxCondition = (min1 + span1 > min0);
             if (maxCondition & minCondition) {
                 continue;
             }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java [UTF-8] Sat May  6 12:09:41 2017
@@ -275,6 +275,11 @@ public final class Resources extends Ind
         public static final short MissingInterpolationOrdinates = 41;
 
         /**
+         * Missing parameter values for “{0}” coordinate operation.
+         */
+        public static final short MissingParameterValues_1 = 74;
+
+        /**
          * No spatial or temporal dimension found in “{0}”
          */
         public static final short MissingSpatioTemporalDimension_1 = 42;
@@ -321,6 +326,19 @@ public final class Resources extends Ind
         public static final short NoSuchOperationMethod_1 = 50;
 
         /**
+         * The coordinate system axes in the given “{0}” description do not conform to the expected
+         * axes according “{1}” authoritative description.
+         */
+        public static final short NonConformAxes_2 = 72;
+
+        /**
+         * The given “{0}” description does not conform to the “{1}” authoritative description.
+         * Differences are found in {2,choice,0#conversion method|1#conversion description|2#coordinate
+         * system|3#datum|4#CRS}.
+         */
+        public static final short NonConformCRS_3 = 73;
+
+        /**
          * No horizontal component found in the “{0}” coordinate reference system.
          */
         public static final short NonHorizontalCRS_1 = 71;

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties [ISO-8859-1] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties [ISO-8859-1] Sat May  6 12:09:41 2017
@@ -35,6 +35,9 @@ MismatchedEllipsoidAxisLength_3   = The
 MismatchedOperationFactories_2    = No coordinate operation from \u201c{0}\u201d to \u201c{1}\u201d because of mismatched factories.
 MisnamedParameter_1               = Despite its name, this parameter is effectively \u201c{0}\u201d.
 NotFormalProjectionParameter_1    = This parameter borrowed from the \u201c{0}\u201d projection is not formally a parameter of this projection.
+NonConformAxes_2                  = The coordinate system axes in the given \u201c{0}\u201d description do not conform to the expected axes according \u201c{1}\u201d authoritative description.
+NonConformCRS_3                   = The given \u201c{0}\u201d description does not conform to the \u201c{1}\u201d authoritative description. \
+                                    Differences are found in {2,choice,0#conversion method|1#conversion description|2#coordinate system|3#datum|4#CRS}.
 
 #
 # Error messages (to be used in exceptions)
@@ -70,6 +73,7 @@ MissingHorizontalDimension_1      = No h
 MissingVerticalDimension_1        = No vertical dimension found in \u201c{0}\u201d
 MissingTemporalDimension_1        = No temporal dimension found in \u201c{0}\u201d
 MissingSpatioTemporalDimension_1  = No spatial or temporal dimension found in \u201c{0}\u201d
+MissingParameterValues_1          = Missing parameter values for \u201c{0}\u201d coordinate operation.
 MissingValueForParameter_1        = Missing value for \u201c{0}\u201d parameter.
 NoConvergence                     = No convergence.
 NoConvergenceForPoints_2          = No convergence for points {0} and {1}.

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties [ISO-8859-1] Sat May  6 12:09:41 2017
@@ -40,6 +40,9 @@ MismatchedEllipsoidAxisLength_3   = Le p
 MismatchedOperationFactories_2    = Il n\u2019y a pas d\u2019op\u00e9rations allant de \u00ab\u202f{0}\u202f\u00bb vers \u00ab\u202f{1}\u202f\u00bb parce que ces derniers sont associ\u00e9s \u00e0 deux fabriques diff\u00e9rentes.
 MisnamedParameter_1               = Malgr\u00e9 son nom, ce param\u00e8tre produit en r\u00e9alit\u00e9 l\u2019effet d\u2019un \u00ab\u202f{0}\u202f\u00bb.
 NotFormalProjectionParameter_1    = Ce param\u00e8tre emprunt\u00e9 \u00e0 la projection \u00ab\u202f{0}\u202f\u00bb n\u2019est pas formellement un param\u00e8tre de cette projection.
+NonConformAxes_2                  = Les axes du syst\u00e8me de coordonn\u00e9es d\u00e9finis dans \u00ab\u202f{0}\u202f\u00bb ne sont pas conformes aux axes attendus d\u2019apr\u00e8s la description officielle de \u00ab\u202f{1}\u202f\u00bb.
+NonConformCRS_3                   = La description donn\u00e9e pour \u00ab\u202f{0}\u202f\u00bb n\u2019est pas conforme \u00e0 la description officielle de \u00ab\u202f{1}\u202f\u00bb. \
+                                    Des diff\u00e9rences ont \u00e9t\u00e9 trouv\u00e9es dans {2,choice,0#la m\u00e9thode de conversion|1#la description de la conversion|2#le syst\u00e8me de coordonn\u00e9es|3#le r\u00e9f\u00e9rentiel|4#le CRS}.
 
 #
 # Error messages (to be used in exceptions)
@@ -75,6 +78,7 @@ MissingHorizontalDimension_1      = Aucu
 MissingVerticalDimension_1        = Aucune dimension verticale n\u2019a \u00e9t\u00e9 trouv\u00e9e dans \u00ab\u202f{0}\u202f\u00bb.
 MissingTemporalDimension_1        = Aucune dimension temporelle n\u2019a \u00e9t\u00e9 trouv\u00e9e dans \u00ab\u202f{0}\u202f\u00bb.
 MissingSpatioTemporalDimension_1  = Aucune dimension spatiale ou temporelle n\u2019a \u00e9t\u00e9 trouv\u00e9e dans \u00ab\u202f{0}\u202f\u00bb.
+MissingParameterValues_1          = Il manque les valeurs des param\u00e8tres pour l\u2019op\u00e9ration \u00ab\u202f{0}\u202f\u00bb.
 MissingValueForParameter_1        = Aucune valeur n\u2019a \u00e9t\u00e9 d\u00e9finie pour le param\u00e8tre \u00ab\u202f{0}\u202f\u00bb.
 NoConvergence                     = Le calcul ne converge pas.
 NoConvergenceForPoints_2          = Le calcul ne converge pas pour les points {0} et {1}.

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java [UTF-8] Sat May  6 12:09:41 2017
@@ -34,6 +34,7 @@ import org.apache.sis.metadata.iso.citat
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.referencing.operation.DefaultOperationMethod;
 import org.apache.sis.referencing.operation.transform.MathTransformProvider;
+import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Workaround;
@@ -43,7 +44,7 @@ import org.apache.sis.util.Workaround;
  * Base class for all providers defined in this package.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 0.8
  * @since   0.6
  * @module
  */
@@ -185,6 +186,28 @@ public abstract class AbstractProvider e
     }
 
     /**
+     * If an operation method is ambiguous according Apache SIS, returns the name of the method that SIS should use.
+     * Otherwise returns {@code null}. The ambiguities that need to be resolved are:
+     *
+     * <ul>
+     *   <li>Method <cite>"Geographic/geocentric conversions"</cite> (EPSG:9602) can be either:
+     *     <ul>
+     *       <li>{@code "Ellipsoid_To_Geocentric"} (implemented by {@link GeographicToGeocentric}</li>
+     *       <li>{@code "Geocentric_To_Ellipsoid"} (implemented by {@link GeocentricToGeographic}</li>
+     *     </ul>
+     *   </li>
+     * </ul>
+     *
+     * @param  context   the potentially ambiguous context.
+     * @return name of the provider to use, or {@code null} if there is nothing to change.
+     *
+     * @since 0.8
+     */
+    public String resolveAmbiguity(final DefaultMathTransformFactory.Context context) {
+        return null;
+    }
+
+    /**
      * Flags whether the source and/or target ellipsoid are concerned by this operation. This method is invoked by
      * {@link org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory} for determining if this
      * operation has {@code "semi_major"}, {@code "semi_minor"}, {@code "src_semi_major"}, {@code "src_semi_minor"}

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeodeticOperation.java [UTF-8] Sat May  6 12:09:41 2017
@@ -19,6 +19,7 @@ package org.apache.sis.internal.referenc
 import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.referencing.operation.Transformation;
 
 
@@ -86,6 +87,8 @@ abstract class GeodeticOperation extends
      * Returns the three-dimensional variant of this operation method, or {@code null} if none.
      * This method needs to be overridden only if the three-dimensional variant is an instance
      * of a different class than this instance.
+     *
+     * <p>This method is not needed on the JDK9 branch.</p>
      */
     Class<? extends GeodeticOperation> variant3D() {
         return null;
@@ -112,12 +115,12 @@ abstract class GeodeticOperation extends
     }
 
     /**
-     * Returns the interface implemented by all coordinate operations that extends this class.
+     * Returns the interface implemented by most coordinate operations that extends this class.
      *
-     * @return fixed to {@link Transformation}.
+     * @return default to {@link Transformation}.
      */
     @Override
-    public final Class<Transformation> getOperationType() {
+    public Class<? extends SingleOperation> getOperationType() {
         return Transformation.class;
     }
 

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic2Dto3D.java [UTF-8] Sat May  6 12:09:41 2017
@@ -21,7 +21,6 @@ import org.opengis.util.FactoryException
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
-import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.apache.sis.referencing.operation.matrix.Matrices;
@@ -41,12 +40,15 @@ import org.apache.sis.parameter.Paramete
  * format the inverse ({@code "INVERSE_MT"}) of 3D to 2D transform.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
- * @since   0.7
+ * @version 0.8
+ *
+ * @see Geographic3Dto2D
+ *
+ * @since 0.7
  * @module
  */
 @XmlTransient
-public final class Geographic2Dto3D extends AbstractProvider {
+public final class Geographic2Dto3D extends GeographicRedimension {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -71,17 +73,24 @@ public final class Geographic2Dto3D exte
      * Constructs a provider with default parameters.
      */
     public Geographic2Dto3D() {
-        super(2, 3, PARAMETERS);
+        this(null);
+    }
+
+    /**
+     * Constructs a provider that can be resized.
+     */
+    Geographic2Dto3D(GeodeticOperation[] redimensioned) {
+        super(2, 3, PARAMETERS, redimensioned);
     }
 
     /**
-     * Returns the operation type.
-     *
-     * @return interface implemented by all coordinate operations that use this method.
+     * Returns the tree-dimensional variant of this class.
+     * Used for having a unique instance of this provider.
+     * This hack is not needed on the JDK9 branch.
      */
     @Override
-    public Class<Conversion> getOperationType() {
-        return Conversion.class;
+    Class<Geographic3Dto2D> variant3D() {
+        return Geographic3Dto2D.class;
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Geographic3Dto2D.java [UTF-8] Sat May  6 12:09:41 2017
@@ -20,7 +20,6 @@ import javax.xml.bind.annotation.XmlTran
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
-import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
@@ -40,12 +39,15 @@ import org.apache.sis.internal.referenci
  * The inverse operation arbitrarily sets the ellipsoidal height to zero.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
- * @since   0.7
+ * @version 0.8
+ *
+ * @see Geographic2Dto3D
+ *
+ * @since 0.7
  * @module
  */
 @XmlTransient
-public final class Geographic3Dto2D extends AbstractProvider {
+public final class Geographic3Dto2D extends GeographicRedimension {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -66,17 +68,18 @@ public final class Geographic3Dto2D exte
      * Constructs a provider with default parameters.
      */
     public Geographic3Dto2D() {
-        super(3, 2, PARAMETERS);
+        this(new GeodeticOperation[4]);
+        redimensioned[0] = new GeographicRedimension(2, redimensioned);
+        redimensioned[1] = new Geographic2Dto3D(redimensioned);
+        redimensioned[2] = this;
+        redimensioned[3] = new GeographicRedimension(3, redimensioned);
     }
 
     /**
-     * Returns the operation type.
-     *
-     * @return interface implemented by all coordinate operations that use this method.
+     * Constructs a provider that can be resized.
      */
-    @Override
-    public Class<Conversion> getOperationType() {
-        return Conversion.class;
+    private Geographic3Dto2D(GeodeticOperation[] redimensioned) {
+        super(3, 2, PARAMETERS, redimensioned);
     }
 
     /**

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/GeographicToGeocentric.java [UTF-8] Sat May  6 12:09:41 2017
@@ -22,10 +22,13 @@ import org.opengis.util.FactoryException
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterValue;
+import org.opengis.referencing.cs.CartesianCS;
+import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.apache.sis.referencing.operation.transform.EllipsoidToCentricTransform;
+import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.internal.util.Constants;
 
@@ -35,7 +38,7 @@ import org.apache.sis.internal.util.Cons
  * This provider creates transforms from geographic to geocentric coordinate reference systems.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 0.8
  *
  * @see GeocentricToGeographic
  *
@@ -85,6 +88,28 @@ public final class GeographicToGeocentri
     }
 
     /**
+     * If the user asked for the <cite>"Geographic/geocentric conversions"</cite> operation but the parameter types
+     * suggest that (s)he intended to convert in the opposite direction, return the name of operation method to use.
+     * We need this check because EPSG defines a single operation method for both {@code "Ellipsoid_To_Geocentric"}
+     * and {@code "Geocentric_To_Ellipsoid"} methods.
+     *
+     * <p><b>Note:</b>  we do not define similar method in {@link GeocentricToGeographic} class because the only
+     * way to obtain that operation method is to ask explicitely for {@code "Geocentric_To_Ellipsoid"} operation.
+     * The ambiguity that we try to resolve here exists only if the user asked for the EPSG:9602 operation, which
+     * is defined only in this class.</p>
+     *
+     * @return {@code "Geocentric_To_Ellipsoid"} if the user apparently wanted to get the inverse of this
+     *         {@code "Ellipsoid_To_Geocentric"} operation, or {@code null} if none.
+     */
+    @Override
+    public String resolveAmbiguity(final DefaultMathTransformFactory.Context context) {
+        if (context.getSourceCS() instanceof CartesianCS && context.getTargetCS() instanceof EllipsoidalCS) {
+            return GeocentricToGeographic.NAME;
+        }
+        return super.resolveAmbiguity(context);
+    }
+
+    /**
      * Notifies {@code DefaultMathTransformFactory} that Geographic/geocentric conversions
      * require values for the {@code "semi_major"} and {@code "semi_minor"} parameters.
      *

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Providers.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Providers.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Providers.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Providers.java [UTF-8] Sat May  6 12:09:41 2017
@@ -27,6 +27,8 @@ import org.apache.sis.internal.util.Lazy
  *
  * <p>This class is <strong>not</strong> thread-safe. Synchronization are user's responsibility.</p>
  *
+ * <p>This class is not needed on the JDK9 branch.</p>
+ *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 0.7
  * @since   0.7
@@ -54,11 +56,11 @@ public final class Providers extends Laz
                 for (int i=cached.size(); --i >= 0;) {
                     final OperationMethod m = cached.get(i);
                     if (m.getClass() == variant3D) {
-                        final GeodeticOperation candidate = ((GeodeticOperation) m).redimensioned[0];
-                        if (candidate != null) {            // Should not be null, but let be safe.
-                            assert candidate.getClass() == element.getClass() : variant3D;
-                            element = candidate;
-                            break;
+                        for (final GeodeticOperation candidate : ((GeodeticOperation) m).redimensioned) {
+                            if (candidate != null && candidate.getClass() == element.getClass()) {
+                                element = candidate;
+                                break;
+                            }
                         }
                     }
                 }

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] Sat May  6 12:09:41 2017
@@ -20,6 +20,7 @@ import java.util.Map;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.logging.LogRecord;
 import org.opengis.util.FactoryException;
 import org.opengis.geometry.Envelope;
 import org.opengis.referencing.NoSuchAuthorityCodeException;
@@ -55,8 +56,10 @@ import org.apache.sis.internal.metadata.
 import org.apache.sis.internal.referencing.PositionalAccuracyConstant;
 import org.apache.sis.internal.referencing.CoordinateOperations;
 import org.apache.sis.internal.referencing.ReferencingUtilities;
+import org.apache.sis.internal.referencing.DefinitionVerifier;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.system.Modules;
+import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.referencing.cs.DefaultVerticalCS;
 import org.apache.sis.referencing.cs.DefaultEllipsoidalCS;
 import org.apache.sis.referencing.crs.DefaultGeographicCRS;
@@ -70,6 +73,7 @@ import org.apache.sis.metadata.iso.exten
 import org.apache.sis.metadata.iso.extent.Extents;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.logging.Logging;
+import org.apache.sis.util.logging.WarningListener;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.Static;
@@ -232,6 +236,14 @@ public final class CRS extends Static {
      * }
      * </div>
      *
+     * If the parsing produced warnings, they will be reported in a logger named {@code "org.apache.sis.io.wkt"}.
+     * In particular, this method verifies if the description provided by the WKT matches the description provided
+     * by the authority ({@code "EPSG:5641"} in above example) and reports discrepancies.
+     * Note that this comparison between parsed CRS and authoritative CRS is specific to this convenience method;
+     * other APIs documented in <cite>see also</cite> section do not perform this comparison automatically.
+     * Should the WKT description and the authoritative description be in conflict, the WKT description prevails
+     * as mandated by ISO 19162 standard (see {@link #fromAuthority fromAuthority(…)} if a different behavior is needed).
+     *
      * <div class="section">Usage and performance considerations</div>
      * This convenience method delegates to
      * {@link org.apache.sis.referencing.factory.GeodeticObjectFactory#createFromWKT(String)}
@@ -250,7 +262,8 @@ public final class CRS extends Static {
      * @return the parsed Coordinate Reference System.
      * @throws FactoryException if the given WKT can not be parsed.
      *
-     * @see org.apache.sis.io.wkt
+     * @see org.apache.sis.io.wkt.WKTFormat
+     * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createFromWKT(String)
      * @see org.apache.sis.geometry.Envelopes#fromWKT(CharSequence)
      * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT 2 specification</a>
      *
@@ -258,7 +271,9 @@ public final class CRS extends Static {
      */
     public static CoordinateReferenceSystem fromWKT(final String text) throws FactoryException {
         ArgumentChecks.ensureNonNull("text", text);
-        return DefaultFactories.forBuildin(CRSFactory.class).createFromWKT(text);
+        final CoordinateReferenceSystem crs = DefaultFactories.forBuildin(CRSFactory.class).createFromWKT(text);
+        DefinitionVerifier.withAuthority(crs, Loggers.WKT, CRS.class, "fromWKT");
+        return crs;
     }
 
     /**
@@ -267,17 +282,116 @@ public final class CRS extends Static {
      * For reading XML documents from readers or input streams,
      * see static methods in the {@link org.apache.sis.xml.XML} class.
      *
+     * <p>If the unmarshalling produced warnings, they will be reported in a logger named {@code "org.apache.sis.xml"}.
+     * In particular, this method verifies if the description provided by the XML matches the description provided by
+     * the authority code given in {@code <gml:identifier>} element, and reports discrepancies.
+     * Note that this comparison between unmarshalled CRS and authoritative CRS is specific to this convenience method;
+     * other APIs documented in <cite>see also</cite> section do not perform this comparison automatically.
+     * Should the XML description and the authoritative description be in conflict, the XML description prevails
+     * (see {@link #fromAuthority fromAuthority(…)} if a different behavior is needed).</p>
+     *
      * @param  xml  coordinate reference system encoded in XML format.
      * @return the unmarshalled Coordinate Reference System.
      * @throws FactoryException if the object creation failed.
      *
+     * @see org.apache.sis.referencing.factory.GeodeticObjectFactory#createFromXML(String)
      * @see org.apache.sis.xml.XML#unmarshal(String)
      *
      * @since 0.7
      */
     public static CoordinateReferenceSystem fromXML(final String xml) throws FactoryException {
         ArgumentChecks.ensureNonNull("text", xml);
-        return DefaultFactories.forBuildin(CRSFactory.class).createFromXML(xml);
+        final CoordinateReferenceSystem crs = DefaultFactories.forBuildin(CRSFactory.class).createFromXML(xml);
+        DefinitionVerifier.withAuthority(crs, Loggers.XML, CRS.class, "fromXML");
+        return crs;
+    }
+
+    /**
+     * Replaces the given coordinate reference system by an authoritative description, if one can be found.
+     * This method can be invoked after constructing a CRS in a context where the EPSG (or other authority)
+     * code is suspected more reliable than the rest of the description. A common case is a <cite>Well Known
+     * Text</cite> (WKT) string declaring wrong projection method or parameter values for the EPSG code that
+     * it pretends to describe. For example:
+     *
+     * <blockquote>
+     *   {@code PROJCS["WGS 84 / Pseudo-Mercator",}<br>
+     *   {@code   }(…base CRS omitted for brevity…)<br>
+     *   {@code   PROJECTION["Mercator (variant A)"],} — <em><b>wrong:</b> shall be "Popular Visualisation Pseudo Mercator"</em><br>
+     *   {@code   }(…parameters and axes omitted for brevity…)<br>
+     *   {@code   AUTHORITY["EPSG", "3857"]]}
+     * </blockquote>
+     *
+     * In such cases, Apache SIS behavior in {@link #fromWKT(String)}, {@link #fromXML(String)} and other methods is
+     * conform to the <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">ISO 19162 specification</a>:
+     *
+     * <blockquote><cite>"Should any attributes or values given in the cited identifier be in conflict with attributes
+     * or values given explicitly in the WKT description, the WKT values shall prevail."</cite></blockquote>
+     *
+     * In situations where the opposite behavior is desired (i.e. to make the authority identifier prevails),
+     * this method can be invoked. This method performs the following actions:
+     *
+     * <ul>
+     *   <li>If the given CRS has an {@linkplain AbstractIdentifiedObject#getIdentifiers() identifier} and if the authority factory can
+     *     {@linkplain org.apache.sis.referencing.factory.GeodeticAuthorityFactory#createCoordinateReferenceSystem(String) create a CRS}
+     *     for that identifier, then:
+     *     <ul>
+     *       <li>If the CRS defined by the authority is {@linkplain Utilities#equalsIgnoreMetadata equal, ignoring metadata},
+     *         to the given CRS, then this method returns silently the <em>authoritative</em> CRS.</li>
+     *       <li>Otherwise if the CRS defined by the authority is equal, ignoring axis order and units, to the given CRS,
+     *         then this method returns a <em>new</em> CRS derived from the authoritative one but with same
+     *         {@linkplain org.apache.sis.referencing.cs.AxesConvention axes convention} than the given CRS.
+     *         A warning is emitted.</li>
+     *       <li>Otherwise this method discards the given CRS and returns the <em>authoritative</em> CRS.
+     *         A warning is emitted with a message indicating where a difference has been found.</li>
+     *     </ul>
+     *   </li>
+     *   <li>Otherwise if the given CRS does not have identifier, then this method
+     *       {@linkplain org.apache.sis.referencing.factory.IdentifiedObjectFinder searches for an equivalent CRS}
+     *       defined by the authority factory. If such CRS is found, then:
+     *     <ul>
+     *       <li>If the CRS defined by the authority is {@linkplain Utilities#equalsIgnoreMetadata equal, ignoring metadata},
+     *         to the given CRS, then this method returns silently the <em>authoritative</em> CRS.</li>
+     *       <li>Otherwise if the CRS defined by the authority is equal, ignoring axis order and units, to the given CRS,
+     *         then this method returns silently a <em>new</em> CRS derived from the authoritative one but with same
+     *         {@linkplain org.apache.sis.referencing.cs.AxesConvention axes convention} than the given CRS.</li>
+     *     </ul>
+     *   </li>
+     *   <li>Otherwise this method silently returns the given CRS as-is.</li>
+     * </ul>
+     *
+     * <b>Note:</b> the warnings emitted by this method are redundant with the warnings emitted by
+     * {@link #fromWKT(String)} and {@link #fromXML(String)}, so the {@code warnings} argument should be {@code null}
+     * when {@code fromAuthority(…)} is invoked for the CRS parsed by one of above-mentioned methods.
+     * A non-null {@code warnings} argument is more useful for CRS parsed by {@link org.apache.sis.io.wkt.WKTFormat}
+     * or {@link org.apache.sis.xml.XML#unmarshal(String)} for instance.
+     *
+     * @param  crs       the CRS to replace by an authoritative CRS, or {@code null}.
+     * @param  factory   the factory where to search for authoritative definitions, or {@code null} for the default.
+     * @param  listener  where to send warnings, or {@code null} for ignoring warnings.
+     * @return the suggested CRS to use (may be the {@code crs} argument itself), or {@code null} if the given CRS was null.
+     * @throws FactoryException if an error occurred while querying the authority factory.
+     *
+     * @since 0.8
+     */
+    public static CoordinateReferenceSystem fromAuthority(CoordinateReferenceSystem crs,
+            final CRSAuthorityFactory factory, final WarningListener<?> listener) throws FactoryException
+    {
+        if (crs != null) {
+            final DefinitionVerifier verification = DefinitionVerifier.withAuthority(crs, factory, true);
+            if (verification != null) {
+                crs = verification.authoritative;
+                if (listener != null) {
+                    final LogRecord record = verification.warning(false);
+                    if (record != null) {
+                        record.setLoggerName(Modules.REFERENCING);
+                        record.setSourceClassName(CRS.class.getName());
+                        record.setSourceMethodName("fromAuthority");
+                        listener.warningOccured(null, record);
+                    }
+                }
+            }
+        }
+        return crs;
     }
 
     /**
@@ -293,7 +407,7 @@ public final class CRS extends Static {
      * they need to be {@linkplain Envelopes#transform(Envelope, CoordinateReferenceSystem) transformed} in the same CRS.
      * However if one CRS is a Transverse Mercator projection while the other CRS is a world-wide geographic CRS, then
      * attempts to use the Transverse Mercator projection as the common CRS is likely to fail since the geographic envelope
-     * may span an area far outside the projection domain of validity. This {@code suggestTargetCRS(…)} method can used
+     * may span an area far outside the projection domain of validity. This {@code suggestCommonTarget(…)} method can used
      * for choosing a common CRS which is less likely to fail.</div>
      *
      * @param  regionOfInterest  the geographic area for which the coordinate operations will be applied,
@@ -305,8 +419,8 @@ public final class CRS extends Static {
      *
      * @since 0.8
      */
-    public static CoordinateReferenceSystem suggestTargetCRS(GeographicBoundingBox regionOfInterest,
-                                                             CoordinateReferenceSystem... sourceCRS)
+    public static CoordinateReferenceSystem suggestCommonTarget(GeographicBoundingBox regionOfInterest,
+                                                                CoordinateReferenceSystem... sourceCRS)
     {
         CoordinateReferenceSystem bestCRS = null;
         /*

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java [UTF-8] Sat May  6 12:09:41 2017
@@ -1594,6 +1594,13 @@ public class GeodeticObjectFactory exten
      * }
      * </div>
      *
+     * If the given text contains non-fatal anomalies
+     * (unknown or unsupported WKT elements, inconsistent unit definitions, unparsable axis abbreviations, <i>etc.</i>),
+     * warnings may be reported in a {@linkplain java.util.logging.Logger logger} named {@code "org.apache.sis.io.wkt"}.
+     * However this parser does not verify if the overall parsed object matches the EPSG (or other authority) definition,
+     * since this geodetic object factory is not an {@linkplain GeodeticAuthorityFactory authority factory}.
+     * For such verification, see the {@link org.apache.sis.referencing.CRS#fromWKT(String)} convenience method.
+     *
      * <div class="section">Usage and performance considerations</div>
      * The default implementation uses a shared instance of {@link org.apache.sis.io.wkt.WKTFormat}
      * with the addition of thread-safety. This is okay for occasional use,

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java [UTF-8] Sat May  6 12:09:41 2017
@@ -20,7 +20,7 @@ import org.opengis.util.FactoryException
 
 
 /**
- * Thrown when an object can not be created because a resource is missing.
+ * Thrown when a particular object can not be created because a resource is missing.
  * The most common case is a NADCON or NTv2 datum shift operation requested while the
  * datum shift grids was not found in the {@code $SIS_DATA/DatumChanges} directory.
  *

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java [UTF-8] Sat May  6 12:09:41 2017
@@ -20,7 +20,7 @@ import org.opengis.referencing.Authority
 
 
 /**
- * Thrown when a factory can not be created because a resource is missing.
+ * Thrown when a whole factory can not be created because a resource is missing.
  * The most common case is when the {@link org.apache.sis.referencing.factory.sql.EPSGFactory}
  * has no connection to an EPSG database.
  *

Modified: sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java?rev=1794136&r1=1794135&r2=1794136&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java [UTF-8] (original)
+++ sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java [UTF-8] Sat May  6 12:09:41 2017
@@ -21,7 +21,9 @@ import java.util.HashMap;
 import org.opengis.metadata.Identifier;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.AuthorityFactory;
+import org.opengis.referencing.crs.GeneralDerivedCRS;
 import org.opengis.referencing.crs.CRSAuthorityFactory;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
 import org.apache.sis.metadata.iso.citation.Citations;
@@ -32,9 +34,31 @@ import org.apache.sis.referencing.factor
 /**
  * A lazy set of {@link CoordinateOperation} objects to be returned by the
  * {@link EPSGDataAccess#createFromCoordinateReferenceSystemCodes(String, String)} method.
+ * There is two different ways in which {@link EPSGDataAccess} get coordinate operations:
  *
- * @author  Martin Desruisseaux (IRD)
- * @version 0.7
+ * <ol>
+ *   <li>The coordinate operation may be the <cite>conversion from base</cite> property of a projected CRS.
+ *       Those conversions are obtained by a SQL query like below (note that this query can return at most
+ *       one result, because {@code COORD_REF_SYS_CODE} is a primary key):
+ *
+ *       {@preformat sql
+ *         SELECT PROJECTION_CONV_CODE FROM "Coordinate Reference System" WHERE SOURCE_GEOGCRS_CODE = ? AND COORD_REF_SYS_CODE = ?
+ *       }
+ *   </li>
+ *
+ *   <li>The coordinate operation may be standalone. This is the case of coordinate transformations having stochastic errors.
+ *       Those transformations are obtained by a SQL query like below (note that this query can return many results):
+ *
+ *       {@preformat sql
+ *         SELECT COORD_OP_CODE FROM "Coordinate_Operation" … WHERE … AND SOURCE_CRS_CODE = ? AND TARGET_CRS_CODE = ?
+ *       }
+ *   </li>
+ * </ol>
+ *
+ * We distinguish those two cases by the presence or absence of a coordinate operation code in the {@link #projections} map.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @version 0.8
  * @since   0.7
  * @module
  */
@@ -42,6 +66,15 @@ final class CoordinateOperationSet exten
     /**
      * The codes of {@link org.opengis.referencing.crs.ProjectedCRS} objects for
      * the specified {@link org.opengis.referencing.operation.Conversion} codes.
+     *
+     * <ul>
+     *   <li>Keys a coordinate operation codes.</li>
+     *   <li>Values are coordinate reference system codes. They are usually {@code ProjectedCRS},
+     *       but the EPSG database sometime use this mechanisms for other kind of CRS.</li>
+     * </ul>
+     *
+     * This map does <strong>not</strong> contain all operations to be returned by this {@code CoordinateOperationSet},
+     * but only the ones to be returned by the first SQL query documented in the class Javadoc.
      */
     private final Map<String,Integer> projections;
 
@@ -77,15 +110,40 @@ final class CoordinateOperationSet exten
     }
 
     /**
-     * Creates an object for the specified code.
+     * Creates a coordinate operation for the specified EPSG code.
      */
     @Override
     protected CoordinateOperation createObject(final String code) throws FactoryException {
-        final Integer crs = projections.get(code);
-        if (crs != null) {
-            return ((CRSAuthorityFactory) factory).createProjectedCRS(String.valueOf(crs)).getConversionFromBase();
-        } else {
-            return ((CoordinateOperationAuthorityFactory) factory).createCoordinateOperation(code);
+        final Integer base = projections.get(code);
+        if (base != null) {
+            /*
+             * First case documented in class Javadoc:
+             *
+             *     SELECT PROJECTION_CONV_CODE FROM "Coordinate Reference System" …
+             *
+             * The result is usually a ProjectedCRS, but not always.
+             */
+            CoordinateReferenceSystem crs;
+            crs = ((CRSAuthorityFactory) factory).createCoordinateReferenceSystem(String.valueOf(base));
+            if (crs instanceof GeneralDerivedCRS) {
+                return ((GeneralDerivedCRS) crs).getConversionFromBase();
+            }
         }
+        /*
+         * Following line is either for the second case documented in class Javadoc, or the first case
+         * when the result is not a derived CRS. Note that we could create a derived CRS here as below:
+         *
+         *     CoordinateOperation op = …,
+         *     if (crs != null && op instanceof Conversion) {
+         *         return DefaultDerivedCRS.create(IdentifiedObjects.getProperties(crs), baseCRS,
+         *                 (Conversion) op, crs.getCoordinateSystem()).getConversionFromBase();
+         *     }
+         *
+         * We don't do that for now because because EPSGDataAccess.createCoordinateReferenceSystem(String)
+         * would be a better place, by generalizing the work done for ProjectedCRS.
+         *
+         * https://issues.apache.org/jira/browse/SIS-357
+         */
+        return ((CoordinateOperationAuthorityFactory) factory).createCoordinateOperation(code);
     }
 }