/* * 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); } } }