1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.jcs.jcache;
20
21 import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
22 import org.apache.commons.jcs.engine.behavior.IElementAttributes;
23 import org.apache.commons.jcs.engine.control.CompositeCache;
24 import org.apache.commons.jcs.engine.control.CompositeCacheConfigurator;
25 import org.apache.commons.jcs.engine.control.CompositeCacheManager;
26 import org.apache.commons.jcs.jcache.lang.Subsitutor;
27 import org.apache.commons.jcs.jcache.proxy.ClassLoaderAwareCache;
28
29 import javax.cache.Cache;
30 import javax.cache.CacheManager;
31 import javax.cache.configuration.Configuration;
32 import javax.cache.spi.CachingProvider;
33 import java.io.ByteArrayInputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.net.URI;
37 import java.net.URL;
38 import java.util.Enumeration;
39 import java.util.Map;
40 import java.util.Properties;
41 import java.util.concurrent.ConcurrentHashMap;
42 import java.util.concurrent.ConcurrentMap;
43
44 import static org.apache.commons.jcs.jcache.Asserts.assertNotNull;
45
46 public class JCSCachingManager implements CacheManager
47 {
48 private static final Subsitutor SUBSTITUTOR = Subsitutor.Helper.INSTANCE;
49 private static final String DEFAULT_CONFIG =
50 "jcs.default=DC\n" +
51 "jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes\n" +
52 "jcs.default.cacheattributes.MaxObjects=200001\n" +
53 "jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache\n" +
54 "jcs.default.cacheattributes.UseMemoryShrinker=true\n" +
55 "jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600\n" +
56 "jcs.default.cacheattributes.ShrinkerIntervalSeconds=60\n" +
57 "jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes\n" +
58 "jcs.default.elementattributes.IsEternal=false\n" +
59 "jcs.default.elementattributes.MaxLife=700\n" +
60 "jcs.default.elementattributes.IdleTime=1800\n" +
61 "jcs.default.elementattributes.IsSpool=true\n" +
62 "jcs.default.elementattributes.IsRemote=true\n" +
63 "jcs.default.elementattributes.IsLateral=true\n";
64
65 private static class InternalManager extends CompositeCacheManager
66 {
67 protected static InternalManager create()
68 {
69 return new InternalManager();
70 }
71
72 protected CompositeCacheConfigurator newConfigurator()
73 {
74 return new CompositeCacheConfigurator()
75 {
76 @Override
77 protected <K, V> CompositeCache<K, V> newCache(
78 final ICompositeCacheAttributes cca, final IElementAttributes ea)
79 {
80 return new ExpiryAwareCache<K, V>( cca, ea );
81 }
82 };
83 }
84
85 @Override
86 protected void initialize() {
87 super.initialize();
88 }
89 }
90
91 private final CachingProvider provider;
92 private final URI uri;
93 private final ClassLoader loader;
94 private final Properties properties;
95 private final ConcurrentMap<String, Cache<?, ?>> caches = new ConcurrentHashMap<String, Cache<?, ?>>();
96 private final Properties configProperties;
97 private volatile boolean closed = false;
98 private InternalManager delegate = InternalManager.create();
99
100 public JCSCachingManager(final CachingProvider provider, final URI uri, final ClassLoader loader, final Properties properties)
101 {
102 this.provider = provider;
103 this.uri = uri;
104 this.loader = loader;
105 this.properties = readConfig(uri, loader, properties);
106 this.configProperties = properties;
107
108 delegate.setJmxName(CompositeCacheManager.JMX_OBJECT_NAME
109 + ",provider=" + provider.hashCode()
110 + ",uri=" + uri.toString().replaceAll(",|:|=|\n", ".")
111 + ",classloader=" + loader.hashCode()
112 + ",properties=" + this.properties.hashCode());
113 delegate.initialize();
114 delegate.configure(this.properties);
115 }
116
117 private Properties readConfig(final URI uri, final ClassLoader loader, final Properties properties) {
118 final Properties props = new Properties();
119 try {
120 if (JCSCachingProvider.DEFAULT_URI.toString().equals(uri.toString()) || uri.toURL().getProtocol().equals("jcs"))
121 {
122
123 final Enumeration<URL> resources = loader.getResources(uri.getPath());
124 if (!resources.hasMoreElements())
125 {
126 props.load(new ByteArrayInputStream(DEFAULT_CONFIG.getBytes("UTF-8")));
127 }
128 else
129 {
130 do
131 {
132 addProperties(resources.nextElement(), props);
133 }
134 while (resources.hasMoreElements());
135 }
136 }
137 else
138 {
139 props.load(uri.toURL().openStream());
140 }
141 } catch (final IOException e) {
142 throw new IllegalStateException(e);
143 }
144
145 if (properties != null)
146 {
147 props.putAll(properties);
148 }
149
150 for (final Map.Entry<Object, Object> entry : props.entrySet()) {
151 if (entry.getValue() == null)
152 {
153 continue;
154 }
155 final String substitute = SUBSTITUTOR.substitute(entry.getValue().toString());
156 if (!substitute.equals(entry.getValue()))
157 {
158 entry.setValue(substitute);
159 }
160 }
161 return props;
162 }
163
164 private void addProperties(final URL url, final Properties aggregator)
165 {
166 InputStream inStream = null;
167 try
168 {
169 inStream = url.openStream();
170 aggregator.load(inStream);
171 }
172 catch (final IOException e)
173 {
174 throw new IllegalArgumentException(e);
175 }
176 finally
177 {
178 if (inStream != null)
179 {
180 try
181 {
182 inStream.close();
183 }
184 catch (final IOException e)
185 {
186
187 }
188 }
189 }
190 }
191
192 private void assertNotClosed()
193 {
194 if (isClosed())
195 {
196 throw new IllegalStateException("cache manager closed");
197 }
198 }
199
200 @Override
201
202 public <K, V, C extends Configuration<K, V>> Cache<K, V> createCache(final String cacheName, final C configuration)
203 throws IllegalArgumentException
204 {
205 assertNotClosed();
206 assertNotNull(cacheName, "cacheName");
207 assertNotNull(configuration, "configuration");
208 final Class<?> keyType = configuration == null ? Object.class : configuration.getKeyType();
209 final Class<?> valueType = configuration == null ? Object.class : configuration.getValueType();
210 if (!caches.containsKey(cacheName))
211 {
212 final Cache<K, V> cache = ClassLoaderAwareCache.wrap(loader,
213 new JCSCache(
214 loader, this, cacheName,
215 new JCSConfiguration(configuration, keyType, valueType),
216 properties,
217 ExpiryAwareCache.class.cast(delegate.getCache(cacheName))));
218 caches.putIfAbsent(cacheName, cache);
219 }
220 else
221 {
222 throw new javax.cache.CacheException("cache " + cacheName + " already exists");
223 }
224 return (Cache<K, V>) getCache(cacheName, keyType, valueType);
225 }
226
227 @Override
228 public void destroyCache(final String cacheName)
229 {
230 assertNotClosed();
231 assertNotNull(cacheName, "cacheName");
232 final Cache<?, ?> cache = caches.remove(cacheName);
233 if (cache != null && !cache.isClosed())
234 {
235 cache.clear();
236 cache.close();
237 }
238 }
239
240 @Override
241 public void enableManagement(final String cacheName, final boolean enabled)
242 {
243 assertNotClosed();
244 assertNotNull(cacheName, "cacheName");
245 final JCSCache<?, ?> cache = getJCSCache(cacheName);
246 if (cache != null)
247 {
248 if (enabled)
249 {
250 cache.enableManagement();
251 }
252 else
253 {
254 cache.disableManagement();
255 }
256 }
257 }
258
259 private JCSCache<?, ?> getJCSCache(final String cacheName)
260 {
261 final Cache<?, ?> cache = caches.get(cacheName);
262 return JCSCache.class.cast(ClassLoaderAwareCache.getDelegate(cache));
263 }
264
265 @Override
266 public void enableStatistics(final String cacheName, final boolean enabled)
267 {
268 assertNotClosed();
269 assertNotNull(cacheName, "cacheName");
270 final JCSCache<?, ?> cache = getJCSCache(cacheName);
271 if (cache != null)
272 {
273 if (enabled)
274 {
275 cache.enableStatistics();
276 }
277 else
278 {
279 cache.disableStatistics();
280 }
281 }
282 }
283
284 @Override
285 public synchronized void close()
286 {
287 if (isClosed())
288 {
289 return;
290 }
291
292 assertNotClosed();
293 for (final Cache<?, ?> c : caches.values())
294 {
295 c.close();
296 }
297 caches.clear();
298 closed = true;
299 if (JCSCachingProvider.class.isInstance(provider))
300 {
301 JCSCachingProvider.class.cast(provider).remove(this);
302 }
303 delegate.shutDown();
304 }
305
306 @Override
307 public <T> T unwrap(final Class<T> clazz)
308 {
309 if (clazz.isInstance(this))
310 {
311 return clazz.cast(this);
312 }
313 throw new IllegalArgumentException(clazz.getName() + " not supported in unwrap");
314 }
315
316 @Override
317 public boolean isClosed()
318 {
319 return closed;
320 }
321
322 @Override
323 public <K, V> Cache<K, V> getCache(final String cacheName)
324 {
325 assertNotClosed();
326 assertNotNull(cacheName, "cacheName");
327 return (Cache<K, V>) doGetCache(cacheName, Object.class, Object.class);
328 }
329
330 @Override
331 public Iterable<String> getCacheNames()
332 {
333 return new ImmutableIterable<String>(caches.keySet());
334 }
335
336 @Override
337 public <K, V> Cache<K, V> getCache(final String cacheName, final Class<K> keyType, final Class<V> valueType)
338 {
339 assertNotClosed();
340 assertNotNull(cacheName, "cacheName");
341 assertNotNull(keyType, "keyType");
342 assertNotNull(valueType, "valueType");
343 try
344 {
345 return doGetCache(cacheName, keyType, valueType);
346 }
347 catch (final IllegalArgumentException iae)
348 {
349 throw new ClassCastException(iae.getMessage());
350 }
351 }
352
353 private <K, V> Cache<K, V> doGetCache(final String cacheName, final Class<K> keyType, final Class<V> valueType)
354 {
355 final Cache<K, V> cache = (Cache<K, V>) caches.get(cacheName);
356 if (cache == null)
357 {
358 return null;
359 }
360
361 final Configuration<K, V> config = cache.getConfiguration(Configuration.class);
362 if ((keyType != null && !config.getKeyType().isAssignableFrom(keyType))
363 || (valueType != null && !config.getValueType().isAssignableFrom(valueType)))
364 {
365 throw new IllegalArgumentException("this cache is <" + config.getKeyType().getName() + ", " + config.getValueType().getName()
366 + "> " + " and not <" + keyType.getName() + ", " + valueType.getName() + ">");
367 }
368 return cache;
369 }
370
371 @Override
372 public CachingProvider getCachingProvider()
373 {
374 return provider;
375 }
376
377 @Override
378 public URI getURI()
379 {
380 return uri;
381 }
382
383 @Override
384 public ClassLoader getClassLoader()
385 {
386 return loader;
387 }
388
389 @Override
390 public Properties getProperties()
391 {
392 return configProperties;
393 }
394
395 public void release(final String name) {
396 caches.remove(name);
397 }
398 }