001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.jcs.jcache.proxy;
020
021import org.apache.commons.jcs.jcache.JCSCache;
022
023import javax.cache.Cache;
024import javax.cache.CacheManager;
025import javax.cache.configuration.CacheEntryListenerConfiguration;
026import javax.cache.configuration.Configuration;
027import javax.cache.integration.CompletionListener;
028import javax.cache.processor.EntryProcessor;
029import javax.cache.processor.EntryProcessorException;
030import javax.cache.processor.EntryProcessorResult;
031import java.io.Serializable;
032import java.util.Iterator;
033import java.util.Map;
034import java.util.Set;
035
036// don't use a proxy, reflection is too slow here :(
037public class ClassLoaderAwareCache<K, V> implements Cache<K, V>
038{
039    private final ClassLoader loader;
040    private final JCSCache<K, V> delegate;
041
042    public ClassLoaderAwareCache(final ClassLoader loader, final JCSCache<K, V> delegate)
043    {
044        this.loader = loader;
045        this.delegate = delegate;
046    }
047
048    private ClassLoader before(final Thread thread)
049    {
050        final ClassLoader tccl = thread.getContextClassLoader();
051        thread.setContextClassLoader(loader);
052        return tccl;
053    }
054
055    public V get(final K key)
056    {
057        final Thread thread = Thread.currentThread();
058        final ClassLoader loader = before(thread);
059        try
060        {
061            return delegate.get(key);
062        }
063        finally
064        {
065            thread.setContextClassLoader(loader);
066        }
067    }
068
069    public Map<K, V> getAll(final Set<? extends K> keys)
070    {
071        final Thread thread = Thread.currentThread();
072        final ClassLoader loader = before(thread);
073        try
074        {
075            return delegate.getAll(keys);
076        }
077        finally
078        {
079            thread.setContextClassLoader(loader);
080        }
081    }
082
083    public boolean containsKey(final K key)
084    {
085        final Thread thread = Thread.currentThread();
086        final ClassLoader loader = before(thread);
087        try
088        {
089            return delegate.containsKey(key);
090        }
091        finally
092        {
093            thread.setContextClassLoader(loader);
094        }
095    }
096
097    public void loadAll(final Set<? extends K> keys, boolean replaceExistingValues, final CompletionListener completionListener)
098    {
099        final Thread thread = Thread.currentThread();
100        final ClassLoader loader = before(thread);
101        try
102        {
103            delegate.loadAll(keys, replaceExistingValues, completionListener);
104        }
105        finally
106        {
107            thread.setContextClassLoader(loader);
108        }
109    }
110
111    public void put(final K key, final V value)
112    {
113        final Thread thread = Thread.currentThread();
114        final ClassLoader loader = before(thread);
115        try
116        {
117            delegate.put(key, value);
118        }
119        finally
120        {
121            thread.setContextClassLoader(loader);
122        }
123    }
124
125    public V getAndPut(final K key, final V value)
126    {
127        final Thread thread = Thread.currentThread();
128        final ClassLoader loader = before(thread);
129        try
130        {
131            return delegate.getAndPut(key, value);
132        }
133        finally
134        {
135            thread.setContextClassLoader(loader);
136        }
137    }
138
139    public void putAll(final Map<? extends K, ? extends V> map)
140    {
141        final Thread thread = Thread.currentThread();
142        final ClassLoader loader = before(thread);
143        try
144        {
145            delegate.putAll(map);
146        }
147        finally
148        {
149            thread.setContextClassLoader(loader);
150        }
151    }
152
153    public boolean putIfAbsent(final K key, final V value)
154    {
155        final Thread thread = Thread.currentThread();
156        final ClassLoader loader = before(thread);
157        try
158        {
159            return delegate.putIfAbsent(key, value);
160        }
161        finally
162        {
163            thread.setContextClassLoader(loader);
164        }
165    }
166
167    public boolean remove(final K key)
168    {
169        final Thread thread = Thread.currentThread();
170        final ClassLoader loader = before(thread);
171        try
172        {
173            return delegate.remove(key);
174        }
175        finally
176        {
177            thread.setContextClassLoader(loader);
178        }
179    }
180
181    public boolean remove(final K key, final V oldValue)
182    {
183        final Thread thread = Thread.currentThread();
184        final ClassLoader loader = before(thread);
185        try
186        {
187            return delegate.remove(key, oldValue);
188        }
189        finally
190        {
191            thread.setContextClassLoader(loader);
192        }
193    }
194
195    public V getAndRemove(final K key)
196    {
197        final Thread thread = Thread.currentThread();
198        final ClassLoader loader = before(thread);
199        try
200        {
201            return delegate.getAndRemove(key);
202        }
203        finally
204        {
205            thread.setContextClassLoader(loader);
206        }
207    }
208
209    public boolean replace(final K key, final V oldValue, final V newValue)
210    {
211        final Thread thread = Thread.currentThread();
212        final ClassLoader loader = before(thread);
213        try
214        {
215            return delegate.replace(key, oldValue, newValue);
216        }
217        finally
218        {
219            thread.setContextClassLoader(loader);
220        }
221    }
222
223    public boolean replace(final K key, final V value)
224    {
225        final Thread thread = Thread.currentThread();
226        final ClassLoader loader = before(thread);
227        try
228        {
229            return delegate.replace(key, value);
230        }
231        finally
232        {
233            thread.setContextClassLoader(loader);
234        }
235    }
236
237    public V getAndReplace(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.getAndReplace(key, value);
244        }
245        finally
246        {
247            thread.setContextClassLoader(loader);
248        }
249    }
250
251    public void removeAll(final Set<? extends K> keys)
252    {
253        final Thread thread = Thread.currentThread();
254        final ClassLoader loader = before(thread);
255        try
256        {
257            delegate.removeAll(keys);
258        }
259        finally
260        {
261            thread.setContextClassLoader(loader);
262        }
263    }
264
265    @Override
266    public void removeAll()
267    {
268        final Thread thread = Thread.currentThread();
269        final ClassLoader loader = before(thread);
270        try
271        {
272            delegate.removeAll();
273        }
274        finally
275        {
276            thread.setContextClassLoader(loader);
277        }
278    }
279
280    @Override
281    public void clear()
282    {
283        final Thread thread = Thread.currentThread();
284        final ClassLoader loader = before(thread);
285        try
286        {
287            delegate.clear();
288        }
289        finally
290        {
291            thread.setContextClassLoader(loader);
292        }
293    }
294
295    public <C extends Configuration<K, V>> C getConfiguration(final Class<C> clazz)
296    {
297        final Thread thread = Thread.currentThread();
298        final ClassLoader loader = before(thread);
299        try
300        {
301            return delegate.getConfiguration(clazz);
302        }
303        finally
304        {
305            thread.setContextClassLoader(loader);
306        }
307    }
308
309    public <T> T invoke(final K key, final EntryProcessor<K, V, T> entryProcessor, final Object... arguments) throws EntryProcessorException
310    {
311        final Thread thread = Thread.currentThread();
312        final ClassLoader loader = before(thread);
313        try
314        {
315            return delegate.invoke(key, entryProcessor, arguments);
316        }
317        finally
318        {
319            thread.setContextClassLoader(loader);
320        }
321    }
322
323    public <T> Map<K, EntryProcessorResult<T>> invokeAll(Set<? extends K> keys, EntryProcessor<K, V, T> entryProcessor, Object... arguments)
324    {
325        final Thread thread = Thread.currentThread();
326        final ClassLoader loader = before(thread);
327        try
328        {
329            return delegate.invokeAll(keys, entryProcessor, arguments);
330        }
331        finally
332        {
333            thread.setContextClassLoader(loader);
334        }
335    }
336
337    @Override
338    public String getName()
339    {
340        final Thread thread = Thread.currentThread();
341        final ClassLoader loader = before(thread);
342        try
343        {
344            return delegate.getName();
345        }
346        finally
347        {
348            thread.setContextClassLoader(loader);
349        }
350    }
351
352    @Override
353    public CacheManager getCacheManager()
354    {
355        final Thread thread = Thread.currentThread();
356        final ClassLoader loader = before(thread);
357        try
358        {
359            return delegate.getCacheManager();
360        }
361        finally
362        {
363            thread.setContextClassLoader(loader);
364        }
365    }
366
367    @Override
368    public void close()
369    {
370        final Thread thread = Thread.currentThread();
371        final ClassLoader loader = before(thread);
372        try
373        {
374            delegate.close();
375        }
376        finally
377        {
378            thread.setContextClassLoader(loader);
379        }
380    }
381
382    @Override
383    public boolean isClosed()
384    {
385        final Thread thread = Thread.currentThread();
386        final ClassLoader loader = before(thread);
387        try
388        {
389            return delegate.isClosed();
390        }
391        finally
392        {
393            thread.setContextClassLoader(loader);
394        }
395    }
396
397    @Override
398    public <T> T unwrap(final Class<T> clazz)
399    {
400        final Thread thread = Thread.currentThread();
401        final ClassLoader loader = before(thread);
402        try
403        {
404            return delegate.unwrap(clazz);
405        }
406        finally
407        {
408            thread.setContextClassLoader(loader);
409        }
410    }
411
412    public void registerCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
413    {
414        final Thread thread = Thread.currentThread();
415        final ClassLoader loader = before(thread);
416        try
417        {
418            delegate.registerCacheEntryListener(cacheEntryListenerConfiguration);
419        }
420        finally
421        {
422            thread.setContextClassLoader(loader);
423        }
424    }
425
426    public void deregisterCacheEntryListener(final CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration)
427    {
428        final Thread thread = Thread.currentThread();
429        final ClassLoader loader = before(thread);
430        try
431        {
432            delegate.deregisterCacheEntryListener(cacheEntryListenerConfiguration);
433        }
434        finally
435        {
436            thread.setContextClassLoader(loader);
437        }
438    }
439
440    @Override
441    public Iterator<Entry<K, V>> iterator()
442    {
443        final Thread thread = Thread.currentThread();
444        final ClassLoader loader = before(thread);
445        try
446        {
447            return delegate.iterator();
448        }
449        finally
450        {
451            thread.setContextClassLoader(loader);
452        }
453    }
454
455    @Override
456    public boolean equals(final Object obj)
457    {
458        if (ClassLoaderAwareCache.class.isInstance(obj))
459        {
460            return delegate.equals(ClassLoaderAwareCache.class.cast(obj).delegate);
461        }
462        return super.equals(obj);
463    }
464
465    @Override
466    public int hashCode()
467    {
468        return delegate.hashCode();
469    }
470
471    public static <K extends Serializable, V extends Serializable> Cache<K, V> wrap(final ClassLoader loader, final JCSCache<K, V> delegate)
472    {
473        ClassLoader dontWrapLoader = ClassLoaderAwareCache.class.getClassLoader();
474        while (dontWrapLoader != null)
475        {
476            if (loader == dontWrapLoader)
477            {
478                return delegate;
479            }
480            dontWrapLoader = dontWrapLoader.getParent();
481        }
482        return new ClassLoaderAwareCache<K, V>(loader, delegate);
483    }
484
485    public static <K extends Serializable, V extends Serializable> JCSCache<K, V> getDelegate(final Cache<?, ?> cache)
486    {
487        if (JCSCache.class.isInstance(cache))
488        {
489            return (JCSCache<K, V>) cache;
490        }
491        return ((ClassLoaderAwareCache<K, V>) cache).delegate;
492    }
493}