Don't use forbidden API in FailableCache

This commit is contained in:
Simon Willnauer 2015-09-14 13:53:59 +02:00
parent 57c5efacf6
commit bd025080c4
1 changed files with 28 additions and 32 deletions

View File

@ -16,12 +16,7 @@
package org.elasticsearch.common.inject.internal; package org.elasticsearch.common.inject.internal;
import com.google.common.cache.CacheBuilder; import java.util.concurrent.ConcurrentHashMap;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.elasticsearch.common.SuppressForbidden;
import java.util.concurrent.ExecutionException;
/** /**
* Lazily creates (and caches) values for keys. If creating the value fails (with errors), an * Lazily creates (and caches) values for keys. If creating the value fails (with errors), an
@ -29,39 +24,40 @@ import java.util.concurrent.ExecutionException;
* *
* @author jessewilson@google.com (Jesse Wilson) * @author jessewilson@google.com (Jesse Wilson)
*/ */
// TODO remove this suppression once we get rid of the CacheBuilder and friends
@SuppressForbidden(reason = "this uses Function in it's method declaration somewhere")
public abstract class FailableCache<K, V> { public abstract class FailableCache<K, V> {
private final LoadingCache<K, Object> delegate = CacheBuilder.newBuilder().build(new CacheLoader<K, Object>() { private final ConcurrentHashMap<K, Object> cache = new ConcurrentHashMap<>();
@Override
public Object load(K key) throws Exception {
Errors errors = new Errors();
V result = null;
try {
result = FailableCache.this.create(key, errors);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
return errors.hasErrors() ? errors : result;
}
});
protected abstract V create(K key, Errors errors) throws ErrorsException; protected abstract V create(K key, Errors errors) throws ErrorsException;
public V get(K key, Errors errors) throws ErrorsException { public V get(K key, Errors errors) throws ErrorsException {
try { Object resultOrError = cache.get(key);
Object resultOrError = delegate.get(key); if (resultOrError == null) {
if (resultOrError instanceof Errors) { synchronized (this) {
errors.merge((Errors) resultOrError); resultOrError = load(key);
throw errors.toException(); // we can't use cache.computeIfAbsent since this might be recursively call this API
} else { cache.putIfAbsent(key, resultOrError);
@SuppressWarnings("unchecked") // create returned a non-error result, so this is safe
V result = (V) resultOrError;
return result;
} }
} catch (ExecutionException e) { }
throw new RuntimeException(e); if (resultOrError instanceof Errors) {
errors.merge((Errors) resultOrError);
throw errors.toException();
} else {
@SuppressWarnings("unchecked") // create returned a non-error result, so this is safe
V result = (V) resultOrError;
return result;
} }
} }
private Object load(K key) {
Errors errors = new Errors();
V result = null;
try {
result = create(key, errors);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
return errors.hasErrors() ? errors : result;
}
} }