1
24 package net.sf.jasperreports.engine.util;
25
26 import java.lang.reflect.InvocationTargetException;
27 import java.util.Map;
28
29 import org.apache.commons.collections4.map.ReferenceMap;
30
31 import net.sf.jasperreports.engine.JRException;
32
33
34
39 public class JRSingletonCache<T>
40 {
41 private static final Object CONTEXT_KEY_NULL = new Object();
42 public static final String EXCEPTION_MESSAGE_KEY_CLASS_NOT_COMPATIBLE = "util.singleton.cache.class.not.compatible";
43 public static final String EXCEPTION_MESSAGE_KEY_CLASS_NOT_FOUND = "util.singleton.cache.class.not.found";
44 public static final String EXCEPTION_MESSAGE_KEY_INSTANCE_ERROR = "util.singleton.cache.instance.error";
45
46 private final ReferenceMap<Object, Map<String,T>> cache;
47 private final Class<T> itf;
48
49
54 public JRSingletonCache(Class<T> itf)
55 {
56 cache = new ReferenceMap<Object, Map<String,T>>(ReferenceMap.ReferenceStrength.WEAK, ReferenceMap.ReferenceStrength.SOFT);
57 this.itf = itf;
58 }
59
60
71 public synchronized T getCachedInstance(String className) throws JRException
72 {
73 Map<String,T> contextCache = getContextInstanceCache();
74 T instance = contextCache.get(className);
75 if (instance == null)
76 {
77 instance = createInstance(className);
78 contextCache.put(className, instance);
79 }
80 return instance;
81 }
82
83 protected T createInstance(String className) throws JRException
84 {
85 try
86 {
87 @SuppressWarnings("unchecked")
88 Class<? extends T> clazz = (Class<? extends T>) JRClassLoader.loadClassForName(className);
89 if (itf != null && !itf.isAssignableFrom(clazz))
90 {
91 throw
92 new JRException(
93 EXCEPTION_MESSAGE_KEY_CLASS_NOT_COMPATIBLE,
94 new Object[]{className, itf.getName()});
95 }
96
97 return clazz.getDeclaredConstructor().newInstance();
98 }
99 catch (ClassNotFoundException e)
100 {
101 throw
102 new JRException(
103 EXCEPTION_MESSAGE_KEY_CLASS_NOT_FOUND,
104 new Object[]{className},
105 e);
106 }
107 catch (InstantiationException | IllegalAccessException
108 | NoSuchMethodException | InvocationTargetException e)
109 {
110 throw
111 new JRException(
112 EXCEPTION_MESSAGE_KEY_INSTANCE_ERROR,
113 new Object[]{className},
114 e);
115 }
116 }
117
118 protected Map<String,T> getContextInstanceCache()
119 {
120 Object contextKey = getContextKey();
121 Map<String,T> contextCache = cache.get(contextKey);
122 if (contextCache == null)
123 {
124 contextCache = new ReferenceMap<String,T>();
125 cache.put(contextKey, contextCache);
126 }
127 return contextCache;
128 }
129
130 protected Object getContextKey()
131 {
132 Object key = Thread.currentThread().getContextClassLoader();
133 if (key == null)
134 {
135 key = CONTEXT_KEY_NULL;
136 }
137 return key;
138 }
139 }
140