com.adobe.cq.social.srp.internal.AbstractCache Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.adobe.cq.social.srp.internal;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
/**
* A simple request cache.
* @param the lookup key
* @param the type of the items in the cache.
*/
public abstract class AbstractCache {
/** by default, use caching. */
public static final boolean DEFAULT_CACHE_ON = true;
/** by default leave items in the cache this long. */
public static final long DEFAULT_CACHE_TTL = 5000;
/** default initial cache size */
public static final int DEFAULT_START_CACHE_SIZE = 100;
/** by default, allow this many items in the cache. */
public static final int DEFAULT_MAX_CACHE_SIZE = 2500;
/** default concurrency level */
public static final int DEFAULT_CONCURRENCY_LEVEL = 4;
private static final Logger LOG = LoggerFactory.getLogger(AbstractCache.class);
private static final long serialVersionUID = 1L;
private boolean useCache = DEFAULT_CACHE_ON;
private Cache> cache;
/**
* @param concurrencyLevel cache concurreny level
* @param cacheStartSize starting cache size
* @param cacheMaxSize the initial size of the cache.
* @param ttl expiration time for cache entries in milliseconds
*/
public AbstractCache(final int concurrencyLevel, final int cacheStartSize, final int cacheMaxSize, final long ttl) {
this.cache =
CacheBuilder.newBuilder().concurrencyLevel(concurrencyLevel).initialCapacity(cacheStartSize)
.maximumSize(cacheMaxSize).expireAfterWrite(ttl, TimeUnit.MILLISECONDS).build();
}
public AbstractCache() {
this.cache =
CacheBuilder.newBuilder().concurrencyLevel(DEFAULT_CONCURRENCY_LEVEL)
.initialCapacity(DEFAULT_START_CACHE_SIZE).maximumSize(DEFAULT_MAX_CACHE_SIZE)
.expireAfterWrite(DEFAULT_CACHE_TTL, TimeUnit.MILLISECONDS).build();
}
public void put(final Y key, final CacheEntry doc) {
// doc can't be null because guava cache doesn't support null values. However, this is just a safeguard here
// because CacheEntry should never by null.
if (key == null || doc == null) {
return;
}
LOG.debug("Updating cache for {}: {}", key, doc.get());
cache.put(key, doc);
}
public void remove(final Object key) {
cache.invalidate(key);
}
public void removeAll(final Iterable> keys) {
cache.invalidateAll(keys);
}
/**
* merge the doc into the current cached item, if it exists. How you merge depends on the type of the cache entry,
* thus this is abstract.
* @param key the key into the cache
* @param doc the changed items
* @param returnedResult the returned result
*/
public abstract void merge(final Y key, final X doc, final X returnedResult);
public CacheEntry get(final Object key) {
if (!useCache) {
LOG.debug("Cache not used for: {}", key);
return null;
}
final CacheEntry doc = cache.getIfPresent(key);
if (LOG.isDebugEnabled()) {
if (doc != null) {
LOG.debug("Cache --HIT--: {}", key);
} else {
LOG.debug("Cache MISS or EXPIRED: {}", key);
}
}
return doc;
}
/**
* Enables or disables the cache.
* @param mode true if the cache should be enabled. False otherwise.
*/
public void setCacheMode(final boolean mode) {
this.useCache = mode;
LOG.debug("Cache is on?: {}", mode);
}
public Set keySet() {
return cache.asMap().keySet();
}
public void clear() {
cache.invalidateAll();
}
}