001: /*
002: Copyright 2004
003: Peter Royal <peter.royal@pobox.com>
004:
005: Licensed under the Apache License, Version 2.0 (the "License");
006: you may not use this file except in compliance with the License.
007: You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: */
017:
018: package com.whirlycott.cache.component.store;
019:
020: import java.io.IOException;
021: import java.util.Enumeration;
022:
023: import org.apache.avalon.framework.activity.Disposable;
024: import org.apache.avalon.framework.activity.Initializable;
025: import org.apache.avalon.framework.configuration.Configurable;
026: import org.apache.avalon.framework.configuration.Configuration;
027: import org.apache.avalon.framework.configuration.ConfigurationException;
028: import org.apache.avalon.framework.thread.ThreadSafe;
029: import org.apache.excalibur.store.Store;
030:
031: import com.whirlycott.cache.Cache;
032: import com.whirlycott.cache.CacheConfiguration;
033: import com.whirlycott.cache.CacheDecorator;
034: import com.whirlycott.cache.CacheMaintenancePolicy;
035: import com.whirlycott.cache.Constants;
036: import com.whirlycott.cache.ManagedCache;
037: import com.whirlycott.cache.Messages;
038:
039: /**
040: * Implementation of the <a href="http://excalibur.apache.org/store/">Apache Excalibur Store</a> using Whirlycache as
041: * the backend.
042: *
043: * @author <a href="mailto:peter.royal@pobox.com">peter royal</a>
044: */
045: public class WhirlycacheStore implements Store, ThreadSafe,
046: Configurable, Initializable, Disposable {
047:
048: /**
049: * This is the cache that holds the data that we are going to use.
050: */
051: private Cache cache;
052:
053: /**
054: * Represents the cache configuration for this specific store.
055: */
056: private CacheConfiguration cacheConfiguration;
057:
058: /**
059: * The class that implements the Policy interface.
060: */
061: private Class cacheMaintenancePolicyClass;
062:
063: /**
064: * The Class that implements the backend ManagedCache interface.
065: */
066: private Class managedCacheClass;
067:
068: /**
069: * Clears all items in the cache.
070: */
071: public void clear() {
072: cache.clear();
073: }
074:
075: /**
076: * Configure the cache using a Configuration object.
077: */
078: public void configure(final Configuration configuration)
079: throws ConfigurationException {
080: final Configuration backend = configuration
081: .getChild(Constants.CONFIG_BACKEND);
082: final Configuration policy = configuration
083: .getChild(Constants.CONFIG_POLICY);
084:
085: cacheConfiguration = new CacheConfiguration();
086:
087: cacheConfiguration.setName(configuration.getChild(
088: Constants.CONFIG_NAME).getValue(toString()));
089: // TODO cacheConfiguration.setBackend(backend.getValue());
090: cacheConfiguration.setMaxSize(configuration.getChild(
091: Constants.CONFIG_MAXSIZE).getValueAsInteger());
092: // TODO cacheConfiguration.setPolicy(policy.getValue());
093: // TODO cacheConfiguration.setTunerSleepTime(configuration.getChild(Constants.CONFIG_TUNER_SLEEPTIME).getValueAsInteger());
094:
095: managedCacheClass = loadManagedCacheClass(backend.getLocation());
096: cacheMaintenancePolicyClass = loadCacheMaintenancePolicyClass(policy
097: .getLocation());
098: }
099:
100: /**
101: * I can't imagine why anybody would rely on this method.
102: */
103: public boolean containsKey(final Object key) {
104: boolean retval = false;
105: if (cache.retrieve(key) != null)
106: retval = true;
107: return retval;
108: }
109:
110: private CacheMaintenancePolicy createCacheMaintenancePolicies(
111: final ManagedCache cache) throws IllegalAccessException,
112: InstantiationException {
113:
114: return (CacheMaintenancePolicy) cacheMaintenancePolicyClass
115: .newInstance();
116: }
117:
118: /**
119: * Shuts down the Whirlycache and its associated tuning thread.
120: */
121: public void dispose() {
122: cache.clear();
123: /*
124: * The field 'cache' is really a CacheDecorator. We don't expose it because
125: * it shouldn't be used directly. But we'll cast it here.
126: */
127: ((CacheDecorator) cache).dispose();
128: }
129:
130: /**
131: * This method is not supported by Whirlycache.
132: */
133: public void free() {
134: // we don't support this
135: }
136:
137: /**
138: * Gets an object out of the whirlycache
139: */
140: public Object get(final Object key) {
141: return cache.retrieve(key);
142: }
143:
144: /**
145: * Initializes a Whirlycache.
146: */
147: public void initialize() throws Exception {
148: final ManagedCache managedCache = (ManagedCache) managedCacheClass
149: .newInstance();
150: cache = new CacheDecorator(managedCache, cacheConfiguration,
151: createCacheMaintenancePolicies(managedCache));
152: }
153:
154: /**
155: * We don't support keys().
156: */
157: public Enumeration keys() {
158: throw new UnsupportedOperationException();
159: }
160:
161: /**
162: * Loads up the specified cache maintenance class
163: * @param _location
164: * @return
165: * @throws ConfigurationException
166: */
167: private Class loadCacheMaintenancePolicyClass(final String _location)
168: throws ConfigurationException {
169: final String policy = null; //TODO cacheConfiguration.getPolicy();
170:
171: try {
172: final Class clazz = Thread.currentThread()
173: .getContextClassLoader().loadClass(policy);
174:
175: if (!CacheMaintenancePolicy.class.isAssignableFrom(clazz)) {
176: final Object[] args = { policy, _location };
177: throw new ConfigurationException(
178: Messages
179: .getCompoundString(
180: "WhirlycacheStore.not_cache_maintenance_policy", args)); //$NON-NLS-1$
181: }
182:
183: return clazz;
184: } catch (final ClassNotFoundException e) {
185: final Object[] args = { policy, _location };
186: throw new ConfigurationException(
187: Messages
188: .getCompoundString(
189: "WhirlycacheStore.cannot_load_policy", args), e); //$NON-NLS-1$
190: }
191: }
192:
193: /**
194: * Loads up the specified managed cache class.
195: * @param _location
196: * @return
197: * @throws ConfigurationException
198: */
199: private Class loadManagedCacheClass(final String _location)
200: throws ConfigurationException {
201: final String backend = null; // TODO cacheConfiguration.getBackend();
202:
203: try {
204: final Class clazz = Thread.currentThread()
205: .getContextClassLoader().loadClass(backend);
206:
207: if (!ManagedCache.class.isAssignableFrom(clazz)) {
208: final Object[] args = { backend, _location };
209: throw new ConfigurationException(
210: Messages
211: .getCompoundString(
212: "WhirlycacheStore.not_managed_cache", args)); //$NON-NLS-1$
213: }
214:
215: return clazz;
216: } catch (final ClassNotFoundException e) {
217: final Object[] args = { backend, _location };
218: throw new ConfigurationException(
219: Messages
220: .getCompoundString(
221: "WhirlycacheStore.cannot_load_backend", args), e); //$NON-NLS-1$
222: }
223: }
224:
225: /**
226: * Removes the specified object from the cache.
227: */
228: public void remove(final Object key) {
229: cache.remove(key);
230: }
231:
232: /**
233: * Returns the number of items in the cache.
234: */
235: public int size() {
236: return cache.size();
237: }
238:
239: /**
240: * Stores a value in the cache that can be retrieved using 'key'.
241: */
242: public void store(final Object key, final Object value)
243: throws IOException {
244: cache.store(key, value);
245: }
246: }
|