sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1724531 [8/13] - in /sis/trunk: ./ application/sis-console/src/main/artifact/bin/ application/sis-console/src/main/artifact/log/ application/sis-console/src/main/java/org/apache/sis/console/ core/sis-build-helper/src/main/java/org/apache/s...
Date Wed, 13 Jan 2016 23:59:41 GMT
Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java?rev=1724531&r1=1724528&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -83,7 +83,6 @@ import static org.apache.sis.test.Refere
  * @module
  */
 @DependsOn({
-    org.apache.sis.referencing.factory.GeodeticObjectFactoryTest.class,
     org.apache.sis.referencing.factory.AuthorityFactoryProxyTest.class,
     org.apache.sis.referencing.factory.IdentifiedObjectFinderTest.class
 })

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/matrix/MatrixTestCase.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -100,7 +100,7 @@ public abstract strictfp class MatrixTes
      *
      * @see NonSquareMatrixTest#printStatistics()
      */
-    static final Statistics statistics = verbose ? new Statistics("|SIS - JAMA|") : null;
+    static final Statistics statistics = VERBOSE ? new Statistics("|SIS - JAMA|") : null;
 
     /**
      * Random number generator, created by {@link #initialize(long)} as the first operation of

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/LambertConicConformalTest.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -110,7 +110,7 @@ public final strictfp class LambertConic
         assertWktEqualsRegex("(?m)\\Q" +
                 "PARAM_MT[“Lambert conic conformal”,\n" +
                 "  PARAMETER[“eccentricity”, 0.0818191908426215],\n" +
-                "  PARAMETER[“n”, 0.64278760968653\\E\\d*\\]\\]");  // 0.6427876096865393 in the original test.
+                "  PARAMETER[“n”, 0.64278760968653\\E\\d*\\Q]]\\E");  // 0.6427876096865393 in the original test.
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -96,7 +96,7 @@ strictfp class MapProjectionTestCase ext
     {
         final Parameters parameters = parameters(provider, ellipse);
         if (centralMeridian  != 0) parameters.parameter(Constants.CENTRAL_MERIDIAN)   .setValue(centralMeridian, NonSI.DEGREE_ANGLE);
-        if (latitudeOfOrigin != 0) parameters.parameter("latitude_of_origin")         .setValue(latitudeOfOrigin);
+        if (latitudeOfOrigin != 0) parameters.parameter(Constants.LATITUDE_OF_ORIGIN) .setValue(latitudeOfOrigin);
         if (standardParallel != 0) parameters.parameter(Constants.STANDARD_PARALLEL_1).setValue(standardParallel);
         if (scaleFactor      != 1) parameters.parameter(Constants.SCALE_FACTOR)       .setValue(scaleFactor);
         if (falseEasting     != 0) parameters.parameter(Constants.FALSE_EASTING)      .setValue(falseEasting);

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -16,7 +16,10 @@
  */
 package org.apache.sis.referencing.operation.transform;
 
+import java.util.Map;
 import java.util.Set;
+import java.util.Collection;
+import java.util.Collections;
 import org.opengis.util.FactoryException;
 import org.opengis.util.NoSuchIdentifierException;
 import org.opengis.referencing.operation.Conversion;
@@ -25,11 +28,21 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.parameter.ParameterValueGroup;
+import org.apache.sis.parameter.Parameterized;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.referencing.operation.DefaultConversion;
 import org.apache.sis.referencing.operation.matrix.Matrix2;
+import org.apache.sis.referencing.crs.DefaultProjectedCRS;
+import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
 import org.apache.sis.internal.referencing.provider.Affine;
 import org.apache.sis.internal.referencing.provider.Mercator1SP;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.util.Constants;
+import org.apache.sis.util.CharSequences;
+
+// Test dependencies
+import org.apache.sis.referencing.cs.HardCodedCS;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -45,7 +58,7 @@ import static org.apache.sis.test.Assert
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
- * @version 0.6
+ * @version 0.7
  * @module
  */
 @DependsOn({
@@ -162,4 +175,68 @@ public final strictfp class DefaultMathT
                 1, 7,
                 0, 1), MathTransforms.getMatrix(tr), STRICT);
     }
+
+    /**
+     * Tests the creation of all registered map projections.
+     * Only the semi-axis lengths are specified. For the rest, we rely on default values.
+     *
+     * @throws FactoryException if the construction of a map projection failed.
+     *
+     * @since 0.7
+     */
+    @Test
+    public void testAllMapProjections() throws FactoryException {
+        /*
+         * Gets all map projections and creates a projection using the WGS84 ellipsoid
+         * and default parameter values.
+         */
+        final Map<String,?> dummyName = Collections.singletonMap(DefaultProjectedCRS.NAME_KEY, "Test");
+        final MathTransformFactory mtFactory = DefaultFactories.forBuildin(MathTransformFactory.class);
+        final Collection<OperationMethod> methods = mtFactory.getAvailableMethods(Projection.class);
+        for (final OperationMethod method : methods) {
+            final String classification = method.getName().getCode();
+            ParameterValueGroup param = mtFactory.getDefaultParameters(classification);
+            param.parameter("semi_major").setValue(6377563.396);
+            param.parameter("semi_minor").setValue(6356256.909237285);
+            final MathTransform mt;
+            try {
+                mt = mtFactory.createParameterizedTransform(param);
+            } catch (InvalidGeodeticParameterException e) {
+                // Some map projections have mandatory parameters which we ignore for now
+                // except for a few well-known projection that we know should not fail.
+                if (classification.contains("Mercator")) {
+                    throw e;
+                }
+                out.print(classification);
+                out.print(CharSequences.spaces(42 - classification.length()));
+                out.print(": ");
+                out.println(e.getLocalizedMessage());
+                continue;
+            }
+            /*
+             * Verifies that the map projection properties are the ones that we specified.
+             * Note that the Equirectangular projection has been optimized as an affine transform, which we skip.
+             */
+            if (mt instanceof LinearTransform) {
+                continue;
+            }
+            assertInstanceOf(classification, Parameterized.class, mt);
+            param = ((Parameterized) mt).getParameterValues();
+            assertEquals(classification, param.getDescriptor().getName().getCode());
+            assertEquals(classification, 6377563.396,       param.parameter("semi_major").doubleValue(), 1E-4);
+            assertEquals(classification, 6356256.909237285, param.parameter("semi_minor").doubleValue(), 1E-4);
+            /*
+             * Creates a ProjectedCRS from the map projection. This part is more an integration test than
+             * a DefaultMathTransformFactory test. Again, the intend is to verify that the properties are
+             * the one that we specified.
+             */
+            final DefaultProjectedCRS crs = new DefaultProjectedCRS(dummyName,
+                    CommonCRS.WGS84.normalizedGeographic(),
+                    new DefaultConversion(dummyName, method, mt, null),
+                    HardCodedCS.PROJECTED);
+            final Conversion projection = crs.getConversionFromBase();
+            assertSame(classification, mt, projection.getMathTransform());
+            assertEquals(classification, projection.getMethod().getName().getCode());
+        }
+    }
 }

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -59,11 +59,7 @@ public final strictfp class EllipsoidToC
      */
     private void createGeodeticConversion(final Ellipsoid ellipsoid, boolean is3D) throws FactoryException {
         transform = EllipsoidToCentricTransform.createGeodeticConversion(
-                DefaultFactories.forBuildin(MathTransformFactory.class),
-                ellipsoid.getSemiMajorAxis(),
-                ellipsoid.getSemiMinorAxis(),
-                ellipsoid.getAxisUnit(), is3D,
-                EllipsoidToCentricTransform.TargetType.CARTESIAN);
+                DefaultFactories.forBuildin(MathTransformFactory.class), ellipsoid, is3D);
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MathTransformTestCase.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -328,6 +328,19 @@ public abstract strictfp class MathTrans
     }
 
     /**
+     * Asserts that the current {@linkplain #transform transform} produces an internal WKT
+     * matching the given regular expression.
+     *
+     * @param expected A regular expression for the expected internal WKT.
+     *
+     * @since 0.7
+     */
+    protected final void assertInternalWktEqualsRegex(final String expected) {
+        assertNotNull("The 'transform' field shall be assigned a value.", transform);
+        ReferencingAssert.assertWktEqualsRegex(Convention.INTERNAL, expected, transform);
+    }
+
+    /**
      * Prints the current {@linkplain #transform transform} as normal and internal WKT.
      * This method is for debugging purpose only.
      *

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/MolodenskyTransformTest.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -25,9 +25,8 @@ import org.apache.sis.internal.referenci
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.referencing.Formulas;
 import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.measure.Longitude;
 
-import static java.lang.StrictMath.toRadians;
+import static java.lang.StrictMath.*;
 
 // Test dependencies
 import org.apache.sis.internal.referencing.provider.GeocentricTranslationTest;
@@ -41,7 +40,10 @@ import static org.apache.sis.test.Assert
 
 
 /**
- * Tests {@link MolodenskyTransform}.
+ * Tests {@link MolodenskyTransform}. The {@link #compareWithGeocentricTranslation()}
+ * method uses {@link EllipsoidToCentricTransform} as a reference implementation.
+ * The errors compared to geocentric translations should not be greater than
+ * approximatively 1 centimetre.
  *
  * @author  Tara Athan
  * @author  Martin Desruisseaux (Geomatys)
@@ -52,10 +54,23 @@ import static org.apache.sis.test.Assert
  */
 @DependsOn({
     CoordinateDomainTest.class,
-    ContextualParametersTest.class
+    ContextualParametersTest.class,
+    EllipsoidToCentricTransformTest.class   // Used as a reference implementation
 })
 public final strictfp class MolodenskyTransformTest extends MathTransformTestCase {
     /**
+     * Creates a new test case.
+     */
+    public MolodenskyTransformTest() {
+        final double delta = toRadians(100.0 / 60) / 1852;      // Approximatively 100 metres
+        derivativeDeltas   = new double[] {delta, delta, 100};  // (Δλ, Δφ, Δh)
+        λDimension         = new int[] {0};                     // Dimension for which to ignore ±360° differences.
+        zDimension         = new int[] {2};                     // Dimension of h where to apply zTolerance
+        zTolerance         = Formulas.LINEAR_TOLERANCE;         // Tolerance for ellipsoidal heights (h)
+        tolerance          = Formulas.ANGULAR_TOLERANCE;        // Tolerance for longitude and latitude in degrees
+    }
+
+    /**
      * Creates a Molodensky transform for a datum shift from WGS84 to ED50.
      * Tolerance thresholds are also initialized.
      *
@@ -66,13 +81,14 @@ public final strictfp class MolodenskyTr
         final Ellipsoid target = CommonCRS.ED50.ellipsoid();
         transform = MolodenskyTransform.createGeodeticTransformation(
                 DefaultFactories.forBuildin(MathTransformFactory.class),
-                source, true, target, true, 84.87, 96.49, 116.95, abridged);
+                source, true, target, true,
+                GeocentricTranslationTest.TX,
+                GeocentricTranslationTest.TY,
+                GeocentricTranslationTest.TZ,
+                abridged);
 
-        final double delta = toRadians(100.0 / 60) / 1852;          // Approximatively 100 metres
-        derivativeDeltas = new double[] {delta, delta, 100};        // (Δλ, Δφ, Δh)
         tolerance  = GeocentricTranslationTest.precision(1);        // Half the precision of target sample point
         zTolerance = GeocentricTranslationTest.precision(3);        // Required precision for h
-        zDimension = new int[] {2};                                 // Dimension of h where to apply zTolerance
         assertFalse(transform.isIdentity());
         validate();
     }
@@ -168,8 +184,8 @@ public final strictfp class MolodenskyTr
 
     /**
      * Tests conversion of random points. The test is performed with the Molodensky transform,
-     * not the abridged one, because the errors caused by the abridged Molondeky method is too
-     * high for this test.
+     * not the abridged one, because the errors caused by the abridged Molodensky method are
+     * too high for this test.
      *
      * @throws FactoryException if an error occurred while creating a transform step.
      * @throws TransformException if a transformation failed.
@@ -181,9 +197,9 @@ public final strictfp class MolodenskyTr
         tolerance  = Formulas.LINEAR_TOLERANCE * 3;     // To be converted in degrees by ToleranceModifier.GEOGRAPHIC
         zTolerance = Formulas.LINEAR_TOLERANCE * 2;
 //      toleranceModifier = ToleranceModifiers.concatenate(ToleranceModifier.GEOGRAPHIC, toleranceModifier);
-        verifyInDomain(new double[] {Longitude.MIN_VALUE, -85, -500},
-                       new double[] {Longitude.MIN_VALUE, +85, +500},
-                       new int[] {8, 8, 8},
+        verifyInDomain(new double[] {-179, -85, -500},
+                       new double[] {+179, +85, +500},
+                       new int[]    {   8,   8,    8},
                        TestUtilities.createRandomNumberGenerator(208129394));
     }
 
@@ -209,11 +225,8 @@ public final strictfp class MolodenskyTr
         transform = factory.createParameterizedTransform(parameters);
         assertEquals(3, transform.getSourceDimensions());
         assertEquals(3, transform.getTargetDimensions());
-        final double delta = toRadians(100.0 / 60) / 1852;          // Approximatively 100 metres
-        derivativeDeltas = new double[] {delta, delta, 100};        // (Δλ, Δφ, Δh)
-        tolerance = Formulas.ANGULAR_TOLERANCE * 5;
-        zTolerance = Formulas.LINEAR_TOLERANCE * 5;
-        zDimension = new int[] {2};
+        tolerance  = Formulas.ANGULAR_TOLERANCE * 5;
+        zTolerance = Formulas.LINEAR_TOLERANCE  * 5;
         verifyInDomain(CoordinateDomain.RANGE_10, ORDINATE_COUNT);
     }
 
@@ -245,28 +258,28 @@ public final strictfp class MolodenskyTr
         create(true);
         assertWktEquals("PARAM_MT[“Abridged_Molodenski”,\n" +
                         "  PARAMETER[“dim”, 3],\n" +
+                        "  PARAMETER[“src_semi_major”, 6378137.0],\n" +
+                        "  PARAMETER[“src_semi_minor”, 6356752.314245179],\n" +
+                        "  PARAMETER[“tgt_semi_major”, 6378388.0],\n" +
+                        "  PARAMETER[“tgt_semi_minor”, 6356911.9461279465],\n" +
                         "  PARAMETER[“dx”, 84.87],\n" +
                         "  PARAMETER[“dy”, 96.49],\n" +
                         "  PARAMETER[“dz”, 116.95],\n" +
                         "  PARAMETER[“Semi-major axis length difference”, 251.0],\n" +
-                        "  PARAMETER[“Flattening difference”, 1.4192702255886284E-5],\n" +
-                        "  PARAMETER[“src_semi_major”, 6378137.0],\n" +
-                        "  PARAMETER[“src_semi_minor”, 6356752.314245179],\n" +
-                        "  PARAMETER[“tgt_semi_major”, 6378388.0],\n" +
-                        "  PARAMETER[“tgt_semi_minor”, 6356911.9461279465]]");
+                        "  PARAMETER[“Flattening difference”, 1.4192702255886284E-5]]");
 
         transform = transform.inverse();
         assertWktEquals("PARAM_MT[“Abridged_Molodenski”,\n" +
                         "  PARAMETER[“dim”, 3],\n" +
+                        "  PARAMETER[“src_semi_major”, 6378388.0],\n" +
+                        "  PARAMETER[“src_semi_minor”, 6356911.9461279465],\n" +
+                        "  PARAMETER[“tgt_semi_major”, 6378137.0],\n" +
+                        "  PARAMETER[“tgt_semi_minor”, 6356752.314245179],\n" +
                         "  PARAMETER[“dx”, -84.87],\n" +
                         "  PARAMETER[“dy”, -96.49],\n" +
                         "  PARAMETER[“dz”, -116.95],\n" +
                         "  PARAMETER[“Semi-major axis length difference”, -251.0],\n" +
-                        "  PARAMETER[“Flattening difference”, -1.4192702255886284E-5],\n" +
-                        "  PARAMETER[“src_semi_major”, 6378388.0],\n" +
-                        "  PARAMETER[“src_semi_minor”, 6356911.9461279465],\n" +
-                        "  PARAMETER[“tgt_semi_major”, 6378137.0],\n" +
-                        "  PARAMETER[“tgt_semi_minor”, 6356752.314245179]]");
+                        "  PARAMETER[“Flattening difference”, -1.4192702255886284E-5]]");
     }
 
     /**
@@ -288,13 +301,13 @@ public final strictfp class MolodenskyTr
                 "    Parameter[“elt_0_0”, 0.017453292519943295],\n" +       // Degrees to radians conversion
                 "    Parameter[“elt_1_1”, 0.017453292519943295]],\n" +
                 "  Param_MT[“Molodensky”,\n" +
+                "    Parameter[“src_semi_major”, 6378137.0],\n" +
+                "    Parameter[“src_semi_minor”, 6356752.314245179],\n" +
+                "    Parameter[“Semi-major axis length difference”, 251.0],\n" +
+                "    Parameter[“Flattening difference”, 1.4192702255886284E-5],\n" +
                 "    Parameter[“X-axis translation”, 84.87],\n" +
                 "    Parameter[“Y-axis translation”, 96.49],\n" +
                 "    Parameter[“Z-axis translation”, 116.95],\n" +
-                "    Parameter[“Semi-major axis length difference”, 251.0],\n" +
-                "    Parameter[“Flattening difference”, 1.4192702255886284E-5],\n" +
-                "    Parameter[“src_semi_major”, 6378137.0],\n" +
-                "    Parameter[“eccentricity”, 0.0818191908426215],\n" +
                 "    Parameter[“abridged”, TRUE],\n" +
                 "    Parameter[“dim”, 3]],\n" +
                 "  Param_MT[“Affine”,\n" +

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ProjectiveTransformTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ProjectiveTransformTest.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ProjectiveTransformTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/ProjectiveTransformTest.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -91,7 +91,7 @@ public strictfp class ProjectiveTransfor
                      * Opportunistically tests ScaledTransform together with ProjectiveTransform.
                      * We takes ScaledTransform as a reference implementation since it is simpler.
                      */
-                    tr = new TransformResultComparator(tr, pt);
+                    tr = new TransformResultComparator(tr, pt, 0);
                 }
                 return tr;
             }

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformResultComparator.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -48,16 +48,17 @@ final strictfp class TransformResultComp
     final MathTransform tested;
 
     /**
-     * The tolerance threshold, which is zero by default.
+     * The tolerance threshold.
      */
-    double tolerance;
+    private final double tolerance;
 
     /**
      * Creates a transform which will compare the results of the two given transforms.
      */
-    TransformResultComparator(final MathTransform reference, final MathTransform tested) {
+    TransformResultComparator(final MathTransform reference, final MathTransform tested, final double tolerance) {
         this.reference = reference;
         this.tested    = tested;
+        this.tolerance = tolerance;
     }
 
     /**
@@ -173,7 +174,7 @@ final strictfp class TransformResultComp
      */
     @Override
     public MathTransform inverse() throws NoninvertibleTransformException {
-        return new TransformResultComparator(reference.inverse(), tested.inverse());
+        return new TransformResultComparator(reference.inverse(), tested.inverse(), tolerance);
     }
 
     /**

Copied: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java (from r1724528, sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java)
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java?p2=sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java&p1=sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java&r1=1724528&r2=1724531&rev=1724531&view=diff
==============================================================================
--- sis/branches/JDK6/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/transform/TransformSeparatorTest.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -30,7 +30,7 @@ import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
-import static org.opengis.test.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/ReferencingAssert.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -45,6 +45,9 @@ import org.apache.sis.internal.util.Cons
 
 import static java.lang.StrictMath.*;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk8.JDK8;
+
 
 /**
  * Assertion methods used by the {@code sis-referencing} module in addition of the ones inherited
@@ -372,7 +375,7 @@ public strictfp class ReferencingAssert
             assertFalse("e2.contains(e1)",   ae.contains  (e1, true));
         }
         final int dimension = e1.getDimension();
-        final int numCases = (int) round(pow(3, dimension));
+        final int numCases = JDK8.toIntExact(round(pow(3, dimension)));
         final GeneralDirectPosition pos = new GeneralDirectPosition(dimension);
         for (int index=0; index<numCases; index++) {
             int n = index;

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/integration/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/integration/package-info.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/integration/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/integration/package-info.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -17,11 +17,14 @@
 
 
 /**
- * Tests the integration between two ore more SIS modules.
+ * Tests the integration between two ore more SIS modules or integration with larger data.
+ * The larger data (e.g. datum shift grids) are not distributed with SIS. If desired, they
+ * must be downloaded by the user and stored in the directory identified by the {@code SIS_DATA}
+ * environment variable.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.7
  * @module
  */
 package org.apache.sis.test.integration;

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -52,7 +52,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.matrix.Matrix2Test.class,
     org.apache.sis.referencing.operation.matrix.Matrix3Test.class,
     org.apache.sis.referencing.operation.matrix.Matrix4Test.class,
-    org.apache.sis.referencing.operation.matrix.NonSquareMatrixTest.class, // Expected to be last MatrixTestCase - see javadoc.
+    org.apache.sis.referencing.operation.matrix.NonSquareMatrixTest.class,          // Expected to be last MatrixTestCase - see javadoc.
     org.apache.sis.referencing.operation.matrix.MatricesTest.class,
     org.apache.sis.referencing.operation.matrix.AffineTransforms2DTest.class,
 
@@ -62,6 +62,7 @@ import org.junit.BeforeClass;
     org.apache.sis.parameter.DefaultParameterValueTest.class,
     org.apache.sis.parameter.DefaultParameterValueGroupTest.class,
     org.apache.sis.parameter.UnmodifiableParameterValueTest.class,
+    org.apache.sis.parameter.UnmodifiableParameterValueGroupTest.class,
     org.apache.sis.parameter.ParametersTest.class,
     org.apache.sis.parameter.ParameterBuilderTest.class,
     org.apache.sis.parameter.ParameterFormatTest.class,
@@ -113,6 +114,7 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.operation.transform.CopyTransformTest.class,
     org.apache.sis.referencing.operation.transform.PassThroughTransformTest.class,
     org.apache.sis.referencing.operation.transform.ConcatenatedTransformTest.class,
+    org.apache.sis.referencing.operation.transform.TransformSeparatorTest.class,
     org.apache.sis.referencing.operation.transform.TransferFunctionTest.class,
     org.apache.sis.referencing.operation.transform.MathTransformsTest.class,
     org.apache.sis.referencing.operation.transform.ContextualParametersTest.class,
@@ -131,8 +133,16 @@ import org.junit.BeforeClass;
     org.apache.sis.internal.referencing.provider.GeocentricTranslationTest.class,
     org.apache.sis.internal.referencing.provider.PositionVector7ParamTest.class,
     org.apache.sis.internal.referencing.provider.CoordinateFrameRotationTest.class,
+    org.apache.sis.internal.referencing.provider.MolodenskyTest.class,
+    org.apache.sis.internal.referencing.provider.FranceGeocentricInterpolationTest.class,
+    org.apache.sis.internal.referencing.provider.NTv2Test.class,
+    org.apache.sis.internal.referencing.provider.NADCONTest.class,
     org.apache.sis.internal.referencing.provider.MapProjectionTest.class,
+    org.apache.sis.internal.referencing.provider.TransverseMercatorTest.class,
     org.apache.sis.internal.referencing.provider.AllProvidersTest.class,
+    org.apache.sis.referencing.operation.transform.InterpolatedTransformTest.class,
+    org.apache.sis.referencing.operation.transform.InterpolatedGeocentricTransformTest.class,
+    org.apache.sis.referencing.operation.transform.InterpolatedMolodenskyTransformTest.class,
     org.apache.sis.referencing.operation.transform.DefaultMathTransformFactoryTest.class,
 
     // Test map projections. Those tests need the providers tested above.
@@ -161,6 +171,11 @@ import org.junit.BeforeClass;
     org.apache.sis.referencing.CommonCRSTest.class,
     org.apache.sis.referencing.CRSTest.class,
 
+    org.apache.sis.referencing.factory.CommonAuthorityFactoryTest.class,
+    org.apache.sis.referencing.factory.AuthorityFactoryProxyTest.class,
+    org.apache.sis.referencing.factory.IdentifiedObjectFinderTest.class,
+    org.apache.sis.referencing.factory.sql.EPSGFactoryTest.class,
+
     org.apache.sis.io.wkt.MathTransformParserTest.class,
     org.apache.sis.io.wkt.GeodeticObjectParserTest.class,
     org.apache.sis.io.wkt.WKTFormatTest.class,
@@ -181,6 +196,7 @@ import org.junit.BeforeClass;
 
     org.apache.sis.referencing.operation.builder.LinearTransformBuilderTest.class,
     org.apache.sis.internal.referencing.ServicesForMetadataTest.class,
+    org.apache.sis.test.integration.DatumShiftTest.class,
     org.apache.sis.test.integration.ReferencingInMetadataTest.class,
     org.apache.sis.test.integration.DefaultMetadataTest.class
 })

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/converter/PathConverter.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/converter/PathConverter.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/converter/PathConverter.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/converter/PathConverter.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -36,7 +36,7 @@ import org.apache.sis.util.Unconvertible
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.7
  * @module
  */
 abstract class PathConverter<S,T> extends SystemConverter<S,T> {
@@ -98,7 +98,7 @@ abstract class PathConverter<S,T> extend
     public static final class FileURI extends PathConverter<File,URI> {
         private static final long serialVersionUID = 1122784850124333991L;
         static final FileURI INSTANCE = new FileURI();
-        public FileURI() {super(File.class, URI.class);} // Instantiated by ServiceLoader.
+        public FileURI() {super(File.class, URI.class);}        // Instantiated by ServiceLoader.
 
         @Override public ObjectConverter<File,URI> unique()  {return INSTANCE;}
         @Override public ObjectConverter<URI,File> inverse() {return URIFile.INSTANCE;}
@@ -113,7 +113,7 @@ abstract class PathConverter<S,T> extend
     public static final class FileURL extends PathConverter<File,URL> {
         private static final long serialVersionUID = 2191394598748096966L;
         static final FileURL INSTANCE = new FileURL();
-        public FileURL() {super(File.class, URL.class);} // Instantiated by ServiceLoader.
+        public FileURL() {super(File.class, URL.class);}        // Instantiated by ServiceLoader.
 
         @Override public ObjectConverter<File,URL> unique()  {return INSTANCE;}
         @Override public ObjectConverter<URL,File> inverse() {return URLFile.INSTANCE;}
@@ -128,7 +128,7 @@ abstract class PathConverter<S,T> extend
     public static final class URLFile extends PathConverter<URL,File> {
         private static final long serialVersionUID = 3669726699184691997L;
         static final URLFile INSTANCE = new URLFile();
-        public URLFile() {super(URL.class, File.class);} // Instantiated by ServiceLoader.
+        public URLFile() {super(URL.class, File.class);}        // Instantiated by ServiceLoader.
 
         @Override public ObjectConverter<URL,File> unique()  {return INSTANCE;}
         @Override public ObjectConverter<File,URL> inverse() {return FileURL.INSTANCE;}
@@ -138,12 +138,12 @@ abstract class PathConverter<S,T> extend
     }
 
     /**
-     * Converter from {@link URL} to {@link File}.
+     * Converter from {@link URI} to {@link File}.
      */
     public static final class URIFile extends PathConverter<URI,File> {
         private static final long serialVersionUID = 5070991554943811760L;
         static final URIFile INSTANCE = new URIFile();
-        public URIFile() {super(URI.class, File.class);} // Instantiated by ServiceLoader.
+        public URIFile() {super(URI.class, File.class);}        // Instantiated by ServiceLoader.
 
         @Override public ObjectConverter<URI,File> unique()  {return INSTANCE;}
         @Override public ObjectConverter<File,URI> inverse() {return FileURI.INSTANCE;}
@@ -158,7 +158,7 @@ abstract class PathConverter<S,T> extend
     public static final class URL_URI extends PathConverter<URL,URI> {
         private static final long serialVersionUID = 6327568235014244008L;
         static final URL_URI INSTANCE = new URL_URI();
-        public URL_URI() {super(URL.class, URI.class);} // Instantiated by ServiceLoader.
+        public URL_URI() {super(URL.class, URI.class);}         // Instantiated by ServiceLoader.
 
         @Override public ObjectConverter<URL,URI> unique()  {return INSTANCE;}
         @Override public ObjectConverter<URI,URL> inverse() {return URI_URL.INSTANCE;}
@@ -173,7 +173,7 @@ abstract class PathConverter<S,T> extend
     public static final class URI_URL extends PathConverter<URI,URL> {
         private static final long serialVersionUID = 5478354821309176895L;
         static final URI_URL INSTANCE = new URI_URL();
-        public URI_URL() {super(URI.class, URL.class);} // Instantiated by ServiceLoader.
+        public URI_URL() {super(URI.class, URL.class);}         // Instantiated by ServiceLoader.
 
         @Override public ObjectConverter<URI,URL> unique()  {return INSTANCE;}
         @Override public ObjectConverter<URL,URI> inverse() {return URL_URI.INSTANCE;}

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/converter/package-info.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/converter/package-info.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/converter/package-info.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/converter/package-info.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -43,7 +43,7 @@
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.7
  * @module
  */
 package org.apache.sis.internal.converter;

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/AutoCloseable.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/AutoCloseable.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/AutoCloseable.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/AutoCloseable.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -16,22 +16,24 @@
  */
 package org.apache.sis.internal.jdk7;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
 
 /**
  * Placeholder for the {@link java.lang.AutoCloseable} interface.
+ * Class annotated by this annotation must have a public {@code close()} method.
  * {@code instanceof} checks and calls to {@code ((AutoCloseable) object).close()} need to be replaced
  * by calls to {@link JDK7#isAutoCloseable(Object)} and {@link JDK7#close(Object)} respectively.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.7
  * @module
  */
-public interface AutoCloseable {
-    /**
-     * See {@link java.lang.AutoCloseable#close()}.
-     *
-     * @throws Exception If an error occurred while closing the resource.
-     */
-    void close() throws Exception;
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AutoCloseable {
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Files.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Files.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Files.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Files.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -18,9 +18,17 @@ package org.apache.sis.internal.jdk7;
 
 import java.util.Set;
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.channels.ByteChannel;
+import java.nio.charset.Charset;
+
 
 /**
  * Place holder for {@link java.nio.file.Files}.
@@ -28,7 +36,7 @@ import java.nio.channels.ByteChannel;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.4
- * @version 0.4
+ * @version 0.7
  * @module
  */
 public final class Files {
@@ -39,6 +47,111 @@ public final class Files {
     }
 
     /**
+     * Creates the directory at the given path.
+     * This method does not create parent directories.
+     *
+     * @param dir The directory to create.
+     * @return The given path.
+     * @throws IOException if the directory can not be created.
+     *
+     * @since 0.7
+     */
+    public static Path createDirectory(final Path dir) throws IOException {
+        if (!dir.mkdir()) {
+            throw new IOException("Can not create directory: " + dir);
+        }
+        return dir;
+    }
+
+    /**
+     * Returns {@code true} if the given path is a directory.
+     *
+     * @param path The path to test.
+     * @return {@code true} if the path is a directory.
+     *
+     * @since 0.7
+     */
+    public static boolean isDirectory(final Path path) {
+        return path.isDirectory();
+    }
+
+    /**
+     * Returns {@code true} if the given path is an ordinary file.
+     *
+     * @param path The path to test.
+     * @return {@code true} if the path is a file.
+     *
+     * @since 0.7
+     */
+    public static boolean isRegularFile(final Path path) {
+        return path.isFile();
+    }
+
+    /**
+     * Returns {@code true} if the file at the given path can be read.
+     *
+     * @param path The path to test.
+     * @return {@code true} if file at the given path can be read.
+     *
+     * @since 0.7
+     */
+    public static boolean isReadable(final Path path) {
+        return path.canRead();
+    }
+
+    /**
+     * Returns {@code true} if the file at the given path can be written.
+     *
+     * @param path The path to test.
+     * @return {@code true} if file at the given path can be written.
+     *
+     * @since 0.7
+     */
+    public static boolean isWritable(final Path path) {
+        return path.canWrite();
+    }
+
+    /**
+     * Returns {@code true} if the given file or directory exits.
+     *
+     * @param path The path to test.
+     * @return {@code true} if file or directory exists.
+     *
+     * @since 0.7
+     */
+    public static boolean exists(final Path path) {
+        return path.exists();
+    }
+
+    /**
+     * Creates a new buffered reader for the given character encoding.
+     *
+     * @param path The path of the file to read.
+     * @param cs The character encoding to use.
+     * @return The reader.
+     * @throws IOException if an error occurred while creating the reader.
+     *
+     * @since 0.7
+     */
+    public static BufferedReader newBufferedReader(final Path path, final Charset cs) throws IOException {
+        return new BufferedReader(new InputStreamReader(new FileInputStream(path), cs.newDecoder()));
+    }
+
+    /**
+     * Creates a new buffered writer for the given character encoding.
+     *
+     * @param path The path of the file to write.
+     * @param cs The character encoding to use.
+     * @return The writer.
+     * @throws IOException if an error occurred while creating the writer.
+     *
+     * @since 0.7
+     */
+    public static BufferedWriter newBufferedWriter(final Path path, final Charset cs) throws IOException {
+        return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path), cs.newEncoder()));
+    }
+
+    /**
      * Simulates {@link java.nio.file.Files#newByteChannel(java.nio.file.Path, java.nio.file.OpenOption[])}.
      *
      * @param  file    The file to open.
@@ -59,4 +172,15 @@ public final class Files {
         }
         return new RandomAccessFile(file, mode).getChannel();
     }
+
+    /**
+     * Creates a new byte channel.
+     *
+     * @param  path    The file to open.
+     * @return The channel.
+     * @throws IOException If an error occurred while opening the channel.
+     */
+    public static ByteChannel newByteChannel(final Path path) throws IOException {
+        return newByteChannel(path, null);
+    }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/JDK7.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/JDK7.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/JDK7.java [iso-8859-1] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/JDK7.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -21,6 +21,7 @@ import java.sql.Connection;
 import java.sql.Statement;
 import java.sql.ResultSet;
 import javax.imageio.stream.ImageInputStream;
+import java.lang.reflect.InvocationTargetException;
 
 
 /**
@@ -29,7 +30,7 @@ import javax.imageio.stream.ImageInputSt
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from GeoAPI)
- * @version 0.3
+ * @version 0.7
  * @module
  */
 public final class JDK7 {
@@ -93,14 +94,26 @@ public final class JDK7 {
     }
 
     /**
+     * Compares to integer values.
+     *
+     * @param x First value to compare.
+     * @param y Second value to compare.
+     * @return Comparison result.
+     */
+    public static int compare(final int x, final int y) {
+        return (x < y) ? -1 : (x == y) ? 0 : 1;
+    }
+
+    /**
      * Simulates the {@code object instanceof AutoCloseable} code.
      *
      * @param  object The object to check, or {@code null}.
      * @return {@code true} if the given object is closeable.
      */
     public static boolean isAutoCloseable(final Object object) {
-        return (object instanceof AutoCloseable) || (object instanceof Closeable) || (object instanceof ImageInputStream) ||
-                (object instanceof Connection) || (object instanceof Statement) || (object instanceof ResultSet);
+        return (object instanceof Closeable) || (object instanceof ImageInputStream) ||
+               (object instanceof Connection) || (object instanceof Statement) || (object instanceof ResultSet) ||
+               (object != null && object.getClass().isAnnotationPresent(AutoCloseable.class));
     }
 
     /**
@@ -117,6 +130,15 @@ public final class JDK7 {
         else if (object instanceof Connection)       ((Connection)       object).close();
         else if (object instanceof Statement)        ((Statement)        object).close();
         else if (object instanceof ResultSet)        ((ResultSet)        object).close();
-        else ((AutoCloseable) object).close(); // Intentionally no 'instanceof' check.
+        else try {
+            object.getClass().getMethod("close", (Class<?>[]) null).invoke(object, (Object[]) null);
+        } catch (InvocationTargetException e) {
+            final Throwable cause = e.getTargetException();
+            if (cause instanceof Exception) {
+                throw (Exception) cause;
+            } else {
+                throw e;
+            }
+        }
     }
 }

Propchange: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/JDK7.java
------------------------------------------------------------------------------
--- svn:mime-type (original)
+++ svn:mime-type Wed Jan 13 23:59:38 2016
@@ -1 +1 @@
-text/plain
+text/plain;charset=UTF-8

Propchange: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk7/Objects.java
------------------------------------------------------------------------------
--- svn:mime-type (original)
+++ svn:mime-type Wed Jan 13 23:59:38 2016
@@ -1 +1 @@
-text/plain
+text/plain;charset=UTF-8

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/jdk8/JDK8.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -26,8 +26,18 @@ import java.util.Locale;
 import java.util.TimeZone;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicReference;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
 import javax.xml.bind.DatatypeConverter;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk7.JDK7;
+import org.apache.sis.internal.jdk7.Objects;
+import org.apache.sis.internal.jdk7.Files;
+import org.apache.sis.internal.jdk7.Path;
+import org.apache.sis.internal.jdk7.StandardCharsets;
+
 
 /**
  * Place holder for some functionalities defined only in JDK8.
@@ -35,7 +45,7 @@ import javax.xml.bind.DatatypeConverter;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.6
+ * @version 0.7
  * @module
  */
 public final class JDK8 {
@@ -53,6 +63,74 @@ public final class JDK8 {
     }
 
     /**
+     * Compares two numbers as unsigned.
+     *
+     * @param  x First unsigned value.
+     * @param  y Second unsigned value.
+     * @return Comparison result.
+     *
+     * @since 0.7
+     */
+    public static int compareUnsigned(final int x, final int y) {
+        return JDK7.compare(x + Integer.MIN_VALUE, y + Integer.MIN_VALUE);
+    }
+
+    /**
+     * Returns the given byte as an unsigned integer.
+     *
+     * @param x The byte to return as an unsigned integer.
+     * @return The unsigned value of the given byte.
+     *
+     * @since 0.7
+     */
+    public static int toUnsignedInt(final byte x) {
+        return x & 0xFF;
+    }
+
+    /**
+     * Returns the given short as an unsigned integer.
+     *
+     * @param x The short to return as an unsigned integer.
+     * @return The unsigned value of the given short.
+     *
+     * @since 0.7
+     */
+    public static int toUnsignedInt(final short x) {
+        return x & 0xFFFF;
+    }
+
+    /**
+     * Safe cast of the given long to integer.
+     *
+     * @param value The value to cast.
+     * @return The casted value.
+     * @throws ArithmeticException if the value overflows.
+     *
+     * @since 0.7
+     */
+    public static int toIntExact(final long value) {
+        final int vi = (int) value;
+        if (vi != value) {
+            throw new ArithmeticException();
+        }
+        return vi;
+    }
+
+    /**
+     * Safe product of the arguments.
+     *
+     * @param x The first value.
+     * @param y The second value.
+     * @return The product.
+     * @throws ArithmeticException if the value overflows.
+     *
+     * @since 0.7
+     */
+    public static int multiplyExact(final int x, final int y) {
+        return toIntExact(x * (long) y);
+    }
+
+    /**
      * Returns the floating-point value adjacent to {@code value} in the direction of negative infinity.
      *
      * @param  value The value for which to get the adjacent value.
@@ -102,6 +180,27 @@ public final class JDK8 {
     }
 
     /**
+     * Removes the entry for the given key, provided that it is currently mapped to the given value.
+     *
+     * @param  <K>   The type of keys.
+     * @param  <V>   The type of values.
+     * @param  map   The map from where to remove the value.
+     * @param  key   The key for the value to remove.
+     * @param  value The value that must exist for allowing removal.
+     * @return {@code true} if the entry has been removed.
+     *
+     * @since 0.7
+     */
+    public static <K,V> boolean remove(final Map<K,V> map, final Object key, final Object value) {
+        final Object current = map.get(key);
+        final boolean c = Objects.equals(current, value) && (current != null || map.containsKey(key));
+        if (c) {
+            map.remove(key);
+        }
+        return c;
+    }
+
+    /**
      * Removes all elements for which the given filter returns {@code true}.
      *
      * @param  <E>        The type of elements in the given collection.
@@ -193,7 +292,33 @@ public final class JDK8 {
         }
         calendar.setTime(date);
         final String text = DatatypeConverter.printDateTime(calendar);
-        CALENDAR.set(calendar); // Recycle for future usage.
+        CALENDAR.set(calendar);                                                 // Recycle for future usage.
         return text;
     }
+
+    /**
+     * Creates a buffered reader using UTF-8 encoding.
+     *
+     * @param path The file to open.
+     * @return The reader.
+     * @throws IOException if an error occurred while opening the reader.
+     *
+     * @since 0.7
+     */
+    public static BufferedReader newBufferedReader(final Path path) throws IOException {
+        return Files.newBufferedReader(path, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Creates a buffered writer using UTF-8 encoding.
+     *
+     * @param path The file to open.
+     * @return The writer.
+     * @throws IOException if an error occurred while opening the writer.
+     *
+     * @since 0.7
+     */
+    public static BufferedWriter newBufferedWriter(final Path path) throws IOException {
+        return Files.newBufferedWriter(path, StandardCharsets.UTF_8);
+    }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -24,97 +24,49 @@ import org.apache.sis.util.logging.Loggi
 
 /**
  * A thread executing short tasks after some (potentially zero nanosecond) delay.
- * This thread is reserved to internal SIS usage - no user code shall be executed here.
- * All submitted tasks shall be very quick, since there is only one thread shared by everyone.
+ * This class should be reserved to internal SIS usage without user's code.
+ * In practice some user code may be indirectly executed through SIS tasks invoking overrideable methods.
+ * But all submitted tasks shall be very quick, since there is only one thread shared by everyone.
  *
- * <div class="note"><b>Note:</b>
- * In practice some user code may be indirectly executed, since some SIS tasks invoke overrideable methods.
- * We may need to revisit the {@code DelayedExecutor} design in a future version if the above happens to be
- * a problem. For example we may allow the user to specify an application-wide scheduled executor and delegate
- * the tasks to that executor.</div>
- *
- * The methods for use in this class are:
+ * <p>The methods for use in this class are:</p>
  * <ul>
- *   <li>{@link #executeDaemonTask(DelayedRunnable)}</li>
- *   <li>{@link #schedule(DelayedRunnable)}</li>
+ *   <li>{@link #schedule(Runnable, long)}</li>
  * </ul>
  *
  * <div class="section">Comparison with {@code java.util.concurrent}</div>
- * We tried to use {@link java.util.concurrent.ScheduledThreadPoolExecutor} in a previous version,
- * but it seems more suitable to heavier tasks in applications controlling their own executor. For
- * example {@code ScheduledThreadPoolExecutor} acts as a fixed-sized pool, thus forcing us to use
- * only one thread if we don't want to waste resources (profiling shows that even a single thread
- * has very low activity). The {@code ThreadPoolExecutor} super-class is more flexible but still
- * have a quite aggressive policy on threads creation, and doesn't handle delayed tasks by itself.
- * We could combine both worlds with a {@code ThreadPoolExecutor} using a {@code DelayedQueue},
- * but it forces us to declare a core pool size of 0 otherwise {@code ThreadPoolExecutor} tries
- * to execute the tasks immediately without queuing them. Combined with the {@code DelayedQueue}
- * characteristics (being an unbounded queue), this result in {@code ThreadPoolExecutor} never
- * creating more than one thread (because it waits for the queue to reject a task before to create
- * more threads than the pool size).
+ * We tried to use {@link java.util.concurrent.ScheduledThreadPoolExecutor} in a previous SIS version,
+ * but its "fixed-sized pool" design forces us to use only one thread if we do not want to waste resources
+ * (profiling shows that even a single thread has very low activity), which reduces the interest of that class.
+ * Combination of {@code ThreadPoolExecutor} super-class with {@code DelayedQueue} were not successful neither.
  *
- * <p>Given that it seems difficult to configure {@code (Scheduled)ThreadPoolExecutor} in such
- * a way that two or more threads are created only when really needed, given that using those
- * thread pools seems an overkill when the pool size is fixed to one thread, given that our
- * profiling has show very low activity for that single thread anyway, and given that we do
- * not need cancellation and shutdown services for house keeping tasks (this is a daemon thread),
+ * <p>Given that it:</p>
+ * <ul>
+ *   <li>it seems difficult to configure {@code (Scheduled)ThreadPoolExecutor} in such a way
+ *       that two or more threads are created only when really needed,</li>
+ *   <li>using those executor services seems an overkill when the pool size is fixed to one thread,</li>
+ *   <li>our profiling has show very low activity for that single thread anyway,</li>
+ *   <li>we do not need cancellation and shutdown services for house keeping tasks (this is a daemon thread),</li>
+ * </ul>
  * a more lightweight solution seems acceptable here. Pseudo-benchmarking using the
- * {@code CacheTest.stress()} tests suggests that the lightweight solution is faster.</p>
- *
- * <div class="section">Future evolution</div>
- * We may remove (again) this class in a future SIS evolution if we happen to need an executor anyway.
- * However it may be better to wait and see what are the executor needs. Setting up an executor implies
- * choosing many arbitrary parameter values like the number of core threads, maximum threads, idle time,
- * queue capacity, etc. Furthermore some platforms (e.g. MacOS) provide OS-specific implementations
- * integrating well in their environment. We may want to let the user provides the executor of his
- * choice, or we way want to have more profiling data for choosing an appropriate executor. But we
- * may need to find some way to give priority to SIS tasks, since most of them are for releasing
- * resources - in which case quick execution probably help the system to run faster.
- * However before to switch from the lightweight solution to a more heavy solution,
- * micro-benchmarking is desirable. The {@code CacheTest.stress()} tests can be used
- * in first approximation.
+ * {@code CacheTest.stress()} tests suggests that the lightweight solution is faster.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.7
  * @module
  *
  * @see <a href="https://issues.apache.org/jira/browse/SIS-76">SIS-76</a>
  */
 public final class DelayedExecutor extends DaemonThread {
     /**
-     * Executes the given short task in a daemon thread. This method shall be invoked for
-     * Apache SIS tasks only, <strong>not</strong> for arbitrary user task. The task must
-     * completes quickly, because we will typically use only one thread for all submitted
-     * tasks. Completion of the task shall not be critical, since the JVM is allowed to
-     * shutdown before task completion.
-     *
-     * <div class="section">Future evolution</div>
-     * If {@code DelayedExecutor} is removed in a future SIS version in favor of JDK6 executors,
-     * then the method signature will probably be {@code Executors.execute(Runnable)}.
-     *
-     * @param task The task to execute.
-     */
-    public static void executeDaemonTask(final DelayedRunnable task) {
-        QUEUE.add(task);
-    }
-
-    /**
      * Schedules the given short task for later execution in a daemon thread.
-     * The task will be executed after the delay specified by {@link DelayedRunnable#getDelay}
-     * The task must completes quickly, because we will typically use only one thread for all
-     * submitted tasks. Completion of the task shall not be critical, since the JVM is allowed
-     * to shutdown before task completion.
-     *
-     * <div class="section">Future evolution</div>
-     * If {@code DelayedExecutor} is removed in a future SIS version in favor of JDK6 executors,
-     * then the method signature will probably be {@code Executors.schedule(Runnable, long, TimeUnit)}.
+     * The task will be executed after the delay specified by {@link DelayedRunnable#getDelay(TimeUnit)}
+     * The task must completes quickly, because we will typically use only one thread for all submitted tasks.
+     * Completion of the task shall not be critical, since the JVM is allowed to shutdown before task completion.
      *
      * @param task The task to schedule for later execution.
      */
     public static void schedule(final DelayedRunnable task) {
-        // For now the implementation is identical to 'execute'. However it may become
-        // different if we choose to use a library-wide executor in a future SIS version.
         QUEUE.add(task);
     }
 

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -39,6 +39,12 @@ public abstract class DelayedRunnable im
      * Time of execution of this task, in nanoseconds provided by {@link System#nanoTime()}.
      * In the particular case of the {@link Immediate} subclass, the meaning of this field is
      * modified: it is rather an ordinal value used for preserving task order.
+     *
+     * <div class="note"><b>Note:</b>
+     * we use {@link System#nanoTime()} instead than {@link System#currentTimeMillis()} because
+     * the later is not guaranteed to be monotonic: {@code currentTimeMillis} may change abruptly
+     * for example if the user adjusts the clock of his operating system.
+     * </div>
      */
     final long timestamp;
 
@@ -74,7 +80,7 @@ public abstract class DelayedRunnable im
     @Override
     public int compareTo(final Delayed other) {
         if (other instanceof Immediate) {
-            return +1; // "Immediate" tasks always have precedence over delayed ones.
+            return +1;                      // "Immediate" tasks always have precedence over delayed ones.
         }
         return Long.signum(timestamp - ((DelayedRunnable) other).timestamp);
     }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Loggers.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -16,6 +16,18 @@
  */
 package org.apache.sis.internal.system;
 
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.Iterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.logging.Handler;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import org.apache.sis.util.Static;
+import org.apache.sis.util.logging.Logging;
+
 
 /**
  * Names of loggers used in SIS other than the "module-wide" loggers. We often use approximatively one logger
@@ -24,10 +36,15 @@ package org.apache.sis.internal.system;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.6
- * @version 0.6
+ * @version 0.7
  * @module
  */
-public final class Loggers {
+public final class Loggers extends Static {
+    /**
+     * The root logger.
+     */
+    public static final String ROOT = "org.apache.sis";
+
     /**
      * The logger for Apache SIS internal operations. The name of this logger does not match the package name
      * of the classes using it, because this logger name does not have the {@code "internal"} part in it.
@@ -35,6 +52,11 @@ public final class Loggers {
     public static final String SYSTEM = "org.apache.sis.system";
 
     /**
+     * The logger for operations related to JDBC operations.
+     */
+    public static final String SQL = "org.apache.sis.sql";
+
+    /**
      * The logger for operations related to XML marshalling or unmarshalling.
      */
     public static final String XML = "org.apache.sis.xml";
@@ -74,8 +96,105 @@ public final class Loggers {
     public static final String LOCALIZATION = "org.apache.sis.util.resources";
 
     /**
+     * The logger name for operation related to application (console, GUI or web).
+     */
+    public static final String APPLICATION = "org.apache.sis.application";
+
+    /**
      * Do not allow instantiation of this class.
      */
     private Loggers() {
     }
+
+    /**
+     * Returns a map of effective logging levels for SIS loggers. The effective logging level take in account the level
+     * of parent loggers and the level of handlers. For example if a logger level is set to {@link Level#FINE} but no
+     * handler have a level finer than {@link Level#INFO}, then the effective logging level will be {@link Level#INFO}.
+     *
+     * <p>This method does not report the loggers that have an effective level identical to its parent logger.</p>
+     *
+     * @return The effective logging levels of SIS loggers.
+     */
+    public static SortedMap<String,Level> getEffectiveLevels() {
+        final SortedMap<String,Level> levels = new TreeMap<String,Level>();
+        for (final Field field : Loggers.class.getDeclaredFields()) {
+            if (Modifier.isStatic(field.getModifiers()) && field.getType() == String.class) try {
+                levels.put((String) field.get(null), null);
+            } catch (IllegalAccessException e) {
+                /*
+                 * Should never happen, unless we added some fields and forgot to update this method.
+                 * In such case forget the problematic fields and search the next one. This is okay
+                 * since this method is only for information purpose.
+                 */
+                Logging.unexpectedException(Logging.getLogger(SYSTEM), Loggers.class, "getEffectiveLevels", e);
+            }
+        }
+        /*
+         * Process the loggers in alphabetical order. The intend is to process parent loggers before child.
+         * The first logger in the map should be the SIS root logger, "org.apache.sis".
+         */
+        final Iterator<Map.Entry<String,Level>> it = levels.entrySet().iterator();
+        while (it.hasNext()) {
+            final Map.Entry<String,Level> entry = it.next();
+            final String name = entry.getKey();
+            final Logger logger = Logging.getLogger(name);
+            Level level = getEffectiveLevel(logger);
+            final Level h = getHandlerLevel(logger);
+            if (h.intValue() > level.intValue()) {
+                level = h;                              // Take in account the logging level of handlers.
+            }
+            entry.setValue(level);
+            /*
+             * Now verify if the level is identical to the effective level of parent logger.
+             * If they are identical, then we remove the entry in order to report only the changes.
+             */
+            Logger parent = logger;
+            while ((parent = parent.getParent()) != null) {
+                final Level p = levels.get(parent.getName());
+                if (p != null) {
+                    if (p.equals(level)) {
+                        it.remove();
+                    }
+                    break;
+                }
+            }
+        }
+        return levels;
+    }
+
+    /**
+     * Returns the effective level of the given logger, searching in the parent loggers if needed.
+     * This method does not verify if handlers have higher level.
+     */
+    private static Level getEffectiveLevel(Logger logger) {
+        while (logger != null) {
+            final Level level = logger.getLevel();
+            if (level != null) {
+                return level;
+            }
+            logger = logger.getParent();
+        }
+        return Level.INFO;      // Default value specified by the java.util.logging framework.
+    }
+
+    /**
+     * Returns the finest level of registered handlers for the given logger.
+     * This method verifies also in the parent handlers if the logger use them.
+     */
+    private static Level getHandlerLevel(Logger logger) {
+        Level level = Level.OFF;
+        while (logger != null) {
+            for (final Handler handler : logger.getHandlers()) {
+                final Level c = handler.getLevel();
+                if (c != null && c.intValue() < level.intValue()) {
+                    level = c;
+                }
+            }
+            if (!logger.getUseParentHandlers()) {
+                break;
+            }
+            logger = logger.getParent();
+        }
+        return level;
+    }
 }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/OSGiActivator.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/OSGiActivator.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/OSGiActivator.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/OSGiActivator.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.internal.system;
 
-import javax.management.JMException;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleEvent;
@@ -30,7 +29,7 @@ import org.osgi.framework.BundleListener
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.7
  * @module
  *
  * @see ServletListener
@@ -50,6 +49,7 @@ public final class OSGiActivator impleme
     @Override
     public void start(final BundleContext context) {
         context.addBundleListener(this);
+        Shutdown.setContainer("OSGi");
     }
 
     /**
@@ -57,10 +57,10 @@ public final class OSGiActivator impleme
      * This method shutdowns the {@code sis-utility} threads.
      *
      * @param  context The execution context of the bundle being stopped.
-     * @throws JMException If an error occurred during unregistration of the supervisor MBean.
+     * @throws Exception If an error occurred during unregistration of the supervisor MBean or resource disposal.
      */
     @Override
-    public void stop(final BundleContext context) throws JMException {
+    public void stop(final BundleContext context) throws Exception {
         context.removeBundleListener(this);
         Shutdown.stop(getClass());
     }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Semaphores.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Semaphores.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Semaphores.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Semaphores.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -36,7 +36,7 @@ public final class Semaphores {
      * {@code AbstractDerivedCRS} objects contain a {@code conversionFromBase} field, which contains a
      * {@code DefaultConversion.targetCRS} field referencing back the {@code AbstractDerivedCRS} object.
      */
-    public static final byte COMPARING = 1;
+    public static final byte CONVERSION_AND_CRS = 1;
 
     /**
      * A flag to indicate that {@link org.apache.sis.referencing.operation.AbstractCoordinateOperation}
@@ -71,7 +71,7 @@ public final class Semaphores {
     /**
      * Returns {@code true} if the given flag is set.
      *
-     * @param flag One of {@link #COMPARING}, {@link #ENCLOSED_IN_OPERATION} or other constants.
+     * @param flag One of {@link #CONVERSION_AND_CRS}, {@link #ENCLOSED_IN_OPERATION} or other constants.
      * @return {@code true} if the given flag is set.
      */
     public static boolean query(final byte flag) {
@@ -82,7 +82,7 @@ public final class Semaphores {
     /**
      * Sets the given flag.
      *
-     * @param flag One of {@link #COMPARING}, {@link #ENCLOSED_IN_OPERATION} or other constants.
+     * @param flag One of {@link #CONVERSION_AND_CRS}, {@link #ENCLOSED_IN_OPERATION} or other constants.
      * @return {@code true} if the given flag was already set.
      */
     public static boolean queryAndSet(final byte flag) {
@@ -99,7 +99,7 @@ public final class Semaphores {
     /**
      * Clears the given flag.
      *
-     * @param flag One of {@link #COMPARING}, {@link #ENCLOSED_IN_OPERATION} or other constants.
+     * @param flag One of {@link #CONVERSION_AND_CRS}, {@link #ENCLOSED_IN_OPERATION} or other constants.
      */
     public static void clear(final byte flag) {
         final Semaphores s = FLAGS.get();

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/ServletListener.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/ServletListener.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/ServletListener.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/ServletListener.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.internal.system;
 
-import javax.management.JMException;
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.annotation.WebListener;
@@ -28,7 +27,7 @@ import javax.servlet.annotation.WebListe
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.7
  * @module
  *
  * @see OSGiActivator
@@ -42,6 +41,8 @@ public final class ServletListener imple
      */
     @Override
     public void contextInitialized(final ServletContextEvent event) {
+        final String env = event.getServletContext().getServerInfo();
+        Shutdown.setContainer(env != null ? env : "Servlet");
     }
 
     /**
@@ -53,7 +54,7 @@ public final class ServletListener imple
     public void contextDestroyed(final ServletContextEvent event) {
         try {
             Shutdown.stop(getClass());
-        } catch (JMException e) {
+        } catch (Exception e) {
             event.getServletContext().log(e.toString(), e);
         }
     }

Modified: sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Shutdown.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Shutdown.java?rev=1724531&r1=1724530&r2=1724531&view=diff
==============================================================================
--- sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Shutdown.java [UTF-8] (original)
+++ sis/trunk/core/sis-utility/src/main/java/org/apache/sis/internal/system/Shutdown.java [UTF-8] Wed Jan 13 23:59:38 2016
@@ -16,48 +16,177 @@
  */
 package org.apache.sis.internal.system;
 
-import javax.management.JMException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.concurrent.Callable;
 import org.apache.sis.util.logging.Logging;
 
+// Branch-dependent imports
+import org.apache.sis.internal.jdk7.Objects;
+
 
 /**
  * A central place where to manage SIS shutdown process.
- * For now this class is not yet registered as a shutdown hock,
- * but it will be in a future version.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
- * @version 0.3
+ * @version 0.7
  * @module
  */
-public final class Shutdown {
+public final class Shutdown extends Thread {
+    /**
+     * Non-null if a shutdown hook is already registered. That shutdown hook is not necessarily {@link #hook}.
+     * It may be an OSGi or Servlet shutdown hook instead, as notified by {@link #setContainer(String)}.
+     */
+    private static String container;
+
+    /**
+     * The shutdown hook to be registered to the JVM {@link Runtime}, created when first needed.
+     */
+    private static Shutdown hook;
+
     /**
-     * Do not allow instantiation of this class.
+     * The resources to dispose. Most recently added resources are last.
+     */
+    private static final List<Callable<?>> resources = new ArrayList<Callable<?>>();
+
+    /**
+     * Creates the thread to be executed at shutdown time.
      */
     private Shutdown() {
+        super(Threads.SIS, "Shutdown");
     }
 
     /**
-     * Shutdowns the {@code sis-utility} threads and unregister the supervisor MBean.
+     * Invoked at JVM shutdown time.
+     */
+    @Override
+    @SuppressWarnings("CallToPrintStackTrace")
+    public void run() {
+        try {
+            Shutdown.stop((Class<?>) null);
+        } catch (Exception e) {
+            /*
+             * Too late for logging since we are in process of shutting down the Java Virtual Machine.
+             * It is still possible to write the stack trace to System.err, but this is about all we can do.
+             */
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Returns the value set by the last call to {@link #setContainer(String)}.
+     *
+     * @return Typically {@code "OSGi"}, {@code "Servlet"} or {@code null}.
+     */
+    public static String getContainer() {
+        synchronized (resources) {
+            return container;
+        }
+    }
+
+    /**
+     * Invoked if the Apache SIS library is executed from an environment that provide its own shutdown hook.
+     * Example of such environments are OSG and servlet containers. In such case, the shutdown hook will not
+     * be registered to the JVM {@link Runtime}.
      *
-     * @param  caller The class invoking this method, to be used only for logging purpose,
-     *         or {@code null} if the logging system is not available anymore (i.e. the JVM
-     *         itself is shutting down).
-     * @throws JMException If an error occurred during unregistration of the supervisor MBean.
+     * @param env A description of the container. Should contain version information if possible.
+     *            Example: {@code "OSGi"} or {@code "JavaServer Web Dev Kit/1.0"}.
      */
-    public static void stop(final Class<?> caller) throws JMException {
+    public static void setContainer(final String env) {
+        Objects.requireNonNull(env);
+        synchronized (resources) {
+            removeShutdownHook();       // Should not be needed but we are paranoiac.
+            container = env;
+        }
+    }
+
+    /**
+     * Registers a code to execute at JVM shutdown time. The resources will be disposed at
+     * shutdown time in reverse order (most recently added resources will be disposed first).
+     *
+     * <p>The same resource shall not be added twice.</p>
+     *
+     * @param resource The resource disposal to register for execution at shutdown time.
+     */
+    public static void register(final Callable<?> resource) {
+        synchronized (resources) {
+            assert !resources.contains(resource);
+            resources.add(resource);
+            if (hook == null && container == null) {
+                hook = new Shutdown();
+                Runtime.getRuntime().addShutdownHook(hook);
+            }
+        }
+    }
+
+    /**
+     * Removes the shutdown hook, if any.
+     */
+    private static void removeShutdownHook() {
+        assert Thread.holdsLock(resources);
+        if (hook != null) {
+            Runtime.getRuntime().removeShutdownHook(hook);
+            hook = null;
+        }
+    }
+
+    /**
+     * Unregisters a code from execution at JVM shutdown time.
+     * This method uses identity comparison (it does not use {@link Object#equals(Object)}).
+     *
+     * @param resource The resource disposal to cancel execution.
+     */
+    public static void unregister(final Callable<?> resource) {
+        synchronized (resources) {
+            for (int i = resources.size(); --i>=0;) {       // Check most recently added resources first.
+                if (resources.get(i) == resource) {
+                    resources.remove(i);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Unregister the supervisor MBean, executes the disposal tasks and shutdowns the {@code sis-utility} threads.
+     *
+     * @param  caller The class invoking this method, to be used only for logging purpose, or {@code null}
+     *         if the logging system is not available anymore (i.e. the JVM itself is shutting down).
+     * @throws Exception If an error occurred during unregistration of the supervisor MBean
+     *         or during a resource disposal.
+     */
+    public static void stop(final Class<?> caller) throws Exception {
+        synchronized (resources) {
+            container = "Shutdown";
+            if (caller != null) {
+                removeShutdownHook();
+            }
+        }
         /*
          * Unregister the MBean before to stop the threads, in order to avoid false alerts
          * in the superviror 'warnings()' method. Failure to unregister the MBean is worth
          * to report, but we will do that only after we completed the other shutdown steps.
          */
-        JMException exception = null;
+        Exception exception = null;
         if (Supervisor.ENABLED) try {
             Supervisor.unregister();
-        } catch (JMException deferred) {
+        } catch (Exception deferred) {
             exception = deferred;
         }
         /*
+         * Dispose resources, if any, starting with most recently registered. The disposal code should not
+         * invoke Shutdown.[un]register(Disposable), but we nevertheless make the loop robust to this case.
+         */
+        synchronized (resources) {
+            int i;
+            while ((i = resources.size()) != 0) try {       // In case run() modifies the resources list.
+                resources.remove(i - 1).call();             // Dispose most recently added resources first.
+            } catch (Exception e) {
+                exception = e;
+            }
+        }
+        /*
          * Following is usually fast, but may potentially take a little while.
          * If an other thread invoked Thread.interrupt() while we were waiting
          * for the threads to terminate, maybe not all threads have terminated



Mime
View raw message