package org.sakaiproject.calendar.impl; import net.sf.ehcache.Cache; import net.sf.ehcache.Element; import org.sakaiproject.calendar.api.ExternalSubscription; /** * Cache of calendars. This class just maps the the requests onto an EhCache which actually * holds the calendars. * * The key feature of this map is that it expires and refreshes data that's contained * within it. This way when a request for a calendar is made we don't have a long pause * while the remote ical is downloaded and parsed. We don't want todo this in the EhCache * expiration listener as that only fires on retrieval from the cache. * {@link net.sf.ehcache.event.CacheEventListener.notifyElementExpired(Ehcache, Element)} * <p> * * We still want to use the LRU features of a cache so that we cache the most popular stuff. * Do we put an item into the cache which manages the refresh? No as we need iterate over the * cache and refresh the items in it. We need to be careful that we don't keep existing items * in the cache through our refreshing of them. * * Ok, so we can use getQuiet to retrieve a cache object without updating it's stats, this * allows us to refresh items, but means we must bind to EhCache directly. * * @author nfernandes */ public class SubscriptionCache { // The EhCache private Cache cache; public void init() { // By default caches created with EhCacheFactoryBean don't have statistics enabled // and there isn't an option to set them. The sakai version of the bean does allow // them to be set but starts up the sakai component manager. cache.setStatisticsEnabled(true); } public void setCache(Cache cache) { this.cache = cache; } public ExternalSubscription get(String url) { Element element = (Element) cache.get(url); if (element != null) { ExternalSubscription sub = (ExternalSubscription) element.getObjectValue(); // We clone this so that the caller can't muller the item in the cache // as we have examples of callers changing the context return copy(sub); } return null; } public void put(ExternalSubscription sub) { String url = sub.getSubscriptionUrl(); if (url == null) { throw new IllegalArgumentException("The ExternalSubscription must have a URL set."); } Element element = new Element(url, copy(sub)); cache.put(element); } private ExternalSubscription copy(ExternalSubscription sub) { // We clone this so that the caller can't muller the item in the cache // as we have examples of callers changing the context return new BaseExternalSubscription(sub.getSubscriptionName(), sub.getSubscriptionUrl(), sub.getContext(), sub.getCalendar(), sub.isInstitutional()); } }