001/* 002 * BridJ - Dynamic and blazing-fast native interop for Java. 003 * http://bridj.googlecode.com/ 004 * 005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/) 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * * Redistributions of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * * Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in the 015 * documentation and/or other materials provided with the distribution. 016 * * Neither the name of Olivier Chafik nor the 017 * names of its contributors may be used to endorse or promote products 018 * derived from this software without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY 021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 */ 031package org.bridj.util; 032 033import java.lang.reflect.Constructor; 034import java.util.HashMap; 035import java.util.Map; 036import java.util.Map.Entry; 037import java.util.concurrent.ConcurrentHashMap; 038 039/** 040 * Cache that creates its missing values automatically, using the value class' 041 * default constructor (override {@link ConcurrentCache#newInstance(Object)} to 042 * call another constructor) 043 */ 044public class ConcurrentCache<K, V> { 045 046 protected final ConcurrentHashMap<K, V> map = new ConcurrentHashMap<K, V>(); 047 protected final Class<V> valueClass; 048 049 public ConcurrentCache(Class<V> valueClass) { 050 this.valueClass = valueClass; 051 } 052 private volatile Constructor<V> valueConstructor; 053 054 private Constructor<V> getValueConstructor() { 055 if (valueConstructor == null) { 056 try { 057 valueConstructor = valueClass.getConstructor(); 058 if (valueConstructor != null && valueConstructor.isAccessible()) { 059 valueConstructor.setAccessible(true); 060 } 061 } catch (Exception ex) { 062 throw new RuntimeException("No accessible default constructor in class " + (valueClass == null ? "null" : valueClass.getName()), ex); 063 } 064 } 065 return valueConstructor; 066 } 067 068 protected V newInstance(K key) { 069 try { 070 return getValueConstructor().newInstance(); 071 } catch (Exception ex) { 072 throw new RuntimeException("Failed to call constructor " + valueConstructor, ex); 073 } 074 } 075 076 public V get(K key) { 077 V v = map.get(key); 078 if (v == null) { 079 V newV = newInstance(key); 080 V oldV = map.putIfAbsent(key, newV); 081 if (oldV != null) { 082 v = oldV; 083 } else { 084 v = newV; 085 } 086 } 087 return v; 088 } 089 090 public void clear() { 091 map.clear(); 092 } 093 094 public Iterable<Entry<K, V>> entrySet() { 095 return map.entrySet(); 096 } 097}