Author: desruisseaux
Date: Sat Oct 14 15:24:11 2017
New Revision: 1812190

URL: http://svn.apache.org/viewvc?rev=1812190&view=rev
Log:
Complete implementation combined URI for multi-dimensional CRS.
https://issues.apache.org/jira/browse/SIS-341

Added:
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
   (with props)
Modified:
    
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
    
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryMock.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactoryTest.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
    
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ArraysExt.java

Modified: 
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-metadata/src/test/java/org/apache/sis/internal/metadata/NameMeaningTest.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -16,10 +16,14 @@
  */
 package org.apache.sis.internal.metadata;
 
+import javax.measure.Unit;
 import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.*;
 import org.opengis.referencing.datum.*;
 import org.opengis.referencing.ReferenceSystem;
+import org.opengis.referencing.operation.OperationMethod;
+import org.opengis.referencing.operation.CoordinateOperation;
+import org.opengis.parameter.ParameterDescriptor;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
@@ -41,19 +45,23 @@ public final strictfp class NameMeaningT
      */
     @Test
     public void testToObjectType() {
-        assertEquals("crs",             NameMeaning.toObjectType(GeographicCRS 
      .class));
-        assertEquals("crs",             NameMeaning.toObjectType(ProjectedCRS  
      .class));
-        assertEquals("crs",             NameMeaning.toObjectType(VerticalCRS   
      .class));
-        assertEquals("crs",             NameMeaning.toObjectType(TemporalCRS   
      .class));
-        assertEquals("datum",           NameMeaning.toObjectType(GeodeticDatum 
      .class));
-        assertEquals("datum",           NameMeaning.toObjectType(VerticalDatum 
      .class));
-        assertEquals("datum",           NameMeaning.toObjectType(TemporalDatum 
      .class));
-        assertEquals("ellipsoid",       NameMeaning.toObjectType(Ellipsoid     
      .class));
-        assertEquals("meridian",        NameMeaning.toObjectType(PrimeMeridian 
      .class));
-        assertEquals("cs",              NameMeaning.toObjectType(EllipsoidalCS 
      .class));
-        assertEquals("cs",              NameMeaning.toObjectType(CartesianCS   
      .class));
-        assertEquals("axis",            
NameMeaning.toObjectType(CoordinateSystemAxis.class));
-        assertEquals("referenceSystem", 
NameMeaning.toObjectType(ReferenceSystem     .class));
+        assertEquals("crs",                 
NameMeaning.toObjectType(GeographicCRS       .class));
+        assertEquals("crs",                 
NameMeaning.toObjectType(ProjectedCRS        .class));
+        assertEquals("crs",                 
NameMeaning.toObjectType(VerticalCRS         .class));
+        assertEquals("crs",                 
NameMeaning.toObjectType(TemporalCRS         .class));
+        assertEquals("datum",               
NameMeaning.toObjectType(GeodeticDatum       .class));
+        assertEquals("datum",               
NameMeaning.toObjectType(VerticalDatum       .class));
+        assertEquals("datum",               
NameMeaning.toObjectType(TemporalDatum       .class));
+        assertEquals("ellipsoid",           NameMeaning.toObjectType(Ellipsoid 
          .class));
+        assertEquals("meridian",            
NameMeaning.toObjectType(PrimeMeridian       .class));
+        assertEquals("cs",                  
NameMeaning.toObjectType(EllipsoidalCS       .class));
+        assertEquals("cs",                  
NameMeaning.toObjectType(CartesianCS         .class));
+        assertEquals("axis",                
NameMeaning.toObjectType(CoordinateSystemAxis.class));
+        assertEquals("referenceSystem",     
NameMeaning.toObjectType(ReferenceSystem     .class));
+        assertEquals("coordinateOperation", 
NameMeaning.toObjectType(CoordinateOperation .class));
+        assertEquals("method",              
NameMeaning.toObjectType(OperationMethod     .class));
+        assertEquals("parameter",           
NameMeaning.toObjectType(ParameterDescriptor .class));
+        assertEquals("uom",                 NameMeaning.toObjectType(Unit      
          .class));
     }
 
     /**

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -170,7 +170,7 @@ public final class Code {
             Identifier fallback = null;
             for (final Identifier identifier : identifiers) {
                 final String code = identifier.getCode();
-                if (code == null) continue; // Paranoiac check.
+                if (code == null) continue;                                    
             // Paranoiac check.
                 if (code.regionMatches(true, 0, "urn:", 0, 4)) {
                     return new Code(identifier);
                 }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -68,6 +68,11 @@ public final class Resources extends Ind
         public static final short AmbiguousEllipsoid_1 = 1;
 
         /**
+         * Can not create objects of type ‘{0}’ from combined URI.
+         */
+        public static final short CanNotCombineUriAsType_1 = 79;
+
+        /**
          * Can not compute the coordinate operation derivative.
          */
         public static final short CanNotComputeDerivative = 2;
@@ -78,7 +83,7 @@ public final class Resources extends Ind
         public static final short CanNotConcatenateTransforms_2 = 3;
 
         /**
-         * Can not create an object of group “{1}” as an instance of class 
‘{0}’.
+         * Can not create an object of type “{1}” as an instance of class 
‘{0}’.
          */
         public static final short CanNotCreateObjectAsInstanceOf_2 = 4;
 
@@ -98,6 +103,11 @@ public final class Resources extends Ind
         public static final short CanNotMapAxisToDirection_1 = 6;
 
         /**
+         * Can not parse component {1} in the combined {0,choice,0#URN|1#URL}.
+         */
+        public static final short CanNotParseCombinedReference_2 = 78;
+
+        /**
          * Target dimension {0} depends on excluded source dimensions.
          */
         public static final short CanNotSeparateTargetDimension_1 = 7;
@@ -427,6 +437,11 @@ public final class Resources extends Ind
         public static final short SingularMatrix = 63;
 
         /**
+         * Combined URI contains unexpected components.
+         */
+        public static final short UnexpectedComponentInURI = 80;
+
+        /**
          * Unexpected dimension for a coordinate system of type ‘{0}’.
          */
         public static final short UnexpectedDimensionForCS_1 = 64;

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties
 [ISO-8859-1] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.properties
 [ISO-8859-1] Sat Oct 14 15:24:11 2017
@@ -42,12 +42,14 @@ NonConformCRS_3                   = The
 #
 # Error messages (to be used in exceptions)
 #
-CanNotConcatenateTransforms_2     = Can not concatenate transforms 
\u201c{0}\u201d and \u201c{1}\u201d.
+CanNotCombineUriAsType_1          = Can not create objects of type 
\u2018{0}\u2019 from combined URI.
 CanNotComputeDerivative           = Can not compute the coordinate operation 
derivative.
-CanNotCreateObjectAsInstanceOf_2  = Can not create an object of group 
\u201c{1}\u201d as an instance of class \u2018{0}\u2019.
+CanNotConcatenateTransforms_2     = Can not concatenate transforms 
\u201c{0}\u201d and \u201c{1}\u201d.
+CanNotCreateObjectAsInstanceOf_2  = Can not create an object of type 
\u201c{1}\u201d as an instance of class \u2018{0}\u2019.
 CanNotInferGridSizeFromValues_1   = Can not infer a grid size from the given 
values in {0} range.
 CanNotInstantiateGeodeticObject_1 = Can not instantiate geodetic object for 
\u201c{0}\u201d.
 CanNotMapAxisToDirection_1        = Can not map an axis from the specified 
coordinate system to the \u201c{0}\u201d direction.
+CanNotParseCombinedReference_2    = Can not parse component {1} in the 
combined {0,choice,0#URN|1#URL}.
 CanNotSeparateTargetDimension_1   = Target dimension {0} depends on excluded 
source dimensions.
 CanNotTransformEnvelopeToGeodetic = Can not transform envelope to a geodetic 
reference system.
 CanNotUseGeodeticParameters_2     = Can not use the {0} geodetic parameters: 
{1}
@@ -96,6 +98,7 @@ NoSuchOperationMethod_1           = No o
 ParameterNotFound_2               = No parameter named \u201c{1}\u201d has 
been found in \u201c{0}\u201d.
 RecursiveCreateCallForCode_2      = Recursive call while creating an object of 
type \u2018{0}\u2019 for code \u201c{1}\u201d.
 SingularMatrix                    = Matrix is singular.
+UnexpectedComponentInURI          = Combined URI contains unexpected 
components.
 UnexpectedDimensionForCS_1        = Unexpected dimension for a coordinate 
system of type \u2018{0}\u2019.
 UnitlessParameter_1               = Parameter \u201c{0}\u201d does not expect 
unit.
 UnknownAuthority_1                = Authority \u201c{0}\u201d is unknown.

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties
 [ISO-8859-1] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.properties
 [ISO-8859-1] Sat Oct 14 15:24:11 2017
@@ -47,13 +47,15 @@ NonConformCRS_3                   = La d
 #
 # Error messages (to be used in exceptions)
 #
-CanNotConcatenateTransforms_2     = Les transformations 
\u00ab\u202f{0}\u202f\u00bb et \u00ab\u202f{1}\u202f\u00bb ne peuvent pas 
\u00eatre combin\u00e9es.
+CanNotCombineUriAsType_1          = Ne peut pas cr\u00e9er d\u2019objets de 
type \u2018{0}\u2019 \u00e0 partir d\u2019un URI combin\u00e9.
 CanNotComputeDerivative           = La d\u00e9riv\u00e9 de 
l\u2019op\u00e9ration sur les coordonn\u00e9es ne peut pas \u00eatre 
calcul\u00e9e.
-CanNotCreateObjectAsInstanceOf_2  = Ne peut pas cr\u00e9er un objet du groupe 
\u00ab\u202f{1}\u202f\u00bb comme une instance de la classe \u2018{0}\u2019.
+CanNotConcatenateTransforms_2     = Les transformations 
\u00ab\u202f{0}\u202f\u00bb et \u00ab\u202f{1}\u202f\u00bb ne peuvent pas 
\u00eatre combin\u00e9es.
+CanNotCreateObjectAsInstanceOf_2  = Ne peut pas cr\u00e9er un objet du type 
\u00ab\u202f{1}\u202f\u00bb comme une instance de la classe \u2018{0}\u2019.
 CanNotInferGridSizeFromValues_1   = Ne peut pas inf\u00e9rer une taille de 
grille \u00e0 partir des valeurs donn\u00e9es dans la plage {0}.
 CanNotInstantiateGeodeticObject_1 = Ne peut pas cr\u00e9er l\u2019objet 
g\u00e9od\u00e9tique pour \u00ab\u202f{0}\u202f\u00bb.
 CanNotMapAxisToDirection_1        = Aucun axe du syst\u00e8me de 
coordonn\u00e9es sp\u00e9cifi\u00e9 n\u2019a pu \u00eatre associ\u00e9 \u00e0 
la direction \u00ab\u202f{0}\u202f\u00bb.
 CanNotSeparateTargetDimension_1   = La dimension de destination {0} 
d\u00e9pend de dimensions sources qui ont \u00e9t\u00e9 exclues.
+CanNotParseCombinedReference_2    = Ne peut pas d\u00e9coder la composante {1} 
dans l\u2019{0,choice,0#URN|1#URL} combin\u00e9.
 CanNotTransformEnvelopeToGeodetic = Ne peut pas transformer l\u2019enveloppe 
vers un r\u00e9f\u00e9rentiel g\u00e9od\u00e9sique.
 CanNotUseGeodeticParameters_2     = Ne peut pas utiliser les param\u00e8tres 
g\u00e9od\u00e9siques {0}\u202f: {1}
 ColinearAxisDirections_2          = Les directions d\u2019axes {0} et {1} sont 
colin\u00e9aires.
@@ -101,6 +103,7 @@ NoSuchOperationMethod_1           = Aucu
 ParameterNotFound_2               = Aucun param\u00e8tre nomm\u00e9 
\u00ab\u202f{1}\u202f\u00bb n\u2019a \u00e9t\u00e9 trouv\u00e9 dans 
\u00ab\u202f{0}\u202f\u00bb.
 RecursiveCreateCallForCode_2      = Appels r\u00e9cursifs lors de la 
cr\u00e9ation d\u2019un objet de type \u2018{0}\u2019 pour le code 
\u00ab\u202f{1}\u202f\u00bb.
 SingularMatrix                    = La matrice est singuli\u00e8re.
+UnexpectedComponentInURI          = L\u2019URI combin\u00e9 contient des 
composantes qui n\u2019\u00e9taient pas attendues.
 UnexpectedDimensionForCS_1        = Dimension inattendue pour un syst\u00e8me 
de coordonn\u00e9es de type \u2018{0}\u2019.
 UnitlessParameter_1               = Le param\u00e8tre 
\u00ab\u202f{0}\u202f\u00bb n\u2019attend pas d\u2019unit\u00e9.
 UnknownAuthority_1                = L\u2019autorit\u00e9 
\u00ab\u202f{0}\u202f\u00bb n\u2019est pas reconnue.

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/AuthorityFactoryProxy.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -569,8 +569,9 @@ abstract class AuthorityFactoryProxy<T>
      */
     private static final Map<String, AuthorityFactoryProxy<?>> BY_URN_TYPE;
     static {
-        final Map<String, AuthorityFactoryProxy<?>> map = new HashMap<>(14);
+        final Map<String, AuthorityFactoryProxy<?>> map = new HashMap<>(16);
         map.put("crs",                  CRS);
+        map.put("crs-compound",         CRS);
         map.put("datum",                DATUM);
         map.put("ellipsoid",            ELLIPSOID);
         map.put("meridian",             PRIME_MERIDIAN);
@@ -610,7 +611,7 @@ abstract class AuthorityFactoryProxy<T>
      * The proxy to use for a given type declared in a URN.
      * For example in the {@code "urn:ogc:def:crs:EPSG::4326"} URN, the proxy 
to use is {@link #CRS}.
      *
-     * @param  typeName  the URN type.
+     * @param  typeName  the name of URN type.
      * @return the proxy for the given type, or {@code null} if the given type 
is illegal.
      */
     @SuppressWarnings("unchecked")

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactory.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -20,6 +20,7 @@ import java.util.ServiceLoader;
 import java.util.Collections;
 import java.util.Collection;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.Set;
 import java.util.Map;
@@ -49,9 +50,13 @@ import org.apache.sis.internal.util.Abst
 import org.apache.sis.internal.util.DefinitionURI;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.util.SetOfUnknownSize;
+import org.apache.sis.internal.metadata.NameMeaning;
 import org.apache.sis.internal.referencing.LazySet;
 import org.apache.sis.internal.referencing.Resources;
+import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ArgumentChecks;
@@ -117,7 +122,7 @@ import org.apache.sis.util.collection.Ba
  * do not need to be thread-safe. See constructor Javadoc for more information.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 0.8
  *
  * @see org.apache.sis.referencing.CRS#getAuthorityFactory(String)
  *
@@ -727,21 +732,47 @@ public class MultiAuthoritiesFactory ext
      * @return the object from one of the authority factory specified at 
construction time.
      * @throws FactoryException if an error occurred while creating the object.
      */
-    final <T> T create(AuthorityFactoryProxy<? extends T> proxy, String code) 
throws FactoryException {
+    private <T> T create(AuthorityFactoryProxy<? extends T> proxy, String 
code) throws FactoryException {
         ArgumentChecks.ensureNonNull("code", code);
         final String authority, version;
         final String[] parameters;
         final DefinitionURI uri = DefinitionURI.parse(code);
         if (uri != null) {
+            Class<? extends T> type = proxy.type;
+            proxy = proxy.specialize(uri.type);
+            /*
+             * If the URN or URL contains combined references for compound 
coordinate reference systems,
+             * create the components. First we verify that all component 
references have been parsed
+             * before to start creating any object.
+             */
+            if (uri.code == null) {
+                final DefinitionURI[] components = uri.components;
+                if (components != null) {
+                    for (int i=0; i < components.length; i++) {
+                        if (components[i] == null) {
+                            throw new 
NoSuchAuthorityCodeException(Resources.format(
+                                    
Resources.Keys.CanNotParseCombinedReference_2, i+1, uri.isHTTP ? 1 : 0),
+                                    uri.authority, null, uri.toString());
+                        }
+                    }
+                    if (proxy != null) type = proxy.type;       // Use the 
more specific type declared in the URN.
+                    return combine(type, components, uri.isHTTP);
+                }
+            }
+            /*
+             * At this point we determined that the URN or URL references a 
single instance (not combined references).
+             * Example: "urn:ogc:def:crs:EPSG:9.1:4326". Verifies that the 
object type is recognized and that a code
+             * is present. The remainder steps are the same as if the user 
gave a simple code (e.g. "EPSG:4326").
+             */
             if (uri.authority == null) {
-                throw new 
NoSuchAuthorityCodeException(Resources.format(Resources.Keys.MissingAuthority_1,
 code), null, uri.code, code);
+                // We want this check before the 'code' value is modified 
below.
+                throw new NoSuchAuthorityCodeException(
+                        Resources.format(Resources.Keys.MissingAuthority_1, 
code), null, uri.code, code);
             }
-            final Class<? extends T> type = proxy.type;
             authority  = uri.authority;
             version    = uri.version;
             code       = uri.code;
             parameters = uri.parameters;
-            proxy      = proxy.specialize(uri.type);
             if (code == null || proxy == null) {
                 final String s = uri.toString();
                 final String message;
@@ -1486,6 +1517,195 @@ public class MultiAuthoritiesFactory ext
     }
 
     /**
+     * Invoked when a {@code createFoo(…)} method is given a combined URI.
+     * A combined URI is a URN or URL referencing other components. For 
example if the given URI
+     * is {@code "urn:ogc:def:crs, crs:EPSG::27700, crs:EPSG::5701"}, then the 
components are:
+     * <ol>
+     *   <li>{@code "urn:ogc:def:crs:EPSG:9.1:27700"}</li>
+     *   <li>{@code "urn:ogc:def:crs:EPSG:9.1:5701"}</li>
+     * </ol>
+     *
+     * We do not require the components to be instance of CRS, since the 
"Definition identifier URNs in
+     * OGC namespace" best practice paper allows other kinds of combination 
(e.g. of coordinate operations).
+     *
+     * @param  <T>         compile-time value of {@code type} argument.
+     * @param  type        type of object to create.
+     * @param  references  parsed URI of the components.
+     * @param  isHTTP      whether the user URI is an URL (i.e. {@code 
"http://something"}) instead than a URN.
+     * @return the combined object.
+     * @throws FactoryException if an error occurred while creating the 
combined object.
+     */
+    private <T> T combine(final Class<T> type, final DefinitionURI[] 
references, final boolean isHTTP) throws FactoryException {
+        /*
+         * Identify the type requested by the user and create all components 
with the assumption that they will
+         * be of that type. This is the most common case. If during iteration 
we find an object of another kind,
+         * then the array type will be downgraded to IdentifiedObject[]. The 
'componentType' variable will keep
+         * its non-null value only if the array stay of the expected sub-type.
+         */
+        final byte requestedType;
+        IdentifiedObject[] components;
+        Class<? extends IdentifiedObject> componentType;
+        if (CoordinateReferenceSystem.class.isAssignableFrom(type)) {
+            requestedType = AuthorityFactoryIdentifier.CRS;
+            componentType = CoordinateReferenceSystem.class;
+            components    = new CoordinateReferenceSystem[references.length];  
     // Intentional covariance.
+        } else if (CoordinateOperation.class.isAssignableFrom(type)) {
+            requestedType = AuthorityFactoryIdentifier.OPERATION;
+            componentType = CoordinateOperation.class;
+            components    = new CoordinateOperation[references.length];        
     // Intentional covariance.
+        } else {
+            throw new 
FactoryException(Resources.format(Resources.Keys.CanNotCombineUriAsType_1, 
type));
+        }
+        final String expected = NameMeaning.toObjectType(componentType);    // 
Note: "compound-crs" ⟶ "crs".
+        for (int i=0; i<references.length; i++) {
+            final DefinitionURI ref = references[i];
+            final IdentifiedObject component = createObject(ref.toString());
+            if (componentType != null && (!componentType.isInstance(component) 
|| !expected.equalsIgnoreCase(ref.type))) {
+                componentType = null;
+                components = Arrays.copyOf(components, components.length, 
IdentifiedObject[].class);
+            }
+            components[i] = component;
+        }
+        /*
+         * At this point we have successfully created all components. The way 
to interpret those components
+         * depends mostly on the type of object requested by the user. For a 
given requested type, different
+         * rules apply depending on the type of components. Those rules are 
described in OGC 07-092r1 (2007):
+         * "Definition identifier URNs in OGC namespace".
+         */
+        IdentifiedObject combined = null;
+        switch (requestedType) {
+            case AuthorityFactoryIdentifier.OPERATION: {
+                if (componentType != null) {
+                    /*
+                     * URN combined references for concatenated operations. We 
build an operation name from
+                     * the operation identifiers (rather than CRS identifiers) 
because this is what the user
+                     * gave to us, and because source/target CRS are not 
guaranteed to be defined. We do not
+                     * yet support swapping roles of source and target CRS if 
an implied-reverse coordinate
+                     * operation is included.
+                     */
+                    final CoordinateOperation[] ops = (CoordinateOperation[]) 
components;
+                    String name = 
IdentifiedObjects.getIdentifierOrName(ops[0]) + " ⟶ "
+                                + 
IdentifiedObjects.getIdentifierOrName(ops[ops.length - 1]);
+                    combined = 
DefaultFactories.forBuildin(CoordinateOperationFactory.class)
+                            
.createConcatenatedOperation(Collections.singletonMap(CoordinateOperation.NAME_KEY,
 name), ops);
+                }
+                break;
+            }
+            case AuthorityFactoryIdentifier.CRS: {
+                if (componentType != null) {
+                    /*
+                     * URN combined references for compound coordinate 
reference systems.
+                     * The URNs of the individual well-known CRSs are listed 
in the same order in which the
+                     * individual coordinate tuples are combined to form the 
CompoundCRS coordinate tuple.
+                     */
+                    combined = CRS.compound((CoordinateReferenceSystem[]) 
components);
+                } else if (!isHTTP) {
+                    final CoordinateSystem cs = remove(references, components, 
CoordinateSystem.class);
+                    if (cs != null) {
+                        final Datum datum = remove(references, components, 
Datum.class);
+                        if (datum != null) {
+                            /*
+                             * URN combined references for datum and 
coordinate system. In this case, the URN shall
+                             * concatenate the URNs of one well-known datum 
and one well-known coordinate system.
+                             */
+                            if (ArraysExt.allEquals(references, null)) {
+                                combined = combine((GeodeticDatum) datum, cs);
+                            }
+                        } else {
+                            /*
+                             * URN combined references for projected or 
derived CRSs. In this case, the URN shall
+                             * concatenate the URNs of the one well-known CRS, 
one well-known Conversion, and one
+                             * well-known CartesianCS. Similar action can be 
taken for derived CRS.
+                             */
+                            CoordinateReferenceSystem baseCRS = 
remove(references, components, CoordinateReferenceSystem.class);
+                            CoordinateOperation op = remove(references, 
components, CoordinateOperation.class);
+                            if (ArraysExt.allEquals(references, null) && op 
instanceof Conversion) {
+                                combined = combine(baseCRS, (Conversion) op, 
cs);
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+        }
+        /*
+         * At this point the combined object has been created if we know how 
to create it.
+         * Maybe the result matches the definition of an existing object in 
the database,
+         * in which case we will use the existing definition for better 
metadata.
+         */
+        if (combined == null) {
+            throw new 
FactoryException(Resources.format(Resources.Keys.UnexpectedComponentInURI));
+        }
+        final IdentifiedObject existing = 
newIdentifiedObjectFinder().findSingleton(combined);
+        return type.cast(existing != null ? existing : combined);
+    }
+
+    /**
+     * If the given {@code type} is found in the given {@code references}, 
sets that reference element to {@code null}
+     * and returns the corresponding {@code components} element. Otherwise 
returns {@code null}. This is equivalent to
+     * {@link Map#remove(Object, Object)} where {@code references} are the 
keys and {@code components} are the values.
+     * We do not bother building that map because the arrays are very short (2 
or 3 elements).
+     */
+    private static <T> T remove(final DefinitionURI[] references, final 
IdentifiedObject[] components, final Class<T> type) {
+        final String expected = NameMeaning.toObjectType(type);
+        for (int i=0; i<references.length; i++) {
+            final DefinitionURI ref = references[i];
+            if (ref != null && expected.equalsIgnoreCase(ref.type)) {
+                references[i] = null;
+                return type.cast(components[i]);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Invoked when a {@code createFoo(…)} method is given a combined URI 
containing a datum and a coordinate system.
+     * If the given information are not sufficient or not applicable, then 
this method returns {@code null}.
+     *
+     * @param  datum  the datum, or {@code null} if missing.
+     * @param  cs     the coordinate system (never null).
+     * @return the combined CRS, or {@code null} if the given information are 
not sufficient.
+     * @throws FactoryException if an error occurred while creating the 
combined CRS.
+     */
+    private static GeodeticCRS combine(final GeodeticDatum datum, final 
CoordinateSystem cs) throws FactoryException {
+        final Map<String,?> properties = 
IdentifiedObjects.getProperties(datum, Datum.IDENTIFIERS_KEY);
+        final CRSFactory factory = 
DefaultFactories.forBuildin(CRSFactory.class);
+        if (datum instanceof GeodeticDatum) {
+            if (cs instanceof EllipsoidalCS) {
+                return factory.createGeographicCRS(properties, datum, 
(EllipsoidalCS) cs);
+            } else if (cs instanceof SphericalCS) {
+                return factory.createGeocentricCRS(properties, datum, 
(SphericalCS) cs);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Invoked when a {@code createFoo(…)} method is given a combined URI 
containing a conversion and a coordinate
+     * system. If the given information are not sufficient or not applicable, 
then this method returns {@code null}.
+     *
+     * @param  baseCRS   the CRS on which the derived CRS will be based on, or 
{@code null} if missing.
+     * @param  fromBase  the conversion from {@code baseCRS} to the CRS to be 
created by this method.
+     * @param  cs        the coordinate system (never null).
+     * @return the combined CRS, or {@code null} if the given information are 
not sufficient.
+     * @throws FactoryException if an error occurred while creating the 
combined CRS.
+     */
+    private static GeneralDerivedCRS combine(final CoordinateReferenceSystem 
baseCRS, final Conversion fromBase,
+            final CoordinateSystem cs) throws FactoryException
+    {
+        if (baseCRS != null && fromBase.getSourceCRS() == null && 
fromBase.getTargetCRS() == null) {
+            final Map<String,?> properties = 
IdentifiedObjects.getProperties(fromBase, Datum.IDENTIFIERS_KEY);
+            final CRSFactory factory = 
DefaultFactories.forBuildin(CRSFactory.class);
+            if (baseCRS instanceof GeographicCRS && cs instanceof CartesianCS) 
{
+                return factory.createProjectedCRS(properties, (GeographicCRS) 
baseCRS, fromBase, (CartesianCS) cs);
+            } else {
+                return factory.createDerivedCRS(properties, baseCRS, fromBase, 
cs);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Creates a finder which can be used for looking up unidentified objects.
      * The default implementation delegates the lookups to the underlying 
factories.
      *

Modified: 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -122,10 +122,10 @@ final class CRSPair {
     }
 
     /**
-     * Return a string representation of this key.
+     * Returns a string representation of this key.
      */
     @Override
     public String toString() {
-        return label(sourceCRS) + " → " + label(targetCRS);
+        return label(sourceCRS) + " ⟶ " + label(targetCRS);
     }
 }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryMock.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryMock.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryMock.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/AuthorityFactoryMock.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -27,6 +27,7 @@ import org.opengis.referencing.crs.CRSAu
 import org.opengis.referencing.crs.GeocentricCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.VerticalCRS;
+import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.cs.CSAuthorityFactory;
 import org.opengis.referencing.datum.DatumAuthorityFactory;
 import org.opengis.referencing.datum.GeodeticDatum;
@@ -40,6 +41,7 @@ import org.apache.sis.measure.Units;
 import org.apache.sis.metadata.iso.extent.Extents;
 import org.apache.sis.referencing.datum.HardCodedDatum;
 import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.referencing.cs.HardCodedCS;
 
 import static org.junit.Assert.*;
 
@@ -48,7 +50,7 @@ import static org.junit.Assert.*;
  * A pseudo-authority factory with hard-coded objects.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 0.8
  * @since   0.7
  * @module
  */
@@ -114,6 +116,7 @@ public final strictfp class AuthorityFac
         if (type.isAssignableFrom(GeodeticDatum.class)) add(codes, 6326, 6322, 
6807, 6301, 6612, 6047);
         if (type.isAssignableFrom(VerticalDatum.class)) add(codes, 5100);
         if (type.isAssignableFrom(VerticalCRS.class))   add(codes, 5714, 9905);
+        if (type.isAssignableFrom(EllipsoidalCS.class)) add(codes, 6422, 6424);
         return codes;
     }
 
@@ -147,6 +150,8 @@ public final strictfp class AuthorityFac
             case 6612: return HardCodedDatum.JGD2000;
             case 6047: return HardCodedDatum.SPHERE;
             case 5100: return HardCodedDatum.MEAN_SEA_LEVEL;
+            case 6422: return HardCodedCS.GEODETIC_φλ;
+            case 6424: return HardCodedCS.GEODETIC_2D;
             default: throw new NoSuchAuthorityCodeException(code, 
authority.getTitle().toString(), code);
         }
     }

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactoryTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactoryTest.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactoryTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/MultiAuthoritiesFactoryTest.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -28,6 +28,8 @@ import org.opengis.referencing.crs.Geoce
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.VerticalCRS;
+import org.opengis.referencing.crs.CompoundCRS;
+import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.datum.DatumAuthorityFactory;
 import org.opengis.referencing.datum.GeodeticDatum;
@@ -36,6 +38,7 @@ import org.opengis.referencing.datum.Ver
 import org.opengis.util.FactoryException;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.metadata.iso.extent.Extents;
+import org.apache.sis.referencing.cs.HardCodedCS;
 import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.referencing.datum.HardCodedDatum;
 import org.apache.sis.measure.Units;
@@ -274,6 +277,89 @@ public final strictfp class MultiAuthori
     }
 
     /**
+     * Tests {@code MultiAuthoritiesFactory.createFoo(String)} from codes in 
the
+     * {@code "urn:ogc:def:type, type₁:authority₁:version₁:code₁, 
type₂:authority₂:version₂:code₂"} form.
+     *
+     * @throws FactoryException if an authority or a code is not recognized.
+     *
+     * @since 0.8
+     */
+    @Test
+    @DependsOnMethod("testCreateFromURNs")
+    public void testCreateFromCombinedURNs() throws FactoryException {
+        final Set<AuthorityFactoryMock> mock = Collections.singleton(new 
AuthorityFactoryMock("MOCK", "2.3"));
+        final MultiAuthoritiesFactory factory = new 
MultiAuthoritiesFactory(mock, mock, mock, null);
+        testCreateFromCombinedURIs(factory, "urn:ogc:def:crs, crs:MOCK::4326, 
crs:MOCK::5714");
+        /*
+         * Following are more unusual combinations described in OGC 07-092r1 
(2007)
+         * "Definition identifier URNs in OGC namespace".
+         */
+        SingleCRS crs = factory.createGeographicCRS("urn:ogc:def:crs, 
datum:MOCK::6326, cs:MOCK::6424");
+        assertSame("datum", HardCodedDatum.WGS84, crs.getDatum());
+        assertSame("cs", HardCodedCS.GEODETIC_2D, crs.getCoordinateSystem());
+        /*
+         * Verify that invalid combined URIs are rejected.
+         */
+        try {
+            factory.createObject("urn:ogc:def:cs, crs:MOCK::4326, 
crs:MOCK::5714");
+            fail("Shall not accept to create CoordinateSystem from combined 
URI.");
+        } catch (FactoryException e) {
+            String message = e.getMessage();
+            assertTrue(message, message.contains("CoordinateSystem"));
+        }
+        try {
+            factory.createObject("urn:ogc:def:crs, datum:MOCK::6326, 
cs:MOCK::6424, cs:MOCK::6422");
+            fail("Shall not accept to create combined URI with unexpected 
objects.");
+        } catch (FactoryException e) {
+            assertNotNull(e.getMessage());
+        }
+    }
+
+    /**
+     * Tests {@code MultiAuthoritiesFactory.createFoo(String)} from codes in 
the
+     * {@code 
"http://www.opengis.net/def/crs-compound?1=(…)/code₁&2=(…)/code₂"} form.
+     *
+     * @throws FactoryException if an authority or a code is not recognized.
+     *
+     * @since 0.8
+     */
+    @Test
+    @DependsOnMethod("testCreateFromHTTPs")
+    public void testCreateFromCombinedHTTPs() throws FactoryException {
+        final Set<AuthorityFactoryMock> mock = Collections.singleton(new 
AuthorityFactoryMock("MOCK", "2.3"));
+        final MultiAuthoritiesFactory factory = new 
MultiAuthoritiesFactory(mock, mock, mock, null);
+        testCreateFromCombinedURIs(factory, 
"http://www.opengis.net/def/crs-compound?";
+                                        + 
"1=http://www.opengis.net/def/crs/MOCK/0/4326&";
+                                        + 
"2=http://www.opengis.net/def/crs/MOCK/0/5714";);
+        testCreateFromCombinedURIs(factory, 
"http://www.opengis.net/def/crs-compound?";
+                                        + 
"2=http://www.opengis.net/def/crs/MOCK/0/5714&";
+                                        + 
"1=http://www.opengis.net/def/crs/MOCK/0/4326";);
+        /*
+         * Contrarily to URN, the HTTP form shall not accept Datum + 
CoordinateSystem combination.
+         */
+        try {
+            factory.createObject("http://www.opengis.net/def/crs-compound?";
+                             + 
"1=http://www.opengis.net/def/datum/MOCK/0/6326&";
+                             + "2=http://www.opengis.net/def/cs/MOCK/0/6424";);
+            fail("Shall not accept Datum + CoordinateSystem combination.");
+        } catch (FactoryException e) {
+            assertNotNull(e.getMessage());
+        }
+    }
+
+    /**
+     * Implementation of {@link #testCreateFromCombinedURNs()} and {@link 
#testCreateFromCombinedHTTPs()}.
+     */
+    private static void testCreateFromCombinedURIs(final 
MultiAuthoritiesFactory factory, final String heightOnWGS84)
+            throws FactoryException
+    {
+        CompoundCRS crs = factory.createCompoundCRS(heightOnWGS84);
+        assertArrayEquals("WGS 84 + MSL height", new SingleCRS[] {
+            HardCodedCRS.WGS84_φλ, HardCodedCRS.GRAVITY_RELATED_HEIGHT
+        }, crs.getComponents().toArray());
+    }
+
+    /**
      * Tests {@link MultiAuthoritiesFactory#getAuthorityCodes(Class)}.
      *
      * @throws FactoryException if an error occurred while fetching the set of 
codes.

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -864,7 +864,7 @@ public final strictfp class CoordinateOp
         assertSame      ("sourceCRS", sourceCRS, operation.getSourceCRS());
         assertSame      ("targetCRS", targetCRS, operation.getTargetCRS());
         assertInstanceOf("operation", ConcatenatedOperation.class, operation);
-        assertEquals    ("name", "CompoundCRS[“Test3D”] → 
CompoundCRS[“Test4D”]", operation.getName().getCode());
+        assertEquals    ("name", "CompoundCRS[“Test3D”] ⟶ 
CompoundCRS[“Test4D”]", operation.getName().getCode());
 
         transform = operation.getMathTransform();
         assertInstanceOf("transform", LinearTransform.class, transform);

Added: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java?rev=1812190&view=auto
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
 (added)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.test.integration;
+
+import org.opengis.util.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.test.DependsOn;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Advances CRS constructions requiring the EPSG geodetic dataset.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 0.8
+ * @since   0.8
+ * @module
+ */
+@DependsOn({
+    org.apache.sis.referencing.CRSTest.class,
+    org.apache.sis.referencing.CommonCRSTest.class,
+    org.apache.sis.referencing.factory.sql.EPSGFactoryTest.class,
+    org.apache.sis.referencing.factory.MultiAuthoritiesFactoryTest.class
+})
+public final strictfp class CoordinateReferenceSystemTest extends TestCase {
+    /**
+     * Tests creation from codes in the
+     * {@code "urn:ogc:def:type, type₁:authority₁:version₁:code₁, 
type₂:authority₂:version₂:code₂"} form.
+     *
+     * @throws FactoryException if an authority or a code is not recognized.
+     */
+    @Test
+    @org.junit.Ignore("Pending a mechanism for detecting if EPSG dataset is 
present.")
+    public void testCreateFromCombinedURN() throws FactoryException {
+        CoordinateReferenceSystem crs = CRS.forCode("urn:ogc:def:crs, 
crs:EPSG::27700, crs:EPSG::5701");
+        assertSame("OSGB 1936 / British National Grid + ODN height", 
CRS.forCode("EPSG:7405"), crs);
+    }
+}

Propchange: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -249,6 +249,7 @@ import org.junit.BeforeClass;
 
     org.apache.sis.distance.LatLonPointRadiusTest.class,        // Pending 
refactoring in a geometry package.
 
+    org.apache.sis.test.integration.CoordinateReferenceSystemTest.class,
     org.apache.sis.test.integration.CoordinateOperationTest.class,
     org.apache.sis.test.integration.DatumShiftTest.class,
     org.apache.sis.test.integration.MetadataTest.class,

Modified: 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ArraysExt.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ArraysExt.java?rev=1812190&r1=1812189&r2=1812190&view=diff
==============================================================================
--- 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ArraysExt.java
 [UTF-8] (original)
+++ 
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/ArraysExt.java
 [UTF-8] Sat Oct 14 15:24:11 2017
@@ -67,7 +67,7 @@ import java.lang.reflect.Array;
  * objects.
  *
  * @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.4
+ * @version 0.8
  *
  * @see Arrays
  *
@@ -1684,6 +1684,33 @@ public final class ArraysExt extends Sta
     }
 
     /**
+     * Returns {@code true} if all values in the specified array are equal to 
the specified value,
+     * which may be {@code null}.
+     *
+     * @param  array  the array to check.
+     * @param  value  the expected value.
+     * @return {@code true} if all elements in the given array are equal to 
the given value.
+     *
+     * @since 0.8
+     */
+    public static boolean allEquals(final Object[] array, final Object value) {
+        if (value == null) {
+            for (int i=0; i<array.length; i++) {
+                if (array[i] != null) {
+                    return false;
+                }
+            }
+        } else {
+            for (int i=0; i<array.length; i++) {
+                if (!value.equals(array[i])) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
      * Returns {@code true} if all values in the specified array are equal to 
the specified value,
      * which may be {@link Double#NaN}.
      *


Reply via email to