1 /* 2 * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 ******************************************************************************* 28 * Copyright (C) 2009-2010, International Business Machines Corporation and * 29 * others. All Rights Reserved. * 30 ******************************************************************************* 31 */ 32 package sun.util.locale; 33 34 import java.lang.ref.ReferenceQueue; 35 import java.lang.ref.SoftReference; 36 import java.util.concurrent.ConcurrentHashMap; 37 import java.util.concurrent.ConcurrentMap; 38 39 public abstract class LocaleObjectCache<K, V> { 40 private ConcurrentMap<K, CacheEntry<K, V>> map; 41 private ReferenceQueue<V> queue = new ReferenceQueue<>(); 42 LocaleObjectCache()43 public LocaleObjectCache() { 44 this(16, 0.75f, 16); 45 } 46 LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel)47 public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) { 48 map = new ConcurrentHashMap<>(initialCapacity, loadFactor, concurrencyLevel); 49 } 50 get(K key)51 public V get(K key) { 52 V value = null; 53 54 cleanStaleEntries(); 55 CacheEntry<K, V> entry = map.get(key); 56 if (entry != null) { 57 value = entry.get(); 58 } 59 if (value == null) { 60 V newVal = createObject(key); 61 // make sure key is normalized *after* the object creation 62 // so that newVal is assured to be created from a valid key. 63 key = normalizeKey(key); 64 if (key == null || newVal == null) { 65 // subclass must return non-null key/value object 66 return null; 67 } 68 69 CacheEntry<K, V> newEntry = new CacheEntry<>(key, newVal, queue); 70 71 entry = map.putIfAbsent(key, newEntry); 72 if (entry == null) { 73 value = newVal; 74 } else { 75 value = entry.get(); 76 if (value == null) { 77 map.put(key, newEntry); 78 value = newVal; 79 } 80 } 81 } 82 return value; 83 } 84 put(K key, V value)85 protected V put(K key, V value) { 86 CacheEntry<K, V> entry = new CacheEntry<>(key, value, queue); 87 CacheEntry<K, V> oldEntry = map.put(key, entry); 88 return (oldEntry == null) ? null : oldEntry.get(); 89 } 90 91 @SuppressWarnings("unchecked") cleanStaleEntries()92 private void cleanStaleEntries() { 93 CacheEntry<K, V> entry; 94 while ((entry = (CacheEntry<K, V>)queue.poll()) != null) { 95 map.remove(entry.getKey()); 96 } 97 } 98 createObject(K key)99 protected abstract V createObject(K key); 100 normalizeKey(K key)101 protected K normalizeKey(K key) { 102 return key; 103 } 104 105 private static class CacheEntry<K, V> extends SoftReference<V> { 106 private K key; 107 CacheEntry(K key, V value, ReferenceQueue<V> queue)108 CacheEntry(K key, V value, ReferenceQueue<V> queue) { 109 super(value, queue); 110 this.key = key; 111 } 112 getKey()113 K getKey() { 114 return key; 115 } 116 } 117 } 118