Home | History | Annotate | Download | only in locale
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 2009-2011, International Business Machines Corporation and    *
      6  * others. All Rights Reserved.                                                *
      7  *******************************************************************************
      8  */
      9 package com.ibm.icu.impl.locale;
     10 
     11 import java.lang.ref.ReferenceQueue;
     12 import java.lang.ref.SoftReference;
     13 import java.util.concurrent.ConcurrentHashMap;
     14 
     15 public abstract class LocaleObjectCache<K, V> {
     16     private ConcurrentHashMap<K, CacheEntry<K, V>> _map;
     17     private ReferenceQueue<V> _queue = new ReferenceQueue<V>();
     18 
     19     public LocaleObjectCache() {
     20         this(16, 0.75f, 16);
     21     }
     22 
     23     public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) {
     24         _map = new ConcurrentHashMap<K, CacheEntry<K, V>>(initialCapacity, loadFactor, concurrencyLevel);
     25     }
     26 
     27     public V get(K key) {
     28         V value = null;
     29 
     30         cleanStaleEntries();
     31         CacheEntry<K, V> entry = _map.get(key);
     32         if (entry != null) {
     33             value = entry.get();
     34         }
     35         if (value == null) {
     36             key = normalizeKey(key);
     37             V newVal = createObject(key);
     38             if (key == null || newVal == null) {
     39                 // subclass must return non-null key/value object
     40                 return null;
     41             }
     42 
     43             CacheEntry<K, V> newEntry = new CacheEntry<K, V>(key, newVal, _queue);
     44 
     45             while (value == null) {
     46                 cleanStaleEntries();
     47                 entry = _map.putIfAbsent(key, newEntry);
     48                 if (entry == null) {
     49                     value = newVal;
     50                     break;
     51                 } else {
     52                     value = entry.get();
     53                 }
     54             }
     55         }
     56         return value;
     57     }
     58 
     59     @SuppressWarnings("unchecked")
     60     private void cleanStaleEntries() {
     61         CacheEntry<K, V> entry;
     62         while ((entry = (CacheEntry<K, V>)_queue.poll()) != null) {
     63             _map.remove(entry.getKey());
     64         }
     65     }
     66 
     67     protected abstract V createObject(K key);
     68 
     69     protected K normalizeKey(K key) {
     70         return key;
     71     }
     72 
     73     private static class CacheEntry<K, V> extends SoftReference<V> {
     74         private K _key;
     75 
     76         CacheEntry(K key, V value, ReferenceQueue<V> queue) {
     77             super(value, queue);
     78             _key = key;
     79         }
     80 
     81         K getKey() {
     82             return _key;
     83         }
     84     }
     85 }
     86