/*
* Copyright Terracotta, Inc.
*
* 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.ehcache.core.internal.resilience;
import java.util.HashMap;
import java.util.Map;
import org.ehcache.spi.loaderwriter.BulkCacheLoadingException;
import org.ehcache.spi.loaderwriter.BulkCacheWritingException;
import org.ehcache.core.spi.store.StoreAccessException;
import org.ehcache.spi.loaderwriter.CacheLoadingException;
import org.ehcache.spi.loaderwriter.CacheWritingException;
import static java.util.Collections.emptyMap;
/**
*
* @author Chris Dennis
*/
public abstract class RobustResilienceStrategy<K, V> implements ResilienceStrategy<K, V> {
private final RecoveryCache<K> cache;
public RobustResilienceStrategy(RecoveryCache<K> cache) {
this.cache = cache;
}
@Override
public V getFailure(K key, StoreAccessException e) {
cleanup(key, e);
return null;
}
@Override
public V getFailure(K key, V loaded, StoreAccessException e) {
cleanup(key, e);
return loaded;
}
@Override
public V getFailure(K key, StoreAccessException e, CacheLoadingException f) {
cleanup(key, e);
throw f;
}
@Override
public boolean containsKeyFailure(K key, StoreAccessException e) {
cleanup(key, e);
return false;
}
@Override
public void putFailure(K key, V value, StoreAccessException e) {
cleanup(key, e);
}
@Override
public void putFailure(K key, V value, StoreAccessException e, CacheWritingException f) {
cleanup(key, e);
throw f;
}
@Override
public void removeFailure(K key, StoreAccessException e) {
cleanup(key, e);
}
@Override
public void removeFailure(K key, StoreAccessException e, CacheWritingException f) {
cleanup(key, e);
throw f;
}
@Override
public void clearFailure(StoreAccessException e) {
cleanup(e);
}
@Override
public V putIfAbsentFailure(K key, V value, V loaderWriterFunctionResult, StoreAccessException e, boolean knownToBeAbsent) {
cleanup(key, e);
if (loaderWriterFunctionResult != null && !loaderWriterFunctionResult.equals(value)) {
return loaderWriterFunctionResult;
} else {
return null;
}
}
@Override
public V putIfAbsentFailure(K key, V value, StoreAccessException e, CacheWritingException f) {
cleanup(key, e);
throw f;
}
@Override
public V putIfAbsentFailure(K key, V value, StoreAccessException e, CacheLoadingException f) {
cleanup(key, e);
throw f;
}
@Override
public boolean removeFailure(K key, V value, StoreAccessException e, boolean knownToBePresent) {
cleanup(key, e);
return knownToBePresent;
}
@Override
public boolean removeFailure(K key, V value, StoreAccessException e, CacheWritingException f) {
cleanup(key, e);
throw f;
}
@Override
public boolean removeFailure(K key, V value, StoreAccessException e, CacheLoadingException f) {
cleanup(key, e);
throw f;
}
@Override
public V replaceFailure(K key, V value, StoreAccessException e) {
cleanup(key, e);
return null;
}
@Override
public V replaceFailure(K key, V value, StoreAccessException e, CacheWritingException f) {
cleanup(key, e);
throw f;
}
@Override
public V replaceFailure(K key, V value, StoreAccessException e, CacheLoadingException f) {
cleanup(key, e);
throw f;
}
@Override
public boolean replaceFailure(K key, V value, V newValue, StoreAccessException e, boolean knownToMatch) {
cleanup(key, e);
return knownToMatch;
}
@Override
public boolean replaceFailure(K key, V value, V newValue, StoreAccessException e, CacheWritingException f) {
cleanup(key, e);
throw f;
}
@Override
public boolean replaceFailure(K key, V value, V newValue, StoreAccessException e, CacheLoadingException f) {
cleanup(key, e);
throw f;
}
@Override
public Map<K, V> getAllFailure(Iterable<? extends K> keys, StoreAccessException e) {
cleanup(keys, e);
HashMap<K, V> result = new HashMap<K, V>();
for (K key : keys) {
result.put(key, null);
}
return result;
}
@Override
public Map<K, V> getAllFailure(Iterable<? extends K> keys, Map<K, V> loaded, StoreAccessException e) {
cleanup(keys, e);
return loaded;
}
@Override
public Map<K, V> getAllFailure(Iterable<? extends K> keys, StoreAccessException e, BulkCacheLoadingException f) {
cleanup(keys, e);
throw f;
}
@Override
public void putAllFailure(Map<? extends K, ? extends V> entries, StoreAccessException e) {
cleanup(entries.keySet(), e);
}
@Override
public void putAllFailure(Map<? extends K, ? extends V> entries, StoreAccessException e, BulkCacheWritingException f) {
cleanup(entries.keySet(), e);
throw f;
}
@Override
public Map<K, V> removeAllFailure(Iterable<? extends K> entries, StoreAccessException e) {
cleanup(entries, e);
return emptyMap();
}
@Override
public Map<K, V> removeAllFailure(Iterable<? extends K> entries, StoreAccessException e, BulkCacheWritingException f) {
cleanup(entries, e);
throw f;
}
private void cleanup(StoreAccessException from) {
filterException(from);
try {
cache.obliterate();
} catch (StoreAccessException e) {
inconsistent(from, e);
return;
}
recovered(from);
}
private void cleanup(Iterable<? extends K> keys, StoreAccessException from) {
filterException(from);
try {
cache.obliterate(keys);
} catch (StoreAccessException e) {
inconsistent(keys, from, e);
return;
}
recovered(keys, from);
}
private void cleanup(K key, StoreAccessException from) {
filterException(from);
try {
cache.obliterate(key);
} catch (StoreAccessException e) {
inconsistent(key, from, e);
return;
}
recovered(key, from);
}
@Deprecated
void filterException(StoreAccessException cae) throws RuntimeException {
if (cae instanceof RethrowingStoreAccessException) {
throw ((RethrowingStoreAccessException) cae).getCause();
}
}
protected abstract void recovered(K key, StoreAccessException from);
protected abstract void recovered(Iterable<? extends K> keys, StoreAccessException from);
protected abstract void recovered(StoreAccessException from);
protected abstract void inconsistent(K key, StoreAccessException because, StoreAccessException... cleanup);
protected abstract void inconsistent(Iterable<? extends K> keys, StoreAccessException because, StoreAccessException... cleanup);
protected abstract void inconsistent(StoreAccessException because, StoreAccessException... cleanup);
}