[utilities COMMIT] /java-support/trunk/src/main/java/net/shibboleth/utilities/java/support/collection/IndexingObjectS...

noreply at shibboleth.net noreply at shibboleth.net
Fri Jun 6 01:35:13 EDT 2014


Author: putmanb
Date: Fri Jun  6 01:35:12 2014
New Revision: 585

URL: http://svn.shibboleth.net/view/utilities?rev=585&view=rev
Log:
Draft of fix for JSPT-39: IndexingObjectStore uses hashCode() in an unsafe manner.

Modified:
    java-support/trunk/src/main/java/net/shibboleth/utilities/java/support/collection/IndexingObjectStore.java

Modified: java-support/trunk/src/main/java/net/shibboleth/utilities/java/support/collection/IndexingObjectStore.java
URL: http://svn.shibboleth.net/view/utilities/java-support/trunk/src/main/java/net/shibboleth/utilities/java/support/collection/IndexingObjectStore.java?rev=585&r1=584&r2=585&view=diff
==============================================================================
--- java-support/trunk/src/main/java/net/shibboleth/utilities/java/support/collection/IndexingObjectStore.java (original)
+++ java-support/trunk/src/main/java/net/shibboleth/utilities/java/support/collection/IndexingObjectStore.java Fri Jun  6 01:35:12 2014
@@ -25,20 +25,29 @@
 import javax.annotation.concurrent.ThreadSafe;
 
 /**
- * This class is used to store instances of objects that may be created independently but are, in face, the same object.
+ * <p>
+ * This class is used to store instances of objects that may be created independently but are, in fact, the same object.
  * For example, KeyInfo XML structures contain keys, certs, and CRLs. Multiple unique instances of
  * a KeyInfo may contain, and separately construct, the exact same cert. KeyInfo could, therefore, create a class-level
  * instance of this object store and put certs within it. In this manner the cert is only sitting in memory once and
  * each KeyInfo simply stores a reference (index) to stored object.
+ * </p>
  * 
+ * <p>
  * This store uses basic reference counting to keep track of how many of the respective objects are pointing to an
- * entry. Adding an object that already exists, as determined by the objects <code>hashCode()</code> method, simply
+ * entry. Adding an object that already exists, as determined by the object's <code>equals()</code> method, simply
  * increments the reference counter. Removing an object decrements the counter. Only when the counter reaches zero is
  * the object actually freed for garbage collection.
+ * </p>
  * 
- * <strong>Note</strong> the instance of an object returned by {@link #get(String)} need not be the same object as 
- * stored via {@link #put(Object)}.  However, their hash codes will be equal.  Therefore this store should never be 
- * used to store objects that produce identical hash codes but are not functionally identical objects.
+ * <p>
+ * <strong>Note:</strong> the instance of an object returned by {@link #get(String)} need not be the same object as 
+ * stored via {@link #put(Object)}.  However, the instances will be equal according to their <code>equals()</code>.
+ * The indexing and storage is based on use of {@link Map}, so the normal caveats related to use of hash-based
+ * collection types apply: if the stored object's <code>hashCode()</code> and <code>equals()</code> methods are 
+ * implemented based on mutable properties of the object, then those object instance's properties should not 
+ * be mutated while the object is stored, otherwise unpredictable behavior will result.
+ * </p>
  * 
  * @param <T> type of object being stored
  */
@@ -50,11 +59,19 @@
 
     /** Backing object data store. */
     private Map<String, StoredObjectWrapper> objectStore;
+    
+    /** Map of object instances to the index value used to reference them externally. */
+    private Map<T, Integer> indexStore;
+    
+    /** The last index sequence used. */
+    private int lastIndex;
 
     /** Constructor. */
     public IndexingObjectStore() {
         rwLock = new ReentrantReadWriteLock();
         objectStore = new LazyMap<>();
+        indexStore = new LazyMap<>();
+        lastIndex = 0;
     }
 
     /** Clears the object store. */
@@ -63,6 +80,7 @@
         writeLock.lock();
         try {
             objectStore.clear();
+            indexStore.clear();
         } finally {
             writeLock.unlock();
         }
@@ -111,7 +129,7 @@
         Lock writeLock = rwLock.writeLock();
         writeLock.lock();
         try {
-            String index = Integer.toString(object.hashCode());
+            String index = getIndex(object);
 
             StoredObjectWrapper objectWrapper = objectStore.get(index);
             if (objectWrapper == null) {
@@ -172,6 +190,7 @@
                 objectWrapper.decremementReferenceCount();
                 if (objectWrapper.getReferenceCount() == 0) {
                     objectStore.remove(index);
+                    removeIndex(objectWrapper.getObject());
                 }
             }
         } finally {
@@ -187,6 +206,30 @@
      */
     public int size() {
         return objectStore.size();
+    }
+    
+    /**
+     * Get the index for the specified object.
+     * 
+     * @param object the target object
+     * @return the object index value
+     */
+    protected String getIndex(T object) {
+        Integer index = indexStore.get(object);

[... 18 lines stripped ...]


More information about the commits mailing list