blob: 72973e1de9b5ebb813cbcd80e1318a009b45141c [file] [log] [blame]
// Copyright (C) 2009 The Android Open Source Project
//
// 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 com.google.gerrit.server.cache;
import static com.google.gerrit.server.cache.EvictionPolicy.LFU;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.SECONDS;
import com.google.gwtorm.protobuf.CodecFactory;
import com.google.gwtorm.protobuf.ProtobufCodec;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.TypeLiteral;
import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;
public final class CacheProvider<K, V> implements Provider<Cache<K, V>>,
NamedCacheBinding<K, V>, UnnamedCacheBinding<K, V> {
private final CacheModule module;
private int memoryLimit;
private int diskLimit;
private long maxAge;
private EvictionPolicy evictionPolicy;
private String cacheName;
private ProxyCache<K, V> cache;
private Provider<EntryCreator<K, V>> entryCreator;
private Class<K> keyClass;
private Class<V> valueClass;
private Provider<V> valueProvider;
@SuppressWarnings("unchecked")
CacheProvider(CacheModule module, TypeLiteral<Cache<K, V>> typeLiteral) {
this.module = module;
memoryLimit(1024);
maxAge(90, DAYS);
evictionPolicy(LFU);
Type[] tmp =
((ParameterizedType) typeLiteral.getType()).getActualTypeArguments();
keyClass = (Class<K>) tmp[0];
valueClass = (Class<V>) tmp[1];
for (Constructor c : valueClass.getDeclaredConstructors()) {
if (c.getAnnotation(Inject.class) != null) {
valueProvider = module.getValueProvider(valueClass);
}
}
try {
ProtobufCodec<K> keyCodec = CodecFactory.encoder(keyClass);
keyCodec.decode(new byte[0]);
} catch (RuntimeException err) {
throw new IllegalStateException("Cannot support " + keyClass
+ " in protobuf format", err);
}
if (valueProvider == null) {
try {
ProtobufCodec<V> valueCodec = CodecFactory.encoder(valueClass);
valueCodec.decode(new byte[0]);
} catch (RuntimeException err) {
throw new IllegalStateException("Cannot support " + valueClass
+ " in protobuf format", err);
}
}
}
@Inject
void setCachePool(final CachePool pool) {
this.cache = pool.register(this);
}
public void bind(Cache<K, V> impl) {
if (cache == null) {
throw new ProvisionException("Cache was never registered");
}
cache.bind(impl);
}
public EntryCreator<K, V> getEntryCreator() {
return entryCreator != null ? entryCreator.get() : null;
}
public Provider<V> getValueProvider() {
return valueProvider;
}
public String getName() {
if (cacheName == null) {
throw new ProvisionException("Cache has no name");
}
return cacheName;
}
public boolean disk() {
return diskLimit() > 0;
}
public int memoryLimit() {
return memoryLimit;
}
public int diskLimit() {
return diskLimit;
}
public long maxAge() {
return maxAge;
}
public Class<K> getKeyClass() {
return keyClass;
}
public Class<V> getValueClass() {
return valueClass;
}
public EvictionPolicy evictionPolicy() {
return evictionPolicy;
}
public NamedCacheBinding<K, V> name(final String name) {
if (cacheName != null) {
throw new IllegalStateException("Cache name already set");
}
cacheName = name;
return this;
}
public NamedCacheBinding<K, V> memoryLimit(final int objects) {
memoryLimit = objects;
return this;
}
public NamedCacheBinding<K, V> diskLimit(final int objects) {
diskLimit = objects;
return this;
}
public NamedCacheBinding<K, V> maxAge(final long duration, final TimeUnit unit) {
maxAge = SECONDS.convert(duration, unit);
return this;
}
@Override
public NamedCacheBinding<K, V> evictionPolicy(final EvictionPolicy policy) {
evictionPolicy = policy;
return this;
}
public NamedCacheBinding<K, V> populateWith(
Class<? extends EntryCreator<K, V>> creator) {
entryCreator = module.getEntryCreator(this, creator);
return this;
}
public Cache<K, V> get() {
if (cache == null) {
throw new ProvisionException("Cache \"" + cacheName + "\" not available");
}
return cache;
}
}