/* * SimpleCache * Copyright (C) 2008 Christian Schenk * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package challengetask.group02.helpers; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * This class provides a very simple implementation of an object cache. * * @author Christian Schenk */ public class SimpleCache<T> { /** Objects are stored here */ private final Map<String, T> objects; /** Holds custom expiration dates */ private final Map<String, Long> expire; /** The default expiration date */ private final long defaultExpire; /** Is used to speed up some operations */ private final ExecutorService threads; /** * Constructs the cache with a default expiration time for the objects of * 100 seconds. */ public SimpleCache() { this(1); } /** * Construct a cache with a custom expiration date for the objects. * * @param defaultExpire * default expiration time in seconds */ public SimpleCache(final long defaultExpire) { this.objects = Collections.synchronizedMap(new HashMap<String, T>()); this.expire = Collections.synchronizedMap(new HashMap<String, Long>()); this.defaultExpire = defaultExpire; this.threads = Executors.newFixedThreadPool(256); Executors.newScheduledThreadPool(2).scheduleWithFixedDelay(this.removeExpired(), this.defaultExpire / 2, this.defaultExpire, TimeUnit.SECONDS); } /** * This Runnable removes expired objects. */ private final Runnable removeExpired() { return new Runnable() { public void run() { for (final String name : expire.keySet()) { if (System.currentTimeMillis() > expire.get(name)) { threads.execute(createRemoveRunnable(name)); } } } }; } /** * Returns a runnable that removes a specific object from the cache. * * @param name * the name of the object */ private final Runnable createRemoveRunnable(final String name) { return new Runnable() { public void run() { objects.remove(name); expire.remove(name); } }; } /** * Returns the default expiration time for the objects in the cache. * * @return default expiration time in seconds */ public long getExpire() { return this.defaultExpire; } /** * Put an object into the cache. * * @param name * the object will be referenced with this name in the cache * @param obj * the object */ public void put(final String name, final T obj) { this.put(name, obj, this.defaultExpire); } /** * Put an object into the cache with a custom expiration date. * * @param name * the object will be referenced with this name in the cache * @param obj * the object * @param expire * custom expiration time in seconds */ public void put(final String name, final T obj, final long expireTime) { this.objects.put(name, obj); this.expire.put(name, System.currentTimeMillis() + expireTime * 1000); } /** * Returns an object from the cache. * * @param name * the name of the object you'd like to get * @param type * the type of the object you'd like to get * @return the object for the given name and type */ public T get(final String name) { final Long expireTime = this.expire.get(name); if (expireTime == null) return null; if (System.currentTimeMillis() > expireTime) { this.threads.execute(this.createRemoveRunnable(name)); return null; } return this.objects.get(name); } /** * Convenience method. */ @SuppressWarnings("unchecked") public <R extends T> R get(final String name, final Class<R> type) { return (R) this.get(name); } }