sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1723176 [1/2] - in /sis/branches/JDK8/core/sis-referencing/src: main/java/org/apache/sis/internal/referencing/provider/ main/java/org/apache/sis/parameter/ main/java/org/apache/sis/referencing/factory/ main/java/org/apache/sis/referencing/...
Date Tue, 05 Jan 2016 21:39:28 GMT
Author: desruisseaux
Date: Tue Jan  5 21:39:28 2016
New Revision: 1723176

URL: http://svn.apache.org/viewvc?rev=1723176&view=rev
Log:
Added more tests and fixed bugs identified by those tests.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java
      - copied, changed from r1723040, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java
Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/FranceGeocentricInterpolation.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -41,6 +41,8 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.Transformation;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.apache.sis.referencing.factory.MissingFactoryResourceException;
+import org.apache.sis.referencing.factory.FactoryDataException;
 import org.opengis.util.FactoryException;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.internal.system.DataDirectory;
@@ -62,6 +64,7 @@ import static java.lang.Float.parseFloat
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 
 
 /**
@@ -352,6 +355,7 @@ public class FranceGeocentricInterpolati
      * @param  averages  An "average" value for the offset in each dimension, or {@code null} if unknown.
      * @param  scale     The factor by which to multiply each compressed value before to add to the average value.
      */
+    @SuppressWarnings("null")
     static DatumShiftGridFile<Angle,Length> getOrLoad(final Path file, final double[] averages, final double scale)
             throws FactoryException
     {
@@ -368,7 +372,12 @@ public class FranceGeocentricInterpolati
                         grid = DatumShiftGridCompressed.compress(g, averages, scale);
                     } catch (IOException | NoninvertibleTransformException | RuntimeException e) {
                         // NumberFormatException, ArithmeticException, NoSuchElementException, possibly other.
-                        throw new FactoryException(Errors.format(Errors.Keys.CanNotParseFile_2, HEADER, file), e);
+                        final String message = Errors.format(Errors.Keys.CanNotParseFile_2, HEADER, file);
+                        if (e instanceof NoSuchFileException) {
+                            throw new MissingFactoryResourceException(message, e);
+                        } else {
+                            throw new FactoryDataException(message, e);
+                        }
                     }
                     grid = grid.useSharedData();
                 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NADCON.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -34,6 +34,8 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.Transformation;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.apache.sis.referencing.factory.MissingFactoryResourceException;
+import org.apache.sis.referencing.factory.FactoryDataException;
 import org.apache.sis.referencing.operation.transform.InterpolatedTransform;
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.parameter.Parameters;
@@ -46,6 +48,7 @@ import org.apache.sis.internal.system.Da
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 
 
 /**
@@ -145,6 +148,7 @@ public final class NADCON extends Abstra
      * @param latitudeShifts   Name of the grid file for latitude shifts.
      * @param longitudeShifts  Name of the grid file for longitude shifts.
      */
+    @SuppressWarnings("null")
     static DatumShiftGridFile<Angle,Angle> getOrLoad(final Path latitudeShifts, final Path longitudeShifts)
             throws FactoryException
     {
@@ -175,7 +179,12 @@ public final class NADCON extends Abstra
                             new Loader(in, buffer, file).readGrid(fb, loader, null);
                         }
                     } catch (IOException | NoninvertibleTransformException | RuntimeException e) {
-                        throw new FactoryException(Errors.format(Errors.Keys.CanNotParseFile_2, "NADCON", file), e);
+                        final String message = Errors.format(Errors.Keys.CanNotParseFile_2, "NADCON", file);
+                        if (e instanceof NoSuchFileException) {
+                            throw new MissingFactoryResourceException(message, e);
+                        } else {
+                            throw new FactoryDataException(message, e);
+                        }
                     }
                     grid = DatumShiftGridCompressed.compress(loader.grid, null, loader.grid.accuracy);
                     grid = grid.useSharedData();

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/NTv2.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -40,6 +40,8 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.Transformation;
 import org.opengis.referencing.operation.NoninvertibleTransformException;
+import org.apache.sis.referencing.factory.MissingFactoryResourceException;
+import org.apache.sis.referencing.factory.FactoryDataException;
 import org.apache.sis.referencing.operation.transform.InterpolatedTransform;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.internal.system.DataDirectory;
@@ -53,6 +55,7 @@ import org.apache.sis.util.resources.Mes
 // Branch-dependent imports
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.NoSuchFileException;
 import java.nio.charset.StandardCharsets;
 
 
@@ -135,6 +138,7 @@ public final class NTv2 extends Abstract
      *
      * @param file Name of the datum shift grid file to load.
      */
+    @SuppressWarnings("null")
     static DatumShiftGridFile<Angle,Angle> getOrLoad(final Path file) throws FactoryException {
         final Path resolved = DataDirectory.DATUM_CHANGES.resolve(file).toAbsolutePath();
         DatumShiftGridFile<?,?> grid = DatumShiftGridFile.CACHE.peek(resolved);
@@ -149,7 +153,12 @@ public final class NTv2 extends Abstract
                         grid = loader.readGrid();
                         loader.reportWarnings();
                     } catch (IOException | NoninvertibleTransformException | RuntimeException e) {
-                        throw new FactoryException(Errors.format(Errors.Keys.CanNotParseFile_2, "NTv2", file), e);
+                        final String message = Errors.format(Errors.Keys.CanNotParseFile_2, "NTv2", file);
+                        if (e instanceof NoSuchFileException) {
+                            throw new MissingFactoryResourceException(message, e);
+                        } else {
+                            throw new FactoryDataException(message, e);
+                        }
                     }
                     grid = grid.useSharedData();
                 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -511,6 +511,20 @@ public class DefaultParameterValue<T> ex
     }
 
     /**
+     * Same as {@link #isFile(Object)}, but accepts also a {@link String} if the type specified
+     * in the parameter descriptor is one of the types documented in {@link #valueFile()}.
+     */
+    private boolean isFileOrString(final Object value) {
+        if (value instanceof String) {
+            final Class<?> type = descriptor.getValueClass();
+            return (type == URI.class) || (type == URL.class)
+                   || Path.class.isAssignableFrom(type)
+                   || File.class.isAssignableFrom(type);
+        }
+        return isFile(value);
+    }
+
+    /**
      * Returns the exception to throw when an incompatible method is invoked for the value type.
      */
     private IllegalStateException missingOrIncompatibleValue(final Object value) {
@@ -553,7 +567,7 @@ public class DefaultParameterValue<T> ex
          * to allow too many conversions for reducing the risk of unexpected behavior.  If we fail to convert, try
          * to set the value anyway since the user may have redefined the setValue(Object, Unit) method.
          */
-        if (isFile(value)) try {
+        if (isFileOrString(value)) try {
             value = ObjectConverters.convert(value, descriptor.getValueClass());
         } catch (UnconvertibleObjectException e) {
             // Level.FINE (not WARNING) because this log duplicates the exception

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/ConcurrentAuthorityFactory.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -18,8 +18,10 @@ package org.apache.sis.referencing.facto
 
 import java.util.Set;
 import java.util.Map;
+import java.util.List;
 import java.util.Deque;
 import java.util.Iterator;
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.WeakHashMap;
 import java.util.IdentityHashMap;
@@ -55,7 +57,6 @@ import org.apache.sis.internal.system.De
 import org.apache.sis.internal.system.Shutdown;
 import org.apache.sis.internal.system.Loggers;
 import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.ArraysExt;
 
 
 /**
@@ -88,12 +89,16 @@ import org.apache.sis.util.ArraysExt;
  * {@link CRSAuthorityFactory} and {@link CoordinateOperationAuthorityFactory} interfaces.
  * Subclasses should select the interfaces that they choose to implement.
  *
+ * @param <DAO> the type of factory used as Data Access Object (DAO)
+ *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.7
  * @version 0.7
  * @module
  */
-public abstract class ConcurrentAuthorityFactory extends GeodeticAuthorityFactory implements AutoCloseable {
+public abstract class ConcurrentAuthorityFactory<DAO extends GeodeticAuthorityFactory>
+        extends GeodeticAuthorityFactory implements AutoCloseable
+{
     /**
      * The authority, cached after first requested.
      */
@@ -113,7 +118,7 @@ public abstract class ConcurrentAuthorit
     private final Cache<Key,Object> cache;
 
     /**
-     * The pool of objects identified by {@link Finder#find(IdentifiedObject)} for each comparison modes.
+     * The pool of objects identified by {@link Finder#find(IdentifiedObject)}.
      * Values may be {@link NilReferencingObject} if an object has been searched but has not been found.
      *
      * <p>Every access to this pool must be synchronized on {@code findPool}.</p>
@@ -122,24 +127,24 @@ public abstract class ConcurrentAuthorit
 
     /**
      * Holds the reference to a Data Access Object used by {@link ConcurrentAuthorityFactory}, together with
-     * information about its usage. In a mono-thread application, there is typically only one {@code DataAccess}
+     * information about its usage. In a mono-thread application, there is typically only one {@code DataAccessRef}
      * instance at a given time. However if more than one than one thread are requesting new objects concurrently,
      * then many instances may exist for the same {@code ConcurrentAuthorityFactory}.
      *
-     * <p>If the Data Access Object is currently in use, then {@code DataAccess} counts how many recursive
+     * <p>If the Data Access Object is currently in use, then {@code DataAccessRef} counts how many recursive
      * invocations of a {@link #factory} {@code createFoo(String)} method is under way in the current thread.
      * This information is used in order to reuse the same factory instead than creating new instances
      * when a {@code GeodeticAuthorityFactory} implementation invokes itself indirectly through the
      * {@link ConcurrentAuthorityFactory}. This assumes that factory implementations are reentrant.</p>
      *
-     * <p>If the Data Access Object has been released, then {@code DataAccess} keep the release timestamp.
+     * <p>If the Data Access Object has been released, then {@code DataAccessRef} keep the release timestamp.
      * This information is used for prioritize the Data Access Objects to close.</p>
      */
-    private static final class DataAccess {
+    private static final class DataAccessRef<DAO extends GeodeticAuthorityFactory> {
         /**
          * The factory used for data access.
          */
-        final GeodeticAuthorityFactory factory;
+        final DAO factory;
 
         /**
          * Incremented on every call to {@link ConcurrentAuthorityFactory#getDataAccess()} and decremented on every call
@@ -156,7 +161,7 @@ public abstract class ConcurrentAuthorit
         /**
          * Creates new Data Access Object information for the given factory.
          */
-        DataAccess(final GeodeticAuthorityFactory factory) {
+        DataAccessRef(final DAO factory) {
             this.factory = factory;
         }
 
@@ -169,7 +174,7 @@ public abstract class ConcurrentAuthorit
             final String text;
             final Number value;
             if (depth != 0) {
-                text = "%s in use with at depth %d";
+                text = "%s in use at depth %d";
                 value = depth;
             } else {
                 text = "%s made available %d seconds ago";
@@ -182,14 +187,14 @@ public abstract class ConcurrentAuthorit
     /**
      * The Data Access Object in use by the current thread.
      */
-    private final ThreadLocal<DataAccess> currentDAO = new ThreadLocal<>();
+    private final ThreadLocal<DataAccessRef<DAO>> currentDAO = new ThreadLocal<>();
 
     /**
      * The Data Access Object instances previously created and released for future reuse.
      * Last used factories must be {@linkplain Deque#addLast(Object) added last}.
      * This is used as a LIFO stack.
      */
-    private final Deque<DataAccess> availableDAOs = new LinkedList<>();
+    private final Deque<DataAccessRef<DAO>> availableDAOs = new LinkedList<>();
 
     /**
      * The amount of Data Access Objects that can still be created. This number is decremented in a block
@@ -204,12 +209,12 @@ public abstract class ConcurrentAuthorit
      * However the reciprocal is not true: this field may be set to {@code false} while a worker factory is currently
      * in use because this field is set to {@code true} only when a worker factory is {@linkplain #release() released}.
      *
-     * <p>Note that we can not use {@code !availableDAOs.isEmpty()} as a replacement of {@code isActive}
+     * <p>Note that we can not use {@code !availableDAOs.isEmpty()} as a replacement of {@code isCleanScheduled}
      * because the queue is empty if all Data Access Objects are currently in use.</p>
      *
      * <p>Every access to this field must be performed in a block synchronized on {@link #availableDAOs}.</p>
      */
-    private boolean isActive;
+    private boolean isCleanScheduled;
 
     /**
      * The delay of inactivity (in nanoseconds) before to close a Data Access Object.
@@ -233,7 +238,7 @@ public abstract class ConcurrentAuthorit
      * @param dataAccessClass The class of Data Access Object (DAO) created by {@link #newDataAccess()}.
      * @param nameFactory The factory to use for parsing authority codes as {@link org.opengis.util.GenericName} instances.
      */
-    protected ConcurrentAuthorityFactory(Class<? extends GeodeticAuthorityFactory> dataAccessClass, NameFactory nameFactory) {
+    protected ConcurrentAuthorityFactory(Class<DAO> dataAccessClass, NameFactory nameFactory) {
         this(dataAccessClass, nameFactory, 100, 8);
         /*
          * NOTE: if the default maximum number of Data Access Objects (currently 8) is augmented,
@@ -253,7 +258,7 @@ public abstract class ConcurrentAuthorit
      *        If more than this amount of threads are querying this {@code ConcurrentAuthorityFactory} concurrently,
      *        additional threads will be blocked until a Data Access Object become available.
      */
-    protected ConcurrentAuthorityFactory(final Class<? extends GeodeticAuthorityFactory> dataAccessClass,
+    protected ConcurrentAuthorityFactory(final Class<DAO> dataAccessClass,
             final NameFactory nameFactory, final int maxStrongReferences, final int maxConcurrentQueries)
     {
         super(nameFactory);
@@ -290,7 +295,7 @@ public abstract class ConcurrentAuthorit
          *   2) Closes the Data Access Objects at JVM shutdown time if the application is standalone,
          *      or when the bundle is uninstalled if running inside an OSGi or Servlet container.
          */
-        Shutdown.register(new ShutdownHook(this));
+        Shutdown.register(new ShutdownHook<>(this));
     }
 
     /**
@@ -322,7 +327,7 @@ public abstract class ConcurrentAuthorit
      * @throws UnavailableFactoryException if the Data Access Object is unavailable because an optional resource is missing.
      * @throws FactoryException if the creation of Data Access Object failed for another reason.
      */
-    protected abstract GeodeticAuthorityFactory newDataAccess() throws UnavailableFactoryException, FactoryException;
+    protected abstract DAO newDataAccess() throws UnavailableFactoryException, FactoryException;
 
     /**
      * Returns a Data Access Object. This method <strong>must</strong>
@@ -331,12 +336,13 @@ public abstract class ConcurrentAuthorit
      * @return Data Access Object (DAO) to use in {@code createFoo(String)} methods.
      * @throws FactoryException if the Data Access Object creation failed.
      */
-    private GeodeticAuthorityFactory getDataAccess() throws FactoryException {
+    @SuppressWarnings("null")
+    private DAO getDataAccess() throws FactoryException {
         /*
          * First checks if the current thread is already using a factory. If yes, we will
          * avoid creating new factories on the assumption that factories are reentrant.
          */
-        DataAccess usage = currentDAO.get();
+        DataAccessRef<DAO> usage = currentDAO.get();
         if (usage == null) {
             synchronized (availableDAOs) {
                 /*
@@ -367,12 +373,12 @@ public abstract class ConcurrentAuthorit
              */
             try {
                 if (usage == null) {
-                    final GeodeticAuthorityFactory factory = newDataAccess();
+                    final DAO factory = newDataAccess();
                     if (factory == null) {
                         throw new UnavailableFactoryException(Errors.format(
                                 Errors.Keys.FactoryNotFound_1, GeodeticAuthorityFactory.class));
                     }
-                    usage = new DataAccess(factory);
+                    usage = new DataAccessRef<>(factory);
                 }
                 assert usage.depth == 0 : usage;
             } finally {
@@ -392,7 +398,7 @@ public abstract class ConcurrentAuthorit
         }
         /*
          * Increment below is safe even if outside the synchronized block,
-         * because each thread own exclusively its DataAccess instance
+         * because each thread own exclusively its DataAccessRef instance.
          */
         usage.depth++;
         return usage.factory;
@@ -403,28 +409,59 @@ public abstract class ConcurrentAuthorit
      * This method marks the factory as available for reuse by other threads.
      */
     private void release() {
-        final DataAccess usage = currentDAO.get();     // A null value here would be an error in our algorithm.
+        final DataAccessRef<DAO> usage = currentDAO.get();  // A null value here would be an error in our algorithm.
         if (--usage.depth == 0) {
             currentDAO.remove();
             synchronized (availableDAOs) {
-                remainingDAOs++;       // Must be done first in case an exception happen after this point.
-                usage.timestamp = System.nanoTime();
-                availableDAOs.addLast(usage);
-                /*
-                 * If the Data Access Object we just released is the first one, awake the
-                 * cleaner thread which was waiting for an indefinite amount of time.
-                 */
-                if (!isActive) {
-                    isActive = true;
-                    DelayedExecutor.schedule(new CloseTask(usage.timestamp + timeout));
-                }
-                availableDAOs.notify();    // We released only one data access, so awake only one thread - not all of them.
+                remainingDAOs++;            // Must be done first in case an exception happen after this point.
+                recycle(usage);
+                availableDAOs.notify();     // We released only one data access, so awake only one thread - not all of them.
             }
         }
         assert usage.depth >= 0 : usage;
     }
 
     /**
+     * Pushes the given DAO in the list of objects available for reuse.
+     */
+    private void recycle(final DataAccessRef<DAO> usage) {
+        usage.timestamp = System.nanoTime();
+        availableDAOs.addLast(usage);
+        /*
+         * If the Data Access Object we just released is the first one, awake the
+         * cleaner thread which was waiting for an indefinite amount of time.
+         */
+        if (!isCleanScheduled) {
+            isCleanScheduled = true;
+            DelayedExecutor.schedule(new CloseTask(usage.timestamp + timeout));
+        }
+    }
+
+    /**
+     * Confirms that the given factories can be closed. If any factory is still in use,
+     * it will be removed from that {@cod factories} list and re-injected in the {@link #availableDAOs} queue.
+     */
+    private void confirmClose(final List<DAO> factories) {
+        assert !Thread.holdsLock(availableDAOs);
+        for (final Iterator<DAO> it = factories.iterator(); it.hasNext();) {
+            final DAO factory = it.next();
+            try {
+                if (canClose(factory)) {
+                    continue;
+                }
+            } catch (Exception e) {
+                unexpectedException("canClose", e);
+                continue;                               // Keep the factory on the list of factories to close.
+            }
+            // Cancel closing for that factory.
+            it.remove();
+            synchronized (availableDAOs) {
+                recycle(new DataAccessRef<>(factory));
+            }
+        }
+    }
+
+    /**
      * A task for invoking {@link ConcurrentAuthorityFactory#closeExpired()} after a delay.
      */
     private final class CloseTask extends DelayedRunnable {
@@ -450,14 +487,13 @@ public abstract class ConcurrentAuthorit
      * @see #close()
      */
     final void closeExpired() {
-        int count = 0;
-        final AutoCloseable[] factories;
+        final List<DAO> factories;
         synchronized (availableDAOs) {
-            factories = new AutoCloseable[availableDAOs.size()];
-            final Iterator<DataAccess> it = availableDAOs.iterator();
+            factories = new ArrayList<>(availableDAOs.size());
+            final Iterator<DataAccessRef<DAO>> it = availableDAOs.iterator();
             final long nanoTime = System.nanoTime();
             while (it.hasNext()) {
-                final DataAccess dao = it.next();
+                final DataAccessRef<DAO> dao = it.next();
                 /*
                  * Computes how much time we need to wait again before we can close the factory.
                  * If this time is greater than some arbitrary amount, do not close the factory
@@ -476,24 +512,23 @@ public abstract class ConcurrentAuthorit
                  * Found an expired factory. Adds it to the list of
                  * factories to close and search for other factories.
                  */
+                factories.add(dao.factory);
                 it.remove();
-                if (dao.factory instanceof AutoCloseable) {
-                    factories[count++] = (AutoCloseable) dao.factory;
-                }
             }
             /*
-             * The DAOs list is empty if all worker factories in the queue have been closed.
-             * Note that some worker factories may still be active outside the queue, because the
-             * workers are added to the queue only after completion of their work.
+             * The DAOs list is empty if all Data Access Objects in the queue have been closed.
+             * Note that some DAOs may still be in use outside the queue, because the DAOs are
+             * added to the queue only after completion of their work.
              * In the later case, release() will reschedule a new task.
              */
-            isActive = !availableDAOs.isEmpty();
+            isCleanScheduled = !availableDAOs.isEmpty();
         }
         /*
          * We must close the factories from outside the synchronized block.
          */
+        confirmClose(factories);
         try {
-            close(factories, count);
+            close(factories);
         } catch (Exception exception) {
             unexpectedException("closeExpired", exception);
         }
@@ -514,6 +549,21 @@ public abstract class ConcurrentAuthorit
     }
 
     /**
+     * Returns {@code true} if the given Data Access Object (DAO) can be closed. This method is invoked automatically
+     * after the {@linkplain #getTimeout timeout} if the given DAO has been idle during all that time.
+     * Subclasses can override this method and return {@code false} if they want to prevent the DAO disposal
+     * under some circumstances.
+     *
+     * <p>The default implementation always returns {@code true}.</p>
+     *
+     * @param factory The Data Access Object which is about to be closed.
+     * @return {@code true} if the given Data Access Object can be closed.
+     */
+    protected boolean canClose(DAO factory) {
+        return true;
+    }
+
+    /**
      * Returns the amount of time that {@code ConcurrentAuthorityFactory} will wait before to close a Data Access Object.
      * This delay is measured from the last time the Data Access Object has been used by a {@code createFoo(String)} method.
      *
@@ -566,7 +616,7 @@ public abstract class ConcurrentAuthorit
     public Citation getAuthority() {
         Citation c = authority;
         if (c == null) try {
-            final GeodeticAuthorityFactory factory = getDataAccess();
+            final DAO factory = getDataAccess();
             try {
                 // Cache only in case of success. If we failed, we
                 // will try again next time this method is invoked.
@@ -597,7 +647,7 @@ public abstract class ConcurrentAuthorit
      */
     @Override
     public Set<String> getAuthorityCodes(final Class<? extends IdentifiedObject> type) throws FactoryException {
-        final GeodeticAuthorityFactory factory = getDataAccess();
+        final DAO factory = getDataAccess();
         try {
             return factory.getAuthorityCodes(type);
             /*
@@ -629,7 +679,7 @@ public abstract class ConcurrentAuthorit
     public InternationalString getDescriptionText(final String code)
             throws NoSuchAuthorityCodeException, FactoryException
     {
-        final GeodeticAuthorityFactory factory = getDataAccess();
+        final DAO factory = getDataAccess();
         try {
             return factory.getDescriptionText(code);
         } finally {
@@ -1489,7 +1539,7 @@ public abstract class ConcurrentAuthorit
                 value = handler.peek();
                 if (!type.isInstance(value)) {
                     final T result;
-                    final GeodeticAuthorityFactory factory = getDataAccess();
+                    final DAO factory = getDataAccess();
                     try {
                         result = proxy.create(factory, key.code);
                     } finally {
@@ -1538,7 +1588,7 @@ public abstract class ConcurrentAuthorit
             try {
                 value = handler.peek();
                 if (!(value instanceof Set<?>)) {
-                    final GeodeticAuthorityFactory factory = getDataAccess();
+                    final DAO factory = getDataAccess();
                     try {
                         value = factory.createFromCoordinateReferenceSystemCodes(sourceCRS, targetCRS);
                     } finally {
@@ -1602,7 +1652,7 @@ public abstract class ConcurrentAuthorit
         /**
          * Creates a finder for the given type of objects.
          */
-        Finder(final ConcurrentAuthorityFactory factory, final Class<? extends IdentifiedObject> type) {
+        Finder(final ConcurrentAuthorityFactory<?> factory, final Class<? extends IdentifiedObject> type) {
             super(factory, type);
         }
 
@@ -1624,7 +1674,7 @@ public abstract class ConcurrentAuthorit
             assert Thread.holdsLock(this);
             assert (acquireCount == 0) == (finder == null) : acquireCount;
             if (acquireCount == 0) {
-                final GeodeticAuthorityFactory delegate = ((ConcurrentAuthorityFactory) factory).getDataAccess();
+                final GeodeticAuthorityFactory delegate = ((ConcurrentAuthorityFactory<?>) factory).getDataAccess();
                 /*
                  * Set 'acquireCount' only after we succeed in fetching the factory, and before any operation on it.
                  * The intend is to get ConcurrentAuthorityFactory.release() invoked if and only if the getDataAccess()
@@ -1649,7 +1699,7 @@ public abstract class ConcurrentAuthorit
             }
             if (--acquireCount == 0) {
                 finder = null;
-                ((ConcurrentAuthorityFactory) factory).release();
+                ((ConcurrentAuthorityFactory<?>) factory).release();
             }
         }
 
@@ -1686,7 +1736,7 @@ public abstract class ConcurrentAuthorit
          */
         @Override
         public IdentifiedObject find(final IdentifiedObject object) throws FactoryException {
-            final Map<IdentifiedObject, IdentifiedObject> findPool = ((ConcurrentAuthorityFactory) factory).findPool;
+            final Map<IdentifiedObject, IdentifiedObject> findPool = ((ConcurrentAuthorityFactory<?>) factory).findPool;
             synchronized (findPool) {
                 final IdentifiedObject candidate = findPool.get(object);
                 if (candidate != null) {
@@ -1738,18 +1788,18 @@ public abstract class ConcurrentAuthorit
      * <p><strong>Do not keep reference to the enclosing factory</strong> - in particular,
      * this class must not be static - otherwise the factory would never been garbage collected.</p>
      */
-    private static final class ShutdownHook extends PhantomReference<ConcurrentAuthorityFactory>    // MUST be static!
-            implements Disposable, Callable<Object>
+    private static final class ShutdownHook<DAO extends GeodeticAuthorityFactory>           // MUST be static!
+            extends PhantomReference<ConcurrentAuthorityFactory<DAO>> implements Disposable, Callable<Object>
     {
         /**
          * The {@link ConcurrentAuthorityFactory#availableDAOs} queue.
          */
-        private final Deque<DataAccess> availableDAOs;
+        private final Deque<DataAccessRef<DAO>> availableDAOs;
 
         /**
          * Creates a new shutdown hook for the given factory.
          */
-        ShutdownHook(final ConcurrentAuthorityFactory factory) {
+        ShutdownHook(final ConcurrentAuthorityFactory<DAO> factory) {
             super(factory, ReferenceQueueConsumer.QUEUE);
             availableDAOs = factory.availableDAOs;
         }
@@ -1777,32 +1827,30 @@ public abstract class ConcurrentAuthorit
          */
         @Override
         public Object call() throws Exception {
-            final AutoCloseable[] factories;
+            final List<DAO> factories;
             synchronized (availableDAOs) {
-                factories = getCloseables(availableDAOs);
+                factories = ConcurrentAuthorityFactory.clear(availableDAOs);
             }
-            close(factories, factories.length);
+            // No call to confirmClose(List<DAO>) as we want to force close.
+            close(factories);
             return null;
         }
     }
 
     /**
-     * Returns all factories implementing the {@link AutoCloseable} interfaces in the given queue.
+     * Clears the given queue and returns all DAO instances that it contained.
      * The given queue shall be the {@link ConcurrentAuthorityFactory#availableDAOs} queue.
      *
      * @param availableDAOs The queue of factories to close.
      */
-    static AutoCloseable[] getCloseables(final Deque<DataAccess> availableDAOs) {
+    static <DAO extends GeodeticAuthorityFactory> List<DAO> clear(final Deque<DataAccessRef<DAO>> availableDAOs) {
         assert Thread.holdsLock(availableDAOs);
-        int count = 0;
-        final AutoCloseable[] factories = new AutoCloseable[availableDAOs.size()];
-        DataAccess dao;
+        final List<DAO> factories = new ArrayList<>(availableDAOs.size());
+        DataAccessRef<DAO> dao;
         while ((dao = availableDAOs.pollFirst()) != null) {
-            if (dao.factory instanceof AutoCloseable) {
-                factories[count++] = (AutoCloseable) dao.factory;
-            }
+            factories.add(dao.factory);
         }
-        return ArraysExt.resize(factories, count);
+        return factories;
     }
 
     /**
@@ -1813,15 +1861,18 @@ public abstract class ConcurrentAuthorit
      * @param  count Number of valid elements in the {@code factories} array.
      * @throws Exception the exception thrown by the first factory that failed to close.
      */
-    static void close(final AutoCloseable[] factories, int count) throws Exception {
+    static <DAO extends GeodeticAuthorityFactory> void close(final List<DAO> factories) throws Exception {
         Exception exception = null;
-        while (--count >= 0) try {
-            factories[count].close();
-        } catch (Exception e) {
-            if (exception == null) {
-                exception = e;
-            } else {
-                exception.addSuppressed(e);
+        for (int i=factories.size(); --i>=0;) {
+            final DAO factory = factories.get(i);
+            if (factory instanceof AutoCloseable) try {
+                ((AutoCloseable) factory).close();
+            } catch (Exception e) {
+                if (exception == null) {
+                    exception = e;
+                } else {
+                    exception.addSuppressed(e);
+                }
             }
         }
         if (exception != null) {
@@ -1846,12 +1897,12 @@ public abstract class ConcurrentAuthorit
     @Override
     public void close() throws FactoryException {
         try {
-            final AutoCloseable[] factories;
+            final List<DAO> factories;
             synchronized (availableDAOs) {
-                factories = getCloseables(availableDAOs);
-                availableDAOs.clear();
+                factories = clear(availableDAOs);
             }
-            close(factories, factories.length);         // Must be invoked outside the synchronized block.
+            confirmClose(factories);
+            close(factories);                       // Must be invoked outside the synchronized block.
         } catch (Exception e) {
             if (e instanceof FactoryException) {
                 throw (FactoryException) e;
@@ -1860,4 +1911,42 @@ public abstract class ConcurrentAuthorit
             }
         }
     }
+
+    /**
+     * Returns a string representation of this factory for debugging purpose only.
+     * The string returned by this method may change in any future SIS version.
+     *
+     * @return A string representation for debugging purpose.
+     */
+    @Debug
+    @Override
+    public String toString() {
+        final String s = super.toString();
+        DataAccessRef<DAO> usage = currentDAO.get();
+        if (usage == null) {
+            synchronized (availableDAOs) {
+                usage = availableDAOs.peekLast();
+            }
+            if (usage == null) {
+                return s;
+            }
+        }
+        return s + System.lineSeparator() + usage;
+    }
+
+    /**
+     * Completes the string representation of this factory for debugging purpose only.
+     * The string formatted by this method may change in any future SIS version.
+     */
+    @Debug
+    @Override
+    final void toString(final StringBuilder buffer) {
+        buffer.append(", cache=").append(cache.size()).append(", DAO=");
+        synchronized (availableDAOs) {
+            buffer.append(availableDAOs.size());
+            if (remainingDAOs <= 0) {
+                buffer.append(" (limit reached)");
+            }
+        }
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -40,6 +40,8 @@ import org.apache.sis.util.iso.AbstractF
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.Classes;
+import org.apache.sis.util.Debug;
 
 
 /**
@@ -1232,4 +1234,25 @@ public abstract class GeodeticAuthorityF
         throw new NoSuchAuthorityCodeException(Errors.format(Errors.Keys.UnexpectedTypeForReference_3, code, type, actual),
                 Citations.getIdentifier(authority, false), trimAuthority(code, authority), code);
     }
+
+    /**
+     * Returns a string representation of this factory for debugging purpose only.
+     * The string returned by this method may change in any future SIS version.
+     *
+     * @return A string representation for debugging purpose.
+     */
+    @Debug
+    @Override
+    public String toString() {
+        final StringBuilder buffer = new StringBuilder(Classes.getShortClassName(this))
+                .append("[“").append(Citations.getIdentifier(getAuthority(), false)).append('”');
+        toString(buffer);
+        return buffer.append(']').toString();
+    }
+
+    /**
+     * Hook for subclasses.
+     */
+    void toString(final StringBuilder buffer) {
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectSet.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -177,7 +177,7 @@ public class IdentifiedObjectSet<T exten
      * @return The authority codes in iteration order.
      */
     public String[] getAuthorityCodes() {
-        return codes.clone();
+        return codes().clone();
     }
 
     /**
@@ -533,6 +533,8 @@ public class IdentifiedObjectSet<T exten
      *   <li>If {@link NoSuchIdentifierException}, returns {@code true} since this exception is caused by an attempt to
      *       {@linkplain org.opengis.referencing.operation.MathTransformFactory#createParameterizedTransform
      *       create a parameterized transform} for an unimplemented operation.</li>
+     *   <li>If {@link MissingFactoryResourceException}, returns {@code true}.</li>
+     *   <li>Otherwise returns {@code false}.</li>
      * </ul>
      *
      * @param  exception The exception that occurred while creating an object.
@@ -540,6 +542,9 @@ public class IdentifiedObjectSet<T exten
      *         or {@code false} if it should be considered fatal.
      */
     protected boolean isRecoverableFailure(final FactoryException exception) {
-        return (exception instanceof NoSuchIdentifierException) && !(exception instanceof NoSuchAuthorityCodeException);
+        if (exception instanceof NoSuchIdentifierException) {
+            return !(exception instanceof NoSuchAuthorityCodeException);
+        }
+        return (exception instanceof MissingFactoryResourceException);
     }
 }

Copied: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java (from r1723040, sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java)
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java?p2=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java&p1=sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java&r1=1723040&r2=1723176&rev=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/MissingFactoryResourceException.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -20,27 +20,35 @@ import org.opengis.util.FactoryException
 
 
 /**
- * Thrown when a factory can not be created because an optional resource is missing.
- * The most common case is when the {@link org.apache.sis.referencing.factory.epsg.EPSGFactory}
- * has no connection to an EPSG database.
+ * Thrown when an object can not be created because a resource is missing.
+ * The most common case is a NADCON or NTv2 datum shift operation requested while the
+ * datum shift grids was not found in the {@code $SIS_DATA/DatumChanges} directory.
  *
- * @author  Martin Desruisseaux (IRD)
+ * <div class="section">Relationship with other exceptions</div>
+ * This exception means that the factory failed to create a particular object.
+ * However the factory may succeed in creating other objects.
+ * By contrast, {@link UnavailableFactoryException} means that the whole factory can not be used at all.
+ *
+ * <p>This exception is <strong>not</strong> for unimplemented operations (for example map projections not yet supported).
+ * For unimplemented operation methods, use {@link org.opengis.util.NoSuchIdentifierException} instead.</p>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
  * @since   0.7
  * @version 0.7
  * @module
  *
  * @see ConcurrentAuthorityFactory#newDataAccess()
  */
-public class UnavailableFactoryException extends FactoryException {
+public class MissingFactoryResourceException extends FactoryException {
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -661925454228937249L;
+    private static final long serialVersionUID = -6726760720630526886L;
 
     /**
      * Construct an exception with no detail message.
      */
-    public UnavailableFactoryException() {
+    public MissingFactoryResourceException() {
     }
 
     /**
@@ -49,7 +57,7 @@ public class UnavailableFactoryException
      * @param  message The detail message. The detail message is saved
      *         for later retrieval by the {@link #getMessage()} method.
      */
-    public UnavailableFactoryException(String message) {
+    public MissingFactoryResourceException(String message) {
         super(message);
     }
 
@@ -63,7 +71,7 @@ public class UnavailableFactoryException
      * @param  cause The cause for this exception. The cause is saved
      *         for later retrieval by the {@link #getCause()} method.
      */
-    public UnavailableFactoryException(String message, Throwable cause) {
+    public MissingFactoryResourceException(String message, Throwable cause) {
         super(message, cause);
     }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -16,14 +16,17 @@
  */
 package org.apache.sis.referencing.factory;
 
-import org.opengis.util.FactoryException;
-
 
 /**
- * Thrown when a factory can not be created because an optional resource is missing.
+ * Thrown when a factory can not be created because a resource is missing.
  * The most common case is when the {@link org.apache.sis.referencing.factory.epsg.EPSGFactory}
  * has no connection to an EPSG database.
  *
+ * <div class="section">Relationship with other exceptions</div>
+ * This exception means that the whole factory is unusable.
+ * By contrast, {@link MissingFactoryResourceException} means that at least one particular object
+ * can not be created, but other objects may be okay.
+ *
  * @author  Martin Desruisseaux (IRD)
  * @since   0.7
  * @version 0.7
@@ -31,7 +34,7 @@ import org.opengis.util.FactoryException
  *
  * @see ConcurrentAuthorityFactory#newDataAccess()
  */
-public class UnavailableFactoryException extends FactoryException {
+public class UnavailableFactoryException extends MissingFactoryResourceException {
     /**
      * Serial number for inter-operability with different versions.
      */

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -615,8 +615,8 @@ addURIs:    for (int i=0; ; i++) {
             try {
                 primaryKeys[i] = Integer.parseInt(code);
             } catch (NumberFormatException e) {
-                final NoSuchIdentifierException ne = new NoSuchIdentifierException(error().getString(
-                        Errors.Keys.IllegalIdentifierForCodespace_2, Constants.EPSG, code), code);
+                final NoSuchAuthorityCodeException ne = new NoSuchAuthorityCodeException(error().getString(
+                        Errors.Keys.IllegalIdentifierForCodespace_2, Constants.EPSG, code), Constants.EPSG, code);
                 ne.initCause(e);
                 throw ne;
             }
@@ -2388,7 +2388,6 @@ addURIs:    for (int i=0; ; i++) {
         try (ResultSet result = executeQuery("Coordinate_Operation Method", "COORD_OP_METHOD_CODE", "COORD_OP_METHOD_NAME",
                 "SELECT COORD_OP_METHOD_CODE," +
                       " COORD_OP_METHOD_NAME," +
-                      " FORMULA," +
                       " REMARKS," +
                       " DEPRECATED" +
                  " FROM [Coordinate_Operation Method]" +
@@ -2397,13 +2396,12 @@ addURIs:    for (int i=0; ; i++) {
             while (result.next()) {
                 final Integer epsg       = getInteger  (code, result, 1);
                 final String  name       = getString   (code, result, 2);
-                final String  formula    = getOptionalString (result, 3);
-                final String  remarks    = getOptionalString (result, 4);
-                final boolean deprecated = getOptionalBoolean(result, 5);
+                final String  remarks    = getOptionalString (result, 3);
+                final boolean deprecated = getOptionalBoolean(result, 4);
                 final Integer[] dim = getDimensionsForMethod(epsg);
                 final ParameterDescriptor<?>[] descriptors = createParameterDescriptors(epsg);
                 Map<String,Object> properties = createProperties("Coordinate_Operation Method", name, epsg, remarks, deprecated);
-                properties.put(OperationMethod.FORMULA_KEY, formula);
+                // We do not store the formula at this time, because the text is very verbose and rarely used.
                 final OperationMethod method = new DefaultOperationMethod(properties, dim[0], dim[1],
                             new DefaultParameterDescriptorGroup(properties, 1, 1, descriptors));
                 returnValue = ensureSingleton(method, returnValue, code);
@@ -2438,6 +2436,7 @@ addURIs:    for (int i=0; ; i++) {
      * @throws FactoryException if the object creation failed for some other reason.
      */
     @Override
+    @SuppressWarnings("null")
     public synchronized CoordinateOperation createCoordinateOperation(final String code)
             throws NoSuchAuthorityCodeException, FactoryException
     {
@@ -2709,8 +2708,10 @@ addURIs:    for (int i=0; ; i++) {
              * Alter the ordering using the information supplied in the supersession table.
              */
             final String[] codes = set.getAuthorityCodes();
-            sort(codes);
-            set.setAuthorityCodes(codes);
+            if (codes.length > 1) {
+                sort(codes);
+                set.setAuthorityCodes(codes);
+            }
         } catch (SQLException exception) {
             throw databaseFailure(CoordinateOperation.class, label, exception);
         }
@@ -2867,7 +2868,6 @@ addURIs:    for (int i=0; ; i++) {
      * Returns {@code true} if the {@link CoordinateOperation} for the specified code is a {@link Projection}.
      * The caller must have verified that the designed operation is a {@link Conversion} before to invoke this method.
      *
-     * @throws NoSuchIdentifierException if the given code has not been found.
      * @throws SQLException If an error occurred while querying the database.
      */
     final boolean isProjection(final Integer code) throws SQLException {
@@ -3044,7 +3044,7 @@ addURIs:    for (int i=0; ; i++) {
      */
     final synchronized boolean canClose() {
         boolean can = true;
-        if (authorityCodes != null) {
+        if (!authorityCodes.isEmpty()) {
             System.gc();                // For cleaning as much weak references as we can before we check them.
             final Iterator<CloseableReference<AuthorityCodes>> it = authorityCodes.values().iterator();
             while (it.hasNext()) {

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -33,7 +33,6 @@ import org.opengis.referencing.operation
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.apache.sis.internal.metadata.sql.Initializer;
 import org.apache.sis.internal.system.DefaultFactories;
-import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
 import org.apache.sis.referencing.factory.ConcurrentAuthorityFactory;
 import org.apache.sis.referencing.factory.UnavailableFactoryException;
 import org.apache.sis.util.ArgumentChecks;
@@ -56,7 +55,7 @@ import org.apache.sis.util.Localized;
  * @version 0.7
  * @module
  */
-public class EPSGFactory extends ConcurrentAuthorityFactory implements CRSAuthorityFactory,
+public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> implements CRSAuthorityFactory,
         CSAuthorityFactory, DatumAuthorityFactory, CoordinateOperationAuthorityFactory, Localized
 {
     /**
@@ -212,7 +211,7 @@ public class EPSGFactory extends Concurr
      *         This exception usually has a {@link SQLException} as its cause.
      */
     @Override
-    protected GeodeticAuthorityFactory newDataAccess() throws FactoryException {
+    protected EPSGDataAccess newDataAccess() throws FactoryException {
         Connection connection = null;
         try {
             connection = dataSource.getConnection();
@@ -260,4 +259,18 @@ public class EPSGFactory extends Concurr
     protected EPSGDataAccess newDataAccess(Connection connection, SQLTranslator translator) throws SQLException {
         return new EPSGDataAccess(this, connection, translator);
     }
+
+    /**
+     * Returns {@code true} if the given Data Access Object (DAO) can be closed. This method is invoked automatically
+     * after the {@linkplain #getTimeout timeout} if the given DAO has been idle during all that time. The default
+     * implementation always returns {@code false} if a set returned by {@link EPSGDataAccess#getAuthorityCodes(Class)}
+     * is still in use.
+     *
+     * @param factory The Data Access Object which is about to be closed.
+     * @return {@code true} if the given Data Access Object can be closed.
+     */
+    @Override
+    protected boolean canClose(final EPSGDataAccess factory) {
+        return factory.canClose();
+    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -86,8 +86,8 @@ import org.apache.sis.util.resources.Mes
  *
  *
  * <div class="section">Standard parameters</div>
- * {@code MathTransform} instances are created from {@linkplain org.apache.sis.parameter.DefaultParameterValueGroup
- * parameter values}. The parameters expected by each operation available in a default Apache SIS installation is
+ * {@code MathTransform} instances are created from {@linkplain DefaultParameterValueGroup parameter values}.
+ * The parameters expected by each operation available in a default Apache SIS installation is
  * <a href="http://sis.apache.org/book/tables/CoordinateOperationMethods.html">listed here</a>.
  * The set of parameters varies for each operation or projection, but the following can be considered typical:
  *
@@ -106,7 +106,7 @@ import org.apache.sis.util.resources.Mes
  * <div class="section">Dynamic parameters</div>
  * A few non-standard parameters are defined for compatibility reasons,
  * but delegates their work to standard parameters. Those dynamic parameters are not listed in the
- * {@linkplain org.apache.sis.parameter.DefaultParameterValueGroup#values() parameter values}.
+ * {@linkplain DefaultParameterValueGroup#values() parameter values}.
  * Dynamic parameters are:
  *
  * <ul>
@@ -609,7 +609,8 @@ public class DefaultMathTransformFactory
         private void ensureCompatibleParameters(final boolean writable) {
             final ParameterDescriptorGroup expected = provider.getParameters();
             if (parameters.getDescriptor() != expected ||
-                    (writable && !(parameters instanceof DefaultParameterValueGroup)))
+                    (writable &&  (parameters instanceof Parameters)
+                              && !(parameters instanceof DefaultParameterValueGroup)))
             {
                 final ParameterValueGroup copy = expected.createValue();
                 Parameters.copy(parameters, copy);

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java?rev=1723176&r1=1723175&r2=1723176&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/referencing/factory/IdentifiedObjectFinderTest.java [UTF-8] Tue Jan  5 21:39:28 2016
@@ -112,7 +112,9 @@ public final strictfp class IdentifiedOb
     /**
      * An authority factory to be used by {@link IdentifiedObjectFinderTest#testFindOnCachedInstance()}.
      */
-    private static final strictfp class Cached extends ConcurrentAuthorityFactory implements CRSAuthorityFactory {
+    private static final strictfp class Cached extends ConcurrentAuthorityFactory<GeodeticAuthorityFactory>
+            implements CRSAuthorityFactory
+    {
         private final GeodeticAuthorityFactory factory;
 
         public Cached(final GeodeticAuthorityFactory factory) {



Mime
View raw message