SGF-459 - Add support for the get(key:Object, valueLoader:Callable) method in Spring Framework 4.3's Cache interface.
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.support;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.gemstone.gemfire.cache.CacheLoader;
|
||||
import com.gemstone.gemfire.cache.CacheLoaderException;
|
||||
import com.gemstone.gemfire.cache.LoaderHelper;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.TimeoutException;
|
||||
|
||||
/**
|
||||
* The CallableCacheLoaderAdapter class is a {@link Callable} and GemFire {@link CacheLoader} implementation that
|
||||
* adapts the {@link Callable} interface into an instance of the {@link CacheLoader} interface. This class is useful
|
||||
* in situations where GemFire developers have several {@link CacheLoader} implementations that they wish to use
|
||||
* with Spring's Cache Abstraction.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see java.util.concurrent.Callable
|
||||
* @see com.gemstone.gemfire.cache.CacheLoader
|
||||
* @see com.gemstone.gemfire.cache.LoaderHelper
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class CallableCacheLoaderAdapter<K, V> implements Callable<V>, CacheLoader<K, V> {
|
||||
|
||||
private final K key;
|
||||
|
||||
private final CacheLoader<K, V> cacheLoader;
|
||||
|
||||
private final Object argument;
|
||||
|
||||
private final Region<K, V> region;
|
||||
|
||||
/**
|
||||
* Constructs an instance of the CallableCacheLoaderAdapter that delegates to the given {@link CacheLoader}.
|
||||
*
|
||||
* @param delegate the {@link CacheLoader} delegated to by this adapter.
|
||||
* @see #CallableCacheLoaderAdapter(CacheLoader, Object, Region, Object)
|
||||
* @see com.gemstone.gemfire.cache.CacheLoader
|
||||
*/
|
||||
public CallableCacheLoaderAdapter(CacheLoader<K, V> delegate) {
|
||||
this(delegate, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the CallableCacheLoaderAdapter that delegates to the given {@link CacheLoader}
|
||||
* and is initialized with the given key for which the value will be loaded along with the {@link Region}
|
||||
* in which the entry (key/value) belongs.
|
||||
*
|
||||
* @param delegate the {@link CacheLoader} delegated to by this adapter.
|
||||
* @param key the key for which the value will be loaded.
|
||||
* @param region the {@link Region} in which the entry (key/value) belongs.
|
||||
* @see #CallableCacheLoaderAdapter(CacheLoader, Object, Region, Object)
|
||||
* @see com.gemstone.gemfire.cache.CacheLoader
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
public CallableCacheLoaderAdapter(CacheLoader<K, V> delegate, K key, Region<K, V> region) {
|
||||
this(delegate, key, region, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the CallableCacheLoaderAdapter that delegates to the given {@link CacheLoader}
|
||||
* and is initialized with the given key for which the value will be loaded along with the {@link Region}
|
||||
* in which the entry (key/value) belongs. Additionally, an argument may be specified for use with the
|
||||
* {@link CacheLoader} delegate.
|
||||
*
|
||||
* @param delegate the {@link CacheLoader} delegated to by this adapter.
|
||||
* @param key the key for which the value will be loaded.
|
||||
* @param region the {@link Region} in which the entry (key/value) belongs.
|
||||
* @param argument the Object argument used with the {@link CacheLoader} delegate.
|
||||
* @see #CallableCacheLoaderAdapter(CacheLoader, Object, Region, Object)
|
||||
* @see com.gemstone.gemfire.cache.CacheLoader
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
public CallableCacheLoaderAdapter(CacheLoader<K, V> delegate, K key, Region<K, V> region, Object argument) {
|
||||
Assert.notNull(delegate, "CacheLoader must not be null");
|
||||
this.cacheLoader = delegate;
|
||||
this.argument = argument;
|
||||
this.key = key;
|
||||
this.region = region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument used by this {@link CacheLoader} to load the value for the specified key.
|
||||
*
|
||||
* @return an Object argument used by this {@link CacheLoader} when loading the value for the specified key.
|
||||
*/
|
||||
protected Object getArgument() {
|
||||
return argument;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link CacheLoader} delegate used to actually load the cache value for the specified key.
|
||||
*
|
||||
* @return a reference to the actual {@link CacheLoader} used when loading the cache value for the specified key.
|
||||
* @see com.gemstone.gemfire.cache.CacheLoader
|
||||
*/
|
||||
protected CacheLoader<K, V> getCacheLoader() {
|
||||
return cacheLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* The specified key for which a value will be loaded by this {@link CacheLoader}.
|
||||
*
|
||||
* @return the specified key for which the value will be loaded.
|
||||
*/
|
||||
protected K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Region to which the entry (key/value) belongs.
|
||||
*
|
||||
* @return the Region to which the entry belongs.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
protected Region<K, V> getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to load a cache value for the specified key. Delegates to {@link #load(LoaderHelper)}.
|
||||
*
|
||||
* @return the loaded cache value for the specified key.
|
||||
* @throws java.lang.IllegalStateException if the {@link Region} or key references are null.
|
||||
* @throws java.lang.Exception if the load operation fails.
|
||||
* @see #load(LoaderHelper)
|
||||
*/
|
||||
public final V call() throws Exception {
|
||||
Assert.state(getKey() != null, "The key for which the value is loaded for cannot be null");
|
||||
Assert.state(getRegion() != null, "The Region to load cannot be null");
|
||||
|
||||
return load(new LoaderHelper<K, V>() {
|
||||
public V netSearch(final boolean doNetLoad) throws CacheLoaderException, TimeoutException {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
return CallableCacheLoaderAdapter.this.getKey();
|
||||
}
|
||||
|
||||
public Region<K, V> getRegion() {
|
||||
return CallableCacheLoaderAdapter.this.getRegion();
|
||||
}
|
||||
|
||||
public Object getArgument() {
|
||||
return CallableCacheLoaderAdapter.this.getArgument();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes any resources used by this {@link CacheLoader}. Delegates to the underlying {@link CacheLoader}.
|
||||
*
|
||||
* @see #getCacheLoader()
|
||||
*/
|
||||
public void close() {
|
||||
getCacheLoader().close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a value for the specified cache (i.e. {@link Region}) and key with the help of the {@link LoaderHelper}.
|
||||
* Delegates to the underlying {@link CacheLoader}.
|
||||
*
|
||||
* @param loaderHelper a {@link LoaderHelper} object passed in from cache service providing access to the key,
|
||||
* {@link Region}, argument, and <code>netSearch</code>.
|
||||
* @return the value supplied for the specified key, or null if no value can be supplied. A local loader will
|
||||
* always be invoked if one exists. Otherwise one remote loader is invoked. Returning <code>null</code> causes
|
||||
* {@link Region#get(Object, Object)} to return <code>null</code>.
|
||||
* @throws CacheLoaderException if an error occurs during the load operation. This exception, or any other
|
||||
* Exception thrown by this method will be propagated back to the application from the
|
||||
* {@link Region#get(Object)} method.
|
||||
* @see com.gemstone.gemfire.cache.CacheLoader#load(LoaderHelper)
|
||||
* @see com.gemstone.gemfire.cache.LoaderHelper
|
||||
* @see #getCacheLoader()
|
||||
*/
|
||||
public V load(LoaderHelper<K, V> loaderHelper) throws CacheLoaderException {
|
||||
return getCacheLoader().load(loaderHelper);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package org.springframework.data.gemfire.support;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.support.SimpleValueWrapper;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
@@ -81,6 +84,33 @@ public class GemfireCache implements Cache {
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(final Object key, final Callable<T> valueLoader) {
|
||||
T value = (T) get(key, Object.class);
|
||||
|
||||
if (value == null) {
|
||||
synchronized (region) {
|
||||
value = (T) get(key, Object.class);
|
||||
|
||||
if (value == null) {
|
||||
try {
|
||||
value = valueLoader.call();
|
||||
put(key, value);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Failed to load value for key [%1$s] using valueLoader [%2$s]", key,
|
||||
ObjectUtils.nullSafeClassName(valueLoader)));
|
||||
//TODO throw ValueRetrievalException when SDG is based on Spring Framework 4.3
|
||||
//throw new ValueRetrievalException(key, valueLoader, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void put(final Object key, final Object value) {
|
||||
if (value != null) {
|
||||
|
||||
Reference in New Issue
Block a user