Coverage Report - org.webslinger.lang.AbstractCache
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractCache
80%
51/64
100%
4/4
0
AbstractCache$1
57%
4/7
N/A
0
AbstractCache$ConcurrentDelegate
71%
22/31
62%
5/8
0
AbstractCache$HardDelegate
100%
3/3
N/A
0
AbstractCache$Ref
N/A
N/A
0
AbstractCache$RefDelegate
100%
2/2
N/A
0
AbstractCache$Soft
0%
0/6
N/A
0
AbstractCache$SoftDelegate
0%
0/2
N/A
0
AbstractCache$StandardDelegate
0%
0/30
0%
0/8
0
AbstractCache$StorageDelegate
N/A
N/A
0
AbstractCache$StorageType
100%
3/3
N/A
0
AbstractCache$StorageType$1
67%
2/3
100%
1/1
0
AbstractCache$StorageType$2
33%
1/3
0%
0/1
0
AbstractCache$ValueDelegate
100%
1/1
N/A
0
AbstractCache$ValueType
100%
4/4
N/A
0
AbstractCache$ValueType$1
100%
2/2
N/A
0
AbstractCache$ValueType$2
50%
1/2
N/A
0
AbstractCache$ValueType$3
100%
2/2
N/A
0
AbstractCache$Weak
100%
6/6
N/A
0
AbstractCache$WeakDelegate
100%
2/2
N/A
0
 
 1  
 package org.webslinger.lang;
 2  
 
 3  
 import java.util.Map;
 4  
 import java.lang.ref.Reference;
 5  
 import java.lang.ref.ReferenceQueue;
 6  
 import java.lang.ref.SoftReference;
 7  
 import java.lang.ref.WeakReference;
 8  
 import java.util.Collections;
 9  
 import java.util.HashMap;
 10  
 import java.util.HashSet;
 11  
 import java.util.Map;
 12  
 import java.util.Set;
 13  
 import java.util.SortedMap;
 14  
 import java.util.TreeMap;
 15  
 import java.util.concurrent.ConcurrentHashMap;
 16  
 import java.util.concurrent.ConcurrentMap;
 17  
 
 18  3170
 public abstract class AbstractCache<K, V> {
 19  1
     private static Map<String, ValueType> overrideValueType = new HashMap<String, ValueType>();
 20  1
     private static Map<String, StorageType> overrideStorageType = new HashMap<String, StorageType>();
 21  
     static {
 22  1
         overrideValueType.put("org.webslinger.commons.vfs.cow.COWFileSystem, cowStatsPerFS", ValueType.SOFT);
 23  1
         overrideValueType.put("org.webslinger.commons.vfs.cow.COWState, entries", ValueType.HARD);
 24  1
         overrideValueType.put("org.webslinger.container.WebslingerContainer, fileInfoCache", ValueType.SOFT);
 25  1
         overrideValueType.put("org.webslinger.container.WebslingerContainer, lookForFilterCache", ValueType.SOFT);
 26  1
         overrideValueType.put("org.webslinger.container.WebslingerContainer, fullPathCache", ValueType.SOFT);
 27  1
         overrideValueType.put("org.webslinger.WebslingerServletContext, filters", ValueType.SOFT);
 28  1
         overrideValueType.put("org.webslinger.WebslingerServletContext, servletListenerCache", ValueType.SOFT);
 29  1
         overrideValueType.put("org.webslinger.WebslingerServletContext, ChainCache", ValueType.SOFT);
 30  1
         overrideValueType.put("org.webslinger.container.FileInfo, cache", ValueType.HARD);
 31  1
         overrideValueType.put("org.webslinger.bsf.janino.JaninoCompiler, cache", ValueType.HARD);
 32  1
         overrideValueType.put("org.webslinger.bsf.groovy.GroovyCompiler, cache", ValueType.HARD);
 33  1
         overrideValueType.put("org.webslinger.template.velocity.VelocityCompiler, cache", ValueType.HARD);
 34  1
         overrideValueType.put("org.webslinger.ext.bsf.rhino.RhinoCompiler, cache", ValueType.HARD);
 35  1
         overrideValueType.put("org.webslinger.ext.bsf.beanshell.BeanShellCompiler, cache", ValueType.HARD);
 36  1
         overrideValueType.put("org.webslinger.ext.bsf.jython.JythonCompiler, cache", ValueType.HARD);
 37  1
         overrideValueType.put("org.webslinger.ext.quercus.bsf.QuercusCompiler, cache", ValueType.HARD);
 38  1
         overrideValueType.put("org.webslinger.ext.quercus.template.QuercusTemplateCompiler, cache", ValueType.HARD);
 39  1
         overrideValueType.put("org.webslinger.ext.template.freemarker.FreemarkerCompiler, cache", ValueType.HARD);
 40  
     }
 41  
 
 42  2900
     protected abstract static class ValueDelegate<K, V> {
 43  
         protected abstract Object createHolder(K key, V value, StorageDelegate<K, V> storage);
 44  
         protected abstract V extractHolder(Object holder);
 45  
     }
 46  
 
 47  267
     protected abstract static class RefDelegate<K, V> extends ValueDelegate<K, V> {
 48  
         protected V extractHolder(Object ref) {
 49  5733
             return ((Ref<K, V>) ref).get();
 50  
         }
 51  
     }
 52  
 
 53  0
     public static final class SoftDelegate<K, V> extends RefDelegate<K, V> {
 54  
         protected Object createHolder(K key, V value, StorageDelegate<K, V> storage) {
 55  0
             return new Soft<K, V>(key, value, storage);
 56  
         }
 57  
     }
 58  
 
 59  267
     public static final class WeakDelegate<K, V> extends RefDelegate<K, V> {
 60  
         protected Object createHolder(K key, V value, StorageDelegate<K, V> storage) {
 61  2123
             return new Weak<K, V>(key, value, storage);
 62  
         }
 63  
     }
 64  
 
 65  2633
     public static final class HardDelegate<K, V> extends ValueDelegate<K, V> {
 66  
         protected V createHolder(K key, V value, StorageDelegate<K, V> storage) {
 67  1323
             return value;
 68  
         }
 69  
 
 70  
         protected V extractHolder(Object value) {
 71  15558
             return (V) value;
 72  
         }
 73  
     }
 74  
 
 75  7
     public enum ValueType {
 76  1
         SOFT {
 77  
             protected <K, V> ValueDelegate<K, V> createDelegate() {
 78  267
                 return new WeakDelegate<K, V>();
 79  
             }
 80  
         },
 81  1
         WEAK {
 82  
             protected <K, V> ValueDelegate<K, V> createDelegate() {
 83  0
                 return new SoftDelegate<K, V>();
 84  
             }
 85  
         },
 86  1
         HARD {
 87  
             protected <K, V> ValueDelegate<K, V> createDelegate() {
 88  2633
                 return new HardDelegate<K, V>();
 89  
             }
 90  
         };
 91  
 
 92  
         protected abstract <K, V> ValueDelegate<K, V> createDelegate();
 93  
     }
 94  
 
 95  
     protected interface StorageDelegate<K, V> {
 96  
         void clear();
 97  
         boolean isEmpty();
 98  
         Set<K> keySet();
 99  
         void remove(ValueDelegate<K, V> valueDelegate, K key, V value);
 100  
         void remove(K key, Object holder);
 101  
         void remove(K key);
 102  
         Iterable<Map.Entry<K, V>> tail(K key);
 103  
         V get(AbstractCache<K, V> ac, ValueDelegate<K, V> valueDelegate, Object id, K key, boolean create) throws Exception;
 104  
     }
 105  
 
 106  
     protected static final class ConcurrentDelegate<K, V, M extends ConcurrentMap<K, Object>> implements StorageDelegate<K, V> {
 107  
         protected M map;
 108  
 
 109  2900
         protected ConcurrentDelegate(M map) {
 110  2900
             this.map = map;
 111  2900
         }
 112  
 
 113  
         public void clear() {
 114  7808
             map.clear();
 115  7808
         }
 116  
 
 117  
         public boolean isEmpty() {
 118  10
             return map.isEmpty();
 119  
         }
 120  
 
 121  
         public Set<K> keySet() {
 122  116
             return map.keySet();
 123  
         }
 124  
 
 125  
         public void remove(K key) {
 126  8
             map.remove(key);
 127  8
         }
 128  
 
 129  
         public void remove(ValueDelegate<K, V> valueDelegate, K key, V value) {
 130  0
             Object holder = map.get(key);
 131  0
             if (holder == null) return;
 132  0
             V oldValue = valueDelegate.extractHolder(holder);
 133  0
             if (oldValue == null || ObjectUtil.equalsHelper(value, oldValue)) {
 134  0
                 map.remove(key, holder);
 135  
             }
 136  0
         }
 137  
 
 138  
         public void remove(K key, Object holder) {
 139  1046
             map.remove(key, holder);
 140  1046
         }
 141  
 
 142  
         public Iterable<Map.Entry<K, V>> tail(K key) {
 143  0
             if (map instanceof SortedMap) return Collections.unmodifiableSortedMap((SortedMap<K, V>) map).entrySet();
 144  0
             throw new UnsupportedOperationException();
 145  
         }
 146  
 
 147  
         public V get(AbstractCache<K, V> ac, ValueDelegate<K, V> valueDelegate, Object id, K key, boolean create) throws Exception {
 148  128672
             Object holder = map.get(key);
 149  
             while (true) {
 150  128694
                 if (holder != null) {
 151  21282
                     V result = valueDelegate.extractHolder(holder);
 152  21285
                     if (result != null) return result;
 153  0
                     map.remove(key, holder);
 154  
                 }
 155  
                 V result;
 156  107405
                 if (create) {
 157  2492
                     result = ac.createValue(id, key);
 158  
                 } else {
 159  104902
                     result = ac.findIfExists(id, key);
 160  104908
                     if (result == null) return null;
 161  
                 }
 162  3446
                 holder = valueDelegate.createHolder(key, result, this);
 163  3445
                 if ((holder = map.putIfAbsent(key, holder)) == null) return result;
 164  2
             }
 165  
         }
 166  
     }
 167  
 
 168  
     protected static final class StandardDelegate<K, V, M extends Map<K, Object>> implements StorageDelegate<K, V> {
 169  
         protected M map;
 170  
 
 171  0
         protected StandardDelegate(M map) {
 172  0
             this.map = map;
 173  0
         }
 174  
 
 175  
         public synchronized void clear() {
 176  0
             map.clear();
 177  0
         }
 178  
 
 179  
         public synchronized boolean isEmpty() {
 180  0
             return map.isEmpty();
 181  
         }
 182  
 
 183  
         public synchronized Set<K> keySet() {
 184  0
             return map.keySet();
 185  
         }
 186  
 
 187  
         public synchronized void remove(K key) {
 188  0
             map.remove(key);
 189  0
         }
 190  
 
 191  
         public synchronized void remove(ValueDelegate<K, V> valueDelegate, K key, V value) {
 192  0
             Object holder = map.get(key);
 193  0
             if (holder == null) return;
 194  0
             if (ObjectUtil.equalsHelper(value, valueDelegate.extractHolder(holder))) {
 195  0
                 map.remove(key);
 196  
             }
 197  0
         }
 198  
 
 199  
         public synchronized void remove(K key, Object holder) {
 200  0
             if (ObjectUtil.equalsHelper(holder, map.get(key))) {
 201  0
                 map.remove(key);
 202  
             }
 203  0
         }
 204  
 
 205  
         public Iterable<Map.Entry<K, V>> tail(K key) {
 206  0
             if (map instanceof SortedMap) return Collections.unmodifiableSortedMap((SortedMap<K, V>) map).entrySet();
 207  0
             throw new UnsupportedOperationException();
 208  
         }
 209  
 
 210  
         public synchronized V get(AbstractCache<K, V> ac, ValueDelegate<K, V> valueDelegate, Object id, K key, boolean create) throws Exception {
 211  0
             Object holder = map.get(key);
 212  0
             if (holder != null) {
 213  0
                 V result = valueDelegate.extractHolder(holder);
 214  0
                 if (result != null) return result;
 215  
             }
 216  
             V result;
 217  0
             if (create) {
 218  0
                 result = ac.createValue(id, key);
 219  
             } else {
 220  0
                 result = ac.findIfExists(id, key);
 221  0
                 if (result == null) return null;
 222  
             }
 223  0
             holder = valueDelegate.createHolder(key, result, this);
 224  0
             map.put(key, holder);
 225  0
             return result;
 226  
         }
 227  
     }
 228  
 
 229  5
     public enum StorageType {
 230  1
         CONCURRENT {
 231  
             protected <K, V> StorageDelegate<K, V> createDelegate(boolean sorted) {
 232  2900
                 if (!sorted) return new ConcurrentDelegate<K, V, ConcurrentHashMap<K, Object>>(new ConcurrentHashMap<K, Object>());
 233  0
                 return new ConcurrentDelegate<K, V, ConcurrentMap<K, Object>>((ConcurrentMap<K, Object>) ConcurrentUtil.<K, Object>createSortedMap());
 234  
             }
 235  
         },
 236  1
         STANDARD {
 237  
             protected <K, V> StorageDelegate<K, V> createDelegate(boolean sorted) {
 238  0
                 if (!sorted) return new StandardDelegate<K, V, HashMap<K, Object>>(new HashMap<K, Object>());
 239  0
                 return new StandardDelegate<K, V, TreeMap<K, Object>>(new TreeMap<K, Object>());
 240  
             }
 241  
         };
 242  
 
 243  
         protected abstract <K, V> StorageDelegate<K, V> createDelegate(boolean sorted);
 244  
     }
 245  
 
 246  1
     private static final ReferenceQueue queue = new ReferenceQueue();
 247  1
     private static final Thread CleanerThread = new Thread() {
 248  
         public void run() {
 249  
             while (true) {
 250  
                 try {
 251  1047
                     Ref<?, ?> ref = (Ref<?, ?>) queue.remove();
 252  1046
                     ref.purge();
 253  0
                 } catch (InterruptedException e) {
 254  0
                     break;
 255  1046
                 }
 256  
             }
 257  0
         }
 258  
     };
 259  
     static {
 260  1
         CleanerThread.setDaemon(true);
 261  1
         CleanerThread.setName("AbstractCache.RefPoller");
 262  1
         CleanerThread.start();
 263  1
     }
 264  
 
 265  
     protected final Class<?> owner;
 266  
     protected final String field;
 267  
     protected final String label;
 268  
     protected final ValueDelegate<K, V> valueDelegate;
 269  
     protected final StorageDelegate<K, V> storageDelegate;
 270  
 
 271  
     private static <K, V> ValueDelegate<K, V> getDelegate(Class<?> owner, String field, String label, ValueType valueType) {
 272  2900
         String key = owner.getName() + ", " + field;
 273  2900
         if (valueType == null) {
 274  0
             valueType = ValueType.SOFT;
 275  2900
         } else if (overrideValueType.containsKey(key)) {
 276  1252
             valueType = overrideValueType.get(key);
 277  
         }
 278  2900
         return valueType.createDelegate();
 279  
     }
 280  
 
 281  
     private static <K, V> StorageDelegate<K, V> getDelegate(Class<?> owner, String field, String label, boolean sorted, StorageType storageType) {
 282  2900
         String key = owner.getName() + ", " + field;
 283  2900
         if (storageType == null) {
 284  0
             storageType = StorageType.STANDARD;
 285  2900
         } else if (overrideStorageType.containsKey(key)) {
 286  0
             storageType = overrideStorageType.get(key);
 287  
         }
 288  2900
         return storageType.createDelegate(sorted);
 289  
     }
 290  
 
 291  2900
     protected AbstractCache(Class<?> owner, String field, String label, ValueType valueType, StorageType storageType, boolean sorted) {
 292  2900
         this.owner = owner;
 293  2900
         this.field = field;
 294  2900
         this.label = label;
 295  2900
         this.valueDelegate = getDelegate(owner, field, label, valueType);
 296  2900
         this.storageDelegate = getDelegate(owner, field, label, sorted, storageType);
 297  2900
     }
 298  
 
 299  
     protected AbstractCache(Class<?> owner, String field, String label, ValueType valueType) {
 300  0
         this(owner, field, label, valueType, null, false);
 301  0
     }
 302  
 
 303  
     protected AbstractCache(Class<?> owner, String field, String label, StorageType storageType, boolean sorted) {
 304  0
         this(owner, field, label, null, storageType, sorted);
 305  0
     }
 306  
 
 307  
     protected AbstractCache(Class<?> owner, String field, String label) {
 308  0
         this(owner, field, label, null, null, false);
 309  0
     }
 310  
 
 311  
     public void clear() {
 312  7808
         storageDelegate.clear();
 313  7808
     }
 314  
 
 315  
     public boolean isEmpty() {
 316  10
         return storageDelegate.isEmpty();
 317  
     }
 318  
 
 319  
     public Set<K> keys() {
 320  116
         return storageDelegate.keySet();
 321  
     }
 322  
 
 323  
     public void remove(K key) {
 324  8
         storageDelegate.remove(key);
 325  8
     }
 326  
 
 327  
     public Iterable<Map.Entry<K, V>> tail(K key) {
 328  0
         return storageDelegate.tail(key);
 329  
     }
 330  
 
 331  
     protected void remove(K key, V value) {
 332  0
         storageDelegate.remove(valueDelegate, key, value);
 333  0
     }
 334  
 
 335  
     protected V get(Object id, K key) throws Exception {
 336  10113
         return get(id, key, true);
 337  
     }
 338  
 
 339  
     protected V get(Object id, K key, boolean create) throws Exception {
 340  128690
         return storageDelegate.get(this, valueDelegate, id, key, create);
 341  
     }
 342  
 
 343  
     protected V findIfExists(Object id, K key) throws Exception {
 344  0
         return null;
 345  
     }
 346  
 
 347  
     protected abstract V createValue(Object id, K key) throws Exception;
 348  
 
 349  
     protected interface Ref<K, V> {
 350  
         V get();
 351  
         void purge();
 352  
     }
 353  
 
 354  
     protected static class Soft<K, V> extends SoftReference<V> implements Ref<K, V> {
 355  
         protected final K key;
 356  
         protected final StorageDelegate<K, V> storage;
 357  
 
 358  
         protected Soft(K key, V value, StorageDelegate<K, V> storage) {
 359  0
             super(value, queue);
 360  0
             this.key = key;
 361  0
             this.storage = storage;
 362  0
         }
 363  
 
 364  
         public void purge() {
 365  0
             storage.remove(key, this);
 366  0
         }
 367  
     }
 368  
 
 369  
     protected static class Weak<K, V> extends WeakReference<V> implements Ref<K, V> {
 370  
         protected final K key;
 371  
         protected final StorageDelegate<K, V> storage;
 372  
 
 373  
         protected Weak(K key, V value, StorageDelegate<K, V> storage) {
 374  2123
             super(value, queue);
 375  2123
             this.key = key;
 376  2123
             this.storage = storage;
 377  2123
         }
 378  
 
 379  
         public void purge() {
 380  1046
             storage.remove(key, this);
 381  1046
         }
 382  
     }
 383  
 }