
org.sakaiproject.memory.impl.EhcacheCache Maven / Gradle / Ivy
/******************************************************************************
* $URL$
* $Id$
******************************************************************************
*
* Copyright (c) 2003-2014 The Apereo Foundation
*
* Licensed under the Educational Community 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://opensource.org/licenses/ecl2
*
* 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.sakaiproject.memory.impl;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.event.CacheEventListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.memory.api.CacheEventListener.CacheEntryEvent;
import org.sakaiproject.memory.api.CacheEventListener.EventType;
import org.sakaiproject.memory.api.CacheStatistics;
import org.sakaiproject.memory.api.Configuration;
import java.util.*;
/**
* Ehcache based implementation of a Cache.
* Includes support for listener, loader (Uses the Ehcache CacheEventListener), and stats
*
* @author Aaron Zeckoski (azeckoski @ unicon.net) (azeckoski @ gmail.com)
*/
public class EhcacheCache extends BasicCache implements CacheEventListener {
final Log log = LogFactory.getLog(BasicMapCache.class);
/**
* Underlying cache implementation
*/
protected Ehcache cache;
/**
* Construct the Cache
* Set the listeners and cache refreshers later
*
* @param cache the ehcache that backs this Sakai cache
*/
public EhcacheCache(Ehcache cache) {
super(cache.getName());
this.cache = cache;
// check if distributed
if (cache.getCacheConfiguration() != null && cache.getCacheConfiguration().getTerracottaConfiguration() != null) {
this.distributed = cache.getCacheConfiguration().getTerracottaConfiguration().isClustered();
}
}
@Override
public void put(K key, V payload) {
cache.put(new Element(key, payload));
}
@Override
public boolean containsKey(K key) {
if (cache.isKeyInCache(key)) {
// commented out the old way because this mechanism is the recommended way, note that this returning true is no guarantee the data will be there and that should NOT be assumed by anyone using this method -AZ
//return (cache.get(key) != null);
return true;
}
return false;
} // containsKey
@Override
public V get(K key) {
final Element element = cache.get(key);
V value;
if (element == null) {
if (loader != null) {
// trigger the cache loader on cache miss
try {
//noinspection unchecked
value = (V) loader.load(key);
} catch (Exception e1) {
value = null;
log.error("Cache loader failed trying to load (" + key + ") for cache (" + getName() + "), return value will be null:" + e1, e1);
}
} else {
// convert to the null value when not found
value = null;
}
} else {
value = (V) element.getObjectValue();
}
return value;
} // get
@Override
public void clear() {
cache.removeAll(false); // no listener triggers
cache.getStatistics().clearStatistics();
} // clear
@Override
public Configuration getConfiguration() {
return new Configuration() {
@Override
public boolean isStatisticsEnabled() {
return cache.isStatisticsEnabled();
}
@Override
public long getMaxEntries() {
return cache.getCacheConfiguration().getMaxEntriesLocalHeap();
}
@Override
public long getTimeToLiveSeconds() {
return cache.getCacheConfiguration().getTimeToLiveSeconds();
}
@Override
public long getTimeToIdleSeconds() {
return cache.getCacheConfiguration().getTimeToIdleSeconds();
}
@Override
public boolean isEternal() {
return cache.getCacheConfiguration().isEternal();
}
@Override
public Properties getAll() {
CacheConfiguration cc = cache.getCacheConfiguration();
Properties p = new Properties();
p.put("maxEntries", cc.getMaxEntriesLocalHeap());
p.put("timeToLiveSeconds", cc.getTimeToLiveSeconds());
p.put("timeToIdleSeconds", cc.getTimeToIdleSeconds());
p.put("eternal", cc.isEternal());
p.put("statisticsEnabled", cache.isStatisticsEnabled());
return p;
}
};
}
@Override
public String getName() {
return this.cache.getName();
}
@Override
public void close() {
this.cache.dispose();
}
@Override
public T unwrap(Class clazz) {
//noinspection unchecked
return (T) cache;
}
@Override
public void registerCacheEventListener(org.sakaiproject.memory.api.CacheEventListener cacheEventListener) {
super.registerCacheEventListener(cacheEventListener);
if (cacheEventListener == null) {
cache.getCacheEventNotificationService().unregisterListener(this);
} else {
cache.getCacheEventNotificationService().registerListener(this);
}
}
@Override
public CacheStatistics getCacheStatistics() {
if (this.cache == null) {
throw new IllegalStateException("Cannot get stats, no cache exists");
}
return new EhcacheCacheStatistics(this.cache);
}
@Override
public Properties getProperties(boolean includeExpensiveDetails) {
Properties p = new Properties();
p.put("name", cache.getName());
p.put("class", this.getClass().getSimpleName());
p.put("cacheClass", cache.getClass().getName());
p.put("guid", cache.getGuid());
p.put("disabled", cache.isDisabled());
p.put("statsEnabled", cache.isStatisticsEnabled());
p.put("status", cache.getStatus().toString());
p.put("maxEntries", cache.getCacheConfiguration().getMaxEntriesLocalHeap());
p.put("timeToLiveSecs", cache.getCacheConfiguration().getTimeToLiveSeconds());
p.put("timeToIdleSecs", cache.getCacheConfiguration().getTimeToIdleSeconds());
p.put("distributed", isDistributed());
p.put("eternal", cache.getCacheConfiguration().isEternal());
if (includeExpensiveDetails) {
p.put("size", cache.getSize());
p.put("avgGetTime", cache.getStatistics().getAverageGetTime());
p.put("hits", cache.getStatistics().getCacheHits());
p.put("misses", cache.getStatistics().getCacheMisses());
p.put("evictions", cache.getStatistics().getEvictionCount());
p.put("count", cache.getStatistics().getMemoryStoreObjectCount());
p.put("searchPerSec", cache.getStatistics().getSearchesPerSecond());
}
return p;
}
@Override
public boolean remove(K key) {
//final Object value = get(key);
boolean found = cache.remove(key);
return found;
} // remove
@Override
public String getDescription() {
final StringBuilder buf = new StringBuilder();
buf.append(cache.getName()).append(" Ehcache");
if (loader != null) {
buf.append(" Loader");
}
if (cacheEventListener != null) {
buf.append(" Listener");
}
if (isDistributed()) {
buf.append(" Distributed");
}
final long hits = cache.getStatistics().getCacheHits();
final long misses = cache.getStatistics().getCacheMisses();
final long total = hits + misses;
final long hitRatio = ((total > 0) ? ((100l * hits) / total) : 0);
// Even when we're not collecting statistics ehcache knows how many objects are in the cache
buf.append(": ").append(" count:").append(cache.getStatistics().getObjectCount());
if (cache.isStatisticsEnabled()) {
buf.append(" hits:").append(hits).append(" misses:").append(misses).append(" hit%:").append(hitRatio);
} else {
buf.append(" NO statistics (not enabled for cache)");
}
return buf.toString();
}
// BULK operations - KNL-1246
@Override
public Map getAll(Set extends K> keys) {
HashMap map = new HashMap<>();
if (!keys.isEmpty()) {
Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy