sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1789729 [5/9] - in /sis/branches/JDK9: ./ application/sis-console/ application/sis-console/src/main/java/org/apache/sis/console/ application/sis-console/src/test/java/org/apache/sis/console/ core/ core/sis-feature/src/main/java/org/apache/...
Date Fri, 31 Mar 2017 18:49:18 GMT
Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -127,7 +127,7 @@ import static org.apache.sis.util.Argume
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
- * @version 0.7
+ * @version 0.8
  * @module
  *
  * @see org.apache.sis.referencing.operation.projection.NormalizedProjection
@@ -501,24 +501,33 @@ public class ContextualParameters extend
      *
      * @see org.apache.sis.referencing.operation.projection.NormalizedProjection#createMapProjection(MathTransformFactory)
      */
-    public synchronized MathTransform completeTransform(final MathTransformFactory factory, final MathTransform kernel)
+    public MathTransform completeTransform(final MathTransformFactory factory, final MathTransform kernel)
             throws FactoryException
     {
-        if (!isFrozen) {
-            freeze();
+        final MathTransform n, d;
+        synchronized (this) {
+            if (!isFrozen) {
+                freeze();
+            }
+            /*
+             * Creates the ConcatenatedTransform, letting the factory returns the cached instance
+             * if the caller already invoked this method previously (which usually do not happen).
+             */
+            n = factory.createAffineTransform(normalize);
+            d = factory.createAffineTransform(denormalize);
+            Matrix m;
+            if ((m = MathTransforms.getMatrix(n)) != null)   normalize = m;
+            if ((m = MathTransforms.getMatrix(d)) != null) denormalize = m;
         }
-        /*
-         * Creates the ConcatenatedTransform, letting the factory returns the cached instance
-         * if the caller already invoked this method previously (which usually do not happen).
-         */
-        final MathTransform n = factory.createAffineTransform(normalize);
-        final MathTransform d = factory.createAffineTransform(denormalize);
-        Matrix m;
-        if ((m = MathTransforms.getMatrix(n)) != null)   normalize = m;
-        if ((m = MathTransforms.getMatrix(d)) != null) denormalize = m;
         if (kernel == null) {   // Undocumented feature useful for MolodenskyTransform constructor.
             return null;
         }
+        /*
+         * Following call must be outside the synchronized block for avoiding dead-lock. This is because the
+         * factory typically contains a WeakHashSet, which invoke in turn the 'equals' methods in this class
+         * (indirectly, through 'kernel' comparison). We need to be outside the synchronized block for having
+         * the locks taken in same order (WeakHashSet lock before the ContextualParameters lock).
+         */
         return factory.createConcatenatedTransform(factory.createConcatenatedTransform(n, kernel), d);
     }
 

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/InterpolatedTransform.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -59,7 +59,7 @@ import org.apache.sis.internal.referenci
  * If the grid indices are non-integer values, then the translations are interpolated using a bilinear interpolation.
  * If the grid indices are outside the grid domain ([0 … <var>width</var>-2] × [0 … <var>height</var>-2]
  * where <var>width</var> and <var>height</var> are the number of columns and rows in the grid),
- * then the translations are extrapolated. The translation is then added to the input coordinates.</p>
+ * then the translations are extrapolated. The translation is finally added to the input coordinates.</p>
  *
  * <p>The input and output coordinates can have any number of dimensions, provided that they are the same
  * than the number of {@linkplain DatumShiftGrid#getTranslationDimensions() translation dimensions}.
@@ -72,6 +72,9 @@ import org.apache.sis.internal.referenci
  * @since   0.7
  * @version 0.8
  * @module
+ *
+ * @see DatumShiftGrid
+ * @see org.apache.sis.referencing.operation.builder.LocalizationGridBuilder
  */
 public class InterpolatedTransform extends DatumShiftTransform {
     /**
@@ -148,7 +151,7 @@ public class InterpolatedTransform exten
             ((DatumShiftGridFile<?,?>) grid).setFileParameters(context);
         }
         /*
-         * Set the normalization matrix to the conversion from grid coordinates (e.g. seconds of angle)
+         * Set the normalization matrix to the conversion from source coordinates (e.g. seconds of angle)
          * to grid indices. This will allow us to invoke DatumShiftGrid.interpolateAtCell(x, y, vector)
          * directly in the transform(…) methods.
          */
@@ -177,9 +180,20 @@ public class InterpolatedTransform exten
             }
         }
         /*
-         * Denormalization is the inverse of all above conversions.
+         * Denormalization is the inverse of all above conversions in the usual case (NADCON and NTv2) where the
+         * source coordinate system is the same than the target coordinate system, for example with axis unit in
+         * degrees. However we also use this InterpolatedTransform implementation for other operation, like the
+         * one created by LocalizationGridBuilder. Those later operations may require a different denormalization
+         * matrix.
          */
-        context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION).setMatrix(normalize.inverse());
+        Matrix denormalize = null;
+        if (grid instanceof DatumShiftGridFile<?,?>) {
+            denormalize = ((DatumShiftGridFile<?,?>) grid).gridToTarget();
+        }
+        if (denormalize == null) {
+            denormalize = normalize.inverse();                      // Normal NACDON and NTv2 case.
+        }
+        context.getMatrix(ContextualParameters.MatrixRole.DENORMALIZATION).setMatrix(denormalize);
         inverse = createInverse();
     }
 

Modified: sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/package-info.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/package-info.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/java/org/apache/sis/referencing/package-info.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -23,7 +23,13 @@
  * <p>The most commonly used kinds of Reference Systems in Apache SIS are the <cite>Coordinate Reference Systems</cite>
  * (CRS), which handle coordinates of arbitrary dimensions. The SIS implementations can handle 2D and 3D coordinates,
  * as well as 4D, 5D, <i>etc</i>. An other less-frequently used kind of Reference System uses labels instead, as in
- * postal address. This package is the root for both kinds, with an emphasis on the one for coordinates.</p>
+ * postal address. This package is the root for both kinds, with an emphasis on the one for coordinates.
+ * The two kinds of referencing system are implemented in the following packages:</p>
+ * <ul>
+ *   <li>{@link org.apache.sis.referencing.crs} for <cite>referencing by coordinates</cite> (ISO 19111)</li>
+ *   <li>{@link org.apache.sis.referencing.gazetteer} for <cite>referencing by geographic identifiers</cite>
+ *       (ISO 19112), together with the linking from geographic identifiers to coordinates.</li>
+ * </ul>
  *
  * <div class="section">Fetching geodetic object instances</div>
  * Geodetic objects can be instantiated either

Modified: sis/branches/JDK9/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod [UTF-8] Fri Mar 31 18:49:16 2017
@@ -43,6 +43,7 @@ org.apache.sis.internal.referencing.prov
 org.apache.sis.internal.referencing.provider.PolarStereographicNorth
 org.apache.sis.internal.referencing.provider.PolarStereographicSouth
 org.apache.sis.internal.referencing.provider.ObliqueStereographic
+org.apache.sis.internal.referencing.provider.ZonedTransverseMercator
 org.apache.sis.internal.referencing.provider.NTv2
 org.apache.sis.internal.referencing.provider.NADCON
 org.apache.sis.internal.referencing.provider.FranceGeocentricInterpolation

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/geometry/TransformTestCase.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -90,7 +90,7 @@ public abstract strictfp class Transform
      */
     @Test
     public final void testTransform() throws FactoryException, TransformException {
-        final ProjectedCRS    targetCRS  = CommonCRS.WGS84.UTM(10, -123.5);
+        final ProjectedCRS    targetCRS  = CommonCRS.WGS84.universal(10, -123.5);
         final GeographicCRS   sourceCRS  = targetCRS.getBaseCRS();
         final Conversion      conversion = targetCRS.getConversionFromBase();
         final MathTransform2D transform  = (MathTransform2D) conversion.getMathTransform();
@@ -199,7 +199,7 @@ public abstract strictfp class Transform
     @Test
     @DependsOnMethod("testTransform")
     public final void testTransformNotOverPole() throws FactoryException, TransformException {
-        final ProjectedCRS  sourceCRS  = CommonCRS.WGS84.UTM(10, -3.5);
+        final ProjectedCRS  sourceCRS  = CommonCRS.WGS84.universal(10, -3.5);
         final GeographicCRS targetCRS  = sourceCRS.getBaseCRS();
         final Conversion    conversion = inverse(sourceCRS.getConversionFromBase());
         final G rectangle = createFromExtremums(sourceCRS, 199980, 4490220, 309780, 4600020);

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/ServicesForMetadataTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -50,7 +50,7 @@ import static org.apache.sis.test.TestUt
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.7
+ * @version 0.8
  * @module
  */
 @DependsOn({
@@ -213,4 +213,14 @@ public final strictfp class ServicesForM
                 ((CoordinateReferenceSystem) components[1]).getCoordinateSystem(),
                 AxisDirection.UP, AxisDirection.NORTH, AxisDirection.EAST);
     }
+
+    /**
+     * Tests {@link org.apache.sis.metadata.iso.extent.Extents#centroid(GeographicBoundingBox)}.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testGeographicBoundingBoxCentroid() {
+        org.apache.sis.metadata.iso.extent.ExtentsTest.testCentroid();
+    }
 }

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/ProvidersTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -95,6 +95,7 @@ public final strictfp class ProvidersTes
             PolarStereographicNorth.class,
             PolarStereographicSouth.class,
             ObliqueStereographic.class,
+            ZonedTransverseMercator.class,
             NTv2.class,
             NADCON.class,
             FranceGeocentricInterpolation.class,

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TransverseMercatorTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TransverseMercatorTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TransverseMercatorTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/TransverseMercatorTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -26,56 +26,65 @@ import static org.junit.Assert.*;
 
 
 /**
- * Tests {@link TransverseMercator} static methods.
+ * Tests {@link TransverseMercator} {@code Zoner} enumeration.
  * This class is about projection parameters only. For test about the Transverse Mercator calculation,
  * see {@link org.apache.sis.referencing.operation.projection.TransverseMercatorTest} instead.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.7
- * @version 0.7
+ * @version 0.8
  * @module
  */
 public final strictfp class TransverseMercatorTest extends TestCase {
     /**
-     * Tests {@link TransverseMercator#zone(double)}.
+     * Tests {@link TransverseMercator.Zoner#zone(double)},
+     * including the special cases for Norway and Svalbard.
      */
     @Test
     public void testZone() {
-        assertEquals(1,  TransverseMercator.zone(-180));
-        assertEquals(10, TransverseMercator.zone(-123));
-        assertEquals(60, TransverseMercator.zone(179.9));
+        assertEquals("180°E",        1, TransverseMercator.Zoner.UTM.zone( 0, -180  ));
+        assertEquals("123°E",       10, TransverseMercator.Zoner.UTM.zone( 0, -123  ));
+        assertEquals("179.9°W",     60, TransverseMercator.Zoner.UTM.zone( 0,  179.9));
+        assertEquals( "4°E band T", 31, TransverseMercator.Zoner.UTM.zone(45,    4  ));
+        assertEquals( "4°E band V", 32, TransverseMercator.Zoner.UTM.zone(56,    4  ));
+        assertEquals("20°E band W", 34, TransverseMercator.Zoner.UTM.zone(71,   20  ));
+        assertEquals("20°E band X", 33, TransverseMercator.Zoner.UTM.zone(72,   20  ));
     }
 
     /**
-     * Tests {@link TransverseMercator#centralMeridian(int)}.
+     * Tests {@link TransverseMercator.Zoner#centralMeridian(int)}.
      */
     @Test
     public void testCentralMeridian() {
-        assertEquals(-177, TransverseMercator.centralMeridian( 1), STRICT);
-        assertEquals(-123, TransverseMercator.centralMeridian(10), STRICT);
-        assertEquals( 177, TransverseMercator.centralMeridian(60), STRICT);
+        assertEquals(-177, TransverseMercator.Zoner.UTM.centralMeridian( 1), STRICT);
+        assertEquals(-123, TransverseMercator.Zoner.UTM.centralMeridian(10), STRICT);
+        assertEquals( 177, TransverseMercator.Zoner.UTM.centralMeridian(60), STRICT);
     }
 
     /**
-     * Tests {@link TransverseMercator#setParameters(ParameterValueGroup, double, boolean, boolean)}.
+     * Tests {@link TransverseMercator.Zoner#setParameters(ParameterValueGroup, double, double)}
+     * followed by {@link TransverseMercator.Zoner#zone(ParameterValueGroup)}.
      */
     @Test
     @DependsOnMethod({
         "testZone",
         "testCentralMeridian"
     })
-    public void testCreate() {
+    public void testSetParameters() {
         final ParameterValueGroup p = TransverseMercator.PARAMETERS.createValue();
-        assertEquals("UTM zone 10N", TransverseMercator.setParameters(p, true, 0, -122));
+        assertEquals("UTM zone 10N", TransverseMercator.Zoner.UTM.setParameters(p, 0, -122));
         assertEquals(Constants.CENTRAL_MERIDIAN, -123, p.parameter(Constants.CENTRAL_MERIDIAN).doubleValue(), STRICT);
         assertEquals(Constants.FALSE_NORTHING, 0, p.parameter(Constants.FALSE_NORTHING).doubleValue(), STRICT);
+        assertEquals("UTM.zone(parameters)", 10, TransverseMercator.Zoner.UTM.zone(p));
 
-        assertEquals("Transverse Mercator", TransverseMercator.setParameters(p, false, 0, -122));
+        assertEquals("Transverse Mercator", TransverseMercator.Zoner.ANY.setParameters(p, 0, -122));
         assertEquals(Constants.CENTRAL_MERIDIAN, -122, p.parameter(Constants.CENTRAL_MERIDIAN).doubleValue(), STRICT);
         assertEquals(Constants.FALSE_NORTHING, 0, p.parameter(Constants.FALSE_NORTHING).doubleValue(), STRICT);
+        assertEquals("UTM.zone(parameters)", 0, TransverseMercator.Zoner.UTM.zone(p));
 
-        assertEquals("UTM zone 10S", TransverseMercator.setParameters(p, false, -0.0, -123));
+        assertEquals("UTM zone 10S", TransverseMercator.Zoner.ANY.setParameters(p, -0.0, -123));
         assertEquals(Constants.CENTRAL_MERIDIAN, -123, p.parameter(Constants.CENTRAL_MERIDIAN).doubleValue(), STRICT);
         assertEquals(Constants.FALSE_NORTHING, 10000000, p.parameter(Constants.FALSE_NORTHING).doubleValue(), STRICT);
+        assertEquals("UTM.zone(parameters)", -10, TransverseMercator.Zoner.UTM.zone(p));
     }
 }

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -75,28 +75,30 @@ public final strictfp class CRSTest exte
      *
      * @throws FactoryException if a CRS can not be constructed.
      *
-     * @see CommonCRSTest#testForCode()
+     * @see EPSGFactoryFallbackTest#testCreateCRS()
      */
     @Test
     public void testForEpsgCode() throws FactoryException {
-        verifyForCode(CommonCRS.WGS84 .geographic(),   "EPSG:4326");
-        verifyForCode(CommonCRS.WGS84 .geographic(),   "urn:ogc:def:crs:EPSG::4326");
-        verifyForCode(CommonCRS.WGS84 .geographic(),   "urn:x-ogc:def:crs:EPSG::4326");
-        verifyForCode(CommonCRS.WGS84 .geographic(),   "http://www.opengis.net/gml/srs/epsg.xml#4326");
-        verifyForCode(CommonCRS.WGS72 .geographic(),   "EPSG:4322");
-        verifyForCode(CommonCRS.SPHERE.geographic(),   "EPSG:4047");
-        verifyForCode(CommonCRS.NAD83 .geographic(),   "EPSG:4269");
-        verifyForCode(CommonCRS.NAD27 .geographic(),   "EPSG:4267");
-        verifyForCode(CommonCRS.ETRS89.geographic(),   "EPSG:4258");
-        verifyForCode(CommonCRS.ED50  .geographic(),   "EPSG:4230");
-        verifyForCode(CommonCRS.WGS84 .geocentric(),   "EPSG:4978");
-        verifyForCode(CommonCRS.WGS72 .geocentric(),   "EPSG:4984");
-        verifyForCode(CommonCRS.ETRS89.geocentric(),   "EPSG:4936");
-        verifyForCode(CommonCRS.WGS84 .geographic3D(), "EPSG:4979");
-        verifyForCode(CommonCRS.WGS72 .geographic3D(), "EPSG:4985");
-        verifyForCode(CommonCRS.ETRS89.geographic3D(), "EPSG:4937");
+        verifyForCode(CommonCRS.WGS84 .geographic(),           "EPSG:4326");
+        verifyForCode(CommonCRS.WGS84 .geographic(),           "urn:ogc:def:crs:EPSG::4326");
+        verifyForCode(CommonCRS.WGS84 .geographic(),           "urn:x-ogc:def:crs:EPSG::4326");
+        verifyForCode(CommonCRS.WGS84 .geographic(),           "http://www.opengis.net/gml/srs/epsg.xml#4326");
+        verifyForCode(CommonCRS.WGS72 .geographic(),           "EPSG:4322");
+        verifyForCode(CommonCRS.SPHERE.geographic(),           "EPSG:4047");
+        verifyForCode(CommonCRS.NAD83 .geographic(),           "EPSG:4269");
+        verifyForCode(CommonCRS.NAD27 .geographic(),           "EPSG:4267");
+        verifyForCode(CommonCRS.ETRS89.geographic(),           "EPSG:4258");
+        verifyForCode(CommonCRS.ED50  .geographic(),           "EPSG:4230");
+        verifyForCode(CommonCRS.WGS84 .geocentric(),           "EPSG:4978");
+        verifyForCode(CommonCRS.WGS72 .geocentric(),           "EPSG:4984");
+        verifyForCode(CommonCRS.ETRS89.geocentric(),           "EPSG:4936");
+        verifyForCode(CommonCRS.WGS84 .geographic3D(),         "EPSG:4979");
+        verifyForCode(CommonCRS.WGS72 .geographic3D(),         "EPSG:4985");
+        verifyForCode(CommonCRS.ETRS89.geographic3D(),         "EPSG:4937");
+        verifyForCode(CommonCRS.WGS84 .universal(88, 120),     "EPSG:5041");
+        verifyForCode(CommonCRS.WGS84 .universal(-40, 2),      "EPSG:32731");
         verifyForCode(CommonCRS.Vertical.MEAN_SEA_LEVEL.crs(), "EPSG:5714");
-        verifyForCode(CommonCRS.Vertical.DEPTH.crs(), "EPSG:5715");
+        verifyForCode(CommonCRS.Vertical.DEPTH.crs(),          "EPSG:5715");
     }
 
     /**
@@ -104,7 +106,7 @@ public final strictfp class CRSTest exte
      *
      * @throws FactoryException if a CRS can not be constructed.
      *
-     * @see CommonCRSTest#testForCode()
+     * @see EPSGFactoryFallbackTest#testCreateCRS()
      */
     @Test
     @DependsOnMethod("testForEpsgCode")

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/CommonCRSTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -79,6 +79,8 @@ public final strictfp class CommonCRSTes
             assertNoCodeCollision(codes, crs, crs.geographic);
             assertNoCodeCollision(codes, crs, crs.geocentric);
             assertNoCodeCollision(codes, crs, crs.geo3D);
+            assertNoCodeCollision(codes, crs, crs.northUPS);
+            assertNoCodeCollision(codes, crs, crs.southUPS);
             for (int zone = crs.firstZone; zone <= crs.lastZone; zone++) {
                 if (crs.northUTM != 0) assertNoCodeCollision(codes, crs, crs.northUTM + zone);
                 if (crs.southUTM != 0) assertNoCodeCollision(codes, crs, crs.southUTM + zone);
@@ -276,19 +278,54 @@ public final strictfp class CommonCRSTes
     }
 
     /**
-     * Tests {@link CommonCRS#UTM(double, double)}.
+     * Tests {@link CommonCRS#universal(double, double)} with Universal Transverse Mercator (UTM) projections.
      *
      * @since 0.7
      */
     @Test
     @DependsOnMethod("testGeographic")
     public void testUTM() {
-        final ProjectedCRS crs = CommonCRS.WGS72.UTM(-45, -122);
+        final ProjectedCRS crs = CommonCRS.WGS72.universal(-45, -122);
         assertEquals("name", "WGS 72 / UTM zone 10S", crs.getName().getCode());
         final ParameterValueGroup pg = crs.getConversionFromBase().getParameterValues();
-        assertEquals(Constants.LATITUDE_OF_ORIGIN, -123, pg.parameter(Constants.CENTRAL_MERIDIAN).doubleValue(), STRICT);
-        assertEquals(Constants.FALSE_NORTHING, 10000000, pg.parameter(Constants.FALSE_NORTHING).doubleValue(),   STRICT);
-        assertSame("Expected a cached instance.", crs, CommonCRS.WGS72.UTM(-45, -122));
-        assertNotSame("Expected a new instance.", crs, CommonCRS.WGS72.UTM(+45, -122));
+        assertEquals(Constants.LATITUDE_OF_ORIGIN,    0, pg.parameter(Constants.LATITUDE_OF_ORIGIN).doubleValue(), STRICT);
+        assertEquals(Constants.CENTRAL_MERIDIAN,   -123, pg.parameter(Constants.CENTRAL_MERIDIAN)  .doubleValue(), STRICT);
+        assertEquals(Constants.SCALE_FACTOR,     0.9996, pg.parameter(Constants.SCALE_FACTOR)      .doubleValue(), STRICT);
+        assertEquals(Constants.FALSE_EASTING,    500000, pg.parameter(Constants.FALSE_EASTING)     .doubleValue(), STRICT);
+        assertEquals(Constants.FALSE_NORTHING, 10000000, pg.parameter(Constants.FALSE_NORTHING)    .doubleValue(), STRICT);
+        assertSame("Expected a cached instance.", crs, CommonCRS.WGS72.universal(-45, -122));
+        assertNotSame("Expected a new instance.", crs, CommonCRS.WGS72.universal(+45, -122));
+    }
+
+    /**
+     * Tests {@link CommonCRS#universal(double, double)} with Universal Polar Stereographic (UPS) projections.
+     *
+     * @since 0.8
+     */
+    @Test
+    @DependsOnMethod("testGeographic")
+    public void testUPS() {
+        final ProjectedCRS crs = CommonCRS.WGS72.universal(-85, -122);
+        assertEquals("name", "WGS 72 / Universal Polar Stereographic South", crs.getName().getCode());
+        final ParameterValueGroup pg = crs.getConversionFromBase().getParameterValues();
+        assertEquals(Constants.LATITUDE_OF_ORIGIN, -90, pg.parameter(Constants.LATITUDE_OF_ORIGIN).doubleValue(), STRICT);
+        assertEquals(Constants.CENTRAL_MERIDIAN,     0, pg.parameter(Constants.CENTRAL_MERIDIAN)  .doubleValue(), STRICT);
+        assertEquals(Constants.SCALE_FACTOR,     0.994, pg.parameter(Constants.SCALE_FACTOR)      .doubleValue(), STRICT);
+        assertEquals(Constants.FALSE_EASTING,  2000000, pg.parameter(Constants.FALSE_EASTING)     .doubleValue(), STRICT);
+        assertEquals(Constants.FALSE_NORTHING, 2000000, pg.parameter(Constants.FALSE_NORTHING)    .doubleValue(), STRICT);
+        assertSame("Expected a cached instance.", crs, CommonCRS.WGS72.universal(-85, -122));
+        assertNotSame("Expected a new instance.", crs, CommonCRS.WGS72.universal(+85, -122));
+    }
+
+    /**
+     * Tests {@link CommonCRS#forDatum(CoordinateReferenceSystem)}.
+     *
+     * @sinc 0.8
+     */
+    @Test
+    @DependsOnMethod("testGeographic")
+    public void testForDatum() {
+        assertSame("WGS84", CommonCRS.WGS84, CommonCRS.forDatum(CommonCRS.WGS84.geographic()));
+        assertSame("WGS72", CommonCRS.WGS72, CommonCRS.forDatum(CommonCRS.WGS72.geographic()));
     }
 }

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -19,11 +19,13 @@ package org.apache.sis.referencing;
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Set;
 import org.opengis.util.FactoryException;
 import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.GeocentricCRS;
+import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.datum.Ellipsoid;
@@ -74,6 +76,12 @@ public final strictfp class EPSGFactoryF
                 EPSGFactoryFallback.INSTANCE.getAuthorityCodes(GeographicCRS.class));
         assertSetEquals(Arrays.asList("5714", "5715", "5703"),
                 EPSGFactoryFallback.INSTANCE.getAuthorityCodes(VerticalCRS.class));
+        /*
+         * There is two many ProjectedCRS codes for enumerating all of them, so test only a sampling.
+         */
+        final Set<String> codes = EPSGFactoryFallback.INSTANCE.getAuthorityCodes(ProjectedCRS.class);
+        assertTrue(codes.containsAll(Arrays.asList("5041", "5042", "32601", "32660", "32701", "32760")));
+        assertTrue(Collections.disjoint(codes, Arrays.asList("7030", "6326", "4326", "4978", "32600", "32700", "5714")));
     }
 
     /**
@@ -141,6 +149,8 @@ public final strictfp class EPSGFactoryF
         verifyCreateCRS(CommonCRS.WGS84 .geographic3D(),          "4979");
         verifyCreateCRS(CommonCRS.WGS72 .geographic3D(),          "4985");
         verifyCreateCRS(CommonCRS.ETRS89.geographic3D(),          "4937");
+        verifyCreateCRS(CommonCRS.WGS84 .universal(-88, 120),     "5042");
+        verifyCreateCRS(CommonCRS.WGS84 .universal( 40, 14),     "32633");
         verifyCreateCRS(CommonCRS.Vertical.MEAN_SEA_LEVEL.crs(),  "5714");
         verifyCreateCRS(CommonCRS.Vertical.DEPTH.crs(),           "5715");
     }

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/StandardDefinitionsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/StandardDefinitionsTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/StandardDefinitionsTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/StandardDefinitionsTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -71,18 +71,42 @@ public final strictfp class StandardDefi
     }
 
     /**
-     * Tests {@link StandardDefinitions#createUTM(int, GeographicCRS, double, boolean, CartesianCS)}.
+     * Tests {@link StandardDefinitions#createUniversal(int, GeographicCRS, boolean, double, double, CartesianCS)}
+     * for a Universal Transverse Mercator (UTM) projection.
      *
      * @since 0.7
      */
     @Test
     @DependsOnMethod("testCreateGeographicCRS")
     public void testCreateUTM() {
-        final ProjectedCRS crs = StandardDefinitions.createUTM(32610, HardCodedCRS.WGS84, 15, -122, HardCodedCS.PROJECTED);
+        final ProjectedCRS crs = StandardDefinitions.createUniversal(32610, HardCodedCRS.WGS84, true, 15, -122, HardCodedCS.PROJECTED);
         assertEquals("name", "WGS 84 / UTM zone 10N", crs.getName().getCode());
         final ParameterValueGroup pg = crs.getConversionFromBase().getParameterValues();
-        assertEquals(Constants.LATITUDE_OF_ORIGIN, -123, pg.parameter(Constants.CENTRAL_MERIDIAN).doubleValue(), STRICT);
-        assertEquals(Constants.FALSE_NORTHING,        0, pg.parameter(Constants.FALSE_NORTHING).doubleValue(),   STRICT);
+        assertEquals(Constants.LATITUDE_OF_ORIGIN,    0, pg.parameter(Constants.LATITUDE_OF_ORIGIN).doubleValue(), STRICT);
+        assertEquals(Constants.CENTRAL_MERIDIAN,   -123, pg.parameter(Constants.CENTRAL_MERIDIAN)  .doubleValue(), STRICT);
+        assertEquals(Constants.SCALE_FACTOR,     0.9996, pg.parameter(Constants.SCALE_FACTOR)      .doubleValue(), STRICT);
+        assertEquals(Constants.FALSE_EASTING,    500000, pg.parameter(Constants.FALSE_EASTING)     .doubleValue(), STRICT);
+        assertEquals(Constants.FALSE_NORTHING,        0, pg.parameter(Constants.FALSE_NORTHING)    .doubleValue(), STRICT);
+    }
+
+    /**
+     * Tests {@link StandardDefinitions#createUniversal(int, GeographicCRS, boolean, double, double, CartesianCS)}
+     * for a Universal Polar Stereographic (UPS) projection. This test cheats a little bit on the coordinate system
+     * by laziness; we are more interested in the projection parameters.
+     *
+     * @since 0.8
+     */
+    @Test
+    @DependsOnMethod("testCreateGeographicCRS")
+    public void testCreateUPS() {
+        final ProjectedCRS crs = StandardDefinitions.createUniversal(5041, HardCodedCRS.WGS84, false, 90, -122, HardCodedCS.PROJECTED);
+        assertEquals("name", "WGS 84 / Universal Polar Stereographic North", crs.getName().getCode());
+        final ParameterValueGroup pg = crs.getConversionFromBase().getParameterValues();
+        assertEquals(Constants.LATITUDE_OF_ORIGIN,  90, pg.parameter(Constants.LATITUDE_OF_ORIGIN).doubleValue(), STRICT);
+        assertEquals(Constants.CENTRAL_MERIDIAN,     0, pg.parameter(Constants.CENTRAL_MERIDIAN)  .doubleValue(), STRICT);
+        assertEquals(Constants.SCALE_FACTOR,     0.994, pg.parameter(Constants.SCALE_FACTOR)      .doubleValue(), STRICT);
+        assertEquals(Constants.FALSE_EASTING,  2000000, pg.parameter(Constants.FALSE_EASTING)     .doubleValue(), STRICT);
+        assertEquals(Constants.FALSE_NORTHING, 2000000, pg.parameter(Constants.FALSE_NORTHING)    .doubleValue(), STRICT);
     }
 
     /**

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGInstallerTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -209,7 +209,7 @@ public final strictfp class EPSGInstalle
              * This implies the creation of a coordinate operation.
              */
             final ProjectedCRS p = factory.createProjectedCRS("EPSG:32215");
-            assertTrue(Utilities.deepEquals(CommonCRS.WGS72.UTM(1, -93), p, ComparisonMode.DEBUG));
+            assertTrue(Utilities.deepEquals(CommonCRS.WGS72.universal(1, -93), p, ComparisonMode.DEBUG));
             /*
              * Get the authority codes. We choose a type that implies an SQL statement
              * with both "DEPRECATED" and "SHOW_CRS" conditions in their "WHERE" clause.

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -175,7 +175,7 @@ public final strictfp class CoordinateOp
         testIdentityTransform(CommonCRS.WGS84.geographic3D());
         testIdentityTransform(CommonCRS.WGS84.geocentric());
         testIdentityTransform(CommonCRS.WGS84.spherical());
-        testIdentityTransform(CommonCRS.WGS84.UTM(0, 0));
+        testIdentityTransform(CommonCRS.WGS84.universal(0, 0));
         testIdentityTransform(CommonCRS.Vertical.DEPTH.crs());
         testIdentityTransform(CommonCRS.Temporal.JULIAN.crs());
     }

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/builder/LinearTransformBuilderTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -16,8 +16,11 @@
  */
 package org.apache.sis.referencing.operation.builder;
 
+import java.util.Map;
+import java.util.HashMap;
 import java.util.Random;
 import java.awt.geom.AffineTransform;
+import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.Matrix;
 import org.apache.sis.geometry.DirectPosition1D;
 import org.apache.sis.geometry.DirectPosition2D;
@@ -34,23 +37,28 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.5
- * @version 0.5
+ * @version 0.8
  * @module
  */
 public final strictfp class LinearTransformBuilderTest extends TestCase {
     /**
      * Tests a very simple case where an exact answer is expected.
+     *
+     * @throws FactoryException if the transform can not be created.
      */
     @Test
-    public void testMinimalist1D() {
+    public void testMinimalist1D() throws FactoryException {
         final LinearTransformBuilder builder = new LinearTransformBuilder();
-        builder.setSourcePoints(
-                new DirectPosition1D(1),
-                new DirectPosition1D(2));
-        builder.setTargetPoints(
-                new DirectPosition1D(1),
-                new DirectPosition1D(3));
-        final Matrix m = builder.create().getMatrix();
+        final Map<DirectPosition1D,DirectPosition1D> pos = new HashMap<>(4);
+        assertNull(pos.put(new DirectPosition1D(1), new DirectPosition1D(1)));
+        assertNull(pos.put(new DirectPosition1D(2), new DirectPosition1D(3)));
+        builder.setControlPoints(pos);
+
+        assertArrayEquals(new double[] {1}, builder.getControlPoint(new int[] {1}), STRICT);
+        assertArrayEquals(new double[] {3}, builder.getControlPoint(new int[] {2}), STRICT);
+        assertNull(                         builder.getControlPoint(new int[] {3}));
+
+        final Matrix m = builder.create(null).getMatrix();
         assertEquals("m₀₀",  2, m.getElement(0, 0), STRICT);
         assertEquals("m₀₁", -1, m.getElement(0, 1), STRICT);
         assertArrayEquals("correlation", new double[] {1}, builder.correlation(), STRICT);
@@ -61,9 +69,11 @@ public final strictfp class LinearTransf
      * Tolerance threshold is set to zero because the math transform has been built from exactly 3 points,
      * in which case we expect an exact solution without rounding errors at the scale of the {@code double}
      * type. This is possible because SIS implementation uses double-double arithmetic.
+     *
+     * @throws FactoryException if the transform can not be created.
      */
     @Test
-    public void testMinimalist2D() {
+    public void testMinimalist2D() throws FactoryException {
         final LinearTransformBuilder builder = new LinearTransformBuilder();
         builder.setSourcePoints(
                 new DirectPosition2D(1, 1),
@@ -73,7 +83,13 @@ public final strictfp class LinearTransf
                 new DirectPosition2D(3, 2),
                 new DirectPosition2D(3, 5),
                 new DirectPosition2D(5, 5));
-        final Matrix m = builder.create().getMatrix();
+
+        assertArrayEquals(new double[] {3, 2}, builder.getControlPoint(new int[] {1, 1}), STRICT);
+        assertArrayEquals(new double[] {3, 5}, builder.getControlPoint(new int[] {1, 2}), STRICT);
+        assertArrayEquals(new double[] {5, 5}, builder.getControlPoint(new int[] {2, 2}), STRICT);
+        assertNull(                            builder.getControlPoint(new int[] {2, 1}));
+
+        final Matrix m = builder.create(null).getMatrix();
 
         // First row (x)
         assertEquals("m₀₀",  2, m.getElement(0, 0), STRICT);
@@ -89,11 +105,96 @@ public final strictfp class LinearTransf
     }
 
     /**
+     * Tests a two-dimensional case where sources coordinates are explicitely given.
+     *
+     * @throws FactoryException if the transform can not be created.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testExplicitSource2D() throws FactoryException {
+        testSetAllPoints(new LinearTransformBuilder());
+        testSetEachPoint(new LinearTransformBuilder());
+    }
+
+    /**
+     * Same test than {@link #testExplicitSource2D()}, but using the
+     * {@link LinearTransformBuilder#LinearTransformBuilder(int...)} constructor.
+     *
+     * @throws FactoryException if the transform can not be created.
+     *
+     * @since 0.8
+     */
+    @Test
+    @DependsOnMethod("testExplicitSource2D")
+    public void testImplicitSource2D() throws FactoryException {
+        testSetAllPoints(new LinearTransformBuilder(2, 3));
+        testSetEachPoint(new LinearTransformBuilder(2, 3));
+    }
+
+    /**
+     * Execution of {@link #testExplicitSource2D()} and {@link #testImplicitSource2D()}
+     * where all control points are specified by a map.
+     */
+    private void testSetAllPoints(final LinearTransformBuilder builder) throws FactoryException {
+        final Map<DirectPosition2D,DirectPosition2D> pos = new HashMap<>(8);
+        assertNull(pos.put(new DirectPosition2D(0, 0), new DirectPosition2D(3, 9)));
+        assertNull(pos.put(new DirectPosition2D(0, 1), new DirectPosition2D(4, 7)));
+        assertNull(pos.put(new DirectPosition2D(0, 2), new DirectPosition2D(6, 6)));
+        assertNull(pos.put(new DirectPosition2D(1, 0), new DirectPosition2D(4, 8)));
+        assertNull(pos.put(new DirectPosition2D(1, 1), new DirectPosition2D(5, 4)));
+        assertNull(pos.put(new DirectPosition2D(1, 2), new DirectPosition2D(8, 2)));
+        builder.setControlPoints(pos);
+        verify(builder);
+    }
+
+    /**
+     * Execution of {@link #testExplicitSource2D()} and {@link #testImplicitSource2D()}
+     * where all control points are specified one-by-one.
+     */
+    private void testSetEachPoint(final LinearTransformBuilder builder) throws FactoryException {
+        builder.setControlPoint(new int[] {0, 0}, new double[] {3, 9});
+        builder.setControlPoint(new int[] {0, 1}, new double[] {4, 7});
+        builder.setControlPoint(new int[] {0, 2}, new double[] {6, 6});
+        builder.setControlPoint(new int[] {1, 0}, new double[] {4, 8});
+        builder.setControlPoint(new int[] {1, 1}, new double[] {5, 4});
+        builder.setControlPoint(new int[] {1, 2}, new double[] {8, 2});
+        verify(builder);
+    }
+
+    /**
+     * Verifies the transform created by {@link #testExplicitSource2D()} and {@link #testImplicitSource2D()}.
+     */
+    private void verify(final LinearTransformBuilder builder) throws FactoryException {
+        final Matrix m = builder.create(null).getMatrix();
+
+        assertArrayEquals(new double[] {3, 9}, builder.getControlPoint(new int[] {0, 0}), STRICT);
+        assertArrayEquals(new double[] {4, 7}, builder.getControlPoint(new int[] {0, 1}), STRICT);
+        assertArrayEquals(new double[] {6, 6}, builder.getControlPoint(new int[] {0, 2}), STRICT);
+        assertArrayEquals(new double[] {4, 8}, builder.getControlPoint(new int[] {1, 0}), STRICT);
+        assertArrayEquals(new double[] {5, 4}, builder.getControlPoint(new int[] {1, 1}), STRICT);
+        assertArrayEquals(new double[] {8, 2}, builder.getControlPoint(new int[] {1, 2}), STRICT);
+        /*
+         * Expect STRICT results because Apache SIS uses double-double arithmetic.
+         */
+        assertEquals("m₀₀",  16 / 12d, m.getElement(0, 0), STRICT);        // First row (x)
+        assertEquals("m₀₁",  21 / 12d, m.getElement(0, 1), STRICT);
+        assertEquals("m₀₂",  31 / 12d, m.getElement(0, 2), STRICT);
+        assertEquals("m₁₀", -32 / 12d, m.getElement(1, 0), STRICT);        // Second row (y)
+        assertEquals("m₁₁", -27 / 12d, m.getElement(1, 1), STRICT);
+        assertEquals("m₁₂", 115 / 12d, m.getElement(1, 2), STRICT);
+
+        assertArrayEquals("correlation", new double[] {0.9656, 0.9536}, builder.correlation(), 0.0001);
+    }
+
+    /**
      * Tests with a random number of points with an exact solution expected.
+     *
+     * @throws FactoryException if the transform can not be created.
      */
     @Test
     @DependsOnMethod("testMinimalist1D")
-    public void testExact1D() {
+    public void testExact1D() throws FactoryException {
         final Random rd = TestUtilities.createRandomNumberGenerator(-6080923837183751016L);
         for (int i=0; i<10; i++) {
             test1D(rd, rd.nextInt(900) + 100, false, 1E-14, 1E-12);
@@ -106,10 +207,12 @@ public final strictfp class LinearTransf
      * <p><b>Note:</b> this test can pass with a random seed most of the time. But we fix the seed anyway
      * because there is always a small probability that truly random points are all colinear, in which case
      * the test would fail. Even if the probability is low, we do not take the risk of random build failures.</p>
+     *
+     * @throws FactoryException if the transform can not be created.
      */
     @Test
     @DependsOnMethod("testMinimalist2D")
-    public void testExact2D() {
+    public void testExact2D() throws FactoryException {
         final Random rd = TestUtilities.createRandomNumberGenerator(41632405806929L);
         for (int i=0; i<10; i++) {
             test2D(rd, rd.nextInt(900) + 100, false, 1E-14, 1E-12);
@@ -118,10 +221,12 @@ public final strictfp class LinearTransf
 
     /**
      * Tests with a random number of points and a random errors in target points.
+     *
+     * @throws FactoryException if the transform can not be created.
      */
     @Test
     @DependsOnMethod("testExact1D")
-    public void testNonExact1D() {
+    public void testNonExact1D() throws FactoryException {
         final Random rd = TestUtilities.createRandomNumberGenerator(8819436190826166876L);
         for (int i=0; i<4; i++) {
             test1D(rd, rd.nextInt(900) + 100, true, 0.02, 0.5);
@@ -136,10 +241,12 @@ public final strictfp class LinearTransf
      * of errors are in the same directions (thus introducing a larger bias than expected), in which case
      * the test would fail. Even if the probability is low, we do not take the risk of such random build
      * failures.</p>
+     *
+     * @throws FactoryException if the transform can not be created.
      */
     @Test
     @DependsOnMethod("testExact2D")
-    public void testNonExact2D() {
+    public void testNonExact2D() throws FactoryException {
         final Random rd = TestUtilities.createRandomNumberGenerator(270575025643864L);
         for (int i=0; i<4; i++) {
             test2D(rd, rd.nextInt(900) + 100, true, 0.02, 0.5);
@@ -155,28 +262,25 @@ public final strictfp class LinearTransf
      * @param  scaleTolerance  tolerance threshold for floating point comparisons.
      */
     private static void test1D(final Random rd, final int numPts, final boolean addErrors,
-            final double scaleTolerance, final double translationTolerance)
+            final double scaleTolerance, final double translationTolerance) throws FactoryException
     {
         final double scale  = rd.nextDouble() * 30 - 12;
         final double offset = rd.nextDouble() * 10 - 4;
-        final DirectPosition1D[] sources = new DirectPosition1D[numPts];
-        final DirectPosition1D[] targets = new DirectPosition1D[numPts];
+        final Map<DirectPosition1D,DirectPosition1D> pos = new HashMap<>(numPts);
         for (int i=0; i<numPts; i++) {
             final DirectPosition1D src = new DirectPosition1D(rd.nextDouble() * 100 - 50);
             final DirectPosition1D tgt = new DirectPosition1D(src.ordinate * scale + offset);
             if (addErrors) {
                 tgt.ordinate += rd.nextDouble() * 10 - 5;
             }
-            sources[i] = src;
-            targets[i] = tgt;
+            assertNull(pos.put(src, tgt));
         }
         /*
          * Create the fitted transform to test.
          */
         final LinearTransformBuilder builder = new LinearTransformBuilder();
-        builder.setSourcePoints(sources);
-        builder.setTargetPoints(targets);
-        final Matrix m = builder.create().getMatrix();
+        builder.setControlPoints(pos);
+        final Matrix m = builder.create(null).getMatrix();
         assertEquals("m₀₀", scale,  m.getElement(0, 0), scaleTolerance);
         assertEquals("m₀₁", offset, m.getElement(0, 1), translationTolerance);
         assertEquals("correlation", 1, StrictMath.abs(builder.correlation()[0]), scaleTolerance);
@@ -191,7 +295,7 @@ public final strictfp class LinearTransf
      * @param  scaleTolerance  tolerance threshold for floating point comparisons.
      */
     private static void test2D(final Random rd, final int numPts, final boolean addErrors,
-            final double scaleTolerance, final double translationTolerance)
+            final double scaleTolerance, final double translationTolerance) throws FactoryException
     {
         /*
          * Create an AffineTransform to use as the reference implementation.
@@ -200,8 +304,7 @@ public final strictfp class LinearTransf
                 rd.nextDouble() * (2 * StrictMath.PI),  // Rotation angle
                 rd.nextDouble() * 30 - 12,              // Center X
                 rd.nextDouble() * 10 - 8);              // Center Y
-        final DirectPosition2D[] sources = new DirectPosition2D[numPts];
-        final DirectPosition2D[] targets = new DirectPosition2D[numPts];
+        final Map<DirectPosition2D,DirectPosition2D> pos = new HashMap<>(numPts);
         for (int i=0; i<numPts; i++) {
             final DirectPosition2D src = new DirectPosition2D(rd.nextDouble() * 100 - 50, rd.nextDouble() * 200 - 75);
             final DirectPosition2D tgt = new DirectPosition2D();
@@ -210,16 +313,14 @@ public final strictfp class LinearTransf
                 tgt.x += rd.nextDouble() * 10 - 5;
                 tgt.y += rd.nextDouble() * 10 - 5;
             }
-            sources[i] = src;
-            targets[i] = tgt;
+            assertNull(pos.put(src, tgt));
         }
         /*
          * Create the fitted transform to test.
          */
         final LinearTransformBuilder builder = new LinearTransformBuilder();
-        builder.setSourcePoints(sources);
-        builder.setTargetPoints(targets);
-        final Matrix m = builder.create().getMatrix();
+        builder.setControlPoints(pos);
+        final Matrix m = builder.create(null).getMatrix();
         /*
          * Compare the coefficients with the reference implementation.
          */

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/GeneralMatrixTest.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -28,7 +28,7 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 public final strictfp class GeneralMatrixTest extends MatrixTestCase {
@@ -117,4 +117,15 @@ public final strictfp class GeneralMatri
         testConvertAfter(new GeneralMatrix(3, 3, true, 1));    // Double precision
         testConvertAfter(new GeneralMatrix(3, 3, true, 2));    // Double-double precision
     }
+
+    /**
+     * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference implementation.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testMultiplyVector() {
+        testMultiplyVector(new GeneralMatrix(3, 3, true, 1));    // Double precision
+        testMultiplyVector(new GeneralMatrix(3, 3, true, 2));    // Double-double precision
+    }
 }

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/Matrix3Test.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -29,7 +29,7 @@ import static org.apache.sis.referencing
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 @DependsOn(SolverTest.class)
@@ -122,4 +122,14 @@ public final strictfp class Matrix3Test
     public void testConvertAfter() {
         testConvertAfter(new Matrix3());
     }
+
+    /**
+     * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference implementation.
+     *
+     * @since 0.8
+     */
+    @Test
+    public void testMultiplyVector() {
+        testMultiplyVector(new Matrix3());
+    }
 }

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -46,7 +46,7 @@ import static org.apache.sis.test.Assert
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.6
+ * @version 0.8
  * @module
  */
 public abstract strictfp class MatrixTestCase extends TestCase {
@@ -269,7 +269,7 @@ public abstract strictfp class MatrixTes
          * End of initialization - now perform the actual test.
          */
         assertEqualsJAMA(reference, matrix, STRICT);
-        for (int k=0; k<50; k++) {
+        for (int k=0; k<NUMBER_OF_REPETITIONS; k++) {
             final int    j = random.nextInt(numRow);
             final int    i = random.nextInt(numCol);
             final double e = random.nextDouble() * 100;
@@ -410,7 +410,7 @@ public abstract strictfp class MatrixTes
             matrix.setElement(0, 1, at.getShearX());
             matrix.setElement(1, 0, at.getShearY());
         }
-        for (int i=0; i<100; i++) {
+        for (int i=0; i<NUMBER_OF_REPETITIONS; i++) {
             /*
              * 1) For the first  30 iterations, test the result of applying only a scale.
              * 2) For the next   30 iterations, test the result of applying only a translation.
@@ -476,7 +476,7 @@ public abstract strictfp class MatrixTes
         final AffineTransform at = AffineTransform.getShearInstance(nextNonZeroRandom(), nextNonZeroRandom());
         matrix.setElement(0, 1, at.getShearX());
         matrix.setElement(1, 0, at.getShearY());
-        for (int i=0; i<30; i++) {
+        for (int i=0; i<NUMBER_OF_REPETITIONS; i++) {
             final Number scale  = nextNonZeroRandom();
             final Number offset = nextNonZeroRandom();
             final int tgtDim = (i & 1);
@@ -496,6 +496,41 @@ public abstract strictfp class MatrixTes
         }
     }
 
+    /**
+     * Tests {@link MatrixSIS#multiply(double[])} using {@link AffineTranform} as a reference implementation.
+     * This test can be run only with matrices of size 3×3. Consequently it is sub-classes responsibility to
+     * add a {@code testMultiplyVector()} method which invoke this method.
+     *
+     * @param  matrix  the matrix of size 3×3 to test.
+     *
+     * @since 0.8
+     */
+    final void testMultiplyVector(final MatrixSIS matrix) {
+        initialize(8433903323905121506L);
+        final AffineTransform at = new AffineTransform();
+        final double vector[] = new double[3];
+        for (int n=0; n<NUMBER_OF_REPETITIONS; n++) {
+            if ((n % 10) == 0) {
+                at.setToRotation(random.nextDouble() * StrictMath.PI);
+                at.scale(nextNonZeroRandom(), nextNonZeroRandom());
+                at.translate(random.nextDouble() * 100 - 50,
+                             random.nextDouble() * 100 - 50);
+                matrix.setElements(new double[] {
+                    at.getScaleX(), at.getShearX(), at.getTranslateX(),
+                    at.getShearY(), at.getScaleY(), at.getTranslateY(),
+                                 0,              0,                  1
+                });
+            }
+            vector[0] = random.nextDouble() * 50 - 25;
+            vector[1] = random.nextDouble() * 50 - 25;
+            vector[2] = 1;
+            final double[] result = matrix.multiply(vector);        // The result to verify.
+            at.transform(vector, 0, vector, 0, 1);                  // The expected result.
+            assertEquals("x", vector[0], result[0], TOLERANCE);
+            assertEquals("y", vector[1], result[1], TOLERANCE);
+        }
+    }
+
     /**
      * Tests {@link MatrixSIS#multiply(Matrix)}.
      */

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/CoordinateDomain.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -37,6 +37,12 @@ import org.apache.sis.referencing.datum.
  * @module
  */
 public strictfp class CoordinateDomain {
+    /*
+     * Note: this class is not declared as an enum yet because moving ARTICLE_CIRCLE and HEIGHT constants
+     *       after the enum declarations causes an "illegal forward reference" compiler error with JDK 8.
+     */
+
+
     /**
      * Latitude of the Article circle, which is 66°33′45.7″ as of March 30, 2015
      * Note that this value fluctuate by 2° over 40,000-year periods.

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/referencing/report/HTMLGenerator.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -26,6 +26,7 @@ import java.io.BufferedWriter;
 import java.io.OutputStreamWriter;
 import java.io.Closeable;
 import org.opengis.util.InternationalString;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Deprecable;
 
@@ -59,7 +60,7 @@ abstract strictfp class HTMLGenerator im
      * The number of space to add or remove in the {@linkplain #margin}
      * when new HTML elements are opened or closed.
      */
-    private static final int INDENTATION = 2;
+    private static final int INDENTATION = Constants.DEFAULT_INDENTATION;
 
     /**
      * Where to write the HTML page.

Modified: sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -162,6 +162,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.projection.MercatorTest.class,
     org.apache.sis.referencing.operation.projection.LambertConicConformalTest.class,
     org.apache.sis.referencing.operation.projection.TransverseMercatorTest.class,
+    org.apache.sis.referencing.operation.projection.ZonedGridSystemTest.class,
     org.apache.sis.referencing.operation.projection.PolarStereographicTest.class,
     org.apache.sis.referencing.operation.projection.ObliqueStereographicTest.class,
     org.apache.sis.referencing.operation.projection.CylindricalEqualAreaTest.class,
@@ -224,6 +225,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.CoordinateOperationFinderTest.class,
     org.apache.sis.referencing.operation.DefaultCoordinateOperationFactoryTest.class,
     org.apache.sis.referencing.operation.builder.LinearTransformBuilderTest.class,
+    org.apache.sis.referencing.operation.builder.LocalizationGridBuilderTest.class,
 
     // Geometry
     org.apache.sis.geometry.AbstractDirectPositionTest.class,
@@ -239,6 +241,7 @@ import org.junit.BeforeClass;
     org.apache.sis.geometry.Shapes2DTest.class,                 // Simpler than EnvelopesTest.
     org.apache.sis.geometry.EnvelopesTest.class,
     org.apache.sis.internal.referencing.ServicesForMetadataTest.class,
+    org.apache.sis.geometry.CoordinateFormatTest.class,
 
     org.apache.sis.distance.LatLonPointRadiusTest.class,        // Pending refactoring in a geometry package.
 

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/converter/ConverterRegistry.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -132,7 +132,7 @@ public class ConverterRegistry {
      */
     @SuppressWarnings("unchecked")
     private <S,T> void put(ClassPair<S,T> key, final ObjectConverter<? super S, ? extends T> converter) {
-        assert key.getClass() == ClassPair.class; // See SystemConverter.equals(Object)
+        assert key.getClass() == ClassPair.class;                   // See SystemConverter.equals(Object)
         assert key.cast(converter) != null : converter;
         assert Thread.holdsLock(converters);
         if (converter instanceof SystemConverter<?,?> &&
@@ -269,7 +269,7 @@ public class ConverterRegistry {
              * for the place where to put the given converter in the hierarchy of converters.
              */
             if (!isInitialized) {
-                isInitialized = true; // Before 'initialize()' for preventing infinite recursivity.
+                isInitialized = true;           // Before 'initialize()' for preventing infinite recursivity.
                 initialize();
             }
             for (Class<? super T> i=targetClass; i!=null && i!=stopAt; i=i.getSuperclass()) {
@@ -354,7 +354,7 @@ public class ConverterRegistry {
              * its source is more specific:  the source of 'converter' is of type <S> while the
              * source of 'existing' is of type <? super S>.
              */
-            assert converter.getSourceClass() == key.sourceClass; // Enforced by parameterized type.
+            assert converter.getSourceClass() == key.sourceClass;       // Enforced by parameterized type.
             if (existing.getSourceClass() == key.sourceClass) {
                 final boolean oldIsExact = isExactlyFor(existing,  key.targetClass);
                 final boolean newIsExact = isExactlyFor(converter, key.targetClass);
@@ -374,7 +374,7 @@ public class ConverterRegistry {
                      * checked the source class in the above 'if' statement.
                      */
                     converter = FallbackConverter.merge((ObjectConverter<S, ? extends T>) existing, converter);
-                    assert key.targetClass.isAssignableFrom(converter.getTargetClass()) : converter; // See FallbackConverter.merge javadoc.
+                    assert key.targetClass.isAssignableFrom(converter.getTargetClass()) : converter;    // See FallbackConverter.merge javadoc.
                 }
             }
         }

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -16,8 +16,11 @@
  */
 package org.apache.sis.internal.jaxb;
 
+import java.util.Map;
+import java.util.HashMap;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
 import javax.xml.bind.JAXBContext;
@@ -47,14 +50,37 @@ import org.apache.sis.internal.system.De
  */
 public abstract class TypeRegistration {
     /**
+     * Undocumented (for now) marshaller property for specifying conversions to apply on root objects
+     * before marshalling. Conversions are applied by the {@link #toImplementation(Object)} method.
+     *
+     * @see #addDefaultRootAdapters(Map)
+     */
+    public static final String ROOT_ADAPTERS = "org.apache.sis.xml.rootAdapters";
+
+    /**
      * The JAXB context, or {@code null} if not yet created or if the classpath changed.
+     *
+     * @see #getSharedContext()
      */
     private static Reference<JAXBContext> context;
+
+    /**
+     * The {@link TypeRegistration} instances found on the classpath for which the
+     * {@link #toImplementation(Object)} method has been overridden.
+     *
+     * @see #addDefaultRootAdapters(Map)
+     */
+    private static TypeRegistration[] converters;
+
+    /**
+     * Forces reloading of JAXB context and converters if the classpath changes.
+     */
     static {
         SystemListener.add(new SystemListener(Modules.UTILITIES) {
             @Override protected void classpathChanged() {
                 synchronized (TypeRegistration.class) {
-                    context = null;
+                    context    = null;
+                    converters = null;
                 }
             }
         });
@@ -67,39 +93,83 @@ public abstract class TypeRegistration {
     }
 
     /**
-     * Adds to the given collection every types that should be given to
-     * the initial JAXB context.
+     * Adds to the given collection every types that should be given to the initial JAXB context.
+     * The types added by this method include only implementation classes having JAXB annotations.
+     * If the module can also marshal arbitrary implementations of some interfaces (e.g. GeoAPI),
+     * then the {@link #canMarshalInterfaces()} method should be overridden.
      *
      * @param  addTo  the collection in which to add new types.
      */
-    public abstract void getTypes(final Collection<Class<?>> addTo);
+    protected abstract void getTypes(final Collection<Class<?>> addTo);
+
+    /**
+     * Returns {@code true} if the module can also marshal arbitrary implementation of some interfaces.
+     * If this method returns {@code true}, then the {@link #toImplementation(Object)} method shall be
+     * overridden.
+     *
+     * @return whether the module can also marshal arbitrary implementation of some interfaces.
+     *
+     * @since 0.8
+     */
+    protected boolean canMarshalInterfaces() {
+        return false;
+    }
 
     /**
-     * Returns the root classes of SIS objects to be marshalled by default.
-     * Those classes can be given as the last argument to the {@code MarshallerPool}
-     * constructors, in order to bound a default set of classes with {@code JAXBContext}.
+     * If the given value needs to be converted before marshalling, apply the conversion now.
+     * Otherwise returns {@code null} if the value class is not recognized, or {@code value}
+     * if the class is recognized but the value does not need to be changed.
+     *
+     * <p>Subclasses that override this method will typically perform an {@code instanceof} check, then
+     * invoke one of the {@code castOrCopy(…)} static methods defined in various Apache SIS classes.</p>
+     *
+     * <p>This method is invoked only if {@link #canMarshalInterfaces()} returns {@code true}.</p>
      *
-     * <p>The list of classes is determined dynamically from the SIS modules found on
-     * the classpath.</p>
+     * @param  value  the value to convert before marshalling.
+     * @return the value to marshall; or {@code null} if this method does not recognize the value class.
+     * @throws JAXBException if an error occurred while converting the given object.
      *
-     * @return the default set of classes to be bound to the {@code JAXBContext}.
+     * @since 0.8
      */
-    private static Class<?>[] defaultClassesToBeBound() {
+    public Object toImplementation(final Object value) throws JAXBException {
+        return null;
+    }
+
+    /**
+     * Scans the classpath for root classes to put in JAXB context and for converters to those classes.
+     * Those lists are determined dynamically from the SIS modules found on the classpath.
+     * The list of root classes is created only if the {@code getTypes} argument is {@code true}.
+     *
+     * @param  getTypes  whether to get the root classes to put in JAXB context (may cause class loading).
+     * @return if {@code getTypes} was {@code true}, the root classes to be bound in {@code JAXBContext}.
+     */
+    private static Class<?>[] load(final boolean getTypes) {
         /*
          * Implementation note: do not keep the ServiceLoader in static field because:
          *
-         * 1) It would cache the TypeRegistration instances, which are not needed after this method call.
+         * 1) It would cache more TypeRegistration instances than needed for this method call.
          * 2) The ClassLoader between different invocations may be different in an OSGi context.
          */
         final ArrayList<Class<?>> types = new ArrayList<>();
-        for (final TypeRegistration t : DefaultFactories.createServiceLoader(TypeRegistration.class)) {
-            t.getTypes(types);
+        final ArrayList<TypeRegistration> toImpl = (converters == null) ? new ArrayList<>() : null;
+        if (toImpl != null || getTypes) {
+            for (final TypeRegistration t : DefaultFactories.createServiceLoader(TypeRegistration.class)) {
+                if (getTypes) {
+                    t.getTypes(types);
+                }
+                if (toImpl != null && t.canMarshalInterfaces()) {
+                    toImpl.add(t);
+                }
+            }
+            if (toImpl != null) {
+                converters = toImpl.toArray(new TypeRegistration[toImpl.size()]);
+            }
         }
         return types.toArray(new Class<?>[types.size()]);
     }
 
     /**
-     * Returns the shared {@code JAXBContext} for the set of {@link #defaultClassesToBeBound()}.
+     * Returns the shared {@code JAXBContext} for the set of {@link #load()}.
      * Note that the {@code JAXBContext} class is thread safe, but the {@code Marshaller},
      * {@code Unmarshaller}, and {@code Validator} classes are not thread safe.
      *
@@ -114,8 +184,43 @@ public abstract class TypeRegistration {
                 return instance;
             }
         }
-        final JAXBContext instance = JAXBContext.newInstance(defaultClassesToBeBound());
+        final JAXBContext instance = JAXBContext.newInstance(load(true));
         context = new WeakReference<>(instance);
         return instance;
     }
+
+    /**
+     * Completes the given properties with an entry for {@link #ROOT_ADAPTERS} if not already present.
+     * If a {@code ROOT_ADAPTERS} entry is already present, then the map is returned unchanged.
+     *
+     * <p>This method store a direct reference to the internal {@code TypeRegistration[]} array in the given map.
+     * <strong>That array shall not be modified.</strong> This method is currently for Apache SIS internal usage only,
+     * because the {@code TypeRegistration} class is not part of public API. However if we add this functionality in a
+     * future SIS release (probably as an interface rather than exposing {@code TypeRegistration} itself), then we may
+     * consider removing this method.</p>
+     *
+     * @param  properties  the properties to complete.
+     * @return the given properties with the {@link #ROOT_ADAPTERS} entry added.
+     *
+     * @since 0.8
+     */
+    public static Map<String,?> addDefaultRootAdapters(final Map<String,?> properties) {
+        if (properties != null && properties.containsKey(ROOT_ADAPTERS)) {
+            return properties;
+        }
+        TypeRegistration[] c;
+        synchronized (TypeRegistration.class) {
+            c = converters;
+            if (c == null) {
+                load(false);
+                c = converters;
+            }
+        }
+        if (properties == null) {
+            return Collections.singletonMap(ROOT_ADAPTERS, c);
+        }
+        final Map<String,Object> copy = new HashMap<>(properties);
+        copy.put(ROOT_ADAPTERS, c);
+        return copy;
+    }
 }

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -55,6 +55,11 @@ public final class Modules {
     /**
      * The {@value} module name.
      */
+    public static final String REFERENCING_BY_IDENTIFIERS = "org.apache.sis.referencing.gazetteer";
+
+    /**
+     * The {@value} module name.
+     */
     public static final String STORAGE = "org.apache.sis.storage";
 
     /**

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/system/OptionalDependency.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/system/OptionalDependency.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/system/OptionalDependency.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/system/OptionalDependency.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -46,6 +46,7 @@ public abstract class OptionalDependency
      * @param dependency  the Maven artifact name (<strong>not</strong> a name from the {@link Modules} class)
      *        of the optional module on which the {@code module} depend.
      */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")
     protected OptionalDependency(final String module, final String dependency) {
         super(module);
         this.dependency = dependency;

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Cloner.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -91,7 +91,7 @@ public class Cloner {
         try {
             if (valueType != type) {
                 method = valueType.getMethod("clone", (Class<?>[]) null);
-                type = valueType; // Set only if the above line succeed.
+                type = valueType;                                           // Set only if the above line succeed.
                 /*
                  * If the class implementing the 'clone()' method is not public, we may not be able to access that
                  * method even if it is public. Try to make the method accessible. If we fail for security reason,

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Constants.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -37,6 +37,14 @@ import org.apache.sis.util.Static;
  */
 public final class Constants extends Static {
     /**
+     * The default indentation value to use in various text formats (both WKT and XML).
+     * We use a small value (2 instead of 4) because OGC's XML are very verbose.
+     *
+     * @see org.apache.sis.setup.OptionKey#INDENTATION
+     */
+    public static final byte DEFAULT_INDENTATION = 2;
+
+    /**
      * The {@value} code space.
      */
     public static final String EPSG = "EPSG";

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/MetadataServices.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/MetadataServices.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/MetadataServices.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/MetadataServices.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -16,7 +16,9 @@
  */
 package org.apache.sis.internal.util;
 
+import java.text.Format;
 import java.util.Locale;
+import java.util.TimeZone;
 import org.opengis.metadata.citation.Citation;
 import org.apache.sis.internal.simple.CitationConstant;
 import org.apache.sis.internal.system.Modules;
@@ -30,7 +32,7 @@ import org.apache.sis.internal.system.Op
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
- * @version 0.7
+ * @version 0.8
  * @module
  */
 public class MetadataServices extends OptionalDependency {
@@ -132,4 +134,17 @@ public class MetadataServices extends Op
     public String getInformation(String key, Locale locale) {
         return null;
     }
+
+    /**
+     * Creates a format for {@link org.opengis.geometry.DirectPosition} instances.
+     *
+     * @param  locale    the locale for the new {@code Format}, or {@code null} for {@code Locale.ROOT}.
+     * @param  timezone  the timezone, or {@code null} for UTC.
+     * @return a {@link org.apache.sis.geometry.CoordinateFormat}.
+     *
+     * @since 0.8
+     */
+    public Format createCoordinateFormat(final Locale locale, final TimeZone timezone) {
+        throw moduleNotFound();
+    }
 }

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/StreamWriterDelegate.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -72,20 +72,20 @@ public class StreamWriterDelegate implem
 
     /** Forwards the call verbatim. */
     @Override
-    public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
-        out.writeEmptyElement(namespaceURI, localName);
+    public void writeEmptyElement(String localName) throws XMLStreamException {
+        out.writeEmptyElement(localName);
     }
 
     /** Forwards the call verbatim. */
     @Override
-    public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
-        out.writeEmptyElement(prefix, localName, namespaceURI);
+    public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
+        out.writeEmptyElement(namespaceURI, localName);
     }
 
     /** Forwards the call verbatim. */
     @Override
-    public void writeEmptyElement(String localName) throws XMLStreamException {
-        out.writeEmptyElement(localName);
+    public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+        out.writeEmptyElement(prefix, localName, namespaceURI);
     }
 
     /** Forwards the call verbatim. */

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/Utilities.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -191,8 +191,10 @@ public final class Utilities extends Sta
         if (precision >= 0) {
             for (int i=0,n=0; i<length; i += n) {
                 if (--precision < 0) {
-                    // Found the amount of characters to keep. The 'n' variable can be
-                    // zero only if precision == 0, in which case the string is empty.
+                    /*
+                     * Found the amount of characters to keep. The 'n' variable can be
+                     * zero only if precision == 0, in which case the string is empty.
+                     */
                     if (n == 0) {
                         value = "";
                     } else {

Modified: sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java?rev=1789729&r1=1789728&r2=1789729&view=diff
==============================================================================
--- sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java [UTF-8] (original)
+++ sis/branches/JDK9/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java [UTF-8] Fri Mar 31 18:49:16 2017
@@ -71,7 +71,7 @@ scan:   while (offset < length) {
                     case '(': parenthesis++; break;
                     case ')': parenthesis--; break;
                     default: {
-                        if (Character.isWhitespace(c)) break;           // Not supposed to be valid, but be lenient.
+                        if (Character.isSpaceChar(c)) break;            // Not supposed to be valid, but be lenient.
                         if (parenthesis != 0) break;
                         break scan;                                     // Non-valid character outside parenthesis.
                     }



Mime
View raw message