blob: fa20fd9d39c4fa57880e6531b75027087fe1fba0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.brooklyn.util.guava;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import com.google.common.base.Function;
import com.google.common.cache.AbstractLoadingCache;
import com.google.common.cache.CacheStats;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
/**
* A cache that transforms its keys before deferring to a delegate {@link LoadingCache}.
*/
// Concise names welcome.
public class KeyTransformingLoadingCache<A, B, V> extends AbstractLoadingCache<A, V> {
private final LoadingCache<B, V> delegate;
private final Function<A, B> keyTransformer;
public KeyTransformingLoadingCache(LoadingCache<B, V> delegate, Function<A, B> keyTransformer) {
this.delegate = delegate;
this.keyTransformer = keyTransformer;
}
public static <A, B, V> KeyTransformingLoadingCache<A, B, V> from(LoadingCache<B, V> delegate, Function<A, B> keyTransformer) {
return new KeyTransformingLoadingCache<A, B, V>(delegate, keyTransformer);
}
protected Function<A, B> keyTransformer() {
return keyTransformer;
}
protected LoadingCache<B, V> delegate() {
return delegate;
}
@Override
public V getIfPresent(Object key) {
try {
@SuppressWarnings("unchecked")
A cast = (A) key;
return delegate().getIfPresent(keyTransformer().apply(cast));
} catch (ClassCastException e) {
return null;
}
}
@Override
public V get(A key, Callable<? extends V> valueLoader) throws ExecutionException {
return delegate().get(keyTransformer().apply(key), valueLoader);
}
/**
* Undefined because we can't prohibit a surjective {@link #keyTransformer()}.
* @throws UnsupportedOperationException
*/
@Override
public ImmutableMap<A, V> getAllPresent(Iterable<?> keys) {
throw new UnsupportedOperationException("getAllPresent in "+getClass().getName() + " undefined");
}
@Override
public void put(A key, V value) {
delegate().put(keyTransformer().apply(key), value);
}
@Override
public void invalidate(Object key) {
try {
@SuppressWarnings("unchecked")
A cast = (A) key;
delegate().invalidate(keyTransformer().apply(cast));
} catch (ClassCastException e) {
// Ignore
}
}
@Override
public void invalidateAll() {
delegate().invalidateAll();
}
@Override
public long size() {
return delegate().size();
}
@Override
public CacheStats stats() {
return delegate().stats();
}
@Override
public V get(A key) throws ExecutionException {
return delegate().get(keyTransformer().apply(key));
}
@Override
public void refresh(A key) {
delegate().refresh(keyTransformer().apply(key));
}
/**
* Undefined because input values are not tracked.
* @throws UnsupportedOperationException
*/
@Override
public ConcurrentMap<A, V> asMap() {
throw new UnsupportedOperationException("asMap in " + getClass().getName() + " undefined");
}
@Override
public void cleanUp() {
delegate().cleanUp();
}
// Users can avoid middle type parameter.
public static class KeyTransformingSameTypeLoadingCache<A, V> extends KeyTransformingLoadingCache<A, A, V> {
public KeyTransformingSameTypeLoadingCache(LoadingCache<A, V> delegate, Function<A, A> keyTransformer) {
super(delegate, keyTransformer);
}
// IDE note: This was named `from` to be consistent with KeyTransformingLoadingCache but Intellij 13
// claims a name clash with the superclass `from`:
// java: name clash: <A,V>from(LoadingCache<A,V>, Function<A,A>) in KeyTransformingSameTypeLoadingCache
// and <A,B,V>from(LoadingCache<B,V>, Function<A,B>) in KeyTransformingLoadingCache have the same erasure,
// yet neither hides the other
public static <A, V> KeyTransformingSameTypeLoadingCache<A, V> with(LoadingCache<A, V> delegate, Function<A, A> keyTransformer) {
return new KeyTransformingSameTypeLoadingCache<A, V>(delegate, keyTransformer);
}
}
}