sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1817596 - in /sis/branches/JDK7: ./ application/sis-openoffice/ core/sis-build-helper/src/main/java/org/apache/sis/internal/book/ core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/ core/sis-metadata/src/main/java/org/ap...
Date Sat, 09 Dec 2017 10:37:12 GMT
Author: desruisseaux
Date: Sat Dec  9 10:37:12 2017
New Revision: 1817596

URL: http://svn.apache.org/viewvc?rev=1817596&view=rev
Log:
Merge from JDK8 branch.

Modified:
    sis/branches/JDK7/   (props changed)
    sis/branches/JDK7/application/sis-openoffice/pom.xml
    sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/Assembler.java
    sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/CodeColorizer.java
    sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst
    sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst
    sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/SIS.lst
    sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
    sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
    sis/branches/JDK7/pom.xml

Propchange: sis/branches/JDK7/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat Dec  9 10:37:12 2017
@@ -1,5 +1,5 @@
 /sis/branches/Android:1430670-1480699
 /sis/branches/JDK6:1394913-1508480
-/sis/branches/JDK8:1584960-1815604
+/sis/branches/JDK8:1584960-1817595
 /sis/branches/JDK9:1773327-1803064
 /sis/trunk:1394364-1508466,1519089-1519674

Modified: sis/branches/JDK7/application/sis-openoffice/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/application/sis-openoffice/pom.xml?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/application/sis-openoffice/pom.xml (original)
+++ sis/branches/JDK7/application/sis-openoffice/pom.xml Sat Dec  9 10:37:12 2017
@@ -141,7 +141,7 @@
         <dependency>
           <groupId>org.apache.sis.non-free</groupId>
           <artifactId>sis-embedded-data</artifactId>
-          <version>0.8-SNAPSHOT</version>
+          <version>${sis.non-free.version}</version>
           <scope>runtime</scope>
         </dependency>
       </dependencies>

Modified: sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/Assembler.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/Assembler.java?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/Assembler.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/Assembler.java
[UTF-8] Sat Dec  9 10:37:12 2017
@@ -391,7 +391,9 @@ public final class Assembler {
                                         tableOfChapterContent = document.createElement("ul");
                                         tableOfChapterContent.setAttribute("class", "toc");
                                         final Node nav = document.createElement("nav");
-                                        nav.appendChild(document.createTextNode(resources.getString("this-chapter")));
+                                        final Node p = document.createElement("p");
+                                        p.appendChild(document.createTextNode(resources.getString("this-chapter")));
+                                        nav.appendChild(p);
                                         nav.appendChild(tableOfChapterContent);
                                         Node insertionPoint = node.getParentNode();     
       // The <header> element.
                                         do insertionPoint = insertionPoint.getNextSibling();
   // The first paragraph.

Modified: sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/CodeColorizer.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/CodeColorizer.java?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/CodeColorizer.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-build-helper/src/main/java/org/apache/sis/internal/book/CodeColorizer.java
[UTF-8] Sat Dec  9 10:37:12 2017
@@ -182,6 +182,17 @@ public final class CodeColorizer {
                 }
                 break;
             }
+            default: {
+                int upper = word.length();
+                while (upper > 0) {
+                    final int c = word.codePointBefore(upper);
+                    if (Character.isUnicodeIdentifierPart(c)) {
+                        word = word.substring(0, upper);
+                        break;
+                    }
+                    upper -= Character.charCount(c);
+                }
+            }
         }
         /*
          * Check if the keyword is a known one. The 'identifierOrigins' map contains only
simple name
@@ -322,7 +333,9 @@ public final class CodeColorizer {
                             nextSubstringStart = lower;
                             lower = text.indexOf(stopCondition, lower+1);
                             if (lower >= 0) {
-                                lower += stopCondition.length();
+                                if (!stopCondition.equals("\n")) {
+                                    lower += stopCondition.length();
+                                }
                                 stopCondition = null;
                             } else {
                                 lower = text.length();

Modified: sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/GEOAPI.lst
[UTF-8] Sat Dec  9 10:37:12 2017
@@ -64,6 +64,7 @@ Ellipsoid
 EllipsoidalCS
 EngineeringCRS
 EngineeringDatum
+Envelope
 EnvironmentalRecord
 EvaluationMethodType
 Event
@@ -233,3 +234,4 @@ VerticalCS
 VerticalDatum
 VerticalDatumType
 VerticalExtent
+createGeodeticDatum

Modified: sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/OGC.lst
[UTF-8] Sat Dec  9 10:37:12 2017
@@ -233,4 +233,6 @@ SV_OperationChainMetadata
 SV_OperationMetadata
 SV_ParameterDirection
 SV_ServiceIdentification
+AXIS
+ORDER
 TOWGS84

Modified: sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/SIS.lst
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/SIS.lst?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/SIS.lst
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-build-helper/src/main/resources/org/apache/sis/internal/book/SIS.lst
[UTF-8] Sat Dec  9 10:37:12 2017
@@ -1,16 +1,37 @@
+AbstractCRS
 AbstractMathTransform
 AngleFormat
+AxesConvention
+Citations
+CommonCRS
 DataStore
+DataStores
 DefaultEllipsoid
+DefaultExtent
 DefaultGeodeticDatum
 DefaultMetadata
 DefaultProjectedCRS
+DirectPosition2D
+Envelope2D
 Envelopes
+Extents
 GeneralEnvelope
 GridGeometry
 IdentifierSpace
+KeyNamePolicy
 Localized
+MathTransforms
+Matrices
+MetadataStandard
 NilObject
 NilReason
 NumberRange
+ObjectConverter
 Range
+ValueExistencePolicy
+JAVABEANS_PROPERTY
+NON_EMPTY
+RIGHT_HANDED
+asValueMap
+castOrCopy
+forConvention

Modified: sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/Extents.java
[UTF-8] Sat Dec  9 10:37:12 2017
@@ -63,11 +63,11 @@ import org.apache.sis.internal.jdk8.JDK8
  * This class provides methods for:
  *
  * <ul>
- *   <li>{@link #getGeographicBoundingBox(Extent)}, {@link #getVerticalRange(Extent)}
- *       and {@link #getDate(Extent, double)}
- *       for fetching geographic or temporal components in a convenient form.</li>
- *   <li>Methods for computing {@linkplain #intersection intersection} of bounding
boxes
- *       and {@linkplain #area area} estimations.</li>
+ *   <li>{@linkplain #getGeographicBoundingBox Fetching geographic},
+ *       {@linkplain #getVerticalRange vertical} or
+ *       {@linkplain #getDate temporal components} in a convenient form.</li>
+ *   <li>Computing {@linkplain #intersection intersection} of bounding boxes</li>
+ *   <li>Computing {@linkplain #area area} estimations.</li>
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/internal/system/Modules.java
[UTF-8] Sat Dec  9 10:37:12 2017
@@ -87,14 +87,14 @@ public final class Modules {
      *
      * @see org.apache.sis.util.Version
      */
-    public static final int MAJOR_VERSION = 0;
+    public static final int MAJOR_VERSION = 1;
 
     /**
      * The minor version number of all Apache SIS modules.
      *
      * @see org.apache.sis.util.Version
      */
-    public static final int MINOR_VERSION = 8;
+    public static final int MINOR_VERSION = 0;
 
     /**
      * The prefix of all classnames in Apache SIS, including a trailing dot.

Modified: sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
[UTF-8] (original)
+++ sis/branches/JDK7/core/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
[UTF-8] Sat Dec  9 10:37:12 2017
@@ -40,47 +40,49 @@ import org.apache.sis.internal.jdk8.Supp
 
 
 /**
- * A concurrent cache mechanism. This implementation is thread-safe and supports concurrency.
- * A cache entry can be locked when an object is in process of being created. The steps
- * are as below:
+ * A concurrent map capable to locks entries for which the value is in process of being computed.
+ * This map is intended for use as a cache, with a goal of avoiding to compute the same values
twice.
+ * This implementation is thread-safe and supports concurrency.
+ * {@code Cache} is based on {@link ConcurrentHashMap} with the addition of three main capabilities:
  *
- * <ol>
- *   <li>Check if the value is already available in the map.
- *       If it is, return it immediately and we are done.</li>
- *   <li>Otherwise, get a lock and check again if the value is already available in
the map
- *       (because the value could have been computed by an other thread between step 1 and
- *       the obtention of the lock). If it is, release the lock and we are done.</li>
- *   <li>Otherwise compute the value, store the result and release the lock.</li>
- * </ol>
+ * <ul>
+ *   <li>Lock an entry when its value is under computation in a thread.</li>
+ *   <li>Block other threads requesting the value of that particular entry until computation
is completed.</li>
+ *   <li>Retain oldest values by soft or weak references instead of strong references.</li>
+ * </ul>
  *
- * The easiest way (except for exception handling) to use this class is to prepare a
- * {@link Callable} statement to be executed only if the object is not in the cache,
- * and to invoke the {@link #getOrCreate getOrCreate} method. Example:
+ * This class can be used by invoking
+ * or {@link #getOrCreate getOrCreate(…)} with lambda functions as below:
  *
  * {@preformat java
  *     private final Cache<String,MyObject> cache = new Cache<String,MyObject>();
  *
- *     public MyObject getMyObject(final String key) throws MyCheckedException {
+ *     public MyObject getMyObject(String key) {
  *         try {
- *             return cache.getOrCreate(key, new Callable<MyObject>() {
- *                 public MyObject call() throws MyCheckedException {
- *                     return createMyObject(key);
- *                 }
- *             });
- *         } catch (MyCheckedException | RuntimeException e) {
- *             throw e;
+ *             return cache.getOrCreate(key, (k) -> createMyObject(k));
  *         } catch (Exception e) {
- *             throw new UndeclaredThrowableException(e);
+ *             // Decide here what to rethrow.
  *         }
  *     }
  * }
  *
- * An alternative is to perform explicitly all the steps enumerated above. This alternative
- * avoid the creation of a temporary {@code Callable} statement which may never be executed,
- * and avoid the exception handling due to the {@code throws Exception} clause. Note that
the
- * call to {@link Handler#putAndUnlock putAndUnlock} <strong>must</strong> be
in the {@code finally}
- * block of a {@code try} block beginning immediately after the call to {@link #lock lock},
- * no matter what the result of the computation is (including {@code null}).
+ * Alternatively, one can handle explicitely the locks.
+ * This alternative sometime provides more flexibility, for example in exception handling.
+ * The steps are as below:
+ *
+ * <ol>
+ *   <li>Check if the value is already available in the map.
+ *       If it is, return it immediately and we are done.</li>
+ *   <li>Otherwise, get a lock and check again if the value is already available in
the map
+ *       (because the value could have been computed by an other thread between step 1 and
+ *       the obtention of the lock). If it is, release the lock and we are done.</li>
+ *   <li>Otherwise compute the value, store the result and release the lock.</li>
+ * </ol>
+ *
+ * Code example is shown below.
+ * Note that the call to {@link Handler#putAndUnlock putAndUnlock(…)} <strong>must</strong>
+ * be inside the {@code finally} block of a {@code try} block beginning immediately after
the call
+ * to {@link #lock lock(…)}, no matter what the result of the computation is (including
{@code null}).
  *
  * {@preformat java
  *     private final Cache<String,MyObject> cache = new Cache<String,MyObject>();
@@ -130,7 +132,8 @@ import org.apache.sis.internal.jdk8.Supp
  * <var>A</var>. If this rule is not meet, deadlock may occur randomly.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.4
+ * @author  Alexis Manin (Geomatys)
+ * @version 1.0
  *
  * @param <K>  the type of key objects.
  * @param <V>  the type of value objects.
@@ -138,11 +141,11 @@ import org.apache.sis.internal.jdk8.Supp
  * @since 0.3
  * @module
  */
-public class Cache<K,V> extends AbstractMap<K,V> {
+public class Cache<K,V> extends AbstractMap<K,V> implements ConcurrentMap<K,V>
{
     /**
-     * The map that contains the cached values. If a value is under the process of being
-     * calculated, then the value will be a temporary instance of {@link Handler}. The
-     * value may also be weak or soft {@link Reference} objects.
+     * The map that contains the cached values. If a value is in the process of being computed,
+     * then the value will be a temporary instance of {@link Handler}.
+     * The value may also be weak or soft {@link Reference} objects.
      */
     private final ConcurrentMap<K,Object> map;
 
@@ -224,11 +227,11 @@ public class Cache<K,V> extends Abstract
      */
     @Override
     public void clear() {
-        map.clear();
-        /*
-         * Do not update "costs" and "totalCost". Instead let adjustReferences(…)
-         * do its job, which needs to be done in a different thread.
-         */
+        synchronized (costs) {
+            map.clear();
+            costs.clear();
+            totalCost = 0;
+        }
     }
 
     /**
@@ -254,14 +257,77 @@ public class Cache<K,V> extends Abstract
     }
 
     /**
-     * Returns {@code true} if this map contains the specified key.
+     * Returns the value mapped to the given key in the cache, potentially waiting for computation
to complete.
+     * This method is similar to {@link #peek(Object)} except that it blocks if the value
is currently under
+     * computation in another thread.
      *
-     * @param  key  the key to check for existence.
-     * @return {@code true} if the given key still exist in this cache.
+     * @param  key  the key of the value to get.
+     * @return the value mapped to the given key, or {@code null} if none.
+     *
+     * @see #peek(Object)
+     * @see #containsKey(Object)
+     * @see #computeIfAbsent(Object, Function)
      */
     @Override
-    public boolean containsKey(final Object key) {
-        return map.containsKey(key);
+    public V get(final Object key) {
+        return valueOf(map.get(key));
+    }
+
+    /**
+     * Returns the value for the given key if it exists, or computes it otherwise.
+     * If a value already exists in the cache, then it is returned immediately.
+     * Otherwise the {@code creator.call()} method is invoked and its result is saved in
this cache for future reuse.
+     *
+     * <div class="note"><b>Example:</b>
+     * the following example shows how this method can be used.
+     * In particular, it shows how to propagate {@code MyCheckedException}:
+     *
+     * {@preformat java
+     *     private final Cache<String,MyObject> cache = new Cache<String,MyObject>();
+     *
+     *     public MyObject getMyObject(final String key) throws MyCheckedException {
+     *         try {
+     *             return cache.getOrCreate(key, new Callable<MyObject>() {
+     *                 public MyObject call() throws MyCheckedException {
+     *                     return createMyObject(key);
+     *                 }
+     *             });
+     *         } catch (MyCheckedException | RuntimeException e) {
+     *             throw e;
+     *         } catch (Exception e) {
+     *             throw new UndeclaredThrowableException(e);
+     *         }
+     *     }
+     * }
+     * </div>
+     *
+     * This method is similar to {@link #computeIfAbsent(Object, Function)} except that it
can propagate
+     * checked exceptions. If the {@code creator} function does not throw any checked exception,
then
+     * invoking {@code computeIfAbsent(…)} is simpler.
+     *
+     * @param  key      the key for which to get the cached or created value.
+     * @param  creator  a method for creating a value, to be invoked only if no value are
cached for the given key.
+     * @return the value for the given key, which may have been created as a result of this
method call.
+     * @throws Exception if an exception occurred during the execution of {@code creator.call()}.
+     *
+     * @see #get(Object)
+     * @see #peek(Object)
+     * @see #computeIfAbsent(Object, Function)
+     */
+    public V getOrCreate(final K key, final Callable<? extends V> creator) throws Exception
{
+        V value = peek(key);
+        if (value == null) {
+            final Handler<V> handler = lock(key);
+            try {
+                value = handler.peek();
+                if (value == null) {
+                    value = creator.call();
+                }
+            } finally {
+                handler.putAndUnlock(value);
+            }
+        }
+        return value;
     }
 
     /**
@@ -273,7 +339,19 @@ public class Cache<K,V> extends Abstract
     }
 
     /**
+     * Ensures that the given value is not an instance of a reserved type.
+     */
+    private static void ensureValidType(final Object value) throws IllegalArgumentException
{
+        if (isReservedType(value)) {
+            throw new IllegalArgumentException(Errors.format(
+                    Errors.Keys.IllegalArgumentClass_2, "value", value.getClass()));
+        }
+    }
+
+    /**
      * Returns the value of the given object, unwrapping it if possible.
+     * If the value is under computation in another thread, this method
+     * will block until the computation is completed.
      */
     @SuppressWarnings("unchecked")
     private static <V> V valueOf(final Object value) {
@@ -291,76 +369,231 @@ public class Cache<K,V> extends Abstract
     }
 
     /**
-     * Puts the given value in cache.
+     * Returns the value of the given object if it is not under computation.
+     * This method is similar to {@link #valueOf(Object)} except that it does
+     * not block if the value is under computation.
+     */
+    @SuppressWarnings("unchecked")
+    private static <V> V immediateValueOf(final Object value) {
+        if (value instanceof Reference<?>) {
+            return ((Reference<V>) value).get();
+        }
+        if (value instanceof Handler<?>) {
+            return null;
+        }
+        return (V) value;
+    }
+
+    /**
+     * Notifies this {@code Cache} instance that an entry has changed. This methods adjusts
+     * cost calculation. This may cause some strong references to become weak references.
      *
-     * @param  key    the key for which to set a value.
-     * @param  value  the value to store.
-     * @return the value previously stored at the given key, or {@code null} if none.
+     * @param  key    key of the entry that changed.
+     * @param  value  the new value. May be {@code null}.
+     */
+    final void notifyChange(final K key, final V value) {
+        DelayedExecutor.schedule(new Strong(key, value));
+    }
+
+    /**
+     * If no value is already mapped and no value is under computation for the given key,
puts the given value
+     * in the cache. Otherwise returns the current value (potentially blocking until the
computation finishes).
+     * A null {@code value} argument is equivalent to a no-op. Otherwise a {@code null} return
value means that
+     * the given {@code value} has been stored in the {@code Cache}.
+     *
+     * @param  key    the key to associate with a value.
+     * @param  value  the value to associate with the given key if no value already exists,
or {@code null}.
+     * @return the existing value mapped to the given key, or {@code null} if none existed
before this method call.
+     *
+     * @see #get(Object)
+     * @see #computeIfAbsent(Object, Function)
+     *
+     * @since 1.0
+     */
+    @Override
+    public V putIfAbsent(final K key, final V value) {
+        if (value == null) {
+            return null;
+        }
+        ensureValidType(value);
+        final Object previous = map.putIfAbsent(key, value);
+        if (previous == null) {
+            // A non-null value means that 'putIfAbsent' did nothing.
+            notifyChange(key, value);
+        }
+        return valueOf(previous);
+    }
+
+    /**
+     * Puts the given value in cache and immediately returns the old value.
+     * A null {@code value} argument removes the entry. If a different value is under computation
in another thread,
+     * then the other thread may fail with an {@link IllegalStateException} unless {@link
#isKeyCollisionAllowed()}
+     * returns {@code true}. For more safety, consider using {@link #putIfAbsent putIfAbsent(…)}
instead.
+     *
+     * @param  key    the key to associate with a value.
+     * @param  value  the value to associate with the given key, or {@code null} for removing
the mapping.
+     * @return the value previously mapped to the given key, or {@code null} if no value
existed before this
+     *         method call or if the value was under computation in another thread.
+     *
+     * @see #get(Object)
+     * @see #putIfAbsent(Object, Object)
      */
     @Override
     public V put(final K key, final V value) {
-        if (isReservedType(value)) {
-            throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.IllegalArgumentClass_2, "value", value.getClass()));
+        ensureValidType(value);
+        final Object previous = (value != null) ? map.put(key, value) : map.remove(key);
+        if (previous != value) {
+            notifyChange(key, value);
         }
-        final Object previous;
-        if (value != null) {
-            previous = map.put(key, value);
-            DelayedExecutor.schedule(new Strong(key, value));
+        return immediateValueOf(previous);
+    }
+
+    /**
+     * If the given key is mapped to any value, replaces that value with the given new value.
+     * Otherwise does nothing. A null {@code value} argument removes the entry.
+     * If a different value is under computation in another thread, then the other thread
may fail with
+     * an {@link IllegalStateException} unless {@link #isKeyCollisionAllowed()} returns {@code
true}.
+     *
+     * @param  key    key of the value to replace.
+     * @param  value  the new value to use in replacement of the previous one, or {@code
null} for removing the mapping.
+     * @return the value previously mapped to the given key, or {@code null} if no value
existed before this
+     *         method call or if the value was under computation in another thread.
+     *
+     * @see #replace(Object, Object, Object)
+     *
+     * @since 1.0
+     */
+    @Override
+    public V replace(final K key, final V value) {
+        ensureValidType(value);
+        final Object previous = (value != null) ? map.replace(key, value) : map.remove(key);
+        if (previous != null) {
+            // A null value means that 'replace' did nothing.
+            notifyChange(key, value);
+        }
+        return immediateValueOf(previous);
+    }
+
+    /**
+     * If the given key is mapped to the given old value, replaces that value with the given
new value.
+     * Otherwise does nothing. A null {@code value} argument removes the entry if the condition
matches.
+     * If a value is under computation in another thread, then this method unconditionally
returns {@code false}.
+     *
+     * @param  key       key of the value to replace.
+     * @param  oldValue  previous value expected to be mapped to the given key.
+     * @param  newValue  the new value to put if the condition matches, or {@code null} for
removing the mapping.
+     * @return {@code true} if the value has been replaced, {@code false} otherwise.
+     *
+     * @since 1.0
+     */
+    @Override
+    public boolean replace(final K key, final V oldValue, final V newValue) {
+        ensureValidType(newValue);
+        final boolean done;
+        if (oldValue != null) {
+            done = (newValue != null) ? map.replace(key, oldValue, newValue) : map.remove(key,
oldValue);
         } else {
-            previous = map.remove(key);
+            done = (newValue != null) && map.putIfAbsent(key, newValue) == null;
+        }
+        if (done) {
+            notifyChange(key, newValue);
+        }
+        return done;
+    }
+
+    /**
+     * Key-value pairs of new entries created during {@link Cache.ReplaceAdapter} execution,
as a chained list.
+     * Calls to {@link Cache#notifyChange(Object, Object)} for those entries need to be deferred
until operation
+     * on {@link Cache#map} completed because {@link Cache#adjustReferences(Object, Object)}
needs the new values
+     * to be present in the map.
+     */
+    private static final class Deferred<K,V> {
+        private final K key;
+        private final V value;
+        private final Deferred<K,V> next;
+
+        /** Creates a new notification to be sent after the {@link Cache#map} operation
completed. */
+        Deferred(final K key, final V value, final Deferred<K,V> next) {
+            this.key   = key;
+            this.value = value;
+            this.next  = next;
+        }
+
+        /** Sends all deferred notifications, starting with the given one. */
+        static <K,V> void notifyChanges(final Cache<K,V> cache, Deferred<K,V>
entry) {
+            while (entry != null) {
+                cache.notifyChange(entry.key, entry.value);
+                entry = entry.next;
+            }
         }
-        return Cache.<V>valueOf(previous);
     }
 
     /**
-     * Removes the value associated to the given key in the cache.
+     * Removes the value mapped to the given key in the cache. If a value is under computation
in another thread,
+     * then the other thread may fail with an {@link IllegalStateException} unless {@link
#isKeyCollisionAllowed()}
+     * returns {@code true}. For more safety, consider using {@link #remove(Object, Object)}
instead.
      *
      * @param  key  the key of the value to removed.
-     * @return the value that were associated to the given key, or {@code null} if none.
+     * @return the value previously mapped to the given key, or {@code null} if no value
existed before this
+     *         method call or if the value was under computation in another thread.
+     *
+     * @see #get(Object)
+     * @see #remove(Object, Object)
      */
     @Override
+    @SuppressWarnings("unchecked")
     public V remove(final Object key) {
-        return Cache.<V>valueOf(map.remove(key));
+        final Object oldValue = map.remove(key);
+        if (oldValue != null) {
+            notifyChange((K) key, null);
+        }
+        return immediateValueOf(oldValue);
     }
 
     /**
-     * Returns the value associated to the given key in the cache. This method is similar
to
-     * {@link #peek} except that it blocks if the value is currently under computation in
an
-     * other thread.
+     * If the given key is mapped to the given old value, removes that value. Otherwise does
nothing.
+     * If a value is under computation in another thread, then this method unconditionally
returns {@code false}.
      *
-     * @param  key  the key of the value to get.
-     * @return the value associated to the given key, or {@code null} if none.
+     * @param  key      key of the value to remove.
+     * @param  oldValue previous value expected to be mapped to the given key.
+     * @return {@code true} if the value has been removed, {@code false} otherwise.
+     *
+     * @see #get(Object)
+     *
+     * @since 1.0
      */
     @Override
-    public V get(final Object key) {
-        return Cache.<V>valueOf(map.get(key));
+    @SuppressWarnings("unchecked")
+    public boolean remove(final Object key, final Object oldValue) {
+        final boolean done = map.remove(key, oldValue);
+        if (done) {
+            notifyChange((K) key, null);
+        }
+        return done;
     }
 
     /**
-     * Returns the value for the given key. If a value already exists in the cache, then
it
-     * is returned immediately. Otherwise the {@code creator.call()} method is invoked and
-     * its result is saved in this cache for future reuse.
+     * Returns {@code true} if this map contains the specified key.
+     * If the value is under computation in another thread, this method returns {@code true}
+     * without waiting for the computation result. This behavior is consistent with other
+     * {@code Map} methods in the following ways:
+     *
+     * <ul>
+     *   <li>{@link #get(Object)} blocks until the computation is completed.</li>
+     *   <li>{@link #put(Object, Object)} returns {@code null} for values under computation,
+     *       i.e. behaves as if keys are temporarily mapped to the {@code null} value until
+     *       the computation is completed.</li>
+     * </ul>
      *
-     * @param  key      the key for which to get the cached or created value.
-     * @param  creator  a method for creating a value, to be invoked only if no value are
cached for the given key.
-     * @return the value for the given key, which may have been created as a result of this
method call.
-     * @throws Exception if an exception occurred during the execution of {@code creator.call()}.
+     * @param  key  the key to check for existence.
+     * @return {@code true} if the given key is mapped to an existing value or a value under
computation.
+     *
+     * @see #get(Object)
+     * @see #peek(Object)
      */
-    public V getOrCreate(final K key, final Callable<? extends V> creator) throws Exception
{
-        V value = peek(key);
-        if (value == null) {
-            final Handler<V> handler = lock(key);
-            try {
-                value = handler.peek();
-                if (value == null) {
-                    value = creator.call();
-                }
-            } finally {
-                handler.putAndUnlock(value);
-            }
-        }
-        return value;
+    @Override
+    public boolean containsKey(final Object key) {
+        return map.containsKey(key);
     }
 
     /**
@@ -370,6 +603,9 @@ public class Cache<K,V> extends Abstract
      *
      * @param  key  the key for which to get the cached value.
      * @return the cached value for the given key, or {@code null} if there is none.
+     *
+     * @see #get(Object)
+     * @see #lock(Object)
      */
     public V peek(final K key) {
         final Object value = map.get(key);
@@ -386,7 +622,7 @@ public class Cache<K,V> extends Abstract
             final V result = ref.get();
             if (result != null && map.replace(key, ref, result)) {
                 ref.clear();                        // Prevents the reference from being
enqueued.
-                DelayedExecutor.schedule(new Strong(key, result));
+                notifyChange(key, result);
             }
             return result;
         }
@@ -397,9 +633,9 @@ public class Cache<K,V> extends Abstract
 
     /**
      * Invoked from the a background thread after a {@linkplain WeakReference weak}
-     * or {@linkplain SoftReference soft} reference has been replaced by a strong one. It
will
-     * looks for older strong references to replace by weak references so that the total
cost
-     * stay below the cost limit.
+     * or {@linkplain SoftReference soft} reference has been replaced by a strong one.
+     * It will looks for older strong references to replace by weak references so that
+     * the total cost stay below the cost limit.
      */
     private final class Strong extends DelayedRunnable.Immediate {
         private final K key;
@@ -479,7 +715,7 @@ public class Cache<K,V> extends Abstract
                      */
                     if (map.replace(key, ref, result)) {
                         ref.clear();                        // Prevents the reference from
being enqueued.
-                        DelayedExecutor.schedule(new Strong(key, result));
+                        notifyChange(key, result);
                     }
                     return new Simple<>(result);
                 }
@@ -530,7 +766,7 @@ public class Cache<K,V> extends Abstract
             return work.new Wait();
         }
         /*
-         * A calculation has already been completed. Returns a wrapper
+         * A computation has already been completed. Returns a wrapper
          * which will just return the result without any processing.
          */
         assert !isReservedType(value) : value;
@@ -540,9 +776,8 @@ public class Cache<K,V> extends Abstract
     }
 
     /**
-     * The handler returned by {@link Cache#lock}, to be used for unlocking and storing the
-     * result. This handler should be used as below (note the {@code try} … {@code catch}
-     * blocks, which are <strong>mandatory</strong>):
+     * The handler returned by {@link Cache#lock}, to be used for unlocking and storing the
result.
+     * This handler should be used as below (the {@code try} … {@code finally} statements
are important):
      *
      * {@preformat java
      *     Value V = null;
@@ -593,12 +828,12 @@ public class Cache<K,V> extends Abstract
 
     /**
      * A simple handler implementation wrapping an existing value. This implementation
-     * is used when the value has been fully calculated in an other thread before this
+     * is used when the value has been fully computed in an other thread before this
      * thread could start its work.
      */
     private final class Simple<V> implements Handler<V> {
         /**
-         * The result calculated in an other thread.
+         * The result computed in an other thread.
          */
         private final V value;
 
@@ -610,7 +845,7 @@ public class Cache<K,V> extends Abstract
         }
 
         /**
-         * Returns the calculated value.
+         * Returns the computed value.
          */
         @Override
         public V peek() {
@@ -663,8 +898,8 @@ public class Cache<K,V> extends Abstract
         }
 
         /**
-         * Waits for the completion of the value computation and returns this result. This
-         * method should be invoked only from an other thread than the one doing the calculation.
+         * Waits for the completion of the value computation and returns this result.
+         * This method should be invoked only from another thread than the one doing the
computation.
          */
         @Override
         public V get() {
@@ -713,6 +948,8 @@ public class Cache<K,V> extends Abstract
             }
             if (done) {
                 DelayedExecutor.schedule(this);
+            } else if (!isKeyCollisionAllowed()) {
+                throw new IllegalStateException(Errors.format(Errors.Keys.KeyCollision_1,
key));
             }
         }
 
@@ -766,8 +1003,8 @@ public class Cache<K,V> extends Abstract
      * than the cost limit, then oldest strong references are replaced by weak references.
      */
     final void adjustReferences(final K key, final V value) {
-        int cost = cost(value);
-        synchronized (costs) {                          // Should not be needed, but done
as a safety.
+        int cost = (value != null) ? cost(value) : 0;
+        synchronized (costs) {
             final Integer old = costs.put(key, cost);
             if (old != null) {
                 cost -= old;
@@ -779,7 +1016,7 @@ public class Cache<K,V> extends Abstract
                      * Converts the current entry from strong reference to weak/soft reference.
                      * We perform this conversion even if the entry is for the value just
added
                      * to the cache, if it happen that the cost is higher than the maximal
one.
-                     * That entry should not be garbage collected to early anyway because
the
+                     * That entry should not be garbage collected too early anyway because
the
                      * caller should still have a strong reference to the value he just created.
                      */
                     final Map.Entry<K,Integer> entry = it.next();

Modified: sis/branches/JDK7/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/pom.xml?rev=1817596&r1=1817595&r2=1817596&view=diff
==============================================================================
--- sis/branches/JDK7/pom.xml (original)
+++ sis/branches/JDK7/pom.xml Sat Dec  9 10:37:12 2017
@@ -499,6 +499,7 @@ Apache SIS is a free software, Java lang
     <maven.compile.source>1.7</maven.compile.source>
     <maven.compile.target>1.7</maven.compile.target>
     <sis.plugin.version>${project.version}</sis.plugin.version>
+    <sis.non-free.version>0.8</sis.non-free.version>
     <geoapi.version>4.0-SNAPSHOT</geoapi.version>
   </properties>
 



Mime
View raw message