View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.commons.jcs3.jcache.proxy;
20  
21  import javax.cache.Cache;
22  import javax.cache.CacheManager;
23  import javax.cache.configuration.CacheEntryListenerConfiguration;
24  import javax.cache.configuration.Configuration;
25  import javax.cache.integration.CompletionListener;
26  import javax.cache.processor.EntryProcessor;
27  import javax.cache.processor.EntryProcessorException;
28  import javax.cache.processor.EntryProcessorResult;
29  
30  import org.apache.commons.jcs3.jcache.JCSCache;
31  
32  import java.io.Serializable;
33  import java.util.Iterator;
34  import java.util.Map;
35  import java.util.Set;
36  
37  // don't use a proxy, reflection is too slow here :(
38  public class ClassLoaderAwareCache<K, V> implements Cache<K, V>
39  {
40      private final ClassLoader loader;
41      private final JCSCache<K, V> delegate;
42  
43      public ClassLoaderAwareCache(final ClassLoader loader, final JCSCache<K, V> delegate)
44      {
45          this.loader = loader;
46          this.delegate = delegate;
47      }
48  
49      private ClassLoader before(final Thread thread)
50      {
51          final ClassLoader tccl = thread.getContextClassLoader();
52          thread.setContextClassLoader(loader);
53          return tccl;
54      }
55  
56      @Override
57      public V get(final K key)
58      {
59          final Thread thread = Thread.currentThread();
60          final ClassLoader loader = before(thread);
61          try
62          {
63              return delegate.get(key);
64          }
65          finally
66          {
67              thread.setContextClassLoader(loader);
68          }
69      }
70  
71      @Override
72      public Map<K, V> getAll(final Set<? extends K> keys)
73      {
74          final Thread thread = Thread.currentThread();
75          final ClassLoader loader = before(thread);
76          try
77          {
78              return delegate.getAll(keys);
79          }
80          finally
81          {
82              thread.setContextClassLoader(loader);
83          }
84      }
85  
86      @Override
87      public boolean containsKey(final K key)
88      {
89          final Thread thread = Thread.currentThread();
90          final ClassLoader loader = before(thread);
91          try
92          {
93              return delegate.containsKey(key);
94          }
95          finally
96          {
97              thread.setContextClassLoader(loader);
98          }
99      }
100 
101     @Override
102     public void loadAll(final Set<? extends K> keys, final boolean replaceExistingValues, final CompletionListener completionListener)
103     {
104         final Thread thread = Thread.currentThread();
105         final ClassLoader loader = before(thread);
106         try
107         {
108             delegate.loadAll(keys, replaceExistingValues, completionListener);
109         }
110         finally
111         {
112             thread.setContextClassLoader(loader);
113         }
114     }
115 
116     @Override
117     public void put(final K key, final V value)
118     {
119         final Thread thread = Thread.currentThread();
120         final ClassLoader loader = before(thread);
121         try
122         {
123             delegate.put(key, value);
124         }
125         finally
126         {
127             thread.setContextClassLoader(loader);
128         }
129     }
130 
131     @Override
132     public V getAndPut(final K key, final V value)
133     {
134         final Thread thread = Thread.currentThread();
135         final ClassLoader loader = before(thread);
136         try
137         {
138             return delegate.getAndPut(key, value);
139         }
140         finally
141         {
142             thread.setContextClassLoader(loader);
143         }
144     }
145 
146     @Override
147     public void putAll(final Map<? extends K, ? extends V> map)
148     {
149         final Thread thread = Thread.currentThread();
150         final ClassLoader loader = before(thread);
151         try
152         {
153             delegate.putAll(map);
154         }
155         finally
156         {
157             thread.setContextClassLoader(loader);
158         }
159     }
160 
161     @Override
162     public boolean putIfAbsent(final K key, final V value)
163     {
164         final Thread thread = Thread.currentThread();
165         final ClassLoader loader = before(thread);
166         try
167         {
168             return delegate.putIfAbsent(key, value);
169         }
170         finally
171         {
172             thread.setContextClassLoader(loader);
173         }
174     }
175 
176     @Override
177     public boolean remove(final K key)
178     {
179         final Thread thread = Thread.currentThread();
180         final ClassLoader loader = before(thread);
181         try
182         {
183             return delegate.remove(key);
184         }
185         finally
186         {
187             thread.setContextClassLoader(loader);
188         }
189     }
190 
191     @Override
192     public boolean remove(final K key, final V oldValue)
193     {
194         final Thread thread = Thread.currentThread();
195         final ClassLoader loader = before(thread);
196         try
197         {
198             return delegate.remove(key, oldValue);
199         }
200         finally
201         {
202             thread.setContextClassLoader(loader);
203         }
204     }
205 
206     @Override
207     public V getAndRemove(final K key)
208     {
209         final Thread thread = Thread.currentThread();
210         final ClassLoader loader = before(thread);
211         try
212         {
213             return delegate.getAndRemove(key);
214         }
215         finally
216         {
217             thread.setContextClassLoader(loader);
218         }
219     }
220 
221     @Override
222     public boolean replace(final K key, final V oldValue, final V newValue)
223     {
224         final Thread thread = Thread.currentThread();
225         final ClassLoader loader = before(thread);
226         try
227         {
228             return delegate.replace(key, oldValue, newValue);
229         }
230         finally
231         {
232             thread.setContextClassLoader(loader);
233         }
234     }
235 
236     @Override
237     public boolean replace(final K key, final V value)
238     {
239         final Thread thread = Thread.currentThread();
240         final ClassLoader loader = before(thread);
241         try
242         {
243             return delegate.replace(key, value);
244         }
245         finally
246         {
247             thread.setContextClassLoader(loader);
248         }
249     }
250 
251     @Override
252     public V getAndReplace(final K key, final V value)
253     {
254         final Thread thread = Thread.currentThread();
255         final ClassLoader loader = before(thread);
256         try
257         {
258             return delegate.getAndReplace(key, value);
259         }
260         finally
261         {
262             thread.setContextClassLoader(loader);
263         }
264     }
265 
266     @Override
267     public void removeAll(final Set<? extends K> keys)
268     {
269         final Thread thread = Thread.currentThread();
270         final ClassLoader loader = before(thread);
271         try
272         {
273             delegate.removeAll(keys);
274         }
275         finally
276         {
277             thread.setContextClassLoader(loader);
278         }
279     }
280 
281     @Override
282     public void removeAll()
283     {
284         final Thread thread = Thread.currentThread();
285         final ClassLoader loader = before(thread);
286         try
287         {
288             delegate.removeAll();
289         }
290         finally
291         {
292             thread.setContextClassLoader(loader);
293         }
294     }
295 
296     @Override
297     public void clear()
298     {
299         final Thread thread = Thread.currentThread();
300         final ClassLoader loader = before(thread);
301         try
302         {
303             delegate.clear();
304         }
305         finally
306         {
307             thread.setContextClassLoader(loader);
308         }
309     }
310 
311     @Override
312     public <C extends Configuration<K, V>> C getConfiguration(final Class<C> clazz)
313     {
314         final Thread thread = Thread.currentThread();
315         final ClassLoader loader = before(thread);
316         try
317         {
318             return delegate.getConfiguration(clazz);
319         }
320         finally
321         {
322             thread.setContextClassLoader(loader);
323         }
324     }
325 
326     @Override
327     public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
328     {
329         final Thread thread = Thread.currentThread();
330         final ClassLoader loader = before(thread);
331         try
332         {
333             return delegate.invoke(key, entryProcessor, arguments);
334         }
335         finally
336         {
337             thread.setContextClassLoader(loader);
338         }
339     }
340 
341     @Override
342     public <T> Map<K, EntryProcessorResult<T>> invokeAll(final Set<? extends K> keys, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments)
343     {
344         final Thread thread = Thread.currentThread();
345         final ClassLoader loader = before(thread);
346         try
347         {
348             return delegate.invokeAll(keys, entryProcessor, arguments);
349         }
350         finally
351         {
352             thread.setContextClassLoader(loader);
353         }
354     }
355 
356     @Override
357     public String getName()
358     {
359         final Thread thread = Thread.currentThread();
360         final ClassLoader loader = before(thread);
361         try
362         {
363             return delegate.getName();
364         }
365         finally
366         {
367             thread.setContextClassLoader(loader);
368         }
369     }
370 
371     @Override
372     public CacheManager getCacheManager()
373     {
374         final Thread thread = Thread.currentThread();
375         final ClassLoader loader = before(thread);
376         try
377         {
378             return delegate.getCacheManager();
379         }
380         finally
381         {
382             thread.setContextClassLoader(loader);
383         }
384     }
385 
386     @Override
387     public void close()
388     {
389         final Thread thread = Thread.currentThread();
390         final ClassLoader loader = before(thread);
391         try
392         {
393             delegate.close();
394         }
395         finally
396         {
397             thread.setContextClassLoader(loader);
398         }
399     }
400 
401     @Override
402     public boolean isClosed()
403     {
404         final Thread thread = Thread.currentThread();
405         final ClassLoader loader = before(thread);
406         try
407         {
408             return delegate.isClosed();
409         }
410         finally
411         {
412             thread.setContextClassLoader(loader);
413         }
414     }
415 
416     @Override
417     public <T> T unwrap(final Class<T> clazz)
418     {
419         final Thread thread = Thread.currentThread();
420         final ClassLoader loader = before(thread);
421         try
422         {
423             return delegate.unwrap(clazz);
424         }
425         finally
426         {
427             thread.setContextClassLoader(loader);
428         }
429     }
430 
431     @Override
432     public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
433     {
434         final Thread thread = Thread.currentThread();
435         final ClassLoader loader = before(thread);
436         try
437         {
438             delegate.registerCacheEntryListener(cacheEntryListenerConfiguration);
439         }
440         finally
441         {
442             thread.setContextClassLoader(loader);
443         }
444     }
445 
446     @Override
447     public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
448     {
449         final Thread thread = Thread.currentThread();
450         final ClassLoader loader = before(thread);
451         try
452         {
453             delegate.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
454         }
455         finally
456         {
457             thread.setContextClassLoader(loader);
458         }
459     }
460 
461     @Override
462     public Iterator<Entry<K, V>> iterator()
463     {
464         final Thread thread = Thread.currentThread();
465         final ClassLoader loader = before(thread);
466         try
467         {
468             return delegate.iterator();
469         }
470         finally
471         {
472             thread.setContextClassLoader(loader);
473         }
474     }
475 
476     @Override
477     public boolean equals(final Object obj)
478     {
479         if (ClassLoaderAwareCache.class.isInstance(obj))
480         {
481             return delegate.equals(ClassLoaderAwareCache.class.cast(obj).delegate);
482         }
483         return super.equals(obj);
484     }
485 
486     @Override
487     public int hashCode()
488     {
489         return delegate.hashCode();
490     }
491 
492     public static <K extends Serializable, V extends Serializable> Cache<K, V> wrap(final ClassLoader loader, final JCSCache<K, V> delegate)
493     {
494         ClassLoader dontWrapLoader = ClassLoaderAwareCache.class.getClassLoader();
495         while (dontWrapLoader != null)
496         {
497             if (loader == dontWrapLoader)
498             {
499                 return delegate;
500             }
501             dontWrapLoader = dontWrapLoader.getParent();
502         }
503         return new ClassLoaderAwareCache<>(loader, delegate);
504     }
505 
506     public static <K extends Serializable, V extends Serializable> JCSCache<K, V> getDelegate(final Cache<?, ?> cache)
507     {
508         if (JCSCache.class.isInstance(cache))
509         {
510             return (JCSCache<K, V>) cache;
511         }
512         return ((ClassLoaderAwareCache<K, V>) cache).delegate;
513     }
514 }