Author: desruisseaux
Date: Thu Apr 21 15:37:26 2016
New Revision: 1740342

URL: http://svn.apache.org/viewvc?rev=1740342&view=rev
Log:
Merge bug fixes from the JDK8 branch.

Modified:
    sis/branches/JDK7/   (props changed)
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
    
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
    
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java

Propchange: sis/branches/JDK7/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Apr 21 15:37:26 2016
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
 /sis/branches/JDK6:1394913-1508480
-/sis/branches/JDK8:1584960-1740205
+/sis/branches/JDK8:1584960-1740312
 /sis/trunk:1394364-1508466,1519089-1519674

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
 [UTF-8] Thu Apr 21 15:37:26 2016
@@ -59,7 +59,7 @@ final class CRSPair {
      */
     @Override
     public int hashCode() {
-        return sourceCRS.hashCode() * 31 + targetCRS.hashCode();
+        return Objects.hashCode(sourceCRS) * 31 + Objects.hashCode(targetCRS);
     }
 
     /**

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
 [UTF-8] Thu Apr 21 15:37:26 2016
@@ -146,6 +146,11 @@ public class CoordinateOperationFinder e
     private final Map<CRSPair,Boolean> previousSearches;
 
     /**
+     * Whether this finder instance is allowed to use {@link 
DefaultCoordinateOperationFactory#cache}.
+     */
+    private final boolean useCache;
+
+    /**
      * Creates a new instance for the given factory and context.
      *
      * @param  registry  the factory to use for creating operations as defined 
by authority, or {@code null} if none.
@@ -160,6 +165,7 @@ public class CoordinateOperationFinder e
         super(registry, factory, context);
         identifierOfStepCRS = new HashMap<>(8);
         previousSearches    = new HashMap<>(8);
+        useCache = (context == null) && (factory == factorySIS);
     }
 
     /**
@@ -190,13 +196,31 @@ public class CoordinateOperationFinder e
     {
         ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
         ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
-        if (!previousSearches.isEmpty()) {
-            // TODO: verify here if the path is defined in EPSG database.
+        if (equalsIgnoreMetadata(sourceCRS, targetCRS)) try {
+            return createFromAffineTransform(AXIS_CHANGES, sourceCRS, 
targetCRS,
+                    
CoordinateSystems.swapAndScaleAxes(sourceCRS.getCoordinateSystem(), 
targetCRS.getCoordinateSystem()));
+        } catch (IllegalArgumentException | ConversionException e) {
+            throw new 
FactoryException(Errors.format(Errors.Keys.CanNotInstantiate_1, new 
CRSPair(sourceCRS, targetCRS)), e);
         }
+        /*
+         * If this method is invoked recursively, verify if the requested 
operation is already in the cache.
+         * We do not perform this verification on the first invocation because 
it was already verified by
+         * DefaultCoordinateOperationFactory.createOperation(…). We do not 
block if the operation is in
+         * process of being computed in another thread because of the risk of 
deadlock. If the operation
+         * is not in the cache, store the key in our internal map for 
preventing infinite recursivity.
+         */
         final CRSPair key = new CRSPair(sourceCRS, targetCRS);
+        if (useCache && !previousSearches.isEmpty()) {
+            final CoordinateOperation op = factorySIS.cache.peek(key);
+            if (op != null) return op;
+        }
         if (previousSearches.put(key, Boolean.TRUE) != null) {
             throw new 
FactoryException(Errors.format(Errors.Keys.RecursiveCreateCallForCode_2, 
CoordinateOperation.class, key));
         }
+        /*
+         * If the user did not specified an area of interest, use the domain 
of validity of the CRS.
+         * Then verify in the EPSG dataset if the operation is explicitely 
defined by an authority.
+         */
         GeographicBoundingBox bbox = 
Extents.getGeographicBoundingBox(areaOfInterest);
         if (bbox == null) {
             bbox = 
Extents.intersection(CRS.getGeographicBoundingBox(sourceCRS),
@@ -897,8 +921,14 @@ public class CoordinateOperationFinder e
          * trivial operations.
          */
         CoordinateOperation main = null;
-        if (step1.getName() == AXIS_CHANGES && mt1.getSourceDimensions() == 
mt1.getTargetDimensions()) main = step2;
-        if (step2.getName() == AXIS_CHANGES && mt2.getSourceDimensions() == 
mt2.getTargetDimensions()) main = step1;
+        final boolean isAxisChange1 = (step1.getName() == AXIS_CHANGES);
+        final boolean isAxisChange2 = (step2.getName() == AXIS_CHANGES);
+        if (isAxisChange1 && isAxisChange2 && isAffine(step1) && 
isAffine(step2)) {
+            main = step2;                                           // 
Arbitrarily take the last step.
+        } else {
+            if (isAxisChange1 && mt1.getSourceDimensions() == 
mt1.getTargetDimensions()) main = step2;
+            if (isAxisChange2 && mt2.getSourceDimensions() == 
mt2.getTargetDimensions()) main = step1;
+        }
         if (main instanceof SingleOperation) {
             final SingleOperation op = (SingleOperation) main;
             final MathTransform mt = 
factorySIS.getMathTransformFactory().createConcatenatedTransform(mt1, mt2);
@@ -911,7 +941,7 @@ public class CoordinateOperationFinder e
         }
         /*
          * Sometime we get a concatenated operation made of an operation 
followed by its inverse.
-         * We can identity those case when the associated MathTransform is the 
identity transform.
+         * We can identify thoses case when the associated MathTransform is 
the identity transform.
          * In such case, simplify by replacing the ConcatenatedTransform by a 
SingleTransform.
          */
         if (main instanceof ConcatenatedOperation && 
main.getMathTransform().isIdentity()) {
@@ -954,6 +984,18 @@ public class CoordinateOperationFinder e
     }
 
     /**
+     * Returns {@code true} if the given operation is non-null and use the 
affine operation method.
+     */
+    private static boolean isAffine(final CoordinateOperation operation) {
+        if (operation instanceof SingleOperation) {
+            if (IdentifiedObjects.isHeuristicMatchForName(((SingleOperation) 
operation).getMethod(), Constants.AFFINE)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Returns {@code true} if the specified operation is an identity 
conversion.
      * This method always returns {@code false} for transformations even if 
their
      * associated math transform is an identity one, because such 
transformations

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
 [UTF-8] Thu Apr 21 15:37:26 2016
@@ -44,6 +44,7 @@ import org.apache.sis.referencing.factor
 import 
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
 import org.apache.sis.util.collection.WeakHashSet;
 import org.apache.sis.util.collection.Containers;
+import org.apache.sis.util.collection.Cache;
 import org.apache.sis.util.iso.AbstractFactory;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
@@ -121,10 +122,21 @@ public class DefaultCoordinateOperationF
     /**
      * Weak references to existing objects.
      * This set is used in order to return a pre-existing object instead of 
creating a new one.
+     * This apply to object created explicitly, not to coordinate operations 
inferred by a call
+     * to {@link #createOperation(CoordinateReferenceSystem, 
CoordinateReferenceSystem)}.
      */
     private final WeakHashSet<IdentifiedObject> pool;
 
     /**
+     * The cache of coordinate operations found for a given pair of source and 
target CRS.
+     * If current implementation, we cache only operations found without 
context (otherwise
+     * we would need to take in account the area of interest and desired 
accuracy in the key).
+     *
+     * @see #createOperation(CoordinateReferenceSystem, 
CoordinateReferenceSystem, CoordinateOperationContext)
+     */
+    final Cache<CRSPair,CoordinateOperation> cache;
+
+    /**
      * Constructs a factory with no default properties.
      */
     public DefaultCoordinateOperationFactory() {
@@ -167,6 +179,7 @@ public class DefaultCoordinateOperationF
             mtFactory = factory;
         }
         pool = new WeakHashSet<>(IdentifiedObject.class);
+        cache = new Cache<>(12, 50, true);
     }
 
     /**
@@ -699,9 +712,32 @@ next:   for (int i=components.size(); --
                                                final 
CoordinateOperationContext context)
             throws OperationNotFoundException, FactoryException
     {
-        final AuthorityFactory registry = USE_EPSG_FACTORY ? 
CRS.getAuthorityFactory(Constants.EPSG) : null;
-        return new CoordinateOperationFinder((registry instanceof 
CoordinateOperationAuthorityFactory) ?
-                (CoordinateOperationAuthorityFactory) registry : null, this, 
context).createOperation(sourceCRS, targetCRS);
+        final Cache.Handler<CoordinateOperation> handler;
+        CoordinateOperation op;
+        if (context == null) {
+            final CRSPair key = new CRSPair(sourceCRS, targetCRS);
+            op = cache.peek(key);
+            if (op != null) {
+                return op;
+            }
+            handler = cache.lock(key);
+        } else {
+            // We currently do not cache the operation when the result may 
depend on the context (see 'this.cache' javadoc).
+            handler = null;
+            op = null;
+        }
+        try {
+            if (handler == null || (op = handler.peek()) == null) {
+                final AuthorityFactory registry = USE_EPSG_FACTORY ? 
CRS.getAuthorityFactory(Constants.EPSG) : null;
+                op = new CoordinateOperationFinder((registry instanceof 
CoordinateOperationAuthorityFactory) ?
+                        (CoordinateOperationAuthorityFactory) registry : null, 
this, context).createOperation(sourceCRS, targetCRS);
+            }
+        } finally {
+            if (handler != null) {
+                handler.putAndUnlock(op);
+            }
+        }
+        return op;
     }
 
     /**

Modified: 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
 [UTF-8] Thu Apr 21 15:37:26 2016
@@ -112,9 +112,9 @@ final class SubOperationInfo {
         final Class<?> targetType = type(target);
         for (final Class<?>[] sourceTypes : COMPATIBLE_TYPES) {
             if (sourceTypes[0].isAssignableFrom(targetType)) {
-                int startAtDimension;
-                int endAtDimension = 0;
                 for (final Class<?> sourceType : sourceTypes) {
+                    int startAtDimension;
+                    int endAtDimension = 0;
                     for (int i=0; i<sourceIsUsed.length; i++) {
                         final SingleCRS source = sources.get(i);
                         startAtDimension = endAtDimension;

Modified: 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
URL: 
http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java?rev=1740342&r1=1740341&r2=1740342&view=diff
==============================================================================
--- 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
 [UTF-8] (original)
+++ 
sis/branches/JDK7/core/sis-referencing/src/test/java/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
 [UTF-8] Thu Apr 21 15:37:26 2016
@@ -512,6 +512,44 @@ public final strictfp class CoordinateOp
     
//////////////////////////////////////////////////////////////////////////////////
 
     /**
+     * Tests the conversion from a four-dimensional geographic CRS to a 
two-dimensional geographic CRS.
+     * The vertical and temporal dimensions are simply dropped.
+     *
+     * @throws FactoryException if the operation can not be created.
+     * @throws TransformException if an error occurred while converting the 
test points.
+     */
+    @Test
+    @DependsOnMethod("testGeographic3D_to_2D")
+    public void testGeographic4D_to_2D() throws FactoryException, 
TransformException {
+        // NOTE: make sure that the 'sourceCRS' below is not equal to any 
other 'sourceCRS' created in this class.
+        final CompoundCRS   sourceCRS = compound("Test4D", 
CommonCRS.WGS84.geographic3D(), CommonCRS.Temporal.UNIX.crs());
+        final GeographicCRS targetCRS = CommonCRS.WGS84.geographic();
+        final CoordinateOperation operation = 
inference.createOperation(sourceCRS, targetCRS);
+        assertSame      ("sourceCRS", sourceCRS,        
operation.getSourceCRS());
+        assertSame      ("targetCRS", targetCRS,        
operation.getTargetCRS());
+
+        transform = operation.getMathTransform();
+        assertInstanceOf("transform", LinearTransform.class, transform);
+        assertEquals("sourceDimensions", 4, transform.getSourceDimensions());
+        assertEquals("targetDimensions", 2, transform.getTargetDimensions());
+        Assert.assertMatrixEquals("transform.matrix", Matrices.create(3, 5, 
new double[] {
+            1, 0, 0, 0, 0,
+            0, 1, 0, 0, 0,
+            0, 0, 0, 0, 1
+        }), ((LinearTransform) transform).getMatrix(), STRICT);
+
+        isInverseTransformSupported = false;
+        verifyTransform(new double[] {
+            30, 10,  20, 1000,
+            20, 30, -10, 3000
+        }, new double[] {
+            30, 10,
+            20, 30
+        });
+        validate();
+    }
+
+    /**
      * Tests the conversion from a three-dimensional geographic CRS to a 
two-dimensional geographic CRS.
      * The vertical dimension is simply dropped.
      *
@@ -639,6 +677,46 @@ public final strictfp class CoordinateOp
     }
 
     /**
+     * Tests extracting the vertical part of a spatio-temporal CRS.
+     *
+     * @throws FactoryException if the operation can not be created.
+     * @throws TransformException if an error occurred while converting the 
test points.
+     */
+    @Test
+    @DependsOnMethod("testGeographic3D_to_EllipsoidalHeight")
+    public void testGeographic4D_to_EllipsoidalHeight() throws 
FactoryException, TransformException {
+        // NOTE: make sure that the 'sourceCRS' below is not equal to any 
other 'sourceCRS' created in this class.
+        final CompoundCRS sourceCRS = compound("Test4D", 
CommonCRS.WGS84.geographic3D(), CommonCRS.Temporal.JULIAN.crs());
+        final VerticalCRS targetCRS = CommonCRS.Vertical.ELLIPSOIDAL.crs();
+        final CoordinateOperation operation = 
inference.createOperation(sourceCRS, targetCRS);
+        assertSame      ("sourceCRS", sourceCRS,        
operation.getSourceCRS());
+        assertSame      ("targetCRS", targetCRS,        
operation.getTargetCRS());
+        assertEquals    ("name",      "Axis changes",   
operation.getName().getCode());
+        assertInstanceOf("operation", Conversion.class, operation);
+
+        transform = operation.getMathTransform();
+        assertInstanceOf("transform", LinearTransform.class, transform);
+        assertEquals("sourceDimensions", 4, transform.getSourceDimensions());
+        assertEquals("targetDimensions", 1, transform.getTargetDimensions());
+        Assert.assertMatrixEquals("transform.matrix", Matrices.create(2, 5, 
new double[] {
+            0, 0, 1, 0, 0,
+            0, 0, 0, 0, 1
+        }), ((LinearTransform) transform).getMatrix(), STRICT);
+
+        isInverseTransformSupported = false;
+        verifyTransform(new double[] {
+             0,  0,  0,  0,
+             5,  8, 20, 10,
+            -5, -8, 24, 30
+        }, new double[] {
+                     0,
+                    20,
+                    24,
+        });
+        validate();
+    }
+
+    /**
      * Convenience method for creating a compound CRS.
      */
     private static CompoundCRS compound(final String name, final 
CoordinateReferenceSystem... components) {
@@ -712,6 +790,7 @@ public final strictfp class CoordinateOp
     @Test
     @DependsOnMethod("testTemporalConversion")
     public void testGeographic3D_to_4D() throws FactoryException, 
TransformException {
+        // NOTE: make sure that the 'sourceCRS' below is not equal to any 
other 'sourceCRS' created in this class.
         final CompoundCRS sourceCRS = compound("Test3D", 
CommonCRS.WGS84.geographic(),   CommonCRS.Temporal.UNIX.crs());
         final CompoundCRS targetCRS = compound("Test4D", 
CommonCRS.WGS84.geographic3D(), CommonCRS.Temporal.MODIFIED_JULIAN.crs());
         final CoordinateOperation operation = 
inference.createOperation(sourceCRS, targetCRS);


Reply via email to