Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

ISPN-2639 Integrate JCache 0.6 version and integrate TCK testing

* Use Maven Invoker Plugin to run TCK automatically in each build.
avoid leaking classloaders.
* Cache manager name for Infinispan JMX configuration should be
composed of the cache manager name and classloader information in
order to guarantee uniqueness. Otherwise, TCK fails with a lot of
JMX domain conflict errors, and there's no real reason for allowing
duplicate domains whose name would be more confusing.
* Infinispan cache manager implementation has a finalize() method to
avoid cache managers being garbage collected without proper shutdown.
* Move to a weak key map for cache manager collections, keyed on
class loader that avoids leaks.
* Make all other references to class loaders weak to avoid keeping
strong references.
* Implement support for UserTransaction
* Use jcache as module name
* Added support for Cache writers.
* Add an assertion to Infinispan Cache so that old values are checked
for null.
* Implement removeAll().
* Some operations should skip loading from cache.
* If cache non transactional, return STATUS_NO_TRANSACTION.
  • Loading branch information...
commit 7889c2d940c8be410f8fb294e9496ef0765660d7 1 parent b0636a7
Galder Zamarreño galderz authored maniksurtani committed
Showing with 2,156 additions and 827 deletions.
  1. +57 −56 core/src/main/java/org/infinispan/DecoratedCache.java
  2. +4 −3 core/src/main/java/org/infinispan/configuration/cache/Configuration.java
  3. +7 −5 core/src/main/java/org/infinispan/configuration/cache/ConfigurationBuilder.java
  4. +4 −3 core/src/main/java/org/infinispan/configuration/global/GlobalConfiguration.java
  5. +7 −6 core/src/main/java/org/infinispan/configuration/global/GlobalConfigurationBuilder.java
  6. +4 −3 core/src/main/java/org/infinispan/configuration/parsing/ConfigurationBuilderHolder.java
  7. +6 −5 core/src/main/java/org/infinispan/configuration/parsing/ParserRegistry.java
  8. +5 −3 core/src/main/java/org/infinispan/context/impl/AbstractInvocationContext.java
  9. +3 −2 core/src/main/java/org/infinispan/factories/ComponentRegistry.java
  10. +3 −2 core/src/main/java/org/infinispan/factories/GlobalComponentRegistry.java
  11. +6 −3 core/src/main/java/org/infinispan/factories/InternalCacheFactory.java
  12. +5 −3 core/src/main/java/org/infinispan/marshall/jboss/DefaultContextClassResolver.java
  13. +4 −3 core/src/main/java/org/infinispan/notifications/AbstractListenerImpl.java
  14. +345 −0 core/src/main/java/org/infinispan/util/WeakValueHashMap.java
  15. +137 −0 jcache/pom.xml
  16. +209 −0 jcache/src/it/tck-runner/pom.xml
  17. +35 −0 jcache/src/it/tck-runner/src/test/java/org/infinispan/jcache/test/tck/DummyTestListener.java
  18. +6 −0 jcache/src/it/tck-runner/src/test/resources/ExcludeList
  19. +3 −0  jcache/src/it/tck-runner/src/test/resources/unwrap.properties
  20. +21 −10 ...va/org/infinispan/jsr107/cache → jcache/src/main/java/org/infinispan/jcache}/ConfigurationAdapter.java
  21. +588 −0 jcache/src/main/java/org/infinispan/jcache/JCache.java
  22. +9 −9 ...n/jsr107/cache/InfinispanCacheEntry.java → jcache/src/main/java/org/infinispan/jcache/JCacheEntry.java
  23. +5 −5 ...ispanCacheListenerAdapter.java → jcache/src/main/java/org/infinispan/jcache/JCacheListenerAdapter.java
  24. +74 −8 ...nfinispanCacheLoaderAdapter.java → jcache/src/main/java/org/infinispan/jcache/JCacheLoaderAdapter.java
  25. +106 −35 ...r107/cache/InfinispanCacheManager.java → jcache/src/main/java/org/infinispan/jcache/JCacheManager.java
  26. +185 −0 jcache/src/main/java/org/infinispan/jcache/JCacheManagerFactory.java
  27. +86 −0 jcache/src/main/java/org/infinispan/jcache/JCacheUserTransaction.java
  28. +11 −8 ...nfinispanCacheWriterAdapter.java → jcache/src/main/java/org/infinispan/jcache/JCacheWriterAdapter.java
  29. +5 −5 ...ache/InfinispanCachingProvider.java → jcache/src/main/java/org/infinispan/jcache/JCachingProvider.java
  30. +2 −2 ...ache/InfinispanStatusConverter.java → jcache/src/main/java/org/infinispan/jcache/JStatusConverter.java
  31. +62 −0 jcache/src/main/java/org/infinispan/jcache/MutableJCacheEntry.java
  32. +1 −1  .../java/org/infinispan/jsr107/cache → jcache/src/main/java/org/infinispan/jcache}/RICacheEntryEvent.java
  33. +1 −1  ...pan/jsr107/cache → jcache/src/main/java/org/infinispan/jcache}/RICacheEntryEventFilteringIterable.java
  34. +1 −1  ...pan/jsr107/cache → jcache/src/main/java/org/infinispan/jcache}/RICacheEntryEventFilteringIterator.java
  35. +1 −1  ...ispan/jsr107/cache → jcache/src/main/java/org/infinispan/jcache}/RICacheEntryListenerRegistration.java
  36. +5 −5 .../java/org/infinispan/jsr107/cache → jcache/src/main/java/org/infinispan/jcache}/RICacheStatistics.java
  37. +64 −0 jcache/src/main/java/org/infinispan/jcache/RIDelegatingCacheMXBean.java
  38. +66 −0 jcache/src/main/java/org/infinispan/jcache/logging/Log.java
  39. +1 −0  jcache/src/main/resources/META-INF/services/javax.cache.spi.CachingProvider
  40. +0 −98 jsr107impl/pom.xml
  41. +0 −398 jsr107impl/src/main/java/org/infinispan/jsr107/cache/InfinispanCache.java
  42. +0 −141 jsr107impl/src/main/java/org/infinispan/jsr107/cache/InfinispanCacheManagerFactory.java
  43. +0 −1  jsr107impl/src/main/resources/META-INF/services/javax.cache.spi.CachingProvider
  44. +11 −1 parent/pom.xml
  45. +1 −0  pom.xml
113 core/src/main/java/org/infinispan/DecoratedCache.java
View
@@ -21,6 +21,7 @@
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
@@ -50,7 +51,7 @@
public class DecoratedCache<K, V> extends AbstractDelegatingAdvancedCache<K, V> {
private final EnumSet<Flag> flags;
- private final ClassLoader classLoader;
+ private final WeakReference<ClassLoader> classLoader;
private final CacheImpl<K, V> cacheImplementation;
public DecoratedCache(AdvancedCache<K, V> delegate, ClassLoader classLoader) {
@@ -69,7 +70,7 @@ public DecoratedCache(AdvancedCache<K, V> delegate, ClassLoader classLoader, Fla
this.flags = EnumSet.noneOf(Flag.class);
this.flags.addAll(Arrays.asList(flags));
}
- this.classLoader = classLoader;
+ this.classLoader = new WeakReference<ClassLoader>(classLoader);
if (flags == null && classLoader == null)
throw new IllegalArgumentException("There is no point in using a DecoratedCache if neither a ClassLoader nor any Flags are set.");
@@ -82,7 +83,7 @@ private DecoratedCache(CacheImpl<K, V> delegate, ClassLoader classLoader, EnumSe
//this constructor is private so we already checked for argument validity
super(delegate);
this.flags = newFlags;
- this.classLoader = classLoader;
+ this.classLoader = new WeakReference<ClassLoader>(classLoader);
this.cacheImplementation = delegate;
}
@@ -104,12 +105,12 @@ private DecoratedCache(CacheImpl<K, V> delegate, ClassLoader classLoader, EnumSe
}
else {
if (this.flags==null) {
- return new DecoratedCache<K, V>(this.cacheImplementation, this.classLoader, EnumSet.copyOf(flagsToAdd));
+ return new DecoratedCache<K, V>(this.cacheImplementation, this.classLoader.get(), EnumSet.copyOf(flagsToAdd));
}
else {
EnumSet<Flag> newFlags = EnumSet.copyOf(this.flags);
newFlags.addAll(flagsToAdd);
- return new DecoratedCache<K, V>(this.cacheImplementation, this.classLoader, newFlags);
+ return new DecoratedCache<K, V>(this.cacheImplementation, this.classLoader.get(), newFlags);
}
}
}
@@ -121,253 +122,253 @@ public ClassLoader getClassLoader() {
return cacheImplementation.getClassLoader();
}
else {
- return this.classLoader;
+ return this.classLoader.get();
}
}
@Override
public void stop() {
- cacheImplementation.stop(classLoader);
+ cacheImplementation.stop(classLoader.get());
}
@Override
public boolean lock(K... keys) {
- return cacheImplementation.lock(Arrays.asList(keys), flags, classLoader);
+ return cacheImplementation.lock(Arrays.asList(keys), flags, classLoader.get());
}
@Override
public boolean lock(Collection<? extends K> keys) {
- return cacheImplementation.lock(keys, flags, classLoader);
+ return cacheImplementation.lock(keys, flags, classLoader.get());
}
@Override
public void putForExternalRead(K key, V value) {
- cacheImplementation.putForExternalRead(key, value, flags, classLoader);
+ cacheImplementation.putForExternalRead(key, value, flags, classLoader.get());
}
@Override
public void evict(K key) {
- cacheImplementation.evict(key, flags, classLoader);
+ cacheImplementation.evict(key, flags, classLoader.get());
}
@Override
public V put(K key, V value, long lifespan, TimeUnit unit) {
- return cacheImplementation.put(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.put(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public V putIfAbsent(K key, V value, long lifespan, TimeUnit unit) {
- return cacheImplementation.putIfAbsent(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.putIfAbsent(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public void putAll(Map<? extends K, ? extends V> map, long lifespan, TimeUnit unit) {
- cacheImplementation.putAll(map, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ cacheImplementation.putAll(map, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public V replace(K key, V value, long lifespan, TimeUnit unit) {
- return cacheImplementation.replace(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.replace(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public boolean replace(K key, V oldValue, V value, long lifespan, TimeUnit unit) {
- return cacheImplementation.replace(key, oldValue, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.replace(key, oldValue, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public V put(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
- return cacheImplementation.put(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader);
+ return cacheImplementation.put(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader.get());
}
@Override
public V putIfAbsent(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
- return cacheImplementation.putIfAbsent(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader);
+ return cacheImplementation.putIfAbsent(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader.get());
}
@Override
public void putAll(Map<? extends K, ? extends V> map, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
- cacheImplementation.putAll(map, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader);
+ cacheImplementation.putAll(map, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader.get());
}
@Override
public V replace(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
- return cacheImplementation.replace(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader);
+ return cacheImplementation.replace(key, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader.get());
}
@Override
public boolean replace(K key, V oldValue, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
- return cacheImplementation.replace(key, oldValue, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader);
+ return cacheImplementation.replace(key, oldValue, value, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> putAsync(K key, V value) {
- return cacheImplementation.putAsync(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.putAsync(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> putAsync(K key, V value, long lifespan, TimeUnit unit) {
- return cacheImplementation.putAsync(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.putAsync(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> putAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
- return cacheImplementation.putAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader);
+ return cacheImplementation.putAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader.get());
}
@Override
public NotifyingFuture<Void> putAllAsync(Map<? extends K, ? extends V> data) {
- return cacheImplementation.putAllAsync(data, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.putAllAsync(data, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<Void> putAllAsync(Map<? extends K, ? extends V> data, long lifespan, TimeUnit unit) {
- return cacheImplementation.putAllAsync(data, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.putAllAsync(data, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<Void> putAllAsync(Map<? extends K, ? extends V> data, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
- return cacheImplementation.putAllAsync(data, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader);
+ return cacheImplementation.putAllAsync(data, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader.get());
}
@Override
public NotifyingFuture<Void> clearAsync() {
- return cacheImplementation.clearAsync(flags, classLoader);
+ return cacheImplementation.clearAsync(flags, classLoader.get());
}
@Override
public NotifyingFuture<V> putIfAbsentAsync(K key, V value) {
- return cacheImplementation.putIfAbsentAsync(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.putIfAbsentAsync(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> putIfAbsentAsync(K key, V value, long lifespan, TimeUnit unit) {
- return cacheImplementation.putIfAbsentAsync(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.putIfAbsentAsync(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> putIfAbsentAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
- return cacheImplementation.putIfAbsentAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader);
+ return cacheImplementation.putIfAbsentAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> removeAsync(Object key) {
- return cacheImplementation.removeAsync(key, flags, classLoader);
+ return cacheImplementation.removeAsync(key, flags, classLoader.get());
}
@Override
public NotifyingFuture<Boolean> removeAsync(Object key, Object value) {
- return cacheImplementation.removeAsync(key, value, flags, classLoader);
+ return cacheImplementation.removeAsync(key, value, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> replaceAsync(K key, V value) {
- return cacheImplementation.replaceAsync(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.replaceAsync(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> replaceAsync(K key, V value, long lifespan, TimeUnit unit) {
- return cacheImplementation.replaceAsync(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.replaceAsync(key, value, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> replaceAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
- return cacheImplementation.replaceAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader);
+ return cacheImplementation.replaceAsync(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader.get());
}
@Override
public NotifyingFuture<Boolean> replaceAsync(K key, V oldValue, V newValue) {
- return cacheImplementation.replaceAsync(key, oldValue, newValue, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.replaceAsync(key, oldValue, newValue, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<Boolean> replaceAsync(K key, V oldValue, V newValue, long lifespan, TimeUnit unit) {
- return cacheImplementation.replaceAsync(key, oldValue, newValue, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.replaceAsync(key, oldValue, newValue, lifespan, unit, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public NotifyingFuture<Boolean> replaceAsync(K key, V oldValue, V newValue, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
- return cacheImplementation.replaceAsync(key, oldValue, newValue, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader);
+ return cacheImplementation.replaceAsync(key, oldValue, newValue, lifespan, lifespanUnit, maxIdle, maxIdleUnit, flags, classLoader.get());
}
@Override
public NotifyingFuture<V> getAsync(K key) {
- return cacheImplementation.getAsync(key, flags, classLoader);
+ return cacheImplementation.getAsync(key, flags, classLoader.get());
}
@Override
public int size() {
- return cacheImplementation.size(flags, classLoader);
+ return cacheImplementation.size(flags, classLoader.get());
}
@Override
public boolean isEmpty() {
- return cacheImplementation.isEmpty(flags, classLoader);
+ return cacheImplementation.isEmpty(flags, classLoader.get());
}
@Override
public boolean containsKey(Object key) {
- return cacheImplementation.containsKey(key, flags, classLoader);
+ return cacheImplementation.containsKey(key, flags, classLoader.get());
}
@Override
public V get(Object key) {
- return cacheImplementation.get(key, flags, classLoader);
+ return cacheImplementation.get(key, flags, classLoader.get());
}
@Override
public V put(K key, V value) {
- return cacheImplementation.put(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.put(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public V remove(Object key) {
- return cacheImplementation.remove(key, flags, classLoader);
+ return cacheImplementation.remove(key, flags, classLoader.get());
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
- cacheImplementation.putAll(m, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ cacheImplementation.putAll(m, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public void clear() {
- cacheImplementation.clear(flags, classLoader);
+ cacheImplementation.clear(flags, classLoader.get());
}
@Override
public Set<K> keySet() {
- return cacheImplementation.keySet(flags, classLoader);
+ return cacheImplementation.keySet(flags, classLoader.get());
}
@Override
public Collection<V> values() {
- return cacheImplementation.values(flags, classLoader);
+ return cacheImplementation.values(flags, classLoader.get());
}
@Override
public Set<Entry<K, V>> entrySet() {
- return cacheImplementation.entrySet(flags, classLoader);
+ return cacheImplementation.entrySet(flags, classLoader.get());
}
@Override
public V putIfAbsent(K key, V value) {
- return cacheImplementation.putIfAbsent(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.putIfAbsent(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public boolean remove(Object key, Object value) {
- return cacheImplementation.remove(key, value, flags, classLoader);
+ return cacheImplementation.remove(key, value, flags, classLoader.get());
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
- return cacheImplementation.replace(key, oldValue, newValue, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.replace(key, oldValue, newValue, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
@Override
public V replace(K key, V value) {
- return cacheImplementation.replace(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader);
+ return cacheImplementation.replace(key, value, cacheImplementation.defaultLifespan, MILLISECONDS, cacheImplementation.defaultMaxIdleTime, MILLISECONDS, flags, classLoader.get());
}
//Not exposed on interface
@@ -378,7 +379,7 @@ public V replace(K key, V value) {
@Override
public void addListener(Object listener) {
if (cacheImplementation.notifier instanceof ClassLoaderAwareListenable) {
- ((ClassLoaderAwareListenable)cacheImplementation.notifier).addListener(listener, classLoader);
+ ((ClassLoaderAwareListenable)cacheImplementation.notifier).addListener(listener, classLoader.get());
} else {
throw new IllegalStateException("The CacheNotifier does not implement the ClassLoaderAwareListenable interface");
}
7 core/src/main/java/org/infinispan/configuration/cache/Configuration.java
View
@@ -18,6 +18,7 @@
*/
package org.infinispan.configuration.cache;
+import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -25,7 +26,7 @@
public class Configuration {
- private final ClassLoader classLoader; //TODO remove this
+ private final WeakReference<ClassLoader> classLoader; //TODO remove this
private final ClusteringConfiguration clusteringConfiguration;
private final CustomInterceptorsConfiguration customInterceptorsConfiguration;
private final DataContainerConfiguration dataContainerConfiguration;
@@ -75,7 +76,7 @@
}
this.moduleConfiguration = Collections.unmodifiableMap(modulesMap);
this.sites = sites;
- this.classLoader = cl;
+ this.classLoader = new WeakReference<ClassLoader>(cl);
}
/**
@@ -83,7 +84,7 @@
*/
@Deprecated
public ClassLoader classLoader() {
- return classLoader;
+ return classLoader == null ? null : classLoader.get();
}
public ClusteringConfiguration clustering() {
12 core/src/main/java/org/infinispan/configuration/cache/ConfigurationBuilder.java
View
@@ -20,6 +20,7 @@
import static java.util.Arrays.asList;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -31,7 +32,7 @@
public class ConfigurationBuilder implements ConfigurationChildBuilder {
- private ClassLoader classLoader;
+ private WeakReference<ClassLoader> classLoader;
private final ClusteringConfigurationBuilder clustering;
private final CustomInterceptorsConfigurationBuilder customInterceptors;
private final DataContainerConfigurationBuilder dataContainer;
@@ -70,12 +71,12 @@ public ConfigurationBuilder() {
}
public ConfigurationBuilder classLoader(ClassLoader cl) {
- this.classLoader = cl;
+ this.classLoader = new WeakReference<ClassLoader>(cl);
return this;
}
ClassLoader classLoader() {
- return classLoader;
+ return classLoader.get();
}
@Override
@@ -209,11 +210,12 @@ public Configuration build(boolean validate) {
dataContainer.create(), deadlockDetection.create(), eviction.create(),
expiration.create(), indexing.create(), invocationBatching.create(),
jmxStatistics.create(), loaders.create(), locking.create(), storeAsBinary.create(),
- transaction.create(), unsafe.create(), versioning.create(), modulesConfig,sites.create() , classLoader);
+ transaction.create(), unsafe.create(), versioning.create(), modulesConfig,sites.create() ,
+ classLoader == null ? null : classLoader.get());
}
public ConfigurationBuilder read(Configuration template) {
- this.classLoader = template.classLoader();
+ this.classLoader = new WeakReference<ClassLoader>(template.classLoader());
this.clustering.read(template.clustering());
this.customInterceptors.read(template.customInterceptors());
this.dataContainer.read(template.dataContainer());
7 core/src/main/java/org/infinispan/configuration/global/GlobalConfiguration.java
View
@@ -22,6 +22,7 @@
*/
package org.infinispan.configuration.global;
+import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -67,7 +68,7 @@
private final ShutdownConfiguration shutdown;
private final Map<Class<?>, ?> modules;
private final SiteConfiguration site;
- private final ClassLoader cl;
+ private final WeakReference<ClassLoader> cl;
GlobalConfiguration(ExecutorFactoryConfiguration asyncListenerExecutor,
ExecutorFactoryConfiguration asyncTransportExecutor, ScheduledExecutorFactoryConfiguration evictionScheduledExecutor,
@@ -88,7 +89,7 @@
}
this.modules = Collections.unmodifiableMap(moduleMap);
this.site = site;
- this.cl = cl;
+ this.cl = new WeakReference<ClassLoader>(cl);
}
public ExecutorFactoryConfiguration asyncListenerExecutor() {
@@ -136,7 +137,7 @@ public ShutdownConfiguration shutdown() {
* Get the classloader in use by this configuration.
*/
public ClassLoader classLoader() {
- return cl;
+ return cl.get();
}
public SiteConfiguration sites() {
13 core/src/main/java/org/infinispan/configuration/global/GlobalConfigurationBuilder.java
View
@@ -23,6 +23,7 @@
package org.infinispan.configuration.global;
+import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -35,7 +36,7 @@
public class GlobalConfigurationBuilder implements GlobalConfigurationChildBuilder {
- private ClassLoader cl;
+ private WeakReference<ClassLoader> cl;
private final TransportConfigurationBuilder transport;
private final GlobalJmxStatisticsConfigurationBuilder globalJmxStatistics;
private final SerializationConfigurationBuilder serialization;
@@ -48,7 +49,7 @@
private final SiteConfigurationBuilder site;
public GlobalConfigurationBuilder() {
- this.cl = Thread.currentThread().getContextClassLoader();
+ this.cl = new WeakReference<ClassLoader>(Thread.currentThread().getContextClassLoader());
this.transport = new TransportConfigurationBuilder(this);
this.globalJmxStatistics = new GlobalJmxStatisticsConfigurationBuilder(this);
this.serialization = new SerializationConfigurationBuilder(this);
@@ -88,11 +89,11 @@ public GlobalConfigurationBuilder nonClusteredDefault() {
}
protected ClassLoader getClassLoader() {
- return cl;
+ return cl.get();
}
public GlobalConfigurationBuilder classLoader(ClassLoader cl) {
- this.cl = cl;
+ this.cl = new WeakReference<ClassLoader>(cl);
return this;
}
@@ -194,12 +195,12 @@ public GlobalConfiguration build() {
shutdown.create(),
modulesConfig,
site.create(),
- cl
+ cl.get()
);
}
public GlobalConfigurationBuilder read(GlobalConfiguration template) {
- this.cl = template.classLoader();
+ this.cl = new WeakReference<ClassLoader>(template.classLoader());
for (Object c : template.modules().values()) {
BuiltBy builtBy = c.getClass().getAnnotation(BuiltBy.class);
7 core/src/main/java/org/infinispan/configuration/parsing/ConfigurationBuilderHolder.java
View
@@ -18,6 +18,7 @@
*/
package org.infinispan.configuration.parsing;
+import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
@@ -31,7 +32,7 @@
private final Map<String, ConfigurationBuilder> namedConfigurationBuilders;
private ConfigurationBuilder currentConfigurationBuilder;
private final Map<Class<? extends ConfigurationParser<?>>, ParserContext> parserContexts;
- private final ClassLoader classLoader;
+ private final WeakReference<ClassLoader> classLoader;
public ConfigurationBuilderHolder() {
this(Thread.currentThread().getContextClassLoader());
@@ -43,7 +44,7 @@ public ConfigurationBuilderHolder(ClassLoader classLoader) {
this.namedConfigurationBuilders = new HashMap<String, ConfigurationBuilder>();
this.currentConfigurationBuilder = defaultConfigurationBuilder;
this.parserContexts = new HashMap<Class<? extends ConfigurationParser<?>>, ParserContext>();
- this.classLoader = classLoader;
+ this.classLoader = new WeakReference<ClassLoader>(classLoader);
}
public GlobalConfigurationBuilder getGlobalConfigurationBuilder() {
@@ -82,7 +83,7 @@ public void setParserContext(Class<? extends ConfigurationParser<?>> parserClass
}
public ClassLoader getClassLoader() {
- return classLoader;
+ return classLoader.get();
}
Map<Class<? extends ConfigurationParser<?>>, ParserContext> getParserContexts() {
11 core/src/main/java/org/infinispan/configuration/parsing/ParserRegistry.java
View
@@ -22,6 +22,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.ref.WeakReference;
import java.util.ServiceLoader;
import javax.xml.namespace.QName;
@@ -43,12 +44,12 @@
*/
public class ParserRegistry {
private final XMLMapper xmlMapper;
- private final ClassLoader cl;
+ private final WeakReference<ClassLoader> cl;
public ParserRegistry(ClassLoader classLoader) {
xmlMapper = XMLMapper.Factory.create();
- this.cl = classLoader;
- ServiceLoader<ConfigurationParser> parsers = ServiceLoader.load(ConfigurationParser.class, cl);
+ this.cl = new WeakReference<ClassLoader>(classLoader);
+ ServiceLoader<ConfigurationParser> parsers = ServiceLoader.load(ConfigurationParser.class, cl.get());
for (ConfigurationParser<?> parser : parsers) {
for (Namespace ns : parser.getSupportedNamespaces()) {
xmlMapper.registerRootElement(new QName(ns.getUri(), ns.getRootElement()), parser);
@@ -58,7 +59,7 @@ public ParserRegistry(ClassLoader classLoader) {
public ConfigurationBuilderHolder parseFile(String filename) throws IOException {
FileLookup fileLookup = FileLookupFactory.newInstance();
- InputStream is = fileLookup.lookupFile(filename, cl);
+ InputStream is = fileLookup.lookupFile(filename, cl.get());
if(is==null) {
throw new FileNotFoundException(filename);
}
@@ -73,7 +74,7 @@ public ConfigurationBuilderHolder parse(InputStream is) {
try {
BufferedInputStream input = new BufferedInputStream(is);
XMLStreamReader streamReader = XMLInputFactory.newInstance().createXMLStreamReader(input);
- ConfigurationBuilderHolder holder = new ConfigurationBuilderHolder(cl);
+ ConfigurationBuilderHolder holder = new ConfigurationBuilderHolder(cl.get());
xmlMapper.parseDocument(holder, streamReader);
streamReader.close();
// Fire all parsingComplete events if any
8 core/src/main/java/org/infinispan/context/impl/AbstractInvocationContext.java
View
@@ -27,6 +27,8 @@
import org.infinispan.context.InvocationContext;
import org.infinispan.remoting.transport.Address;
+import java.lang.ref.WeakReference;
+
/**
* Common features of transaction and invocation contexts
*
@@ -41,7 +43,7 @@
protected byte contextFlags = 0;
private Address origin;
// Class loader associated with this invocation which supports AdvancedCache.with() functionality
- private ClassLoader classLoader;
+ private WeakReference<ClassLoader> classLoader;
// if this or any context subclass ever needs to store a boolean, always use a context flag instead. This is far
// more space-efficient. Note that this value will be stored in a byte, which means up to 8 flags can be stored in
@@ -134,12 +136,12 @@ public AbstractInvocationContext clone() {
@Override
public ClassLoader getClassLoader() {
- return classLoader;
+ return classLoader.get();
}
@Override
public void setClassLoader(ClassLoader classLoader) {
- this.classLoader = classLoader;
+ this.classLoader = new WeakReference<ClassLoader>(classLoader);
}
@Override
5 core/src/main/java/org/infinispan/factories/ComponentRegistry.java
View
@@ -41,6 +41,7 @@
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
+import java.lang.ref.WeakReference;
import java.util.Map;
import static org.infinispan.factories.KnownComponentNames.MODULE_COMMAND_INITIALIZERS;
@@ -64,7 +65,7 @@
private ResponseGenerator responseGenerator;
private CommandsFactory commandsFactory;
- protected final ClassLoader defaultClassLoader;
+ protected final WeakReference<ClassLoader> defaultClassLoader;
@Inject
public void setCacheManagerNotifier(CacheManagerNotifier cacheManagerNotifier) {
@@ -80,7 +81,7 @@ public void setCacheManagerNotifier(CacheManagerNotifier cacheManagerNotifier) {
*/
public ComponentRegistry(String cacheName, Configuration configuration, AdvancedCache<?, ?> cache,
GlobalComponentRegistry globalComponents, ClassLoader defaultClassLoader) {
- this.defaultClassLoader = defaultClassLoader;
+ this.defaultClassLoader = new WeakReference<ClassLoader>(defaultClassLoader);
try {
this.cacheName = cacheName;
if (cacheName == null) throw new ConfigurationException("Cache name cannot be null!");
5 core/src/main/java/org/infinispan/factories/GlobalComponentRegistry.java
View
@@ -50,6 +50,7 @@
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -96,7 +97,7 @@
final ConcurrentMap<String, ComponentRegistry> namedComponents = new ConcurrentHashMap<String, ComponentRegistry>(4);
- protected final ClassLoader defaultClassLoader;
+ protected final WeakReference<ClassLoader> defaultClassLoader;
/**
* Creates an instance of the component registry. The configuration passed in is automatically registered.
@@ -114,7 +115,7 @@ public GlobalComponentRegistry(GlobalConfiguration configuration,
// Load up the component metadata
componentMetadataRepo.initialize(moduleProperties.getModuleMetadataFiles(configuredClassLoader), configuredClassLoader);
- defaultClassLoader = registerDefaultClassLoader(configuredClassLoader);
+ defaultClassLoader = new WeakReference<ClassLoader>(registerDefaultClassLoader(configuredClassLoader));
try {
// this order is important ...
9 core/src/main/java/org/infinispan/factories/InternalCacheFactory.java
View
@@ -33,6 +33,8 @@
import org.infinispan.transaction.xa.recovery.RecoveryAdminOperations;
import org.infinispan.xsite.XSiteAdminOperations;
+import java.lang.ref.WeakReference;
+
/**
* An internal factory for constructing Caches. Used by the {@link DefaultCacheManager}, this is not intended as public
* API.
@@ -45,7 +47,7 @@
* @since 4.0
*/
public class InternalCacheFactory<K, V> extends AbstractNamedCacheComponentFactory {
- private ClassLoader defaultClassLoader;
+ private WeakReference<ClassLoader> defaultClassLoader;
/**
* This implementation clones the configuration passed in before using it.
@@ -89,7 +91,8 @@ private void bootstrap(String cacheName, AdvancedCache<?, ?> cache, Configuratio
this.configuration = configuration;
// injection bootstrap stuff
- componentRegistry = new ComponentRegistry(cacheName, configuration, cache, globalComponentRegistry, defaultClassLoader);
+ componentRegistry = new ComponentRegistry(cacheName, configuration, cache, globalComponentRegistry,
+ defaultClassLoader == null ? null : defaultClassLoader.get());
/*
--------------------------------------------------------------------------------------------------------------
@@ -116,7 +119,7 @@ private void bootstrap(String cacheName, AdvancedCache<?, ?> cache, Configuratio
* @param loader class loader to use as a default.
*/
public void setDefaultClassLoader(ClassLoader loader) {
- this.defaultClassLoader = loader;
+ this.defaultClassLoader = new WeakReference<ClassLoader>(loader);
}
@Override
8 core/src/main/java/org/infinispan/marshall/jboss/DefaultContextClassResolver.java
View
@@ -21,6 +21,8 @@
import org.jboss.marshalling.ContextClassResolver;
+import java.lang.ref.WeakReference;
+
/**
* This class refines <code>ContextClassLoader</code> to add a default class loader
* in case the context class loader is <code>null</code>.
@@ -30,15 +32,15 @@
*/
public class DefaultContextClassResolver extends ContextClassResolver {
- private ClassLoader defaultClassLoader;
+ private WeakReference<ClassLoader> defaultClassLoader;
public DefaultContextClassResolver(ClassLoader defaultClassLoader) {
- this.defaultClassLoader = defaultClassLoader;
+ this.defaultClassLoader = new WeakReference<ClassLoader>(defaultClassLoader);
}
@Override
protected ClassLoader getClassLoader() {
ClassLoader loader = super.getClassLoader();
- return loader != null ? loader : defaultClassLoader;
+ return loader != null ? loader : defaultClassLoader.get();
}
}
7 core/src/main/java/org/infinispan/notifications/AbstractListenerImpl.java
View
@@ -33,6 +33,7 @@
import org.infinispan.util.logging.Log;
import java.lang.annotation.Annotation;
+import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -190,13 +191,13 @@ protected static void testListenerMethodValidity(Method m, Class<?> allowedParam
public final Object target;
public final Method method;
public final boolean sync;
- public final ClassLoader classLoader;
+ public final WeakReference<ClassLoader> classLoader;
public ListenerInvocation(Object target, Method method, boolean sync, ClassLoader classLoader) {
this.target = target;
this.method = method;
this.sync = sync;
- this.classLoader = classLoader;
+ this.classLoader = new WeakReference<ClassLoader>(classLoader);
}
public void invoke(final Object event) {
@@ -206,7 +207,7 @@ public void invoke(final Object event) {
public void run() {
ClassLoader contextClassLoader = null;
if (classLoader != null) {
- contextClassLoader = setContextClassLoader(classLoader);
+ contextClassLoader = setContextClassLoader(classLoader.get());
}
try {
method.invoke(target, event);
345 core/src/main/java/org/infinispan/util/WeakValueHashMap.java
View
@@ -0,0 +1,345 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2005, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.util;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.AbstractSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This Map will remove entries when the value in the map has been cleaned from
+ * garbage collection
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
+ * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a>
+ * @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
+ * @see <a href="http://anonsvn.jboss.org/repos/common/common-core/trunk/src/main/java/org/jboss/util/collection/">
+ * JBoss Common Core source code for origins of this class</a>
+ */
+public final class WeakValueHashMap<K, V> extends java.util.AbstractMap<K, V> {
+
+ /**
+ * Hash table mapping keys to ref values
+ */
+ private Map<K, ValueRef<K, V>> map;
+
+ /**
+ * Reference queue for cleared RefKeys
+ */
+ private ReferenceQueue<V> queue = new ReferenceQueue<V>();
+
+ /**
+ * Constructs a new, empty <code>WeakValueHashMap</code> with the given
+ * initial capacity and the given load factor.
+ *
+ * @param initialCapacity The initial capacity of the <code>WeakValueHashMap</code>
+ * @param loadFactor The load factor of the <code>WeakValueHashMap</code>
+ * @throws IllegalArgumentException If the initial capacity is less than
+ * zero, or if the load factor is
+ * nonpositive
+ */
+ public WeakValueHashMap(int initialCapacity, float loadFactor) {
+ map = createMap(initialCapacity, loadFactor);
+ }
+
+ /**
+ * Constructs a new, empty <code>WeakValueHashMap</code> with the given
+ * initial capacity and the default load factor, which is
+ * <code>0.75</code>.
+ *
+ * @param initialCapacity The initial capacity of the <code>WeakValueHashMap</code>
+ * @throws IllegalArgumentException If the initial capacity is less than
+ * zero
+ */
+ public WeakValueHashMap(int initialCapacity) {
+ map = createMap(initialCapacity);
+ }
+
+ /**
+ * Constructs a new, empty <code>WeakValueHashMap</code> with the default
+ * initial capacity and the default load factor, which is
+ * <code>0.75</code>.
+ */
+ public WeakValueHashMap() {
+ map = createMap();
+ }
+
+ /**
+ * Constructs a new <code>WeakValueHashMap</code> with the same mappings as
+ * the specified <tt>Map</tt>. The <code>WeakValueHashMap</code> is created
+ * with an initial capacity of twice the number of mappings in the specified
+ * map or 11 (whichever is greater), and a default load factor, which is
+ * <tt>0.75</tt>.
+ *
+ * @param t the map whose mappings are to be placed in this map.
+ * @since 1.3
+ */
+ public WeakValueHashMap(Map<K, V> t) {
+ this(Math.max(2 * t.size(), 11), 0.75f);
+ putAll(t);
+ }
+
+ /**
+ * Create new value ref instance.
+ *
+ * @param key the key
+ * @param value the value
+ * @param q the ref queue
+ * @return new value ref instance
+ */
+ private ValueRef<K, V> create(K key, V value, ReferenceQueue<V> q) {
+ return WeakValueRef.create(key, value, q);
+ }
+
+ /**
+ * Create map.
+ *
+ * @param initialCapacity the initial capacity
+ * @param loadFactor the load factor
+ * @return new map instance
+ */
+ private Map<K, ValueRef<K, V>> createMap(int initialCapacity, float loadFactor) {
+ return new HashMap<K, ValueRef<K, V>>(initialCapacity, loadFactor);
+ }
+
+ /**
+ * Create map.
+ *
+ * @param initialCapacity the initial capacity
+ * @return new map instance
+ */
+ private Map<K, ValueRef<K, V>> createMap(int initialCapacity) {
+ return new HashMap<K, ValueRef<K, V>>(initialCapacity);
+ }
+
+ /**
+ * Create map.
+ *
+ * @return new map instance
+ */
+ protected Map<K, ValueRef<K, V>> createMap() {
+ return new HashMap<K, ValueRef<K, V>>();
+ }
+
+ @Override
+ public int size() {
+ processQueue();
+ return map.size();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ processQueue();
+ return map.containsKey(key);
+ }
+
+ @Override
+ public V get(Object key) {
+ processQueue();
+ ValueRef<K, V> ref = map.get(key);
+ if (ref != null)
+ return ref.get();
+ return null;
+ }
+
+ @Override
+ public V put(K key, V value) {
+ processQueue();
+ ValueRef<K, V> ref = create(key, value, queue);
+ ValueRef<K, V> result = map.put(key, ref);
+ if (result != null)
+ return result.get();
+ return null;
+ }
+
+ @Override
+ public V remove(Object key) {
+ processQueue();
+ ValueRef<K, V> result = map.remove(key);
+ if (result != null)
+ return result.get();
+ return null;
+ }
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ processQueue();
+ return new EntrySet();
+ }
+
+ @Override
+ public void clear() {
+ processQueue();
+ map.clear();
+ }
+
+ @Override
+ public String toString() {
+ return map.toString();
+ }
+
+ /**
+ * Remove all entries whose values have been discarded.
+ */
+ @SuppressWarnings("unchecked")
+ private void processQueue() {
+ ValueRef<K, V> ref = (ValueRef<K, V>) queue.poll();
+ while (ref != null) {
+ // only remove if it is the *exact* same WeakValueRef
+ if (ref == map.get(ref.getKey()))
+ map.remove(ref.getKey());
+
+ ref = (ValueRef<K, V>) queue.poll();
+ }
+ }
+
+ /**
+ * EntrySet.
+ */
+ private class EntrySet extends AbstractSet<Entry<K, V>> {
+
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ return new EntrySetIterator(map.entrySet().iterator());
+ }
+
+ @Override
+ public int size() {
+ return WeakValueHashMap.this.size();
+ }
+ }
+
+ /**
+ * EntrySet iterator
+ */
+ private class EntrySetIterator implements Iterator<Entry<K, V>> {
+
+ /**
+ * The delegate
+ */
+ private Iterator<Entry<K, ValueRef<K, V>>> delegate;
+
+ /**
+ * Create a new EntrySetIterator.
+ *
+ * @param delegate the delegate
+ */
+ public EntrySetIterator(Iterator<Entry<K, ValueRef<K, V>>> delegate) {
+ this.delegate = delegate;
+ }
+
+ public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ public Entry<K, V> next() {
+ Entry<K, ValueRef<K, V>> next = delegate.next();
+ return next.getValue();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("remove");
+ }
+ }
+
+ /**
+ * Weak value ref.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
+ * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a>
+ * @author <a href="mailto:ales.justin@jboss.org">Ales Justin</a>
+ */
+ private static class WeakValueRef<K, V>
+ extends WeakReference<V> implements ValueRef<K, V> {
+
+ /**
+ * The key
+ */
+ public K key;
+
+ /**
+ * Safely create a new WeakValueRef
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param key the key
+ * @param val the value
+ * @param q the reference queue
+ * @return the reference or null if the value is null
+ */
+ static <K, V> WeakValueRef<K, V> create(K key, V val, ReferenceQueue<V> q) {
+ if (val == null)
+ return null;
+ else
+ return new WeakValueRef<K, V>(key, val, q);
+ }
+
+ /**
+ * Create a new WeakValueRef.
+ *
+ * @param key the key
+ * @param val the value
+ * @param q the reference queue
+ */
+ private WeakValueRef(K key, V val, ReferenceQueue<V> q) {
+ super(val, q);
+ this.key = key;
+ }
+
+ public K getKey() {
+ return key;
+ }
+
+ public V getValue() {
+ return get();
+ }
+
+ public V setValue(V value) {
+ throw new UnsupportedOperationException("setValue");
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(get());
+ }
+ }
+
+ public interface ValueRef<K, V> extends Map.Entry<K, V> {
+
+ /**
+ * Get underlying value.
+ *
+ * @return the value
+ */
+ V get();
+ }
+
+}
+
137 jcache/pom.xml
View
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source
+ ~ Copyright 2013 Red Hat Inc. and/or its affiliates and other
+ ~ contributors as indicated by the @author tags. All rights reserved.
+ ~ See the copyright.txt in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-parent</artifactId>
+ <version>5.3.0-SNAPSHOT</version>
+ <relativePath>../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>infinispan-jcache</artifactId>
+ <packaging>bundle</packaging>
+ <name>Infinispan JCACHE (JSR-107) implementation</name>
+ <description>JCACHE (JSR-107) implementation using Infinispan</description>
+
+ <!-- This module declares components that either has lifecycle (@Start or
+ @Stop) or uses @Inject to retrieve dependencies -->
+ <properties>
+ <module.skipComponentMetaDataProcessing>false
+ </module.skipComponentMetaDataProcessing>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>infinispan-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.cache</groupId>
+ <artifactId>cache-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.enterprise</groupId>
+ <artifactId>cdi-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss</groupId>
+ <artifactId>jboss-common-core</artifactId>
+ <version>2.2.20.GA</version>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>infinispan-core</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+ <repositories>
+ <repository>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <id>sonatype-snapshot-repository</id>
+ <name>Sonatype snapshot to be removed once everything becomes stable
+ </name>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </repository>
+ </repositories>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ ${project.groupId}.jcache.*;version=${project.version};-split-package:=error
+ </Export-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+
+ <!-- Use invoker plugin to run TCK tests once Infinispan JSR-107
+ implementation has been built and installed in the repo -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <configuration>
+ <addTestClassPath>true</addTestClassPath>
+ <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+ <pomIncludes>
+ <pomInclude>*/pom.xml</pomInclude>
+ </pomIncludes>
+ <postBuildHookScript>verify</postBuildHookScript>
+ <goals>
+ <goal>clean</goal>
+ <goal>package</goal>
+ </goals>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>install</goal>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+</project>
209 jcache/src/it/tck-runner/pom.xml
View
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ JBoss, Home of Professional Open Source
+ ~ Copyright 2013 Red Hat Inc. and/or its affiliates and other
+ ~ contributors as indicated by the @author tags. All rights reserved.
+ ~ See the copyright.txt in the distribution for a full listing of
+ ~ individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-parent</artifactId>
+ <version>5.3.0-SNAPSHOT</version>
+ <relativePath>../../../../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>infinispan-jcache-tck-runner</artifactId>
+ <packaging>bundle</packaging>
+ <name>Infinispan JCACHE (JSR-107) TCK Runner</name>
+ <description>JCACHE (JSR-107) TCK runner for Infinispan implementation</description>
+
+ <properties>
+ <domain-lib-dir>${project.build.directory}/domainlib</domain-lib-dir>
+ <domain-jar>domain.jar</domain-jar>
+
+ <CacheManagerImpl>org.infinispan.jcache.InfinispanCacheManager</CacheManagerImpl>
+ <CacheImpl>org.infinispan.jcache.InfinispanCache</CacheImpl>
+ <CacheInvocationContextImpl>org.infinispan.cdi.interceptor.context.CacheKeyInvocationContextImpl</CacheInvocationContextImpl>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>infinispan-jcache</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!--<dependency>-->
+ <!--<groupId>${project.groupId}</groupId>-->
+ <!--<artifactId>infinispan-cdi</artifactId>-->
+ <!--<scope>test</scope>-->
+ <!--</dependency>-->
+
+ <dependency>
+ <groupId>javax.cache</groupId>
+ <artifactId>cache-tests</artifactId>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <!--<dependency>-->
+ <!--<groupId>javax.cache</groupId>-->
+ <!--<artifactId>cdi-weld-annotations-test-harness</artifactId>-->
+ <!--<scope>test</scope>-->
+ <!--</dependency>-->
+ </dependencies>
+
+ <build>
+ <testResources>
+ <testResource>
+ <directory>src/test/resources</directory>
+ <filtering>true</filtering>
+ </testResource>
+ </testResources>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <!--Required because JUnit will not detect tests simply included in a dep-->
+ <execution>
+ <id>copy-cache-tests</id>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.testOutputDirectory}</outputDirectory>
+ <includeArtifactIds>cache-tests</includeArtifactIds>
+ <includeScope>test</includeScope>
+ <excludes>**/unwrap.properties</excludes>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-domain</id>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>javax.cache</groupId>
+ <artifactId>app-domain</artifactId>
+ <version>${version.javax.cache}</version>
+ <outputDirectory>${domain-lib-dir}</outputDirectory>
+ <destFileName>${domain-jar}</destFileName>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <forkMode>none</forkMode>
+ <systemPropertyVariables>
+ <domainJar>${domain-lib-dir}/${domain-jar}</domainJar>
+ </systemPropertyVariables>
+ <properties>
+ <property>
+ <name>listener</name>
+ <value>org.infinispan.jcache.test.tck.DummyTestListener</value>
+ </property>
+ </properties>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-junit4</artifactId>
+ <version>${version.maven.surefire}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <repositories>
+ <repository>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <id>sonatype-snapshot-repository</id>
+ <name>Sonatype snapshot to be removed once everything becomes stable</name>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </repository>
+ </repositories>
+
+ <profiles>
+
+ <!--To run all tests do not specify any profile-->
+
+ <!-- Profile for running basic tests.
+ Use mvn -P test-basic-cache clean install -->
+ <profile>
+ <id>test-basic-cache</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <include>**/interceptor/*Test.java</include>
+ </excludes>
+ <systemPropertyVariables>
+ <domainJar>${domain-lib-dir}/${domain-jar}</domainJar>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <!-- Profile for running optional tests.
+ Use mvn -P test-optional-cache clean install -->
+ <profile>
+ <id>test-optional-cache</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/interceptor/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ </profiles>
+
+</project>
35 jcache/src/it/tck-runner/src/test/java/org/infinispan/jcache/test/tck/DummyTestListener.java
View
@@ -0,0 +1,35 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011 Red Hat Inc. and/or its affiliates and other
+ * contributors as indicated by the @author tags. All rights reserved.
+ * See the copyright.txt in the distribution for a full listing of
+ * individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.infinispan.jcache.test.tck;
+
+import org.junit.runner.notification.RunListener;
+
+/**
+ * Plug dummy test listener to TCK testsuite so that Infinispan's TestNG
+ * listener is not used and avoid dependency on core test jar.
+ *
+ * @auhor Galder Zamarreño
+ */
+public class DummyTestListener extends RunListener {
+
+}
6 jcache/src/it/tck-runner/src/test/resources/ExcludeList
View
@@ -0,0 +1,6 @@
+#List tests to be excluded.
+#Lines beginning with a '#' are comments
+#Enter One method per line with syntax FULL_CLASS_NAME#METHOD_NAME as in the example below
+
+# This is a dummy test that fails if not in the exclude list.
+org.jsr107.tck.CachingTest#dummyTest
3  jcache/src/it/tck-runner/src/test/resources/unwrap.properties
View
@@ -0,0 +1,3 @@
+javax.cache.CacheManager=${CacheManagerImpl}
+javax.cache.Cache=${CacheImpl}
+javax.cache.annotation.CacheInvocationContext=${CacheInvocationContextImpl}
31 ...infinispan/jsr107/cache/ConfigurationAdapter.java → ...a/org/infinispan/jcache/ConfigurationAdapter.java
View
@@ -16,35 +16,33 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
-package org.infinispan.jsr107.cache;
+package org.infinispan.jcache;
-import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.transaction.TransactionMode;
+import javax.cache.CacheLoader;
+import javax.cache.CacheWriter;
+
/**
- * ConfigurationAdapter takes {@link javax.cache.Configuration} and creates equivalent instance of
- * {@link org.infinispan.configuration.cache.Configuration}
+ * ConfigurationAdapter takes {@link javax.cache.Configuration} and creates
+ * equivalent instance of {@link org.infinispan.configuration.cache.Configuration}
*
* @author Vladimir Blagojevic
+ * @author Galder Zamarreño
* @since 5.3
*/
public class ConfigurationAdapter<K, V> {
private javax.cache.Configuration<K, V> c;
- private ClassLoader classLoader;
- public ConfigurationAdapter(javax.cache.Configuration<K, V> configuration,
- ClassLoader classLoader) {
+ public ConfigurationAdapter(javax.cache.Configuration<K, V> configuration) {
this.c = configuration;
- this.classLoader = classLoader;
}
public org.infinispan.configuration.cache.Configuration build() {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.storeAsBinary().enabled(c.isStoreByValue());
- cb.classLoader(classLoader);
- cb.clustering().cacheMode(CacheMode.DIST_SYNC);
switch (c.getTransactionMode()) {
case NONE:
@@ -81,6 +79,19 @@ public ConfigurationAdapter(javax.cache.Configuration<K, V> configuration,
default:
break;
}
+
+ CacheLoader<K,? extends V> cacheLoader = c.getCacheLoader();
+ if (cacheLoader != null) {
+ // User-defined cache loader will be plugged once cache has started
+ cb.loaders().addStore().cacheStore(new JCacheLoaderAdapter());
+ }
+
+ CacheWriter<? super K,? super V> cacheWriter = c.getCacheWriter();
+ if (cacheWriter != null) {
+ // User-defined cache writer will be plugged once cache has started
+ cb.loaders().addStore().cacheStore(new JCacheWriterAdapter());
+ }
+
//TODO
//whatever else is needed
return cb.build();
588 jcache/src/main/java/org/infinispan/jcache/JCache.java
View
@@ -0,0 +1,588 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tag. All rights reserved.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+package org.infinispan.jcache;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+
+import javax.cache.*;
+import javax.cache.event.CacheEntryEventFilter;
+import javax.cache.event.CacheEntryListener;
+import javax.cache.event.CacheEntryListenerException;
+import javax.cache.event.CacheEntryListenerRegistration;
+
+import org.infinispan.AdvancedCache;
+import org.infinispan.context.Flag;
+import org.infinispan.util.InfinispanCollections;
+
+/**
+ * Infinispan's implementation of {@link javax.cache.Cache} interface.
+ *
+ * @author Vladimir Blagojevic
+ * @author Galder Zamarreño
+ * @since 5.3
+ */
+public class JCache<K, V> implements Cache<K, V> {
+
+ private final JCacheManager cacheManager;
+ private final Configuration<K, V> configuration;
+ private final AdvancedCache<K, V> cache;
+ private final AdvancedCache<K, V> ignoreReturnValuesCache;
+ private final AdvancedCache<K, V> skipCacheLoadCache;
+ private final CacheStatisticsMXBean stats;
+ private final CacheMXBean mxBean;
+ private final ConcurrentHashMap<CacheEntryListener<? super K, ? super V>, CacheEntryListenerRegistration<? super K, ? super V>> listeners = new ConcurrentHashMap<CacheEntryListener<? super K, ? super V>, CacheEntryListenerRegistration<? super K, ? super V>>();
+
+ private final ExpiryPolicy<? super K, ? super V> expiryPolicy;
+ private final ExecutorService executorService = Executors.newFixedThreadPool(1);
+
+ public JCache(AdvancedCache<K, V> cache,
+ JCacheManager cacheManager, Configuration<K, V> c) {
+ super();
+ this.cache = cache;
+ this.ignoreReturnValuesCache = cache.withFlags(Flag.IGNORE_RETURN_VALUES);
+ this.skipCacheLoadCache = cache.withFlags(Flag.SKIP_CACHE_LOAD);
+ this.cacheManager = cacheManager;
+ // a configuration copy as required by the spec
+ this.configuration = new SimpleConfiguration<K, V>(c);
+ this.mxBean = new RIDelegatingCacheMXBean<K, V>(this);
+ this.stats = new RICacheStatistics(this);
+ this.expiryPolicy = configuration.getExpiryPolicy();
+
+ for (CacheEntryListenerRegistration<? super K, ? super V> r : c
+ .getCacheEntryListenerRegistrations()) {
+
+ RICacheEntryListenerRegistration<K, V> lr = new RICacheEntryListenerRegistration<K, V>(
+ r.getCacheEntryListener(), r.getCacheEntryFilter(), r.isOldValueRequired(),
+ r.isSynchronous());
+
+ listeners.put(r.getCacheEntryListener(), lr);
+ }
+ }
+
+ public Map<CacheEntryListener<? super K, ? super V>, CacheEntryListenerRegistration<? super K, ? super V>> getListeners(){
+ return listeners;
+ }
+
+ @Override
+ public Status getStatus() {
+ return JStatusConverter.convert(cache.getStatus());
+ }
+
+ @Override
+ public void start() {
+ // no op
+ //TOOD need to check state before start?
+ cache.start();
+
+ //add listener as they were wiped out on stop
+ cache.addListener(new JCacheListenerAdapter<K, V>(this));
+ }
+
+ @Override
+ public void stop() {
+ cache.stop();
+ }
+
+ @Override
+ public void clear() {
+ cache.clear();
+ }
+
+ @Override
+ public boolean containsKey(K key) {
+ checkStarted();
+ return skipCacheLoadCache.containsKey(key);
+ }
+
+ @Override
+ public V get(K key) {
+ checkStarted();
+ V value = cache.get(key);
+ if (value != null)
+ updateTTLForAccessed(cache,
+ new JCacheEntry<K, V>(key, value));
+
+ return value;
+ }
+
+ @Override
+ public Map<K, V> getAll(Set<? extends K> keys) {
+ checkStarted();
+ verifyKeys(keys);
+ if (keys.isEmpty()) {
+ return InfinispanCollections.emptyMap();
+ }
+
+ /**
+ * TODO: Just an idea here to consider down the line: if keys.size() is big (TBD...), each of
+ * this get calls could maybe be swapped by getAsync() in order to paralelise the retrieval of
+ * entries. It'd be interesting to do a small performance test to see after which number of
+ * elements doing it in paralel becomes more efficient than sequential :)
+ */
+ Map<K, V> result = new HashMap<K, V>(keys.size());
+ for (K key : keys) {
+ V value = get(key);
+ if (value != null) {
+ result.put(key, value);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public V getAndPut(K key, V value) {
+ checkStarted();
+ return put(cache, key, value, false);
+ }
+
+ @Override
+ public V getAndRemove(K key) {
+ checkStarted();
+ return skipCacheLoadCache.remove(key);
+ }
+
+ @Override
+ public V getAndReplace(K key, V value) {
+ checkStarted();
+ return skipCacheLoadCache.replace(key, value);
+ }
+
+ @Override
+ public CacheManager getCacheManager() {
+ return cacheManager;
+ }
+
+ @Override
+ public Configuration<K, V> getConfiguration() {
+ return configuration;
+ }
+
+ @Override
+ public CacheMXBean getMBean() {
+ return mxBean;
+ }
+
+ @Override
+ public String getName() {
+ return cache.getName();
+ }
+
+ @Override
+ public CacheStatisticsMXBean getStatistics() {
+ checkStarted();
+ if (configuration.isStatisticsEnabled()) {
+ return stats;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public <T> T invokeEntryProcessor(K key, EntryProcessor<K, V, T> entryProcessor) {
+ checkStarted();
+
+ // TODO: We've no unlock, and this is supposed be executable without transactions
+ // TODO: We force a transaction somehow? What if no transaction config is available?
+ // TODO: Spec says exclusive lock should be on reads too...
+
+ return entryProcessor.process(
+ new MutableJCacheEntry<K, V>(cache, key, cache.get(key)));
+ }
+
+ @Override
+ public Iterator<Cache.Entry<K, V>> iterator() {
+ checkStarted();
+ return new Itr();
+ }
+
+ @Override
+ public Future<V> load(final K key) {
+ checkStarted();
+
+ final CacheLoader<K, ? extends V> cacheLoader = configuration.getCacheLoader();
+
+ // Spec required, needs to be done even if no cache loader configured
+ verifyKey(key);
+
+ // Spec required
+ if (cacheLoader == null || containsKey(key)) {
+ return null;
+ }
+
+ FutureTask<V> task = new FutureTask<V>(new Callable<V>() {
+ @Override
+ public V call() throws Exception {
+ Entry<K, ? extends V> entry = cacheLoader.load(key);
+ put(entry.getKey(), entry.getValue());
+ return entry.getValue();
+ }
+ });
+ executorService.submit(task);
+ return task;
+ }
+
+ @Override
+ public Future<Map<K, ? extends V>> loadAll(final Set<? extends K> keys) {
+ checkStarted();
+ verifyKeys(keys);
+ final CacheLoader<K, ? extends V> cacheLoader = configuration.getCacheLoader();
+
+ if (cacheLoader == null) {
+ return null;
+ }
+
+ FutureTask<Map<K, ? extends V>> task = new FutureTask<Map<K, ? extends V>>(
+ new Callable<Map<K, ? extends V>>() {
+ @Override
+ public Map<K, ? extends V> call() throws Exception {
+ ArrayList<K> keysNotInStore = new ArrayList<K>();
+ for (K key : keys) {
+ if (!containsKey(key))
+ keysNotInStore.add(key);
+ }
+ Map<K, ? extends V> value = cacheLoader.loadAll(keysNotInStore);
+ putAll(value);
+ return value;
+ }
+ });
+ executorService.submit(task);
+ return task;
+ }
+
+ @Override
+ public void put(K key, V value) {
+ checkStarted();
+ put(ignoreReturnValuesCache, key, value, false);
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> inputMap) {
+ checkStarted();
+ // spec required check
+ if (inputMap == null || inputMap.containsKey(null) || inputMap.containsValue(null)) {
+ throw new NullPointerException(
+ "inputMap is null or keys/values contain a null entry: " + inputMap);
+ }
+ /**
+ * TODO Similar to mentioned before, it'd be interesting to see if multiple putAsync() calls
+ * could be executed in parallel to speed up.
+ *
+ */
+ for (Map.Entry<? extends K, ? extends V> e : inputMap.entrySet())
+ put(ignoreReturnValuesCache, e.getKey(), e.getValue(), false);
+ }
+
+ @Override
+ public boolean putIfAbsent(K key, V value) {
+ checkStarted();
+ return put(skipCacheLoadCache, key, value, true) == null;
+ }
+
+ @Override
+ public boolean registerCacheEntryListener(
+ CacheEntryListener<? super K, ? super V> cacheEntryListener, boolean requireOldValue,
+ CacheEntryEventFilter<? super K, ? super V> cacheEntryFilter, boolean synchronous) {
+ if (cacheEntryListener == null) {
+ throw new CacheEntryListenerException("A listener may not be null");
+ }
+ RICacheEntryListenerRegistration<K, V> registration = new RICacheEntryListenerRegistration<K, V>(
+ cacheEntryListener, cacheEntryFilter, requireOldValue, synchronous);
+ return listeners.putIfAbsent(cacheEntryListener, registration) != null;
+ }
+
+ @Override
+ public boolean remove(K key) {
+ checkStarted();
+ V remove = cache.remove(key);
+ return remove != null;
+ }
+
+ @Override
+ public boolean remove(K key, V oldValue) {
+ checkStarted();
+ return cache.remove(key, oldValue);
+ }
+
+ @Override
+ public void removeAll() {
+ checkStarted();
+ // Calling cache.clear() won't work since there's currently no way to
+ // for an Infinispan cache store to figure out all keys store and pass
+ // them to CacheWriter.deleteAll(), hence, delete individually.
+ // TODO: What happens with entries only in store but not in memory?
+
+ // Delete asynchronously and then wait for removals to complete
+ List<Future<V>> futures = new ArrayList<Future<V>>();
+ for (Cache.Entry<K, V> entry : this)
+ futures.add(cache.removeAsync(entry.getKey()));
+
+ for (Future<V> future : futures) {
+ try {
+ future.get(10, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new CacheException(
+ "Interrupted while waiting for remove to complete");
+ } catch (Exception e) {
+ throw new CacheException(
+ "Removing all entries from cache failed", e);
+ }
+ }
+ }
+
+ @Override
+ public void removeAll(Set<? extends K> keys) {
+ checkStarted();
+ // TODO remove but notify listeners
+ verifyKeys(keys);
+ for (K k : keys) {
+ remove(k);
+ }
+ }
+
+ @Override
+ public boolean replace(K key, V value) {
+ checkStarted();
+ return replace(skipCacheLoadCache, key, null, value, false);
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ checkStarted();
+ return replace(skipCacheLoadCache, key, oldValue, newValue, true);
+ }
+
+ @Override
+ public boolean unregisterCacheEntryListener(CacheEntryListener<?, ?> cacheEntryListener) {
+ return cacheEntryListener != null
+ && listeners.remove(cacheEntryListener) != null;
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> clazz) {
+ if (clazz.isAssignableFrom(this.getClass())) {
+ return clazz.cast(this);
+ } else {
+ throw new IllegalArgumentException("Unwrapping to type " + clazz + " failed ");
+ }
+ }
+
+ public long size() {
+ return cache.size();
+ }
+
+ private void checkStarted() {
+ if (!getStatus().equals(Status.STARTED)) {
+ throw new IllegalStateException("Cache is in " + getStatus() + " state");
+ }
+ }
+
+ private void verifyKeys(Set<? extends K> keys) {
+ // spec required
+ if (keys == null || keys.contains(null)) {
+ throw new NullPointerException("keys is null or keys contains a null: " + keys);
+ }
+ }
+
+ private void verifyKey(K key) {
+ // spec required
+ if (key == null)
+ throw new NullPointerException("Key cannot be null");
+ }
+
+ private void verifyNewValue(V newValue) {
+ if (newValue == null)
+ throw new NullPointerException(
+ "New value cannot be null");
+ }
+
+ private void verifyOldValue(V oldValue) {
+ if (oldValue == null)
+ throw new NullPointerException(
+ "Old value cannot be null");
+ }
+
+ private V put(AdvancedCache<K, V> cache, K key, V value,
+ boolean isPutIfAbsent) {
+ boolean isCreated = !cache.containsKey(key);
+ V ret;
+ Configuration.Duration ttl;
+ Entry<K, V> entry = new JCacheEntry<K, V>(key, value);
+ if (isCreated) {
+ ttl = expiryPolicy.getTTLForCreatedEntry(entry);
+ } else {
+ // TODO: Retrieve existing lifespan setting for entry from internal container?
+ ttl = expiryPolicy.getTTLForModifiedEntry(entry, null);
+ }
+
+ if (ttl == null || ttl.isEternal()) {
+ ret = isPutIfAbsent
+ ? cache.putIfAbsent(key, value)
+ : cache.put(key, value);
+ } else if (ttl.equals(Configuration.Duration.ZERO)) {
+ // TODO: Can this be avoided?
+ // Special case for ZERO because the Infinispan remove()
+ // implementation returns true if entry was expired in the removal
+ // (since it was previously stored). JSR-107 TCK expects that if
+ // ZERO is passed, the entry is not stored and removal returns false.
+ // So, if entry is created, do not store it in the cache.
+ // If the entry is modified, explicitly remove it.
+ if (!isCreated)
+ ret = cache.remove(key);
+ else
+ ret = null;
+ } else {
+ long duration = ttl.getDurationAmount();
+ TimeUnit timeUnit = ttl.getTimeUnit();
+ ret = isPutIfAbsent
+ ? cache.putIfAbsent(key, value, duration, timeUnit)
+ : cache.put(key, value, duration, timeUnit);
+ }
+
+ return ret;
+ }
+
+ @SuppressWarnings("unchecked") // Varargs as generics should be supportable
+ private boolean replace(AdvancedCache<K, V> cache,
+ K key, V oldValue, V value, boolean isConditional) {
+ boolean exists = cache.containsKey(key);
+ if (exists) {
+ Entry<K, V> entry = new JCacheEntry<K, V>(key, value);
+ // TODO: Retrieve existing lifespan setting for entry from internal container?
+ Configuration.Duration ttl = expiryPolicy
+ .getTTLForModifiedEntry(entry, null);
+
+ if (ttl == null || ttl.isEternal()) {
+ return isConditional
+ ? cache.replace(key, oldValue, value)
+ : cache.replace(key, value) != null;
+ } else if (ttl.equals(Configuration.Duration.ZERO)) {
+ // TODO: Can this be avoided?
+ // Remove explicitly
+ return cache.remove(key) != null;
+ } else {
+ long duration = ttl.getDurationAmount();
+ TimeUnit timeUnit = ttl.getTimeUnit();
+ return isConditional
+ ? cache.replace(key, oldValue, value, duration, timeUnit)
+ : cache.replace(key, value, duration, timeUnit) != null;
+ }
+ }
+
+ if (isConditional) {
+ // Even if replace fails, values have to be validated (required by TCK)
+ verifyOldValue(oldValue);
+ }
+
+ verifyNewValue(value);
+ return false;
+ }
+
+ private void updateTTLForAccessed(AdvancedCache<K, V> cache, Entry<K, V> entry) {
+ // TODO: Retrieve existing maxIdle setting for entry from internal container?
+ Configuration.Duration ttl =
+ expiryPolicy.getTTLForAccessedEntry(entry, null);
+
+ if (ttl != null) {
+ if (ttl.equals(Configuration.Duration.ZERO)) {
+ // TODO: Expiry of 0 does not seem to remove entry when next accessed.
+ // Hence, explicitly removing the entry.
+ cache.remove(entry.getKey());
+ } else {
+ // The expiration policy could potentially return different values
+ // every time, so don't think we can rely on maxIdle.
+ long durationAmount = ttl.getDurationAmount();
+ TimeUnit timeUnit = ttl.getTimeUnit();
+ cache.put(entry.getKey(), entry.getValue(), durationAmount, timeUnit);
+ }
+ }
+ }
+
+ private class Itr implements Iterator<Cache.Entry<K, V>> {
+
+ private final Iterator<Map.Entry<K, V>> it = cache.entrySet().iterator();
+ private Entry<K, V> current;
+ private Entry<K, V> next;
+
+ Itr() {
+ fetchNext();
+ }
+
+ private void fetchNext() {
+ if (it.hasNext()) {
+ Map.Entry<K, V> entry = it.next();
+ next = new JCacheEntry<K, V>(
+ entry.getKey(), entry.getValue());
+ } else {
+ next = null;
+ }
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ if (next == null)
+ fetchNext();
+
+ if (next == null)
+ throw new NoSuchElementException();
+
+ // Set return value
+ Entry<K, V> ret = next;
+
+ // Force expiration if needed
+ updateTTLForAccessed(cache, next);
+
+ current = next;
+
+ // Fetch next...
+ fetchNext();
+
+ return ret;
+ }
+
+ @Override
+ public void remove() {
+ if (current == null)
+ throw new IllegalStateException();
+
+ K k = current.getKey();
+ current = null;
+ cache.remove(k);
+ }
+ }
+
+}
18 ...infinispan/jsr107/cache/InfinispanCacheEntry.java → .../main/java/org/infinispan/jcache/JCacheEntry.java
View
@@ -16,29 +16,29 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
-package org.infinispan.jsr107.cache;
+package org.infinispan.jcache;