001: /* Copyright 2004 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005: package org.jasig.portal.utils.cache;
006:
007: import java.util.Collection;
008: import java.util.HashMap;
009: import java.util.Iterator;
010: import java.util.Map;
011: import java.util.Set;
012:
013: import org.apache.commons.logging.Log;
014: import org.apache.commons.logging.LogFactory;
015: import org.springframework.beans.factory.DisposableBean;
016: import org.springframework.beans.factory.InitializingBean;
017:
018: import com.whirlycott.cache.Cache;
019: import com.whirlycott.cache.CacheConfiguration;
020: import com.whirlycott.cache.CacheException;
021: import com.whirlycott.cache.CacheManager;
022:
023: /**
024: * Implementation of the <code>CacheFactory</code> that will return instances of a cache
025: * backed by WhirlyCache.
026: *
027: * <p>As WhirlyCache does not use the standard map API, these caches are wrapped by a Map.
028: *
029: * @author Scott Battaglia
030: * @version $Revision: 36184 $ $Date: 2005-10-13 14:32:56 -0700 (Thu, 13 Oct 2005) $
031: *
032: */
033: public final class WhirlyCacheCacheFactory implements CacheFactory,
034: InitializingBean, DisposableBean {
035:
036: /** Message to display when the cache is found and intanciated already. */
037: private static final String LOG_MESSAGE_FOUND_IN_CACHE = " found in CacheFactory already, returning existing instance.";
038:
039: /** Message to display if the cache was not found in the map and we instanciate a new one. */
040: private static final String LOG_MESSAGE_NOT_FOUND_IN_CACHE = " not found in CacheFactory, instanciating new instance.";
041:
042: /** Message to display if we cannot find the cache at all. */
043: private static final String LOG_MESSAGE_INVALID = " is not a valid cache for this CacheFactory";
044:
045: /** Instance of Commons Logging for logging purposes */
046: private static final Log log = LogFactory
047: .getLog(WhirlyCacheCacheFactory.class);
048:
049: /** Instance of WhirlyCache manager in order to manage caches from this factory. */
050: private final CacheManager cacheManager = CacheManager
051: .getInstance();
052:
053: /** Map of caches so that we always return the same instance. */
054: private final Map caches = new HashMap();
055:
056: public synchronized Map getCache(String cacheName)
057: throws IllegalArgumentException {
058: if (this .caches.containsKey(cacheName)) {
059: log.debug(cacheName + LOG_MESSAGE_FOUND_IN_CACHE);
060: return (Map) this .caches.get(cacheName);
061: }
062:
063: try {
064: log.debug(cacheName + LOG_MESSAGE_NOT_FOUND_IN_CACHE);
065: final CacheConfiguration config = (CacheConfiguration) CacheManager
066: .getConfiguration().get(cacheName);
067: final Map map = new WhirlyCacheMap(this .cacheManager
068: .getCache(cacheName), config);
069: this .caches.put(cacheName, map);
070: return map;
071: } catch (CacheException ce) {
072: log.error(ce, ce);
073: throw new IllegalArgumentException(cacheName
074: + LOG_MESSAGE_INVALID);
075: }
076: }
077:
078: public synchronized Map getCache() throws IllegalArgumentException {
079: return (Map) this .caches.get(DEFAULT);
080: }
081:
082: public void afterPropertiesSet() throws Exception {
083: final CacheConfiguration config = (CacheConfiguration) CacheManager
084: .getConfiguration().get(DEFAULT);
085: this .caches.put(DEFAULT, new WhirlyCacheMap(this .cacheManager
086: .getCache(), config));
087: }
088:
089: public void destroy() throws Exception {
090: log.info("Shutting down cacheManager...");
091: this .cacheManager.shutdown();
092: }
093:
094: protected static final class WhirlyCacheMap implements Map {
095: private final Cache cache;
096: private final int expirationTime;
097:
098: protected WhirlyCacheMap(final Cache cache,
099: final CacheConfiguration config) {
100: this .cache = cache;
101:
102: if (config != null) {
103: final String exprTimeStr = config
104: .getAttribute("expire-time");
105:
106: int tempExprTime = -1;
107: if (exprTimeStr != null) {
108: try {
109: tempExprTime = Integer.parseInt(exprTimeStr) * 1000; //Convert seconds to miliseconds
110: } catch (NumberFormatException nfe) {
111: log
112: .warn(
113: "Invalid 'expire-time' specified in whirly cache configuration file for cache '"
114: + config.getName()
115: + "'", nfe);
116: }
117: }
118:
119: this .expirationTime = tempExprTime;
120: } else {
121: this .expirationTime = -1;
122: }
123: }
124:
125: public void clear() {
126: this .cache.clear();
127: }
128:
129: public boolean containsKey(final Object key) {
130: return this .cache.retrieve(key) != null;
131: }
132:
133: public boolean containsValue(final Object value) {
134: throw new UnsupportedOperationException(
135: "containsValue is not supported on WhirlyCache backed maps.");
136: }
137:
138: public Set entrySet() {
139: throw new UnsupportedOperationException(
140: "entrySet() is not supported on WhirlyCache backed maps.");
141: }
142:
143: public Object get(final Object key) {
144: return this .cache.retrieve(key);
145: }
146:
147: public boolean isEmpty() {
148: return this .cache.size() == 0;
149: }
150:
151: public Set keySet() {
152: throw new UnsupportedOperationException(
153: "keySet() is not supported on WhirlyCache backed maps.");
154: }
155:
156: public Object put(final Object key, final Object value) {
157: this .cache.store(key, value, this .expirationTime);
158: return value;
159: }
160:
161: public void putAll(final Map map) {
162: for (final Iterator iter = map.keySet().iterator(); iter
163: .hasNext();) {
164: final Object key = iter.next();
165: final Object value = map.get(key);
166: this .cache.store(key, value, this .expirationTime);
167: }
168: }
169:
170: public Object remove(final Object key) {
171: return this .cache.remove(key);
172: }
173:
174: public int size() {
175: return this .cache.size();
176: }
177:
178: public Collection values() {
179: throw new UnsupportedOperationException(
180: "values() is not supported on WhirlyCache backed maps.");
181: }
182: }
183: }
|