1 /* 2 * Copyright (c) 2010, 2018, 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 final ConcurrentMap<K, CacheEntry<K, V>> map; 41 private final 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 key = normalizeKey(key); 61 V newVal = createObject(key); 62 if (key == null || newVal == null) { 63 // subclass must return non-null key/value object 64 return null; 65 } 66 67 CacheEntry<K, V> newEntry = new CacheEntry<>(key, newVal, queue); 68 entry = map.putIfAbsent(key, newEntry); 69 if (entry == null) { 70 value = newVal; 71 } else { 72 value = entry.get(); 73 if (value == null) { 74 map.put(key, newEntry); 75 value = newVal; 76 } 77 } 78 } 79 return value; 80 } 81 put(K key, V value)82 protected V put(K key, V value) { 83 CacheEntry<K, V> entry = new CacheEntry<>(key, value, queue); 84 CacheEntry<K, V> oldEntry = map.put(key, entry); 85 return (oldEntry == null) ? null : oldEntry.get(); 86 } 87 88 // Android-changed: Make it public / protected to clean stale entries before Zygote forks 89 @SuppressWarnings("unchecked") cleanStaleEntries()90 public void cleanStaleEntries() { 91 CacheEntry<K, V> entry; 92 while ((entry = (CacheEntry<K, V>)queue.poll()) != null) { 93 map.remove(entry.getKey(), entry); 94 } 95 } 96 createObject(K key)97 protected abstract V createObject(K key); 98 normalizeKey(K key)99 protected K normalizeKey(K key) { 100 return key; 101 } 102 103 private static class CacheEntry<K, V> extends SoftReference<V> { 104 private K key; 105 CacheEntry(K key, V value, ReferenceQueue<V> queue)106 CacheEntry(K key, V value, ReferenceQueue<V> queue) { 107 super(value, queue); 108 this.key = key; 109 } 110 getKey()111 K getKey() { 112 return key; 113 } 114 } 115 } 116