Coverage Report - org.apache.commons.classscan.util.ReapingHashMap
 
Classes in this File Line Coverage Branch Coverage Complexity
ReapingHashMap
54%
12/22
N/A
1.909
ReapingHashMap$HashWeakReference
60%
6/10
25%
1/4
1.909
ReapingHashMap$KeyReference
90%
10/11
50%
2/4
1.909
ReapingHashMap$ReaperThread
87%
7/8
N/A
1.909
 
 1  
 /*
 2  
  * Licensed under the Apache License, Version 2.0 (the "License");
 3  
  * you may not use this file except in compliance with the License.
 4  
  * You may obtain a copy of the License at
 5  
  *
 6  
  *      http://www.apache.org/licenses/LICENSE-2.0
 7  
  *
 8  
  * Unless required by applicable law or agreed to in writing, software
 9  
  * distributed under the License is distributed on an "AS IS" BASIS,
 10  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11  
  * See the License for the specific language governing permissions and
 12  
  * limitations under the License.
 13  
  */
 14  
 package org.apache.commons.classscan.util;
 15  
 
 16  
 import java.lang.ref.Reference;
 17  
 import java.lang.ref.ReferenceQueue;
 18  
 import java.lang.ref.WeakReference;
 19  
 import java.util.Collection;
 20  
 import java.util.Map;
 21  
 import java.util.Set;
 22  
 import java.util.concurrent.ConcurrentHashMap;
 23  
 import java.util.concurrent.ConcurrentMap;
 24  
 
 25  27
 public final class ReapingHashMap<K, V> implements Map<K, V> {
 26  
 
 27  9
     private final ConcurrentMap<HashWeakReference<K>, V> innerMap = new ConcurrentHashMap<HashWeakReference<K>, V>();
 28  9
     private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
 29  9
     private final Thread reaper = new ReaperThread();
 30  
 
 31  9
     public ReapingHashMap() {
 32  9
         reaper.setDaemon(true);
 33  9
         reaper.start();
 34  9
     }
 35  
 
 36  
     private class ReaperThread extends Thread {
 37  9
         ReaperThread() {
 38  9
             super("WeakConcurrentHashMap-" + System.identityHashCode(ReapingHashMap.this) + "-reaper");
 39  9
         }
 40  
 
 41  
         @Override
 42  
         public void run() {
 43  
             for (;;) {
 44  
                 try {
 45  18
                     Reference<? extends K> ref = queue.remove();
 46  9
                     HashWeakReference<? extends K> key = (HashWeakReference<? extends K>) ref;
 47  9
                     innerMap.remove(key);
 48  
                 }
 49  0
                 catch (InterruptedException ignore) {
 50  9
                 }
 51  
             }
 52  
         }
 53  
     }
 54  
 
 55  
     @Override
 56  
     public V put(K key, V value) {
 57  18
         HashWeakReference<K> innerKey = new HashWeakReference<K>(key, queue);
 58  18
         return innerMap.put(innerKey, value);
 59  
     }
 60  
 
 61  
     @Override
 62  
     public V get(Object key) {
 63  36
         KeyReference<Object> innerKey = new KeyReference<Object>(key);
 64  36
         return innerMap.get(innerKey);
 65  
     }
 66  
 
 67  
     @Override
 68  
     public void clear() {
 69  0
         throw new UnsupportedOperationException();
 70  
     }
 71  
 
 72  
     @Override
 73  
     public boolean containsKey(Object key) {
 74  0
         throw new UnsupportedOperationException();
 75  
     }
 76  
 
 77  
     @Override
 78  
     public boolean containsValue(Object value) {
 79  0
         throw new UnsupportedOperationException();
 80  
     }
 81  
 
 82  
     @Override
 83  
     public Set<Map.Entry<K, V>> entrySet() {
 84  0
         throw new UnsupportedOperationException();
 85  
     }
 86  
 
 87  
     @Override
 88  
     public boolean isEmpty() {
 89  0
         throw new UnsupportedOperationException();
 90  
     }
 91  
 
 92  
     @Override
 93  
     public Set<K> keySet() {
 94  0
         throw new UnsupportedOperationException();
 95  
     }
 96  
 
 97  
     @Override
 98  
     public void putAll(Map<? extends K, ? extends V> m) {
 99  0
         throw new UnsupportedOperationException();
 100  
     }
 101  
 
 102  
     @Override
 103  
     public V remove(Object key) {
 104  0
         throw new UnsupportedOperationException();
 105  
     }
 106  
 
 107  
     @Override
 108  
     public int size() {
 109  0
         throw new UnsupportedOperationException();
 110  
     }
 111  
 
 112  
     @Override
 113  
     public Collection<V> values() {
 114  0
         throw new UnsupportedOperationException();
 115  
     }
 116  
     
 117  
     static class HashWeakReference<T> extends WeakReference<T> {
 118  
         private final int hashCode;
 119  
 
 120  
         HashWeakReference(T referent, ReferenceQueue<? super T> queue) {
 121  54
             super(referent, queue);
 122  54
             hashCode = System.identityHashCode(referent);
 123  54
         }
 124  
 
 125  
         @Override
 126  
         public int hashCode() {
 127  27
             return hashCode;
 128  
         }
 129  
 
 130  
         @Override
 131  
         public boolean equals(Object obj) {
 132  36
                 if(this==obj) {
 133  36
                         return true;
 134  
                 }
 135  0
                 if(obj instanceof KeyReference) {
 136  
                         @SuppressWarnings("unchecked")
 137  0
                             KeyReference<T> key= (KeyReference<T>)obj;
 138  0
                         return key.compare(this);
 139  
                 }
 140  0
                 throw new UnsupportedOperationException(obj.getClass().getCanonicalName());
 141  
         }
 142  
     }
 143  
 
 144  
     static class KeyReference<T> {
 145  
             private final T key;
 146  
             private final int keyHash;
 147  
             
 148  36
             public KeyReference(T key) {
 149  36
                     this.key= key;
 150  36
                     keyHash= System.identityHashCode(key);
 151  36
             }
 152  
             
 153  
             @Override
 154  
             public int hashCode() {
 155  36
                     return keyHash;
 156  
             }
 157  
 
 158  
             /**
 159  
              * HashMap should only compare KeyReference with HashWeakReference
 160  
              */
 161  
             @Override
 162  
             public boolean equals(Object obj) {
 163  18
                     if(obj instanceof  HashWeakReference) {
 164  
                             @SuppressWarnings("unchecked")
 165  18
                             HashWeakReference<T> weakKey = (HashWeakReference<T>)obj;
 166  18
                             return compare(weakKey);
 167  
                     }
 168  0
                 throw new UnsupportedOperationException(obj.getClass().getCanonicalName());
 169  
             }
 170  
 
 171  
         boolean compare(HashWeakReference<T> ref) {        
 172  18
                 T t = ref.get();
 173  18
                     return key==t;
 174  
         }
 175  
     }
 176  
 }