package de.invesdwin.util.collections.loadingcache.guava; import java.util.Map; import javax.annotation.concurrent.NotThreadSafe; import com.google.common.base.Optional; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; import de.invesdwin.util.assertions.Assertions; import de.invesdwin.util.collections.loadingcache.guava.internal.OptionalValueWrapperLoadingCache; import de.invesdwin.util.collections.loadingcache.guava.internal.WrapperLoadingCacheMap; import de.invesdwin.util.time.duration.Duration; @SuppressWarnings({ "unchecked", "rawtypes" }) @NotThreadSafe public class GuavaLoadingCacheMapConfig { /** * Scale concurrency with CPUs. */ private Integer concurrencyLevel = Runtime.getRuntime().availableProcessors(); private Long maximumSize; private Duration expireAfterWrite; private Duration expireAfterAccess; private Boolean softValues; private Boolean weakKeys; private Boolean weakValues; private IRemovalListener removalListener; public Integer getConcurrencyLevel() { return concurrencyLevel; } public GuavaLoadingCacheMapConfig withConcurrencyLevel(final Integer concurrencyLevel) { this.concurrencyLevel = concurrencyLevel; return this; } public Long getMaximumSize() { return maximumSize; } public GuavaLoadingCacheMapConfig withMaximumSize(final Long maximumSize) { this.maximumSize = maximumSize; return this; } public GuavaLoadingCacheMapConfig withMaximumSize(final Integer maximumSize) { if (this.maximumSize == null) { this.maximumSize = null; } else { this.maximumSize = maximumSize.longValue(); } return this; } public Duration getExpireAfterWrite() { return expireAfterWrite; } public GuavaLoadingCacheMapConfig withExpireAfterWrite(final Duration expireAfterWrite) { this.expireAfterWrite = expireAfterWrite; return this; } public Duration getExpireAfterAccess() { return expireAfterAccess; } public GuavaLoadingCacheMapConfig withExpireAfterAccess(final Duration expireAfterAccess) { this.expireAfterAccess = expireAfterAccess; return this; } public GuavaLoadingCacheMapConfig withSoftValues(final Boolean softValues) { this.softValues = softValues; return this; } public Boolean getSoftValues() { return softValues; } public GuavaLoadingCacheMapConfig withWeakKeys(final Boolean weakKeys) { this.weakKeys = weakKeys; return this; } public Boolean getWeakKeys() { return weakKeys; } public GuavaLoadingCacheMapConfig withWeakValues(final Boolean weakValues) { this.weakValues = weakValues; return this; } public Boolean getWeakValues() { return weakValues; } public IRemovalListener getRemovalListener() { return removalListener; } public GuavaLoadingCacheMapConfig withRemovalListener(final IRemovalListener removalListener) { this.removalListener = removalListener; return this; } <K, V> Map<K, V> newMap(final AGuavaLoadingCacheMap<K, V> parent) { final CacheBuilder<Object, Object> builder = newCacheBuilder(); final LoadingCache<K, V> delegate = new OptionalValueWrapperLoadingCache<K, V>( builder.<K, Optional<V>> build(new CacheLoader<K, Optional<V>>() { @Override public Optional<V> load(final K key) throws Exception { final V value = parent.loadValue(key); return Optional.fromNullable(value); } })) { @Override protected boolean isPutAllowed(final K key, final V value) { return parent.isPutAllowed(key, value); }; }; return new WrapperLoadingCacheMap<K, V>(delegate); } private <K, V> CacheBuilder<Object, Object> newCacheBuilder() { final CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder(); if (maximumSize != null) { builder.maximumSize(maximumSize); } if (concurrencyLevel != null) { builder.concurrencyLevel(concurrencyLevel); } if (expireAfterAccess != null) { builder.expireAfterAccess(expireAfterAccess.longValue(), expireAfterAccess.getTimeUnit().timeUnitValue()); } if (expireAfterWrite != null) { builder.expireAfterWrite(expireAfterWrite.longValue(), expireAfterWrite.getTimeUnit().timeUnitValue()); } configureKeysAndValues(builder); if (removalListener != null) { Assertions.assertThat(builder.removalListener(new RemovalListener<K, Optional<V>>() { private final IRemovalListener<K, V> delegate = removalListener; @Override public void onRemoval(final RemovalNotification<K, Optional<V>> notification) { delegate.onRemoval(notification.getKey(), notification.getValue().get(), notification.getCause()); } })).isNotNull(); } return builder; } private void configureKeysAndValues(final CacheBuilder<Object, Object> builder) { if (softValues != null && softValues) { builder.softValues(); } if (weakKeys != null && weakKeys) { builder.weakKeys(); } if (weakValues != null && weakValues) { builder.weakValues(); } } }