/*
* Copyright 2015 Ben Manes. All Rights Reserved.
*
* 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.github.benmanes.caffeine.jcache.configuration;
import static java.util.Objects.requireNonNull;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import javax.annotation.Nullable;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.CompleteConfiguration;
import javax.cache.configuration.Factory;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.expiry.ExpiryPolicy;
import javax.cache.integration.CacheLoader;
import javax.cache.integration.CacheWriter;
import com.github.benmanes.caffeine.cache.Expiry;
import com.github.benmanes.caffeine.cache.Ticker;
import com.github.benmanes.caffeine.cache.Weigher;
import com.github.benmanes.caffeine.jcache.copy.Copier;
import com.github.benmanes.caffeine.jcache.copy.JavaSerializationCopier;
/**
* A JCache configuration with Caffeine specific settings.
* <p>
* The initial settings disable <tt>store by value</tt> so that entries are not copied when crossing
* the {@link javax.cache.Cache} API boundary. If enabled and the {@link Copier} is not explicitly
* set, then the {@link JavaSerializationCopier} will be used. This differs from
* {@link MutableConfiguration} which enables <tt>store by value</tt> at construction.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
public final class CaffeineConfiguration<K, V> implements CompleteConfiguration<K, V> {
private static final Factory<Copier> JAVA_COPIER = JavaSerializationCopier::new;
private static final Factory<Ticker> SYSTEM_TICKER = Ticker::systemTicker;
private static final long serialVersionUID = 1L;
private final MutableConfiguration<K, V> delegate;
private Factory<Weigher<K, V>> weigherFactory;
private Factory<Expiry<K, V>> expiryFactory;
private Factory<Copier> copierFactory;
private Factory<Ticker> tickerFactory;
private Long refreshAfterWriteNanos;
private Long expireAfterAccessNanos;
private Long expireAfterWriteNanos;
private Long maximumWeight;
private Long maximumSize;
public CaffeineConfiguration() {
delegate = new MutableConfiguration<>();
delegate.setStoreByValue(false);
tickerFactory = SYSTEM_TICKER;
copierFactory = JAVA_COPIER;
}
public CaffeineConfiguration(CompleteConfiguration<K, V> configuration) {
delegate = new MutableConfiguration<>(configuration);
if (configuration instanceof CaffeineConfiguration<?, ?>) {
CaffeineConfiguration<K, V> config = (CaffeineConfiguration<K, V>) configuration;
refreshAfterWriteNanos = config.refreshAfterWriteNanos;
expireAfterAccessNanos = config.expireAfterAccessNanos;
expireAfterWriteNanos = config.expireAfterWriteNanos;
expiryFactory = config.expiryFactory;
copierFactory = config.copierFactory;
tickerFactory = config.tickerFactory;
weigherFactory = config.weigherFactory;
maximumWeight = config.maximumWeight;
maximumSize = config.maximumSize;
} else {
tickerFactory = SYSTEM_TICKER;
copierFactory = JAVA_COPIER;
}
}
@Override
public Class<K> getKeyType() {
return delegate.getKeyType();
}
@Override
public Class<V> getValueType() {
return delegate.getValueType();
}
/** See {@link MutableConfiguration#setTypes}. */
public void setTypes(Class<K> keyType, Class<V> valueType) {
delegate.setTypes(keyType, valueType);
}
@Override
public Iterable<CacheEntryListenerConfiguration<K, V>> getCacheEntryListenerConfigurations() {
return delegate.getCacheEntryListenerConfigurations();
}
/** See {@link MutableConfiguration#addCacheEntryListenerConfiguration}. */
public void addCacheEntryListenerConfiguration(
CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
delegate.addCacheEntryListenerConfiguration(cacheEntryListenerConfiguration);
}
/** See {@link MutableConfiguration#removeCacheEntryListenerConfiguration}. */
public void removeCacheEntryListenerConfiguration(
CacheEntryListenerConfiguration<K, V> cacheEntryListenerConfiguration) {
delegate.removeCacheEntryListenerConfiguration(cacheEntryListenerConfiguration);
}
@Override
public Factory<CacheLoader<K, V>> getCacheLoaderFactory() {
return delegate.getCacheLoaderFactory();
}
/** See {@link MutableConfiguration#setCacheLoaderFactory}. */
public void setCacheLoaderFactory(Factory<? extends CacheLoader<K, V>> factory) {
delegate.setCacheLoaderFactory(factory);
}
@Override
public Factory<CacheWriter<? super K, ? super V>> getCacheWriterFactory() {
return delegate.getCacheWriterFactory();
}
/** @return a writer created by the configured factory or null if not set. */
public @Nullable CacheWriter<K , V> getCacheWriter() {
if (hasCacheWriter()) {
@SuppressWarnings("unchecked")
CacheWriter<K , V> writer = (CacheWriter<K, V>) getCacheWriterFactory().create();
return writer;
}
return null;
}
/** @return if the cache writer factory is specified. */
public boolean hasCacheWriter() {
return getCacheWriterFactory() != null;
}
/** See {@link MutableConfiguration#setCacheWriterFactory}. */
public void setCacheWriterFactory(Factory<? extends CacheWriter<? super K, ? super V>> factory) {
delegate.setCacheWriterFactory(factory);
}
@Override
public Factory<ExpiryPolicy> getExpiryPolicyFactory() {
return delegate.getExpiryPolicyFactory();
}
/** See {@link MutableConfiguration#setExpiryPolicyFactory}. */
public void setExpiryPolicyFactory(Factory<? extends ExpiryPolicy> factory) {
delegate.setExpiryPolicyFactory(factory);
}
@Override
public boolean isReadThrough() {
return delegate.isReadThrough();
}
/** See {@link MutableConfiguration#setReadThrough}. */
public void setReadThrough(boolean isReadThrough) {
delegate.setReadThrough(isReadThrough);
}
@Override
public boolean isWriteThrough() {
return delegate.isWriteThrough();
}
/** See {@link MutableConfiguration#setWriteThrough}. */
public void setWriteThrough(boolean isWriteThrough) {
delegate.setWriteThrough(isWriteThrough);
}
@Override
public boolean isStoreByValue() {
return delegate.isStoreByValue();
}
/** See {@link MutableConfiguration#setStoreByValue}. */
public void setStoreByValue(boolean isStoreByValue) {
delegate.setStoreByValue(isStoreByValue);
}
@Override
public boolean isStatisticsEnabled() {
return delegate.isStatisticsEnabled();
}
/** See {@link MutableConfiguration#setStatisticsEnabled}. */
public void setStatisticsEnabled(boolean enabled) {
delegate.setStatisticsEnabled(enabled);
}
/** See {@link MutableConfiguration#isManagementEnabled}. */
@Override
public boolean isManagementEnabled() {
return delegate.isManagementEnabled();
}
/** See {@link MutableConfiguration#setManagementEnabled}. */
public void setManagementEnabled(boolean enabled) {
delegate.setManagementEnabled(enabled);
}
/**
* Returns the {@link Factory} for the {@link Copier} to be used for the cache.
*
* @return the {@link Factory} for the {@link Copier}
*/
public Factory<Copier> getCopierFactory() {
return copierFactory;
}
/**
* Set the {@link Factory} for the {@link Copier}.
*
* @param factory the {@link Copier} {@link Factory}
*/
public void setCopierFactory(Factory<Copier> factory) {
copierFactory = requireNonNull(factory);
}
/**
* Returns the {@link Factory} for the {@link Ticker} to be used for the cache.
*
* @return the {@link Factory} for the {@link Ticker}
*/
public Factory<Ticker> getTickerFactory() {
return tickerFactory;
}
/**
* Set the {@link Factory} for the {@link Ticker}.
*
* @param factory the {@link Ticker} {@link Factory}
*/
public void setTickerFactory(Factory<Ticker> factory) {
tickerFactory = requireNonNull(factory);
}
/**
* Returns the refresh after write in nanoseconds.
*
* @return the duration in nanoseconds
*/
public OptionalLong getRefreshAfterWrite() {
return (refreshAfterWriteNanos == null)
? OptionalLong.empty()
: OptionalLong.of(refreshAfterWriteNanos);
}
/**
* Set the refresh after write in nanoseconds.
*
* @param refreshAfterWriteNanos the duration in nanoseconds
*/
public void setRefreshAfterWrite(OptionalLong refreshAfterWriteNanos) {
this.refreshAfterWriteNanos = refreshAfterWriteNanos.isPresent()
? refreshAfterWriteNanos.getAsLong()
: null;
}
/**
* Returns the expire after write in nanoseconds.
*
* @return the duration in nanoseconds
*/
public OptionalLong getExpireAfterWrite() {
return (expireAfterWriteNanos == null)
? OptionalLong.empty()
: OptionalLong.of(expireAfterWriteNanos);
}
/**
* Set the expire after write in nanoseconds.
*
* @param expireAfterWriteNanos the duration in nanoseconds
*/
public void setExpireAfterWrite(OptionalLong expireAfterWriteNanos) {
this.expireAfterWriteNanos = expireAfterWriteNanos.isPresent()
? expireAfterWriteNanos.getAsLong()
: null;
}
/**
* Returns the expire after access in nanoseconds.
*
* @return the duration in nanoseconds
*/
public OptionalLong getExpireAfterAccess() {
return (expireAfterAccessNanos == null)
? OptionalLong.empty()
: OptionalLong.of(expireAfterAccessNanos);
}
/**
* Set the expire after write in nanoseconds.
*
* @param expireAfterAccessNanos the duration in nanoseconds
*/
public void setExpireAfterAccess(OptionalLong expireAfterAccessNanos) {
this.expireAfterAccessNanos = expireAfterAccessNanos.isPresent()
? expireAfterAccessNanos.getAsLong()
: null;
}
/**
* Returns the {@link Factory} for the {@link Expiry} to be used for the cache.
*
* @return the {@link Factory} for the {@link Expiry}
*/
public Optional<Factory<Expiry<K, V>>> getExpiryFactory() {
return Optional.ofNullable(expiryFactory);
}
/**
* Set the {@link Factory} for the {@link Expiry}.
*
* @param factory the {@link Expiry} {@link Factory}
*/
@SuppressWarnings("unchecked")
public void setExpiryFactory(Optional<Factory<? extends Expiry<K, V>>> factory) {
expiryFactory = (Factory<Expiry<K, V>>) factory.orElse(null);
}
/**
* Set the maximum weight.
*
* @param maximumSize the maximum size
*/
public void setMaximumSize(OptionalLong maximumSize) {
this.maximumSize = maximumSize.isPresent()
? maximumSize.getAsLong()
: null;
}
/**
* Returns the maximum weight to be used for the cache.
*
* @return the maximum size
*/
public OptionalLong getMaximumSize() {
return (maximumSize == null)
? OptionalLong.empty()
: OptionalLong.of(maximumSize);
}
/**
* Set the maximum weight.
*
* @param maximumWeight the maximum weighted size
*/
public void setMaximumWeight(OptionalLong maximumWeight) {
this.maximumWeight = maximumWeight.isPresent()
? maximumWeight.getAsLong()
: null;
}
/**
* Returns the maximum weight to be used for the cache.
*
* @return the maximum weight
*/
public OptionalLong getMaximumWeight() {
return (maximumWeight == null)
? OptionalLong.empty()
: OptionalLong.of(maximumWeight);
}
/**
* Returns the {@link Factory} for the {@link Weigher} to be used for the cache.
*
* @return the {@link Factory} for the {@link Weigher}
*/
public Factory<Weigher<K, V>> getWeigherFactory() {
return weigherFactory;
}
/**
* Set the {@link Factory} for the {@link Copier}.
*
* @param factory the {@link Copier} {@link Factory}
*/
public void setWeigherFactory(Factory<Weigher<K, V>> factory) {
weigherFactory = requireNonNull(factory);
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof CaffeineConfiguration<?, ?>)) {
return false;
}
CaffeineConfiguration<?, ?> config = (CaffeineConfiguration<?, ?>) o;
return Objects.equals(refreshAfterWriteNanos, config.refreshAfterWriteNanos)
&& Objects.equals(expireAfterAccessNanos, config.expireAfterAccessNanos)
&& Objects.equals(expireAfterWriteNanos, config.expireAfterWriteNanos)
&& Objects.equals(copierFactory, config.copierFactory)
&& Objects.equals(tickerFactory, config.tickerFactory)
&& Objects.equals(weigherFactory, config.weigherFactory)
&& Objects.equals(maximumWeight, config.maximumWeight)
&& Objects.equals(maximumSize, config.maximumSize)
&& delegate.equals(config.delegate);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
}