*/
private Object retrieveInternal(
Object key, final CacheableObjectProvider provider) {
Object value = null;
AsyncResult async = asyncQuery(key, Period.INDEFINITELY);
// Act on the state of the entry. It is possible that within this
// window where the entry is not synchronized that the entry could
// change, the only case were it cannot is if it was in the update
// state as all other threads will see it as pending and wait.
// Some of the things that can happen in this window are:
// 1) Entries may have been removed, either implicitly, or explicitly.
// 2) Entries may have expired on another thread.
// 3) Entries may have moved groups.
// 4) Entries may have new values.
if (async.isReady()) {
value = async.getValue();
} else {
ProviderResult result = null;
Throwable throwable = null;
boolean failed = true;
try {
// Get the entry, this will return null if the entry is marked
// as being uncacheable.
CacheEntry entry = async.getEntry();
// Get the provider to retrieve the object. It is given the
// whole entry so that it can perform revalidation of an
// existing entry if it has expired.
result = provider.retrieve(clock, key, entry);
if (result == null) {
throw new IllegalStateException("Result from provider is null");
}
// Request to the provider did not fail.
failed = false;
} catch (RuntimeException e) {
// Remember the exception so that it can be stored in the
// entry to indicate the original cause.
throwable = e;
// Rethrow the exceptions.
throw e;
} catch (Error e) {
// Remember the exception so that it can be stored in the
// entry to indicate the original cause.
throwable = e;
// Rethrow the exceptions.
throw e;
} finally {
if (failed) {
async.failed(throwable);
} else {
// the cache must be updated even if the result has a
// non-null throwable
value = async.update(result);
// if the result has a throwable, thow it wrapped inside a
// runtime exception
Throwable cause = result.getThrowable();
if (cause != null) {