sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1394362 - in /sis/trunk/sis-utility/src: main/java/org/apache/sis/util/collection/ main/java/org/apache/sis/util/resources/ test/java/org/apache/sis/test/ test/java/org/apache/sis/util/collection/
Date Fri, 05 Oct 2012 05:17:14 GMT
Author: desruisseaux
Date: Fri Oct  5 05:17:13 2012
New Revision: 1394362

URL: http://svn.apache.org/viewvc?rev=1394362&view=rev
Log:
Added a safe guard in WeakHashSet and WeakValueHashMap against too early capacity reduction.

Added:
    sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java   (with
props)
    sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
  (with props)
    sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
  (with props)
    sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestConfiguration.java
      - copied, changed from r1394344, sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java
Modified:
    sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java
    sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java
    sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakValueHashMap.java
    sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java
    sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java
    sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java
    sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakHashSetTest.java
    sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java

Modified: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java?rev=1394362&r1=1394361&r2=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java (original)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java Fri
Oct  5 05:17:13 2012
@@ -23,6 +23,7 @@ import java.lang.ref.WeakReference;
 import java.lang.reflect.Array;
 
 import org.apache.sis.util.Disposable;
+import org.apache.sis.util.resources.Messages;
 import org.apache.sis.internal.util.ReferenceQueueConsumer;
 
 
@@ -50,9 +51,12 @@ abstract class WeakEntry<E> extends Weak
     static final int HASH_MASK = Integer.MAX_VALUE;
 
     /**
-     * Number of millisecond to wait before to rehash the table for reducing its size.
+     * Number of nanoseconds to wait before to rehash the table for reducing its size.
+     * When the garbage collector collects a lot of elements, we will at least this amount
of time
+     * before rehashing the tables, in case lot of news elements are going to be added. Without
this
+     * field, we noticed many "reduce", "expand", "reduce", "expand", <i>etc.</i>
cycles.
      */
-    static final long HOLD_TIME = 60 * 1000L;
+    static final long REHASH_DELAY = 4000000000L;
 
     /**
      * The next entry, or {@code null} if there is none.
@@ -147,8 +151,8 @@ abstract class WeakEntry<E> extends Weak
         }
         final Logger logger = Collections.LOGGER;
         if (logger.isLoggable(Level.FINEST)) {
-            final LogRecord record = new LogRecord(Level.FINEST,
-                    "Rehash from " + oldTable.length + " to " + table.length);
+            final LogRecord record = Messages.getResources(null).getLogRecord(Level.FINEST,
+                    Messages.Keys.ChangedContainerCapacity_2, oldTable.length, table.length);
             record.setSourceMethodName(callerMethod);
             record.setSourceClassName(entryType.getEnclosingClass().getName());
             record.setLoggerName(logger.getName());
@@ -176,6 +180,6 @@ abstract class WeakEntry<E> extends Weak
      * @return Maximal number of elements for not rehashing.
      */
     static int upperCapacityThreshold(final int capacity) {
-        return capacity + (capacity >>> 2);
+        return capacity - (capacity >>> 2);
     }
 }

Modified: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java?rev=1394362&r1=1394361&r2=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java (original)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakHashSet.java Fri
Oct  5 05:17:13 2012
@@ -123,6 +123,14 @@ public class WeakHashSet<E> extends Abst
     private final boolean mayContainArrays;
 
     /**
+     * The last time when {@link #table} was not in need for rehash. When the garbage collector
+     * collected a lot of elements, we will wait a few seconds before rehashing {@link #table}
+     * in case lot of news elements are going to be added. Without this field, we noticed
many
+     * "reduce", "expand", "reduce", "expand", <i>etc.</i> cycles.
+     */
+    private transient long lastTimeNormalCapacity;
+
+    /**
      * Creates a {@code WeakHashSet} for elements of the specified type.
      *
      * @param <E>  The type of elements in the set.
@@ -139,8 +147,9 @@ public class WeakHashSet<E> extends Abst
      * @param type The type of the element to be included in this set.
      */
     protected WeakHashSet(final Class<E> type) {
-        elementType      = type;
-        mayContainArrays = type.isArray() || type.equals(Object.class);
+        elementType            = type;
+        mayContainArrays       = type.isArray() || type.equals(Object.class);
+        lastTimeNormalCapacity = System.nanoTime();
         /*
          * Workaround for the "generic array creation" compiler error.
          * Otherwise we would use the commented-out line instead.
@@ -171,8 +180,12 @@ public class WeakHashSet<E> extends Abst
             count--;
             assert isValid();
             if (count < lowerCapacityThreshold(capacity)) {
-                table = (Entry[]) WeakEntry.rehash(table, count, "remove");
-                assert isValid();
+                final long currentTime = System.nanoTime();
+                if (currentTime - lastTimeNormalCapacity > REHASH_DELAY) {
+                    table = (Entry[]) WeakEntry.rehash(table, count, "remove");
+                    lastTimeNormalCapacity = currentTime;
+                    assert isValid();
+                }
             }
         }
     }
@@ -362,12 +375,14 @@ public class WeakHashSet<E> extends Abst
                 /*
                  * Check if the table needs to be rehashed, and add {@code obj} to the table.
                  */
-                if (count >= upperCapacityThreshold(table.length)) {
-                    this.table = table = (Entry[]) rehash(table, count, "add");
-                    index = hash % table.length;
+                if (++count >= lowerCapacityThreshold(table.length)) {
+                    if (count > upperCapacityThreshold(table.length)) {
+                        this.table = table = (Entry[]) rehash(table, count, "add");
+                        index = hash % table.length;
+                    }
+                    lastTimeNormalCapacity = System.nanoTime();
                 }
                 table[index] = new Entry(elementType.cast(obj), table[index], hash);
-                count++;
             }
         }
         assert isValid();

Modified: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakValueHashMap.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakValueHashMap.java?rev=1394362&r1=1394361&r2=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakValueHashMap.java
(original)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/util/collection/WeakValueHashMap.java
Fri Oct  5 05:17:13 2012
@@ -196,6 +196,14 @@ public class WeakValueHashMap<K,V> exten
     private transient Set<Map.Entry<K,V>> entrySet;
 
     /**
+     * The last time when {@link #table} was not in need for rehash. When the garbage collector
+     * collected a lot of elements, we will wait a few seconds before rehashing {@link #table}
+     * in case lot of news entries are going to be added. Without this field, we noticed
many
+     * "reduce", "expand", "reduce", "expand", <i>etc.</i> cycles.
+     */
+    private transient long lastTimeNormalCapacity;
+
+    /**
      * Creates a {@code WeakValueHashMap} for keys of the specified type.
      *
      * @param  <K>  The type of keys in the map.
@@ -213,8 +221,9 @@ public class WeakValueHashMap<K,V> exten
      * @param keyType The type of keys in the map.
      */
     protected WeakValueHashMap(final Class<K> keyType) {
-        this.keyType     = keyType;
-        mayContainArrays = keyType.isArray() || keyType.equals(Object.class);
+        this.keyType           = keyType;
+        mayContainArrays       = keyType.isArray() || keyType.equals(Object.class);
+        lastTimeNormalCapacity = System.nanoTime();
         /*
          * Workaround for the "generic array creation" compiler error.
          * Otherwise we would use the commented-out line instead.
@@ -238,8 +247,12 @@ public class WeakValueHashMap<K,V> exten
             count--;
             assert isValid();
             if (count < lowerCapacityThreshold(capacity)) {
-                table = (Entry[]) WeakEntry.rehash(table, count, "remove");
-                assert isValid();
+                final long currentTime = System.nanoTime();
+                if (currentTime - lastTimeNormalCapacity > REHASH_DELAY) {
+                    table = (Entry[]) WeakEntry.rehash(table, count, "remove");
+                    lastTimeNormalCapacity = currentTime;
+                    assert isValid();
+                }
             }
         }
     }
@@ -359,12 +372,14 @@ public class WeakValueHashMap<K,V> exten
             }
         }
         if (value != null) {
-            if (count >= upperCapacityThreshold(table.length)) {
-                this.table = table = (Entry[]) rehash(table, count, "put");
-                index = hash % table.length;
+            if (++count >= lowerCapacityThreshold(table.length)) {
+                if (count > upperCapacityThreshold(table.length)) {
+                    this.table = table = (Entry[]) rehash(table, count, "put");
+                    index = hash % table.length;
+                }
+                lastTimeNormalCapacity = System.nanoTime();
             }
             table[index] = new Entry(keyType.cast(key), value, table[index], hash);
-            count++;
         }
         assert isValid();
         return oldValue;

Added: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java?rev=1394362&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java (added)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java Fri Oct
 5 05:17:13 2012
@@ -0,0 +1,220 @@
+/*
+ * 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.util.resources;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+import org.opengis.util.InternationalString;
+
+
+/**
+ * Locale-dependent resources for miscellaneous (often logging) messages.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.3 (derived from geotk-2.2)
+ * @version 0.3
+ * @module
+ */
+public final class Messages extends IndexedResourceBundle {
+    /**
+     * Resource keys. This class is used when compiling sources, but no dependencies to
+     * {@code Keys} should appear in any resulting class files. Since the Java compiler
+     * inlines final integer values, using long identifiers will not bloat the constant
+     * pools of compiled classes.
+     *
+     * @author  Martin Desruisseaux (IRD, Geomatys)
+     * @since   0.3 (derived from geotk-2.2)
+     * @version 0.3
+     * @module
+     */
+    public static final class Keys {
+        private Keys() {
+        }
+
+        /**
+         * Changed the container capacity from {0} to {1} elements.
+         */
+        public static final int ChangedContainerCapacity_2 = 0;
+    }
+
+    /**
+     * Constructs a new resource bundle loading data from the given UTF file.
+     *
+     * @param filename The file or the JAR entry containing resources.
+     */
+    Messages(final String filename) {
+        super(filename);
+    }
+
+    /**
+     * Returns the {@code Keys} class.
+     */
+    @Override
+    final Class<?> getKeysClass() throws ClassNotFoundException {
+        assert super.getKeysClass() == Keys.class;
+        return Keys.class;
+    }
+
+    /**
+     * Returns resources in the given locale.
+     *
+     * @param  locale The locale, or {@code null} for the default locale.
+     * @return Resources in the given locale.
+     * @throws MissingResourceException if resources can't be found.
+     */
+    public static Messages getResources(final Locale locale) throws MissingResourceException
{
+        return getBundle(Messages.class, locale);
+    }
+
+    /**
+     * Gets a string for the given key from this resource bundle or one of its parents.
+     *
+     * @param  key The key for the desired string.
+     * @return The string for the given key.
+     * @throws MissingResourceException If no object for the given key can be found.
+     */
+    public static String format(final int key) throws MissingResourceException {
+        return getResources(null).getString(key);
+    }
+
+    /**
+     * Gets a string for the given key are replace all occurrence of "{0}"
+     * with values of {@code arg0}.
+     *
+     * @param  key The key for the desired string.
+     * @param  arg0 Value to substitute to "{0}".
+     * @return The formatted string for the given key.
+     * @throws MissingResourceException If no object for the given key can be found.
+     */
+    public static String format(final int    key,
+                                final Object arg0) throws MissingResourceException
+    {
+        return getResources(null).getString(key, arg0);
+    }
+
+    /**
+     * Gets a string for the given key are replace all occurrence of "{0}",
+     * "{1}", with values of {@code arg0}, {@code arg1}.
+     *
+     * @param  key The key for the desired string.
+     * @param  arg0 Value to substitute to "{0}".
+     * @param  arg1 Value to substitute to "{1}".
+     * @return The formatted string for the given key.
+     * @throws MissingResourceException If no object for the given key can be found.
+     */
+    public static String format(final int    key,
+                                final Object arg0,
+                                final Object arg1) throws MissingResourceException
+    {
+        return getResources(null).getString(key, arg0, arg1);
+    }
+
+    /**
+     * Gets a string for the given key are replace all occurrence of "{0}",
+     * "{1}", with values of {@code arg0}, {@code arg1}, etc.
+     *
+     * @param  key The key for the desired string.
+     * @param  arg0 Value to substitute to "{0}".
+     * @param  arg1 Value to substitute to "{1}".
+     * @param  arg2 Value to substitute to "{2}".
+     * @return The formatted string for the given key.
+     * @throws MissingResourceException If no object for the given key can be found.
+     */
+    public static String format(final int    key,
+                                final Object arg0,
+                                final Object arg1,
+                                final Object arg2) throws MissingResourceException
+    {
+        return getResources(null).getString(key, arg0, arg1, arg2);
+    }
+
+    /**
+     * Gets a string for the given key are replace all occurrence of "{0}",
+     * "{1}", with values of {@code arg0}, {@code arg1}, etc.
+     *
+     * @param  key The key for the desired string.
+     * @param  arg0 Value to substitute to "{0}".
+     * @param  arg1 Value to substitute to "{1}".
+     * @param  arg2 Value to substitute to "{2}".
+     * @param  arg3 Value to substitute to "{3}".
+     * @return The formatted string for the given key.
+     * @throws MissingResourceException If no object for the given key can be found.
+     */
+    public static String format(final int    key,
+                                final Object arg0,
+                                final Object arg1,
+                                final Object arg2,
+                                final Object arg3) throws MissingResourceException
+    {
+        return getResources(null).getString(key, arg0, arg1, arg2, arg3);
+    }
+
+    /**
+     * The international string to be returned by {@link formatInternational}.
+     */
+    private static final class International extends ResourceInternationalString {
+        private static final long serialVersionUID = -229348959712294903L;
+
+        International(int key)              {super(key);}
+        International(int key, Object args) {super(key, args);}
+        @Override IndexedResourceBundle getBundle(Locale locale) {
+            return getResources(locale);
+        }
+    }
+
+    /**
+     * Gets an international string for the given key. This method does not check for the
key
+     * validity. If the key is invalid, then a {@link MissingResourceException} may be thrown
+     * when a {@link InternationalString#toString(Locale)} method is invoked.
+     *
+     * @param  key The key for the desired string.
+     * @return An international string for the given key.
+     */
+    public static InternationalString formatInternational(final int key) {
+        return new International(key);
+    }
+
+    /**
+     * Gets an international string for the given key. This method does not check for the
key
+     * validity. If the key is invalid, then a {@link MissingResourceException} may be thrown
+     * when a {@link InternationalString#toString(Locale)} method is invoked.
+     *
+     * {@note This method is redundant with the one expecting <code>Object...</code>,
but avoid
+     *        the creation of a temporary array. There is no risk of confusion since the
two
+     *        methods delegate their work to the same <code>format</code> method
anyway.}
+     *
+     * @param  key The key for the desired string.
+     * @param  arg Values to substitute to "{0}".
+     * @return An international string for the given key.
+     */
+    public static InternationalString formatInternational(final int key, final Object arg)
{
+        return new International(key, arg);
+    }
+
+    /**
+     * Gets an international string for the given key. This method does not check for the
key
+     * validity. If the key is invalid, then a {@link MissingResourceException} may be thrown
+     * when a {@link InternationalString#toString(Locale)} method is invoked.
+     *
+     * @param  key  The key for the desired string.
+     * @param  args Values to substitute to "{0}", "{1}", <i>etc</i>.
+     * @return An international string for the given key.
+     */
+    public static InternationalString formatInternational(final int key, final Object...
args) {
+        return new International(key, args);
+    }
+}

Propchange: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties?rev=1394362&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
(added)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
Fri Oct  5 05:17:13 2012
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+ChangedContainerCapacity_2=Changed the container capacity from {0} to {1} elements.

Propchange: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.properties
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties?rev=1394362&view=auto
==============================================================================
--- sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
(added)
+++ sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
Fri Oct  5 05:17:13 2012
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+ChangedContainerCapacity_2=Changement de la capacit\u00e9 du conteneur de {0} vers {1} \u00e9l\u00e9ments.

Propchange: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/trunk/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.properties
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java?rev=1394362&r1=1394361&r2=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java (original)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/Assert.java Fri Oct  5 05:17:13
2012
@@ -16,8 +16,12 @@
  */
 package org.apache.sis.test;
 
+import java.util.Set;
+import java.util.Map;
 import java.util.Arrays;
 import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.LinkedHashMap;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -32,6 +36,9 @@ import org.xml.sax.SAXException;
 
 import org.apache.sis.util.CharSequences;
 
+// Related to JDK7
+import org.apache.sis.internal.util.Objects;
+
 
 /**
  * Assertion methods used by the SIS project in addition of the JUnit and GeoAPI assertions.
@@ -76,6 +83,68 @@ public strictfp class Assert extends org
     }
 
     /**
+     * Asserts that the given set contains the same elements.
+     * In case of failure, this method lists the missing or unexpected elements.
+     *
+     * @param expected The expected set, or {@code null}.
+     * @param actual   The actual set, or {@code null}.
+     */
+    public static void assertSetEquals(final Set<?> expected, final Set<?> actual)
{
+        if (expected != null && actual != null && !expected.isEmpty()) {
+            final Set<Object> r = new LinkedHashSet<Object>(expected);
+            assertTrue("The two sets are disjoint.",                 r.removeAll(actual));
+            assertTrue("The set is missing elements: " + r,          r.isEmpty());
+            assertTrue("The set unexpectedly became empty.",         r.addAll(actual));
+            assertTrue("The two sets are disjoint.",                 r.removeAll(expected));
+            assertTrue("The set contains unexpected elements: " + r, r.isEmpty());
+        }
+        assertEquals("Set.equals(Object) failed:", expected, actual);
+    }
+
+    /**
+     * Asserts that the given map contains the same entries.
+     * In case of failure, this method lists the missing or unexpected entries.
+     *
+     * @param expected The expected map, or {@code null}.
+     * @param actual   The actual map, or {@code null}.
+     */
+    public static void assertMapEquals(final Map<?,?> expected, final Map<?,?>
actual) {
+        if (expected != null && actual != null && !expected.isEmpty()) {
+            final Map<Object,Object> r = new LinkedHashMap<Object,Object>(expected);
+            for (final Map.Entry<?,?> entry : actual.entrySet()) {
+                final Object key = entry.getKey();
+                if (!r.containsKey(key)) {
+                    fail("Unexpected entry for key " + key);
+                }
+                final Object ve = r.remove(key);
+                final Object va = entry.getValue();
+                if (!Objects.equals(ve, va)) {
+                    fail("Wrong value for key " + key + ": expected " + ve + " but got "
+ va);
+                }
+            }
+            if (!r.isEmpty()) {
+                fail("The map is missing entries: " + r);
+            }
+            r.putAll(actual);
+            for (final Map.Entry<?,?> entry : expected.entrySet()) {
+                final Object key = entry.getKey();
+                if (!r.containsKey(key)) {
+                    fail("Missing an entry for key " + key);
+                }
+                final Object ve = entry.getValue();
+                final Object va = r.remove(key);
+                if (!Objects.equals(ve, va)) {
+                    fail("Wrong value for key " + key + ": expected " + ve + " but got "
+ va);
+                }
+            }
+            if (!r.isEmpty()) {
+                fail("The map contains unexpected elements:" + r);
+            }
+        }
+        assertEquals("Map.equals(Object) failed:", expected, actual);
+    }
+
+    /**
      * Ensures that a tree is equals to an other tree.
      * This method invokes itself recursively for every child nodes.
      *

Modified: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java?rev=1394362&r1=1394361&r2=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java (original)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestCase.java Fri Oct  5 05:17:13
2012
@@ -37,8 +37,8 @@ import org.apache.sis.util.logging.Loggi
 import org.junit.After;
 import org.junit.runner.RunWith;
 
-import static org.apache.sis.test.TestSuite.VERBOSE_OUTPUT_KEY;
-import static org.apache.sis.test.TestSuite.OUTPUT_ENCODING_KEY;
+import static org.apache.sis.test.TestConfiguration.VERBOSE_OUTPUT_KEY;
+import static org.apache.sis.test.TestConfiguration.OUTPUT_ENCODING_KEY;
 
 
 /**
@@ -74,9 +74,9 @@ import static org.apache.sis.test.TestSu
 public abstract strictfp class TestCase {
     /**
      * If non-null, the output writer where to print debugging information.
-     * This field is non-null if the {@value org.apache.sis.test.TestSuite#VERBOSE_OUTPUT_KEY}
-     * system property is set to {@code true}. The encoding will by the system default, unless
-     * the {@value org.apache.sis.test.TestSuite#OUTPUT_ENCODING_KEY} system property has
been
+     * This field is non-null if the {@value org.apache.sis.test.TestConfiguration#VERBOSE_OUTPUT_KEY}
+     * system property is set to {@code true}. This writer will use the system default encoding,
unless
+     * the {@value org.apache.sis.test.TestConfiguration#OUTPUT_ENCODING_KEY} system property
has been
      * set to a different value.
      *
      * @see org.apache.sis.test

Copied: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestConfiguration.java (from
r1394344, sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java)
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestConfiguration.java?p2=sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestConfiguration.java&p1=sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java&r1=1394344&r2=1394362&rev=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java (original)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestConfiguration.java Fri Oct
 5 05:17:13 2012
@@ -16,20 +16,18 @@
  */
 package org.apache.sis.test;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import org.apache.sis.util.Static;
 
 
 /**
- * Base class of Apache SIS test suites (except the ones that extend GeoAPI suites).
+ * Information about the configuration of tests
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3 (derived from geotk-3.16)
  * @version 0.3
  * @module
  */
-@RunWith(Suite.class)
-public abstract strictfp class TestSuite {
+public final strictfp class TestConfiguration extends Static {
     /**
      * The {@value} system property for enabling verbose outputs.
      * If this {@linkplain System#getProperties() system property} is set to {@code true},
@@ -46,8 +44,19 @@ public abstract strictfp class TestSuite
     public static final String OUTPUT_ENCODING_KEY = "org.apache.sis.test.encoding";
 
     /**
-     * Creates a new test suite.
+     * Do not allow instantiation of this class.
      */
-    protected TestSuite() {
+    private TestConfiguration() {
+    }
+
+    /**
+     * Returns {@code true} if tests that may depend on the garbage collector activity are
allowed.
+     * Those tests are a little bit dangerous since they may randomly fail on a server too
busy for
+     * running the garbage collector as fast as expected.
+     *
+     * @return {@code true} if tests that may depend on garbage collector activity are allowed.
+     */
+    public static boolean allowGarbageCollectorDependentTests() {
+        return true;
     }
 }

Modified: sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java?rev=1394362&r1=1394361&r2=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java (original)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/test/TestSuite.java Fri Oct  5 05:17:13
2012
@@ -31,21 +31,6 @@ import org.junit.runners.Suite;
 @RunWith(Suite.class)
 public abstract strictfp class TestSuite {
     /**
-     * The {@value} system property for enabling verbose outputs.
-     * If this {@linkplain System#getProperties() system property} is set to {@code true},
-     * then the {@link TestCase#out} field will be set to a non-null value.
-     */
-    public static final String VERBOSE_OUTPUT_KEY = "org.apache.sis.test.verbose";
-
-    /**
-     * The {@value} system property for setting the output encoding.
-     * This property is used only if the {@link #VERBOSE_OUTPUT_KEY} property
-     * is set to "{@code true}". If this property is not set, then the system
-     * encoding will be used.
-     */
-    public static final String OUTPUT_ENCODING_KEY = "org.apache.sis.test.encoding";
-
-    /**
      * Creates a new test suite.
      */
     protected TestSuite() {

Modified: sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakHashSetTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakHashSetTest.java?rev=1394362&r1=1394361&r2=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakHashSetTest.java
(original)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakHashSetTest.java
Fri Oct  5 05:17:13 2012
@@ -20,9 +20,10 @@ import java.util.HashSet;
 import java.util.Random;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.TestConfiguration;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
@@ -36,17 +37,27 @@ import static org.junit.Assert.*;
  */
 public final strictfp class WeakHashSetTest extends TestCase {
     /**
+     * The size of the test sets to be created.
+     */
+    private static final int SAMPLE_SIZE = 500;
+
+    /**
+     * Number of time to retry the tests.
+     */
+    private static final int NUM_RETRY = 4;
+
+    /**
      * Tests the {@link WeakHashSet} using strong references.
      * The tested {@link WeakHashSet} should behave like a standard {@link Set} object.
      */
     @Test
     public void testStrongReferences() {
         final Random random = new Random();
-        for (int pass=0; pass<20; pass++) {
+        for (int pass=0; pass<NUM_RETRY; pass++) {
             final WeakHashSet<Integer> weakSet = WeakHashSet.newInstance(Integer.class);
             final HashSet<Integer> strongSet = new HashSet<Integer>();
-            for (int i=0; i<1000; i++) {
-                final Integer value = random.nextInt(500);
+            for (int i=0; i<SAMPLE_SIZE; i++) {
+                final Integer value = random.nextInt(SAMPLE_SIZE);
                 if (random.nextBoolean()) {
                     /*
                      * Tests addition.
@@ -71,6 +82,7 @@ public final strictfp class WeakHashSetT
                 assertEquals("contains:", strongSet.contains(value), weakSet.contains(value));
                 assertEquals("equals:", strongSet, weakSet);
             }
+            assertSetEquals(strongSet, weakSet);
         }
     }
 
@@ -84,11 +96,11 @@ public final strictfp class WeakHashSetT
     @DependsOnMethod("testStrongReferences")
     public void testWeakReferences() throws InterruptedException {
         final Random random = new Random();
-        for (int pass=0; pass<2; pass++) {
+        for (int pass=0; pass<NUM_RETRY; pass++) {
             final WeakHashSet<Integer> weakSet = WeakHashSet.newInstance(Integer.class);
             final HashSet<Integer> strongSet = new HashSet<Integer>();
-            for (int i=0; i<500; i++) {
-                final Integer value = new Integer(random.nextInt(500)); // Really need new
instances
+            for (int i=0; i<SAMPLE_SIZE; i++) {
+                final Integer value = new Integer(random.nextInt(SAMPLE_SIZE)); // Really
need new instances
                 if (random.nextBoolean()) {
                     /*
                      * Tests addition.
@@ -131,12 +143,30 @@ public final strictfp class WeakHashSetT
                 }
                 assertTrue("containsAll:", weakSet.containsAll(strongSet));
             }
-            // Do our best to lets GC finish its work.
-            for (int i=0; i<4; i++) {
-                Thread.sleep(50);
-                System.gc();
+            /*
+             * The test below needs the garbage collector to complete fully its job in a
timely
+             * manner. A failure in those tests is not necessarily a WeakValueHashMap bug,
as it
+             * could be caused by a heavy server load preventing GC to complete its work.
If this
+             * happen too often, we may turn off the "allow garbage collector dependent tests"
flag.
+             */
+            if (TestConfiguration.allowGarbageCollectorDependentTests()) {
+                int retry = 4;
+                do { // Do our best to lets GC finish its work.
+                    Thread.sleep(50);
+                    System.gc();
+                } while (--retry >= 0 && weakSet.size() != strongSet.size());
+                assertSetEquals(strongSet, weakSet);
+                /*
+                 * Clearing all strong references should make the set empty.
+                 */
+                strongSet.clear();
+                retry = 4;
+                do { // Do our best to lets GC finish its work.
+                    assertTrue("Expected an empty set.", --retry >= 0);
+                    Thread.sleep(50);
+                    System.gc();
+                } while (!weakSet.isEmpty());
             }
-            assertEquals("equals:", strongSet, weakSet);
         }
     }
 

Modified: sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java?rev=1394362&r1=1394361&r2=1394362&view=diff
==============================================================================
--- sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java
(original)
+++ sis/trunk/sis-utility/src/test/java/org/apache/sis/util/collection/WeakValueHashMapTest.java
Fri Oct  5 05:17:13 2012
@@ -19,10 +19,11 @@ package org.apache.sis.util.collection;
 import java.util.HashMap;
 import java.util.Random;
 import org.apache.sis.test.TestCase;
+import org.apache.sis.test.TestConfiguration;
 import org.apache.sis.test.DependsOnMethod;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import static org.apache.sis.test.Assert.*;
 
 
 /**
@@ -41,13 +42,18 @@ public final strictfp class WeakValueHas
     private static final int SAMPLE_SIZE = 500;
 
     /**
+     * Number of time to retry the tests.
+     */
+    private static final int NUM_RETRY = 2;
+
+    /**
      * Tests the {@link WeakValueHashMap} using strong references.
      * The tested {@link WeakValueHashMap} should behave like a standard {@link Map} object.
      */
     @Test
     public void testStrongReferences() {
         final Random random = new Random();
-        for (int pass=0; pass<4; pass++) {
+        for (int pass=0; pass<NUM_RETRY; pass++) {
             final WeakValueHashMap<Integer,Integer> weakMap = WeakValueHashMap.newInstance(Integer.class);
             final HashMap<Integer,Integer> strongMap = new HashMap<Integer,Integer>();
             for (int i=0; i<SAMPLE_SIZE; i++) {
@@ -63,8 +69,7 @@ public final strictfp class WeakValueHas
                     // Test remove
                     assertSame("remove:", strongMap.remove(key), weakMap.remove(key));
                 }
-                assertEquals("size:", strongMap.size(), weakMap.size());
-                assertEquals("equals:", strongMap, weakMap);
+                assertMapEquals(strongMap, weakMap);
             }
         }
     }
@@ -80,7 +85,7 @@ public final strictfp class WeakValueHas
     @DependsOnMethod("testStrongReferences")
     public void testWeakReferences() throws InterruptedException {
         final Random random = new Random();
-        for (int pass=0; pass<2; pass++) {
+        for (int pass=0; pass<NUM_RETRY; pass++) {
             final WeakValueHashMap<Integer,Integer> weakMap = WeakValueHashMap.newInstance(Integer.class);
             final HashMap<Integer,Integer> strongMap = new HashMap<Integer,Integer>();
             for (int i=0; i<SAMPLE_SIZE; i++) {
@@ -121,12 +126,30 @@ public final strictfp class WeakValueHas
                 }
                 assertTrue("containsAll:", weakMap.entrySet().containsAll(strongMap.entrySet()));
             }
-            // Do our best to lets GC finish its work.
-            for (int i=0; i<4; i++) {
-                Thread.sleep(50);
-                System.gc();
+            /*
+             * The test below needs the garbage collector to complete fully its job in a
timely
+             * manner. A failure in those tests is not necessarily a WeakValueHashMap bug,
as it
+             * could be caused by a heavy server load preventing GC to complete its work.
If this
+             * happen too often, we may turn off the "allow garbage collector dependent tests"
flag.
+             */
+            if (TestConfiguration.allowGarbageCollectorDependentTests()) {
+                int retry = 4;
+                do { // Do our best to lets GC finish its work.
+                    Thread.sleep(50);
+                    System.gc();
+                } while (--retry >= 0 && weakMap.size() != strongMap.size());
+                assertMapEquals(strongMap, weakMap);
+                /*
+                 * Clearing all strong references should make the map empty.
+                 */
+                strongMap.clear();
+                retry = 4;
+                do { // Do our best to lets GC finish its work.
+                    assertTrue("Expected an empty map.", --retry >= 0);
+                    Thread.sleep(50);
+                    System.gc();
+                } while (!weakMap.isEmpty());
             }
-            assertEquals("equals:", strongMap, weakMap);
         }
     }
 



Mime
View raw message