You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2015/12/08 23:50:01 UTC
svn commit: r1718735 - in /sis/branches/JDK8/core:
sis-referencing/src/main/java/org/apache/sis/referencing/factory/
sis-utility/src/main/java/org/apache/sis/internal/system/
sis-utility/src/main/java/org/apache/sis/util/collection/
sis-utility/src/mai...
Author: desruisseaux
Date: Tue Dec 8 22:50:00 2015
New Revision: 1718735
URL: http://svn.apache.org/viewvc?rev=1718735&view=rev
Log:
Retrofit 'ThreadedAuthorityFactory' (from Geotk) into CachedAuthorityFactory.
Added:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java (with props)
Modified:
sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CachingAuthorityFactory.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/IdentifiedObjectFinder.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/Threads.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/package-info.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CachingAuthorityFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CachingAuthorityFactory.java?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CachingAuthorityFactory.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CachingAuthorityFactory.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -18,7 +18,11 @@ package org.apache.sis.referencing.facto
import java.util.Set;
import java.util.Map;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.WeakHashMap;
+import java.util.concurrent.TimeUnit;
import java.lang.ref.WeakReference;
import java.io.PrintWriter;
import javax.measure.unit.Unit;
@@ -34,30 +38,45 @@ import org.opengis.util.InternationalStr
import org.opengis.metadata.extent.Extent;
import org.opengis.metadata.citation.Citation;
import org.opengis.parameter.ParameterDescriptor;
+import org.apache.sis.util.Classes;
import org.apache.sis.util.Debug;
import org.apache.sis.util.Disposable;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.collection.Cache;
import org.apache.sis.internal.referencing.NilReferencingObject;
-import org.apache.sis.internal.simple.SimpleCitation;
import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.system.DelayedExecutor;
+import org.apache.sis.internal.system.DelayedRunnable;
import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.util.resources.Errors;
/**
- * An authority factory that caches all objects created by another factory.
+ * A concurrent authority factory that caches all objects created by another factory.
* All {@code createFoo(String)} methods first check if a previously created object exists for the given code.
* If such object exists, it is returned. Otherwise, the object creation is delegated to another factory given
* by {@link #createBackingStore()} and the result is cached in this factory.
*
- * <p>Objects are cached by strong references, up to the amount of objects specified at construction time.
- * If a greater amount of objects are cached, the oldest ones will be retained through a
+ * <p>{@code CachingAuthorityFactory} delays the call to {@code createBackingStore()} until first needed,
+ * and {@linkplain Disposable#dispose() dispose} it after some timeout. This approach allows to establish
+ * a connection to a database (for example) and keep it only for a relatively short amount of time.</p>
+ *
+ * <div class="section">Caching strategy</div>
+ * Objects are cached by strong references, up to the amount of objects specified at construction time.
+ * If a greater amount of objects are cached, then the oldest ones will be retained through a
* {@linkplain WeakReference weak reference} instead of a strong one.
- * This means that this caching factory will continue to return them as long as they are in use somewhere
- * else in the Java virtual machine, but will be discarded (and recreated on the fly if needed) otherwise.</p>
+ * This means that this caching factory will continue to return those objects as long as they are in use somewhere
+ * else in the Java virtual machine, but will be discarded (and recreated on the fly if needed) otherwise.
+ *
+ * <div class="section">Multi-threading</div>
+ * The cache managed by this class is concurrent. However the backing stores are assumed non-concurrent.
+ * If two or more threads are accessing this factory in same time, then two or more backing store instances
+ * may be created. The maximal amount of instances to create is specified at {@code CachingAuthorityFactory}
+ * construction time. If more backing store instances are needed, some of the threads will block until an
+ * instance become available.
*
- * <div class="section">Not for subclasses</div>
+ * <div class="section">Note for subclasses</div>
* This abstract class does not implement any of the {@link DatumAuthorityFactory}, {@link CSAuthorityFactory},
* {@link CRSAuthorityFactory} and {@link CoordinateOperationAuthorityFactory} interfaces.
* Subclasses should select the interfaces that they choose to implement.
@@ -69,24 +88,14 @@ import org.apache.sis.internal.system.Lo
*/
public abstract class CachingAuthorityFactory extends GeodeticAuthorityFactory implements Disposable {
/**
- * The default value for {@link #maxStrongReferences}.
- */
- static final int DEFAULT_MAX = 100;
-
- /**
- * The citation for unknown authority name.
- */
- private static final Citation UNKNOWN = new SimpleCitation("Unknown");
-
- /**
* The authority, cached after first requested.
*/
private transient volatile Citation authority;
/**
- * The pool of cached objects. The keys are instances of {@link Key} or {@link CodePair}.
+ * The pool of cached objects.
*/
- private final Cache<Object,Object> cache;
+ private final Cache<Key,Object> cache;
/**
* The pool of objects identified by {@link Finder#find(IdentifiedObject)} for each comparison modes.
@@ -97,22 +106,145 @@ public abstract class CachingAuthorityFa
private final Map<IdentifiedObject, IdentifiedObject> findPool = new WeakHashMap<>();
/**
- * Constructs an instance with a default number of entries to keep by strong reference.
+ * Holds the reference to a backing store used by {@link CachingAuthorityFactory} together with information
+ * about its usage. In a mono-thread application, there is typically only one {@code BackingStore} 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 CachingAuthorityFactory}.
+ *
+ * <p>If the backing store is currently in use, then {@code BackingStore} 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 CachingAuthorityFactory}. This assumes that factory implementations are reentrant.</p>
+ *
+ * <p>If the backing store has been released, then {@code BackingStore} keep the release timestamp.
+ * This information is used for prioritize the backing stores to dispose.</p>
+ */
+ private static final class BackingStore {
+ /**
+ * The factory used as a backing store.
+ */
+ final GeodeticAuthorityFactory factory;
+
+ /**
+ * Incremented on every call to {@link CachingAuthorityFactory#getBackingStore()} and decremented on every call
+ * to {@link CachingAuthorityFactory#release()}. When this value reach zero, the factory is really released.
+ */
+ int depth;
+
+ /**
+ * The timestamp (<strong>not</strong> relative to epoch) at the time the backing store factory has been
+ * released. This timestamp shall be obtained by a call to {@link System#nanoTime()} for consistency with
+ * {@link DelayedRunnable}.
+ */
+ long timestamp;
+
+ /**
+ * Creates new backing store information for the given factory.
+ */
+ BackingStore(final GeodeticAuthorityFactory factory) {
+ this.factory = factory;
+ }
+
+ /**
+ * Returns a string representation for debugging purpose only.
+ */
+ @Debug
+ @Override
+ public String toString() {
+ final String text;
+ final Number value;
+ if (depth != 0) {
+ text = "%s in use with at depth %d";
+ value = depth;
+ } else {
+ text = "%s made available %d seconds ago";
+ value = (System.nanoTime() - timestamp) / 1E+9; // Convert nanoseconds to seconds.
+ }
+ return String.format(text, Classes.getShortClassName(factory), value);
+ }
+ }
+
+ /**
+ * The backing store in use by the current thread.
+ */
+ private final ThreadLocal<BackingStore> currentStore = new ThreadLocal<>();
+
+ /**
+ * The backing store 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<BackingStore> availableStores = new LinkedList<>();
+
+ /**
+ * The amount of backing stores that can still be created. This number is decremented in a block synchronized
+ * on {@link #availableStores} every time a backing store is in use, and incremented once released.
+ */
+ private int remainingBackingStores;
+
+ /**
+ * {@code true} if the call to {@link #disposeExpired()} is scheduled for future execution in the background
+ * cleaner thread. A value of {@code true} implies that this factory contains at least one active backing store.
+ * 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 !stores.isEmpty()} as a replacement of {@code isActive}
+ * because the queue is empty if all backing stores are currently in use.</p>
+ *
+ * <p>Every access to this field must be performed in a block synchronized on {@link #availableStores}.</p>
+ */
+ private boolean isActive;
+
+ /**
+ * {@code true} if {@link #dispose()} has been invoked.
+ *
+ * <p>Every access to this field must be performed in a block synchronized on {@link #availableStores}.</p>
+ */
+ private boolean isDisposed;
+
+ /**
+ * The delay of inactivity (in nanoseconds) before to close a backing store.
+ * Every access to this field must be performed in a block synchronized on {@link #availableStores}.
+ *
+ * @see #getTimeout(TimeUnit)
+ */
+ private long timeout = 60_000_000_000L; // One minute
+
+ /**
+ * The maximal difference between the scheduled time and the actual time in order to perform the factory disposal,
+ * in nanoseconds. This is used as a tolerance value for possible wait time inaccuracy.
+ */
+ static final long TIMEOUT_RESOLUTION = 200_000_000L; // 0.2 second
+
+ /**
+ * Constructs an instance with a default number of threads and a default number of entries to keep
+ * by strong references. Note that those default values may change in any future SIS versions based
+ * on experience gained.
*/
protected CachingAuthorityFactory() {
- this(DEFAULT_MAX);
+ this(100, 8);
+ /*
+ * NOTE: if the default maximum number of backing stores (currently 8) is augmented,
+ * make sure to augment the number of runner threads in the "StressTest" class to a greater amount.
+ */
}
/**
* Constructs an instance with the specified number of entries to keep by strong references.
- * In a number of object greater than {@code maxStrongReferences} are created, then the strong references
+ * If a number of object greater than {@code maxStrongReferences} are created, then the strong references
* for the eldest ones will be replaced by weak references.
*
* @param maxStrongReferences The maximum number of objects to keep by strong reference.
+ * @param maxConcurrentQueries The maximal amount of backing stores to use concurrently.
+ * If more than this amount of threads are querying this {@code CachingAuthorityFactory} concurrently,
+ * additional threads will be blocked until a backing store become available.
*/
- protected CachingAuthorityFactory(final int maxStrongReferences) {
- super(DefaultFactories.forBuildin(NameFactory.class)); // TODO
+ protected CachingAuthorityFactory(final int maxStrongReferences, final int maxConcurrentQueries) {
+ super(DefaultFactories.forBuildin(NameFactory.class));
ArgumentChecks.ensurePositive("maxStrongReferences", maxStrongReferences);
+ ArgumentChecks.ensureStrictlyPositive("maxConcurrentQueries", maxConcurrentQueries);
+ remainingBackingStores = maxConcurrentQueries;
cache = new Cache<>(20, maxStrongReferences, false);
cache.setKeyCollisionAllowed(true);
/*
@@ -124,20 +256,238 @@ public abstract class CachingAuthorityFa
}
/**
- * Returns the backing store authority factory. The returned backing store must be thread-safe.
- * This method shall be used together with {@link #release()} in a {@code try ... finally} block.
+ * Returns the number of backing stores. This count does not include the backing stores
+ * that are currently under execution. This method is used only for testing purpose.
+ */
+ @Debug
+ final int countBackingStores() {
+ synchronized (availableStores) {
+ return availableStores.size();
+ }
+ }
+
+ /**
+ * Creates a new backing store authority factory. This method is invoked the first time a {@code createFoo(String)}
+ * method is invoked. It may also be invoked again if additional factories are needed in different threads,
+ * or if all factories have been disposed after the timeout.
+ *
+ * <div class="section">Multi-threading</div>
+ * This method (but not necessarily the returned factory) needs to be thread-safe;
+ * {@code CachingAuthorityFactory} does not hold any lock when invoking this method.
+ * Subclasses are responsible to apply their own synchronization if needed,
+ * but are encouraged to avoid doing so if possible.
+ * In addition, implementations should not invoke other {@code CachingAuthorityFactory}
+ * methods during this method execution in order to avoid never-ending loop.
+ *
+ * @return The backing store to uses in {@code createFoo(String)} methods.
+ * @throws UnavailableFactoryException if the backing store is unavailable because an optional resource is missing.
+ * @throws FactoryException if the creation of backing store failed for another reason.
+ */
+ protected abstract GeodeticAuthorityFactory createBackingStore() throws UnavailableFactoryException, FactoryException;
+
+ /**
+ * Returns a backing store authority factory. This method <strong>must</strong>
+ * be used together with {@link #release()} in a {@code try ... finally} block.
*
* @return The backing store to use in {@code createXXX(…)} methods.
- * @throws FactoryException if the creation of backing store failed.
+ * @throws FactoryException if the backing store creation failed.
*/
private GeodeticAuthorityFactory getBackingStore() throws FactoryException {
- throw new UnsupportedOperationException("Not yet implemented");
+ /*
+ * 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.
+ */
+ BackingStore usage = currentStore.get();
+ if (usage == null) {
+ synchronized (availableStores) {
+ if (isDisposed) {
+ throw new UnavailableFactoryException(Errors.format(Errors.Keys.DisposedFactory));
+ }
+ /**
+ * If we have reached the maximal amount of backing stores allowed, wait for a backing store
+ * to become available. In theory the 0.2 second timeout is not necessary, but we put it as a
+ * safety in case we fail to invoke a notify() matching this wait(), for example someone else
+ * is waiting on this monitor or because the release(…) method threw an exception.
+ */
+ while (remainingBackingStores == 0) {
+ try {
+ availableStores.wait(TIMEOUT_RESOLUTION);
+ } catch (InterruptedException e) {
+ // Someone does not want to let us sleep.
+ throw new FactoryException(e.getLocalizedMessage(), e);
+ }
+ }
+ /*
+ * Reuse the most recently used factory, if available. If there is no factory available for reuse,
+ * creates a new one. We do not add it to the queue now; it will be done by the release(…) method.
+ */
+ usage = availableStores.pollLast();
+ remainingBackingStores--; // Should be done last when we are sure to not fail.
+ }
+ /*
+ * If there is a need to create a new factory, do that outside the synchronized block because this
+ * creation may involve a lot of client code. This is better for reducing the dead-lock risk.
+ * Subclasses are responsible of synchronizing their createBackingStore() method if necessary.
+ */
+ try {
+ if (usage == null) {
+ final GeodeticAuthorityFactory factory = createBackingStore();
+ if (factory == null) {
+ throw new UnavailableFactoryException(Errors.format(
+ Errors.Keys.FactoryNotFound_1, GeodeticAuthorityFactory.class));
+ }
+ usage = new BackingStore(factory);
+ currentStore.set(usage);
+ }
+ assert usage.depth == 0 : usage;
+ } finally {
+ /*
+ * If any kind of error occurred, restore the 'remainingBackingStores' field as if no code were executed.
+ * This code would not have been needed if we were allowed to decrement 'remainingBackingStores' only as
+ * the very last step (when we know that everything else succeed). But it needed to be decremented inside
+ * the synchronized block.
+ */
+ if (usage == null) {
+ synchronized (availableStores) {
+ remainingBackingStores++;
+ }
+ }
+ }
+ }
+ /*
+ * Increment below is safe even if outside the synchronized block,
+ * because each thread own exclusively its BackingStore instance
+ */
+ usage.depth++;
+ return usage.factory;
}
/**
- * Releases the backing store previously obtained with {@link #getBackingStore}.
+ * Releases the backing store previously obtained with {@link #getBackingStore()}.
+ * This method marks the factory as available for reuse by other threads.
*/
private void release() {
+ final BackingStore usage = currentStore.get(); // A null value here would be an error in our algorithm.
+ if (--usage.depth == 0) {
+ synchronized (availableStores) {
+ if (isDisposed) return;
+ remainingBackingStores++; // Must be done first in case an exception happen after this point.
+ usage.timestamp = System.nanoTime();
+ availableStores.addLast(usage);
+ /*
+ * If the backing store we just released is the first one, awake the
+ * disposer thread which was waiting for an indefinite amount of time.
+ */
+ if (!isActive) {
+ isActive = true;
+ DelayedExecutor.schedule(new DisposeTask(usage.timestamp + timeout));
+ }
+ availableStores.notify(); // We released only one backing store, so awake only one thread - not all of them.
+ }
+ }
+ assert usage.depth >= 0 : usage;
+ }
+
+ /**
+ * A task for invoking {@link CachingAuthorityFactory#disposeExpired()} after a delay.
+ */
+ private final class DisposeTask extends DelayedRunnable {
+ /**
+ * Creates a new task to be executed at the given time,
+ * in nanoseconds relative to {@link System#nanoTime()}.
+ */
+ DisposeTask(final long timestamp) {
+ super(timestamp);
+ }
+
+ /** Invoked when the delay expired. */
+ @Override public void run() {
+ disposeExpired();
+ }
+ }
+
+ /**
+ * Disposes the expired backing stores. This method should be invoked from a background task only.
+ * This method may reschedule the task again for an other execution if it appears that at least one
+ * backing store was not ready for disposal.
+ *
+ * @see #dispose()
+ */
+ final void disposeExpired() {
+ int count = 0;
+ final Disposable[] toDispose;
+ synchronized (availableStores) {
+ toDispose = new Disposable[availableStores.size()];
+ final Iterator<BackingStore> it = availableStores.iterator();
+ final long nanoTime = System.nanoTime();
+ while (it.hasNext()) {
+ final BackingStore store = it.next();
+ /*
+ * Computes how much time we need to wait again before we can dispose the factory.
+ * If this time is greater than some arbitrary amount, do not dispose the factory
+ * and wait again.
+ */
+ final long nextTime = store.timestamp + timeout;
+ if (nextTime - nanoTime > TIMEOUT_RESOLUTION) {
+ /*
+ * Found a factory which is not expired. Stop the search,
+ * since the iteration is expected to be ordered.
+ */
+ DelayedExecutor.schedule(new DisposeTask(nextTime));
+ break;
+ }
+ /*
+ * Found an expired factory. Adds it to the list of
+ * factories to dispose and search for other factories.
+ */
+ it.remove();
+ if (store.factory instanceof Disposable) {
+ toDispose[count++] = (Disposable) store.factory;
+ }
+ }
+ /*
+ * The stores list is empty if all worker factories in the queue have been disposed.
+ * 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.
+ * In the later case, release() will reschedule a new task.
+ */
+ isActive = !availableStores.isEmpty();
+ }
+ /*
+ * We must dispose the factories from outside the synchronized block.
+ */
+ while (--count >= 0) {
+ toDispose[count].dispose();
+ }
+ }
+
+ /**
+ * Returns the amount of time that {@code CachingAuthorityFactory} will wait before to dispose a backing store.
+ * This delay is measured from the last time the backing store has been used by a {@code createFoo(String)} method.
+ *
+ * @param unit The desired unit of measurement for the timeout.
+ * @return The current timeout in the given unit of measurement.
+ */
+ public long getTimeout(final TimeUnit unit) {
+ synchronized (availableStores) {
+ return unit.convert(timeout, TimeUnit.NANOSECONDS);
+ }
+ }
+
+ /**
+ * Sets a timer for disposing the backing store after the specified amount of time of inactivity.
+ * If a new backing store is needed after the disposal of the last one, then the {@link #createBackingStore()}
+ * method will be invoked again.
+ *
+ * @param delay The delay of inactivity before to close a backing store.
+ * @param unit The unit of measurement of the given delay.
+ */
+ public void setTimeout(long delay, final TimeUnit unit) {
+ ArgumentChecks.ensureStrictlyPositive("delay", delay);
+ delay = unit.toNanos(delay);
+ synchronized (availableStores) {
+ timeout = delay; // Will be taken in account after the next factory to dispose.
+ }
}
/**
@@ -155,7 +505,10 @@ public abstract class CachingAuthorityFa
* </li>
* </ul>
*
- * @return The organization responsible for definition of the database.
+ * If this method can not get a backing store factory (for example because no database connection is available),
+ * then this method returns {@code null}.
+ *
+ * @return The organization responsible for definition of the database, or {@code null} if unavailable.
*/
@Override
public Citation getAuthority() {
@@ -170,7 +523,6 @@ public abstract class CachingAuthorityFa
release();
}
} catch (FactoryException e) {
- c = UNKNOWN;
Logging.unexpectedException(Logging.getLogger(Loggers.CRS_FACTORY),
CachingAuthorityFactory.class, "getAuthority", e);
}
@@ -936,15 +1288,30 @@ public abstract class CachingAuthorityFa
/**
* The key objects to use in the {@link CachingAuthorityFactory#cache}.
+ * This is one of the following pairs of values:
+ * <ul>
+ * <li>For all {@code CachingAuthorityFactory.createFoo(String)} methods:
+ * <ol>
+ * <li>The {@code Foo} {@link Class} of the cached object.</li>
+ * <li>The authority code of the cached object.</li>
+ * </ol>
+ * </li>
+ * <li>For {@link CachingAuthorityFactory#createFromCoordinateReferenceSystemCodes(String, String)}:
+ * <ol>
+ * <li>The authority code of source CRS (stored in the "type" field even if the name is not right).</li>
+ * <li>The authority code of target CRS (stored in the "code" field).</li>
+ * </ol>
+ * </li>
+ * </ul>
*
* @see <a href="http://jira.geotoolkit.org/browse/GEOTK-2">GEOTK-2</a>
*/
private static final class Key {
- /** The type of the cached object. */ final Class<?> type;
+ /** The type of the cached object. */ final Object type;
/** The cached object authority code. */ final String code;
/** Creates a new key for the given type and code. */
- Key(final Class<?> type, final String code) {
+ Key(final Object type, final String code) {
this.type = type;
this.code = code;
}
@@ -965,12 +1332,18 @@ public abstract class CachingAuthorityFa
/** String representation used by {@link CacheRecord}. */
@Override @Debug public String toString() {
- final StringBuilder buffer = new StringBuilder("Key[").append(code);
- if (buffer.length() > 15) { // Arbitrary limit in string length.
- buffer.setLength(15);
- buffer.append('…');
+ final StringBuilder buffer = new StringBuilder();
+ if (type instanceof Class<?>) {
+ buffer.append("Code[“").append(code);
+ if (buffer.length() > 15) { // Arbitrary limit in string length.
+ buffer.setLength(15);
+ buffer.append('…');
+ }
+ buffer.append("” : ").append(((Class<?>) type).getSimpleName());
+ } else {
+ buffer.append("CodePair[“").append(type).append("” → “").append(code).append('”');
}
- return buffer.append(" : ").append(type.getSimpleName()).append(']').toString();
+ return buffer.append(']').toString();
}
}
@@ -1039,7 +1412,7 @@ public abstract class CachingAuthorityFa
{
ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
- final CodePair key = new CodePair(trimAuthority(sourceCRS), trimAuthority(targetCRS));
+ final Key key = new Key(trimAuthority(sourceCRS), trimAuthority(targetCRS));
Object value = cache.peek(key);
if (!(value instanceof Set<?>)) {
final Cache.Handler<Object> handler = cache.lock(key);
@@ -1061,40 +1434,6 @@ public abstract class CachingAuthorityFa
}
/**
- * A pair of codes for operations to cache with
- * {@link CachingAuthorityFactory#createFromCoordinateReferenceSystemCodes(String, String)}.
- */
- private static final class CodePair {
- /** Codes of source and target CRS. */
- private final String source, target;
-
- /** Creates a new key for the given pair of codes. */
- public CodePair(final String source, final String target) {
- this.source = source;
- this.target = target;
- }
-
- /** Returns the hash code value for this key. */
- @Override public int hashCode() {
- return source.hashCode() + target.hashCode() * 31;
- }
-
- /** Compares this key with the given object for equality .*/
- @Override public boolean equals(final Object other) {
- if (other instanceof CodePair) {
- final CodePair that = (CodePair) other;
- return source.equals(that.source) && target.equals(that.target);
- }
- return false;
- }
-
- /** String representation used by {@link CacheRecord}. */
- @Override @Debug public String toString() {
- return "CodePair[" + source + " → " + target + ']';
- }
- }
-
- /**
* Returns a finder which can be used for looking up unidentified objects.
* The default implementation delegates lookup to the underlying backing store and caches the result.
*
@@ -1280,10 +1619,32 @@ public abstract class CachingAuthorityFa
*/
@Override
public void dispose() {
- cache.clear();
- authority = null;
- synchronized (findPool) {
- findPool.clear();
+ try {
+ int count = 0;
+ final Disposable[] factories;
+ synchronized (availableStores) {
+ isDisposed = true;
+ remainingBackingStores = 0;
+ factories = new Disposable[availableStores.size()];
+ BackingStore store;
+ while ((store = availableStores.pollFirst()) != null) {
+ if (store.factory instanceof Disposable) {
+ factories[count++] = (Disposable) store.factory;
+ }
+ }
+ }
+ /*
+ * Factory disposal must be done outside the synchronized block.
+ */
+ while (--count >= 0) {
+ factories[count].dispose();
+ }
+ } finally {
+ synchronized (findPool) {
+ findPool.clear();
+ }
+ cache.clear();
+ authority = null;
}
}
}
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=1718735&r1=1718734&r2=1718735&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 Dec 8 22:50:00 2015
@@ -32,9 +32,10 @@ import org.opengis.util.GenericName;
import org.opengis.util.NameFactory;
import org.opengis.util.FactoryException;
import org.opengis.util.InternationalString;
-import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.internal.util.Citations;
import org.apache.sis.referencing.AbstractIdentifiedObject;
import org.apache.sis.util.iso.AbstractFactory;
+import org.apache.sis.util.resources.Vocabulary;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
@@ -79,8 +80,12 @@ public abstract class GeodeticAuthorityF
/**
* Returns the organization or party responsible for definition and maintenance of the database.
+ * This method may return {@code null} if it can not obtain this information, for example because
+ * the connection to a database is not available.
*
- * @return The organization responsible for definition of the database.
+ * @return The organization responsible for definition of the database, or {@code null} if unknown.
+ *
+ * @see #getVendor()
*/
@Override
public abstract Citation getAuthority();
@@ -92,7 +97,7 @@ public abstract class GeodeticAuthorityF
* <p>The default implementation returns always {@code null}.</p>
*
* @return A description of the underlying backing store, or {@code null} if none.
- * @throws FactoryException if a failure occurs while fetching the backing store description.
+ * @throws FactoryException if a failure occurred while fetching the backing store description.
*/
public InternationalString getBackingStoreDescription() throws FactoryException {
return null;
@@ -751,7 +756,7 @@ public abstract class GeodeticAuthorityF
final GenericName name = nameFactory.parseGenericName(null, code);
if (name instanceof ScopedName) {
final GenericName scope = ((ScopedName) name).path();
- if (Citations.identifierMatches(getAuthority(), scope.toString())) {
+ if (Citations.identifierMatches(getAuthority(), null, scope.toString())) {
return name.tip().toString().trim();
}
}
@@ -767,9 +772,10 @@ public abstract class GeodeticAuthorityF
* @return An exception initialized with an error message built from the specified informations.
*/
protected final NoSuchAuthorityCodeException noSuchAuthorityCode(final Class<?> type, final String code) {
- final InternationalString authority = getAuthority().getTitle();
+ final String authority = Citations.getIdentifier(getAuthority(), false);
return new NoSuchAuthorityCodeException(Errors.format(Errors.Keys.NoSuchAuthorityCode_3,
- authority, type, code), authority.toString(), trimAuthority(code), code);
+ (authority != null) ? authority : Vocabulary.formatInternational(Vocabulary.Keys.Untitled),
+ type, code), authority, trimAuthority(code), code);
}
/**
@@ -795,7 +801,7 @@ public abstract class GeodeticAuthorityF
} else {
actual = object.getClass();
}
- throw new NoSuchAuthorityCodeException(Errors.format(Errors.Keys.UnexpectedTypeForReference_3,
- code, type, actual), getAuthority().getTitle().toString(), trimAuthority(code), code);
+ throw new NoSuchAuthorityCodeException(Errors.format(Errors.Keys.UnexpectedTypeForReference_3, code, type, actual),
+ Citations.getIdentifier(getAuthority(), false), trimAuthority(code), code);
}
}
Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -149,8 +149,9 @@ public class IdentifiedObjectFinder {
/**
* Returns the authority of the factory used by this finder.
+ * The default implementation delegates to {@link GeodeticAuthorityFactory#getAuthority()}.
*
- * @return The authority of the factory used for the searches.
+ * @return The authority of the factory used for the searches, or {@code null} if unknown.
* @throws FactoryException If an error occurred while fetching the authority.
*/
public Citation getAuthority() throws FactoryException {
Added: 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=1718735&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+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.
+ * The most common case is when the {@link org.apache.sis.referencing.factory.epsg.EPSGFactory}
+ * has no connection to an EPSG database.
+ *
+ * @author Martin Desruisseaux (IRD)
+ * @since 0.7
+ * @version 0.7
+ * @module
+ *
+ * @see CachingAuthorityFactory#createBackingStore()
+ */
+public class UnavailableFactoryException extends FactoryException {
+ /**
+ * Serial number for inter-operability with different versions.
+ */
+ private static final long serialVersionUID = -661925454228937249L;
+
+ /**
+ * Construct an exception with no detail message.
+ */
+ public UnavailableFactoryException() {
+ }
+
+ /**
+ * Construct an exception with the specified detail message.
+ *
+ * @param message The detail message. The detail message is saved
+ * for later retrieval by the {@link #getMessage()} method.
+ */
+ public UnavailableFactoryException(String message) {
+ super(message);
+ }
+
+ /**
+ * Construct an exception with the specified cause.
+ *
+ * @param cause The cause for this exception. The cause is saved
+ * for later retrieval by the {@link #getCause()} method.
+ */
+ public UnavailableFactoryException(Throwable cause) {
+ super(cause.getLocalizedMessage(), cause);
+ }
+
+ /**
+ * Construct an exception with the specified detail message and cause.
+ * The cause is the exception thrown in the underlying database
+ * (e.g. {@link java.io.IOException} or {@link java.sql.SQLException}).
+ *
+ * @param message The detail message. The detail message is saved
+ * for later retrieval by the {@link #getMessage()} method.
+ * @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) {
+ super(message, cause);
+ }
+}
Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/UnavailableFactoryException.java
------------------------------------------------------------------------------
svn:mime-type = text/plain;charset=UTF-8
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedExecutor.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -24,97 +24,49 @@ import org.apache.sis.util.logging.Loggi
/**
* A thread executing short tasks after some (potentially zero nanosecond) delay.
- * This thread is reserved to internal SIS usage - no user code shall be executed here.
- * All submitted tasks shall be very quick, since there is only one thread shared by everyone.
+ * This class should be reserved to internal SIS usage without user's code.
+ * In practice some user code may be indirectly executed through SIS tasks invoking overrideable methods.
+ * But all submitted tasks shall be very quick, since there is only one thread shared by everyone.
*
- * <div class="note"><b>Note:</b>
- * In practice some user code may be indirectly executed, since some SIS tasks invoke overrideable methods.
- * We may need to revisit the {@code DelayedExecutor} design in a future version if the above happens to be
- * a problem. For example we may allow the user to specify an application-wide scheduled executor and delegate
- * the tasks to that executor.</div>
- *
- * The methods for use in this class are:
+ * <p>The methods for use in this class are:</p>
* <ul>
- * <li>{@link #executeDaemonTask(DelayedRunnable)}</li>
- * <li>{@link #schedule(DelayedRunnable)}</li>
+ * <li>{@link #schedule(Runnable, long)}</li>
* </ul>
*
* <div class="section">Comparison with {@code java.util.concurrent}</div>
- * We tried to use {@link java.util.concurrent.ScheduledThreadPoolExecutor} in a previous version,
- * but it seems more suitable to heavier tasks in applications controlling their own executor. For
- * example {@code ScheduledThreadPoolExecutor} acts as a fixed-sized pool, thus forcing us to use
- * only one thread if we don't want to waste resources (profiling shows that even a single thread
- * has very low activity). The {@code ThreadPoolExecutor} super-class is more flexible but still
- * have a quite aggressive policy on threads creation, and doesn't handle delayed tasks by itself.
- * We could combine both worlds with a {@code ThreadPoolExecutor} using a {@code DelayedQueue},
- * but it forces us to declare a core pool size of 0 otherwise {@code ThreadPoolExecutor} tries
- * to execute the tasks immediately without queuing them. Combined with the {@code DelayedQueue}
- * characteristics (being an unbounded queue), this result in {@code ThreadPoolExecutor} never
- * creating more than one thread (because it waits for the queue to reject a task before to create
- * more threads than the pool size).
+ * We tried to use {@link java.util.concurrent.ScheduledThreadPoolExecutor} in a previous SIS version,
+ * but its "fixed-sized pool" design forces us to use only one thread if we do not want to waste resources
+ * (profiling shows that even a single thread has very low activity), which reduces the interest of that class.
+ * Combination of {@code ThreadPoolExecutor} super-class with {@code DelayedQueue} were not successful neither.
*
- * <p>Given that it seems difficult to configure {@code (Scheduled)ThreadPoolExecutor} in such
- * a way that two or more threads are created only when really needed, given that using those
- * thread pools seems an overkill when the pool size is fixed to one thread, given that our
- * profiling has show very low activity for that single thread anyway, and given that we do
- * not need cancellation and shutdown services for house keeping tasks (this is a daemon thread),
+ * <p>Given that it:</p>
+ * <ul>
+ * <li>it seems difficult to configure {@code (Scheduled)ThreadPoolExecutor} in such a way
+ * that two or more threads are created only when really needed,</li>
+ * <li>using those executor services seems an overkill when the pool size is fixed to one thread,</li>
+ * <li>our profiling has show very low activity for that single thread anyway,</li>
+ * <li>we do not need cancellation and shutdown services for house keeping tasks (this is a daemon thread),</li>
+ * </ul>
* a more lightweight solution seems acceptable here. Pseudo-benchmarking using the
- * {@code CacheTest.stress()} tests suggests that the lightweight solution is faster.</p>
- *
- * <div class="section">Future evolution</div>
- * We may remove (again) this class in a future SIS evolution if we happen to need an executor anyway.
- * However it may be better to wait and see what are the executor needs. Setting up an executor implies
- * choosing many arbitrary parameter values like the number of core threads, maximum threads, idle time,
- * queue capacity, etc. Furthermore some platforms (e.g. MacOS) provide OS-specific implementations
- * integrating well in their environment. We may want to let the user provides the executor of his
- * choice, or we way want to have more profiling data for choosing an appropriate executor. But we
- * may need to find some way to give priority to SIS tasks, since most of them are for releasing
- * resources - in which case quick execution probably help the system to run faster.
- * However before to switch from the lightweight solution to a more heavy solution,
- * micro-benchmarking is desirable. The {@code CacheTest.stress()} tests can be used
- * in first approximation.
+ * {@code CacheTest.stress()} tests suggests that the lightweight solution is faster.
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.3
- * @version 0.3
+ * @version 0.7
* @module
*
* @see <a href="https://issues.apache.org/jira/browse/SIS-76">SIS-76</a>
*/
public final class DelayedExecutor extends DaemonThread {
/**
- * Executes the given short task in a daemon thread. This method shall be invoked for
- * Apache SIS tasks only, <strong>not</strong> for arbitrary user task. The task must
- * completes quickly, because we will typically use only one thread for all submitted
- * tasks. Completion of the task shall not be critical, since the JVM is allowed to
- * shutdown before task completion.
- *
- * <div class="section">Future evolution</div>
- * If {@code DelayedExecutor} is removed in a future SIS version in favor of JDK6 executors,
- * then the method signature will probably be {@code Executors.execute(Runnable)}.
- *
- * @param task The task to execute.
- */
- public static void executeDaemonTask(final DelayedRunnable task) {
- QUEUE.add(task);
- }
-
- /**
* Schedules the given short task for later execution in a daemon thread.
- * The task will be executed after the delay specified by {@link DelayedRunnable#getDelay}
- * The task must completes quickly, because we will typically use only one thread for all
- * submitted tasks. Completion of the task shall not be critical, since the JVM is allowed
- * to shutdown before task completion.
- *
- * <div class="section">Future evolution</div>
- * If {@code DelayedExecutor} is removed in a future SIS version in favor of JDK6 executors,
- * then the method signature will probably be {@code Executors.schedule(Runnable, long, TimeUnit)}.
+ * The task will be executed after the delay specified by {@link DelayedRunnable#getDelay(TimeUnit)}
+ * The task must completes quickly, because we will typically use only one thread for all submitted tasks.
+ * Completion of the task shall not be critical, since the JVM is allowed to shutdown before task completion.
*
* @param task The task to schedule for later execution.
*/
public static void schedule(final DelayedRunnable task) {
- // For now the implementation is identical to 'execute'. However it may become
- // different if we choose to use a library-wide executor in a future SIS version.
QUEUE.add(task);
}
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/DelayedRunnable.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -39,6 +39,12 @@ public abstract class DelayedRunnable im
* Time of execution of this task, in nanoseconds provided by {@link System#nanoTime()}.
* In the particular case of the {@link Immediate} subclass, the meaning of this field is
* modified: it is rather an ordinal value used for preserving task order.
+ *
+ * <div class="note"><b>Note:</b>
+ * we use {@link System#nanoTime()} instead than {@link System#currentTimeMillis()} because
+ * the later is not guaranteed to be monotonic: {@code currentTimeMillis} may change abruptly
+ * for example if the user adjusts the clock of his operating system.
+ * </div>
*/
final long timestamp;
@@ -74,7 +80,7 @@ public abstract class DelayedRunnable im
@Override
public int compareTo(final Delayed other) {
if (other instanceof Immediate) {
- return +1; // "Immediate" tasks always have precedence over delayed ones.
+ return +1; // "Immediate" tasks always have precedence over delayed ones.
}
return Long.signum(timestamp - ((DelayedRunnable) other).timestamp);
}
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/Threads.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/Threads.java?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/Threads.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/Threads.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -16,8 +16,6 @@
*/
package org.apache.sis.internal.system;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.ExecutorService;
import org.apache.sis.util.Static;
import org.apache.sis.util.logging.Logging;
@@ -34,7 +32,7 @@ import org.apache.sis.util.logging.Loggi
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.3
- * @version 0.3
+ * @version 0.7
* @module
*/
final class Threads extends Static {
@@ -83,19 +81,6 @@ final class Threads extends Static {
static DaemonThread lastCreatedDaemon;
/**
- * Executor to shutdown. This is a copy of the {@code <removed class>} executor static final
- * field, copied here only when the {@code <removed class>} class is loaded and initialized.
- * We proceed that way for avoiding dependency from {@code Threads} to {@code <removed class>}.
- *
- * <p>This field has been temporarily fixed to {@code null} since we removed executor as of
- * <a href="https://issues.apache.org/jira/browse/SIS-76">SIS-76</a>. However we may revert
- * to a modifiable field in a future version if we choose to use executor again. In the main
- * time, we declare this field as {@code final} for allowing the Javac compiler to omit all
- * compiled code inside {@code if (executor != null)} block.</p>
- */
- private static final ExecutorService executor = null;
-
- /**
* Do not allows instantiation of this class.
*/
private Threads() {
@@ -114,20 +99,6 @@ final class Threads extends Static {
* we were waiting for the daemon threads to die.
*/
static synchronized void shutdown(final long stopWaitingAt) throws InterruptedException {
- if (executor != null) {
- executor.shutdown();
- /*
- * Wait for work completion. In theory this is not necessary since the daemon
- * tasks are only house-cleaning work. We nevertheless wait for their completion
- * as a safety. There tasks are supposed to be short.
- */
- final long delay = stopWaitingAt - System.nanoTime();
- if (delay > 0) {
- executor.awaitTermination(delay, TimeUnit.NANOSECONDS);
- // Even if the tasks didn't completed, continue without waiting for them.
- // We can not log at this point, since the logging framework may be shutdown.
- }
- }
DaemonThread.killAll(lastCreatedDaemon, stopWaitingAt);
}
}
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/package-info.java?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/package-info.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/system/package-info.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -25,7 +25,7 @@
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.3
- * @version 0.3
+ * @version 0.7
* @module
*/
package org.apache.sis.internal.system;
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -32,10 +32,9 @@ import org.apache.sis.util.Disposable;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.internal.system.DelayedRunnable;
+import org.apache.sis.internal.system.DelayedExecutor;
import org.apache.sis.internal.system.ReferenceQueueConsumer;
-import static org.apache.sis.internal.system.DelayedExecutor.executeDaemonTask;
-
// Branch-dependent imports
import java.util.function.Supplier;
@@ -304,7 +303,7 @@ public class Cache<K,V> extends Abstract
final Object previous;
if (value != null) {
previous = map.put(key, value);
- executeDaemonTask(new Strong(key, value));
+ DelayedExecutor.schedule(new Strong(key, value));
} else {
previous = map.remove(key);
}
@@ -383,8 +382,8 @@ public class Cache<K,V> extends Abstract
final Reference<V> ref = (Reference<V>) value;
final V result = ref.get();
if (result != null && map.replace(key, ref, result)) {
- ref.clear(); // Prevents the reference from being enqueued.
- executeDaemonTask(new Strong(key, result));
+ ref.clear(); // Prevents the reference from being enqueued.
+ DelayedExecutor.schedule(new Strong(key, result));
}
return result;
}
@@ -476,8 +475,8 @@ public class Cache<K,V> extends Abstract
* would be useless.
*/
if (map.replace(key, ref, result)) {
- ref.clear(); // Prevents the reference from being enqueued.
- executeDaemonTask(new Strong(key, result));
+ ref.clear(); // Prevents the reference from being enqueued.
+ DelayedExecutor.schedule(new Strong(key, result));
}
return new Simple<>(result);
}
@@ -710,7 +709,7 @@ public class Cache<K,V> extends Abstract
lock.unlock();
}
if (done) {
- executeDaemonTask(this);
+ DelayedExecutor.schedule(this);
}
}
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java [UTF-8] Tue Dec 8 22:50:00 2015
@@ -201,6 +201,11 @@ public final class Errors extends Indexe
public static final short DirectoryNotExpected_1 = 165;
/**
+ * The factory has been disposed.
+ */
+ public static final short DisposedFactory = 206;
+
+ /**
* Element “{0}” is duplicated.
*/
public static final short DuplicatedElement_1 = 16;
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties [ISO-8859-1] Tue Dec 8 22:50:00 2015
@@ -51,6 +51,7 @@ CloneNotSupported_1 = Can
ColinearAxisDirections_2 = Axis directions {0} and {1} are colinear.
DeadThread_1 = Thread \u201c{0}\u201d is dead.
DirectoryNotExpected_1 = The \u201c{0}\u201d file points to a directory instead of a regular file.
+DisposedFactory = The factory has been disposed.
DuplicatedElement_1 = Element \u201c{0}\u201d is duplicated.
DuplicatedIdentifier_1 = Name or identifier \u201c{0}\u201d is used more than once.
DuplicatedOption_1 = Option \u201c{0}\u201d is duplicated.
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1718735&r1=1718734&r2=1718735&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties [ISO-8859-1] Tue Dec 8 22:50:00 2015
@@ -48,6 +48,7 @@ CloneNotSupported_1 = Un o
ColinearAxisDirections_2 = Les directions d\u2019axes {0} et {1} sont colin\u00e9aires.
DeadThread_1 = La t\u00e2che \u00ab\u202f{0}\u202f\u00bb est morte.
DirectoryNotExpected_1 = Le fichier \u00ab\u202f{0}\u202f\u00bb d\u00e9signe un r\u00e9pertoire plut\u00f4t qu\u2019un fichier r\u00e9gulier.
+DisposedFactory = La fabrique a \u00e9t\u00e9 dispos\u00e9e.
DuplicatedElement_1 = L\u2019\u00e9lement \u00ab\u202f{0}\u202f\u00bb est dupliqu\u00e9.
DuplicatedIdentifier_1 = Le nom ou l\u2019identifiant \u00ab\u202f{0}\u202f\u00bb est utilis\u00e9 plus d\u2019une fois.
DuplicatedOption_1 = L\u2019option \u00ab\u202f{0}\u202f\u00bb est dupliqu\u00e9e.