sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1770449 - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/internal/referencing/ main/java/org/apache/sis/referencing/ test/java/org/apache/sis/referencing/
Date Sat, 19 Nov 2016 00:41:12 GMT
Author: desruisseaux
Date: Sat Nov 19 00:41:12 2016
New Revision: 1770449

URL: http://svn.apache.org/viewvc?rev=1770449&view=rev
Log:
Make AuthorityFactories more robust to race conditions.

Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/CoordinateOperations.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/CoordinateOperations.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/CoordinateOperations.java?rev=1770449&r1=1770448&r2=1770449&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/CoordinateOperations.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/CoordinateOperations.java
[UTF-8] Sat Nov 19 00:41:12 2016
@@ -63,7 +63,7 @@ public final class CoordinateOperations
     /**
      * Returns the factory.
      *
-     * @return The system-wide factory.
+     * @return the system-wide factory.
      */
     public static DefaultCoordinateOperationFactory factory() {
         DefaultCoordinateOperationFactory c = factory;

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java?rev=1770449&r1=1770448&r2=1770449&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/AuthorityFactories.java
[UTF-8] Sat Nov 19 00:41:12 2016
@@ -31,6 +31,7 @@ import org.apache.sis.internal.system.Lo
 import org.apache.sis.internal.system.Modules;
 import org.apache.sis.internal.system.SystemListener;
 import org.apache.sis.referencing.factory.MultiAuthoritiesFactory;
+import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
 import org.apache.sis.referencing.factory.UnavailableFactoryException;
 import org.apache.sis.referencing.factory.sql.EPSGFactory;
 import org.apache.sis.util.logging.Logging;
@@ -44,15 +45,16 @@ import org.apache.sis.util.logging.Loggi
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.7
- * @version 0.7
+ * @version 0.8
  * @module
  */
 final class AuthorityFactories<T extends AuthorityFactory> extends LazySet<T>
{
     /**
      * An array containing only the EPSG factory. Content of this array is initially null.
      * The EPSG factory will be created when first needed by {@link #initialValues()}.
+     * This array is returned directly (not cloned) by {@link #initialValues()}.
      */
-    private static final AuthorityFactory[] EPSG = new AuthorityFactory[1];
+    private static final GeodeticAuthorityFactory[] EPSG = new GeodeticAuthorityFactory[1];
 
     /**
      * The unique system-wide authority factory instance that contains all factories found
on the classpath,
@@ -95,7 +97,7 @@ final class AuthorityFactories<T extends
     /**
      * Sets the EPSG factory to the given value.
      */
-    static void EPSG(final AuthorityFactory factory) {
+    static void EPSG(final GeodeticAuthorityFactory factory) {
         synchronized (EPSG) {
             EPSG[0] = factory;
         }
@@ -109,16 +111,18 @@ final class AuthorityFactories<T extends
      * the EPSG data source does not exist, or replace the {@code EPSGFactory} by a {@code
EPSGFactoryFallback}
      * later if attempt to use the returned factory fails.
      */
-    static AuthorityFactory EPSG() {
+    static GeodeticAuthorityFactory EPSG() {
         synchronized (EPSG) {
-            AuthorityFactory factory = EPSG[0];
-            if (factory == null) try {
-                factory = new EPSGFactory(null);
-            } catch (FactoryException e) {
-                log(e, false);
-                factory = EPSGFactoryFallback.INSTANCE;
+            GeodeticAuthorityFactory factory = EPSG[0];
+            if (factory == null) {
+                try {
+                    factory = new EPSGFactory(null);
+                } catch (FactoryException e) {
+                    log(e, false);
+                    factory = EPSGFactoryFallback.INSTANCE;
+                }
+                EPSG[0] = factory;
             }
-            EPSG[0] = factory;
             return factory;
         }
     }
@@ -128,42 +132,53 @@ final class AuthorityFactories<T extends
      * this method replaces the {@link EPSGFactory} instance by {@link EPSGFactoryFallback}
in order to prevent
      * the same exception to be thrown and logged on every calls to {@link CRS#forCode(String)}.
      */
-    static CRSAuthorityFactory fallback(final UnavailableFactoryException e) throws UnavailableFactoryException
{
+    static GeodeticAuthorityFactory fallback(final UnavailableFactoryException e) throws
UnavailableFactoryException {
         final boolean isTransient = (e.getCause() instanceof SQLTransientException);
         final AuthorityFactory unavailable = e.getUnavailableFactory();
-        final CRSAuthorityFactory factory;
+        GeodeticAuthorityFactory factory;
+        final boolean alreadyDone;
         synchronized (EPSG) {
-            if (unavailable != EPSG[0]) {
-                throw e;                                // Exception did not come from a
factory that we control.
-            }
-            factory = EPSGFactoryFallback.INSTANCE;
-            if (!isTransient) {
-                ALL.reload();
-                EPSG[0] = factory;
+            factory = EPSG[0];
+            alreadyDone = (factory == EPSGFactoryFallback.INSTANCE);
+            if (!alreadyDone) {                             // May have been set in another
thread (race condition).
+                if (unavailable != factory) {
+                    throw e;                                // Exception did not come from
a factory that we control.
+                }
+                factory = EPSGFactoryFallback.INSTANCE;
+                if (!isTransient) {
+                    ALL.reload();
+                    EPSG[0] = factory;
+                }
             }
         }
-        log(e, true);
+        if (!alreadyDone) {
+            log(e, true);
+        }
         return factory;
     }
 
     /**
      * Notifies that a factory is unavailable, but without giving a fallback and without
logging.
-     * The caller is responsible for logging a warning and to provide its own fallback.
+     * The caller is responsible for throwing an exception, or for logging a warning and
provide its own fallback.
      *
-     * @return {@code true} on success, or {@code false} if this method did nothing.
+     * @return {@code false} if the caller can try again, or {@code true} if the failure
can be considered final.
      */
     static boolean failure(final UnavailableFactoryException e) {
         if (!(e.getCause() instanceof SQLTransientException)) {
             final AuthorityFactory unavailable = e.getUnavailableFactory();
             synchronized (EPSG) {
-                if (unavailable == EPSG[0]) {
+                final GeodeticAuthorityFactory factory = EPSG[0];
+                if (factory == EPSGFactoryFallback.INSTANCE) {      // May have been set
in another thread.
+                    return false;
+                }
+                if (unavailable == factory) {
                     ALL.reload();
                     EPSG[0] = EPSGFactoryFallback.INSTANCE;
-                    return true;
+                    return false;
                 }
             }
         }
-        return false;
+        return true;
     }
 
     /**
@@ -187,6 +202,8 @@ final class AuthorityFactories<T extends
      *
      * <p>This method tries to instantiate an {@link EPSGFactory} if possible,
      * or an {@link EPSGFactoryFallback} otherwise.</p>
+     *
+     * @return the EPSG factory in an array. Callers shall not modify the returned array.
      */
     @Override
     @SuppressWarnings("unchecked")

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java?rev=1770449&r1=1770448&r2=1770449&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
[UTF-8] Sat Nov 19 00:41:12 2016
@@ -334,7 +334,7 @@ public final class CRS extends Static {
         try {
             return factory.createOperation(sourceCRS, targetCRS, context);
         } catch (UnavailableFactoryException e) {
-            if (!AuthorityFactories.failure(e)) {
+            if (AuthorityFactories.failure(e)) {
                 throw e;
             } try {
                 // Above method call replaced the EPSG factory by a fallback. Try again.

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java?rev=1770449&r1=1770448&r2=1770449&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CommonCRS.java
[UTF-8] Sat Nov 19 00:41:12 2016
@@ -27,28 +27,24 @@ import javax.measure.quantity.Time;
 import org.opengis.util.FactoryException;
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.AuthorityFactory;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.crs.VerticalCRS;
 import org.opengis.referencing.crs.TemporalCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.GeocentricCRS;
 import org.opengis.referencing.crs.ProjectedCRS;
-import org.opengis.referencing.crs.CRSAuthorityFactory;
 import org.opengis.referencing.cs.TimeCS;
 import org.opengis.referencing.cs.VerticalCS;
 import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.cs.SphericalCS;
 import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.cs.AxisDirection;
-import org.opengis.referencing.cs.CSAuthorityFactory;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.datum.PrimeMeridian;
 import org.opengis.referencing.datum.VerticalDatum;
 import org.opengis.referencing.datum.VerticalDatumType;
 import org.opengis.referencing.datum.TemporalDatum;
-import org.opengis.referencing.datum.DatumAuthorityFactory;
 import org.apache.sis.referencing.datum.DefaultVerticalDatum;
 import org.apache.sis.referencing.datum.DefaultTemporalDatum;
 import org.apache.sis.referencing.cs.AxesConvention;
@@ -59,6 +55,7 @@ import org.apache.sis.referencing.crs.De
 import org.apache.sis.referencing.crs.DefaultVerticalCRS;
 import org.apache.sis.referencing.crs.DefaultGeographicCRS;
 import org.apache.sis.referencing.crs.DefaultGeocentricCRS;
+import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
 import org.apache.sis.referencing.factory.UnavailableFactoryException;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.internal.referencing.provider.TransverseMercator;
@@ -515,7 +512,7 @@ public enum CommonCRS {
             synchronized (this) {
                 object = geographic(cached);
                 if (object == null) {
-                    final CRSAuthorityFactory factory = crsFactory();
+                    final GeodeticAuthorityFactory factory = factory();
                     if (factory != null) try {
                         cached = object = factory.createGeographicCRS(String.valueOf(geographic));
                         return object;
@@ -571,7 +568,7 @@ public enum CommonCRS {
                 object = cachedGeo3D;
                 if (object == null) {
                     if (geo3D != 0) {
-                        final CRSAuthorityFactory factory = crsFactory();
+                        final GeodeticAuthorityFactory factory = factory();
                         if (factory != null) try {
                             cachedGeo3D = object = factory.createGeographicCRS(String.valueOf(geo3D));
                             return object;
@@ -629,7 +626,7 @@ public enum CommonCRS {
                 object = cachedGeocentric;
                 if (object == null) {
                     if (geocentric != 0) {
-                        final CRSAuthorityFactory factory = crsFactory();
+                        final GeodeticAuthorityFactory factory = factory();
                         if (factory != null) try {
                             cachedGeocentric = object = factory.createGeocentricCRS(String.valueOf(geocentric));
                             return object;
@@ -686,7 +683,7 @@ public enum CommonCRS {
                      */
                     SphericalCS cs = null;
                     if (this == DEFAULT) {
-                        final CSAuthorityFactory factory = csFactory();
+                        final GeodeticAuthorityFactory factory = factory();
                         if (factory != null) try {
                             cs = factory.createSphericalCS("6404");
                         } catch (FactoryException e) {
@@ -735,7 +732,7 @@ public enum CommonCRS {
             synchronized (this) {
                 object = datum(cached);
                 if (object == null) {
-                    final DatumAuthorityFactory factory = datumFactory();
+                    final GeodeticAuthorityFactory factory = factory();
                     if (factory != null) try {
                         cached = object = factory.createGeodeticDatum(String.valueOf(datum));
                         return object;
@@ -779,7 +776,7 @@ public enum CommonCRS {
                     if (this == NAD83) {
                         object = ETRS89.ellipsoid();            // Share the same instance
for NAD83 and ETRS89.
                     } else {
-                        final DatumAuthorityFactory factory = datumFactory();
+                        final GeodeticAuthorityFactory factory = factory();
                         if (factory != null) try {
                             cached = object = factory.createEllipsoid(String.valueOf(ellipsoid));
                             return object;
@@ -819,7 +816,7 @@ public enum CommonCRS {
                     if (this != DEFAULT) {
                         object = DEFAULT.primeMeridian();           // Share the same instance
for all constants.
                     } else {
-                        final DatumAuthorityFactory factory = datumFactory();
+                        final GeodeticAuthorityFactory factory = factory();
                         if (factory != null) try {
                             cached = object = factory.createPrimeMeridian(StandardDefinitions.GREENWICH);
                             return object;
@@ -942,7 +939,7 @@ public enum CommonCRS {
                 code = Short.toUnsignedInt(isSouth ? southUTM : northUTM);
                 if (code != 0) {
                     code += zone;
-                    final CRSAuthorityFactory factory = crsFactory();
+                    final GeodeticAuthorityFactory factory = factory();
                     if (factory != null) try {
                         return factory.createProjectedCRS(String.valueOf(code));
                     } catch (FactoryException e) {
@@ -1191,7 +1188,7 @@ public enum CommonCRS {
                     object = crs(cached);
                     if (object == null) {
                         if (isEPSG) {
-                            final CRSAuthorityFactory factory = crsFactory();
+                            final GeodeticAuthorityFactory factory = factory();
                             if (factory != null) try {
                                 cached = object = factory.createVerticalCRS(String.valueOf(crs));
                                 return object;
@@ -1256,7 +1253,7 @@ public enum CommonCRS {
                     object = datum(cached);
                     if (object == null) {
                         if (isEPSG) {
-                            final DatumAuthorityFactory factory = datumFactory();
+                            final GeodeticAuthorityFactory factory = factory();
                             if (factory != null) try {
                                 cached = object = factory.createVerticalDatum(String.valueOf(datum));
                                 return object;
@@ -1577,39 +1574,11 @@ public enum CommonCRS {
      * Returns the EPSG factory to use for creating CRS, or {@code null} if none.
      * If this method returns {@code null}, then the caller will silently fallback on hard-coded
values.
      */
-    static CRSAuthorityFactory crsFactory() {
+    static GeodeticAuthorityFactory factory() {
         if (!EPSGFactoryFallback.FORCE_HARDCODED) {
-            final AuthorityFactory factory = AuthorityFactories.EPSG();
+            final GeodeticAuthorityFactory factory = AuthorityFactories.EPSG();
             if (!(factory instanceof EPSGFactoryFallback)) {
-                return (CRSAuthorityFactory) factory;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the EPSG factory to use for creating coordinate systems, or {@code null} if
none.
-     * If this method returns {@code null}, then the caller will silently fallback on hard-coded
values.
-     */
-    static CSAuthorityFactory csFactory() {
-        if (!EPSGFactoryFallback.FORCE_HARDCODED) {
-            final AuthorityFactory factory = AuthorityFactories.EPSG();
-            if (!(factory instanceof EPSGFactoryFallback)) {
-                return (CSAuthorityFactory) factory;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the EPSG factory to use for creating datum, ellipsoids and prime meridians,
or {@code null} if none.
-     * If this method returns {@code null}, then the caller will silently fallback on hard-coded
values.
-     */
-    static DatumAuthorityFactory datumFactory() {
-        if (!EPSGFactoryFallback.FORCE_HARDCODED) {
-            final AuthorityFactory factory = AuthorityFactories.EPSG();
-            if (!(factory instanceof EPSGFactoryFallback)) {
-                return (DatumAuthorityFactory) factory;
+                return factory;
             }
         }
         return null;
@@ -1623,7 +1592,7 @@ public enum CommonCRS {
         String message = Resources.format(Resources.Keys.CanNotInstantiateGeodeticObject_1,
(Constants.EPSG + ':') + code);
         message = Exceptions.formatChainedMessages(null, message, e);
         final LogRecord record = new LogRecord(Level.WARNING, message);
-        if (!(e instanceof UnavailableFactoryException) || !AuthorityFactories.failure((UnavailableFactoryException)
e)) {
+        if (!(e instanceof UnavailableFactoryException) || AuthorityFactories.failure((UnavailableFactoryException)
e)) {
             // Append the stack trace only if the exception is the the one we expect when
the factory is not available.
             record.setThrown(e);
         }

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java?rev=1770449&r1=1770448&r2=1770449&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/EPSGFactoryFallbackTest.java
[UTF-8] Sat Nov 19 00:41:12 2016
@@ -25,10 +25,10 @@ import org.opengis.referencing.crs.Verti
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.GeocentricCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.crs.CRSAuthorityFactory;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.PrimeMeridian;
+import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Utilities;
 
@@ -180,7 +180,7 @@ public final strictfp class EPSGFactoryF
     /**
      * Sets the EPSG factory to the given instance and clears the cache of all {@link CommonCRS}
enumeration values.
      */
-    private static void setEPSGFactory(final CRSAuthorityFactory factory) {
+    private static void setEPSGFactory(final GeodeticAuthorityFactory factory) {
         AuthorityFactories.EPSG(factory);
         for (final CommonCRS          crs : CommonCRS         .values()) crs.clear();
         for (final CommonCRS.Vertical crs : CommonCRS.Vertical.values()) crs.clear();
@@ -195,7 +195,7 @@ public final strictfp class EPSGFactoryF
     @Test
     @DependsOnMethod({"testGetAuthorityCodes", "testCreateCRS"})
     public void compareAllCodes() throws FactoryException {
-        final CRSAuthorityFactory EPSG = (CRSAuthorityFactory) AuthorityFactories.EPSG();
+        final GeodeticAuthorityFactory EPSG = AuthorityFactories.EPSG();
         try {
             setEPSGFactory(EPSGFactoryFallback.INSTANCE);
             final ArrayList<String> codes = new ArrayList<>(EPSGFactoryFallback.INSTANCE.getAuthorityCodes(CoordinateReferenceSystem.class));



Mime
View raw message