001 package org.bridj.util;
002
003 import java.lang.reflect.Constructor;
004 import java.util.HashMap;
005 import java.util.Map;
006 import java.util.Map.Entry;
007 import java.util.concurrent.ConcurrentHashMap;
008
009 /**
010 * Cache that creates its missing values automatically, using the value class' default constructor (override {@link ConcurrentCache#newInstance(Object)} to call another constructor)
011 */
012 public class ConcurrentCache<K, V> {
013 protected final ConcurrentHashMap<K, V> map = new ConcurrentHashMap<K, V>();
014 protected final Class<V> valueClass;
015
016 public ConcurrentCache(Class<V> valueClass) {
017 this.valueClass = valueClass;
018 }
019
020 private volatile Constructor<V> valueConstructor;
021 private Constructor<V> getValueConstructor() {
022 if (valueConstructor == null) {
023 try {
024 valueConstructor = valueClass.getConstructor();
025 if (valueConstructor != null && valueConstructor.isAccessible())
026 valueConstructor.setAccessible(true);
027 } catch (Exception ex) {
028 throw new RuntimeException("No accessible default constructor in class " + (valueClass == null ? "null" : valueClass.getName()), ex);
029 }
030 }
031 return valueConstructor;
032 }
033
034 protected V newInstance(K key) {
035 try {
036 return getValueConstructor().newInstance();
037 } catch (Exception ex) {
038 throw new RuntimeException("Failed to call constructor " + valueConstructor, ex);
039 }
040 }
041
042 public V get(K key) {
043 V v = map.get(key);
044 if (v == null) {
045 V newV = newInstance(key);
046 V oldV = map.putIfAbsent(key, newV);
047 if (oldV != null)
048 v = oldV;
049 else
050 v = newV;
051 }
052 return v;
053 }
054
055 public void clear() {
056 map.clear();
057 }
058
059 public Iterable<Entry<K, V>> entrySet() {
060 return map.entrySet();
061 }
062 }