001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.rm.factory;
020:
021: import java.util.*;
022: import java.util.logging.*;
023:
024: import org.openharmonise.commons.cache.*;
025: import org.openharmonise.commons.dsi.AbstractDataStoreInterface;
026: import org.openharmonise.rm.resources.AbstractObject;
027:
028: import EDU.oswego.cs.dl.util.concurrent.*;
029:
030: /**
031: * This singleton class provides a single point of interface for the
032: * caching of the core objects within Harmonise.
033: *
034: * @author Michael Bell
035: * @version $Revision: 1.3 $
036: *
037: */
038: public class CacheHandler {
039:
040: /**
041: * The singleton instance for this class
042: */
043: private static CacheHandler m_instance = null;
044:
045: /**
046: * The default inital size of the <code>Map</code> containing all caches
047: */
048: private static final int DEFAULT_CACHESIZE = 50;
049:
050: /**
051: * The data store interface
052: */
053: private AbstractDataStoreInterface m_dsi = null;
054:
055: /**
056: * The <code>Map</code> containing all caches handled by this cache handler
057: */
058: private Map m_caches;
059:
060: /**
061: * Read-write lock to enable locking of cache map access
062: */
063: private ReadWriteLock m_lock = new WriterPreferenceReadWriteLock();
064:
065: private static Logger m_logger = Logger
066: .getLogger(CacheHandler.class.getName());
067:
068: /**
069: * Constructs a new cache handler.
070: *
071: * @param dbinterf the data store interface for this object
072: */
073: private CacheHandler(AbstractDataStoreInterface dbinterf) {
074: m_dsi = dbinterf;
075: m_caches = new HashMap(DEFAULT_CACHESIZE);
076: }
077:
078: /**
079: * Returns the singleton instance of <code>CacheHandler</code>.
080: *
081: * @param dbinterf the data store interface for the returned instance
082: * @return the singleton instance
083: */
084: public static synchronized CacheHandler getInstance(
085: AbstractDataStoreInterface dbinterf) {
086: if (m_instance == null) {
087: m_instance = new CacheHandler(dbinterf);
088: }
089:
090: return m_instance;
091: }
092:
093: /**
094: * Returns the object for the given class name and id.
095: *
096: * @param sClassname the name of class of the object to be returned
097: * @param nId the id of object to be returned
098: * @return the object matching class and id
099: * @throws CacheException if an error occurs getting object from the cache
100: */
101: public Object getObject(String sClassname, int nId)
102: throws CacheException {
103: Object cachedObject = null;
104:
105: if (nId > 0) {
106: AbstractCache cache = getCache(sClassname);
107:
108: cachedObject = cache.getObject(String.valueOf(nId));
109: } else {
110: cachedObject = GeneralCache.createObject(m_dsi, sClassname,
111: nId);
112: }
113:
114: return cachedObject;
115: }
116:
117: /**
118: * Returns an object for the given class name and path.
119: *
120: * @param sClassname the name of class of the object to be returned
121: * @param sPath the path of object to be returned
122: * @return the object matching class and path
123: * @throws CacheException if an error occurs getting object from the cache
124: */
125: public Object getObjectFromPath(String sClassname, String sPath)
126: throws CacheException {
127: Object cachedObject = null;
128:
129: if ((sPath != null) && (sPath.length() > 0)) {
130: GeneralCache cache = (GeneralCache) getCache(sClassname);
131:
132: cachedObject = cache.getObjectFromPath(sPath);
133: } else {
134: cachedObject = GeneralCache.createObject(m_dsi, sClassname,
135: -1);
136: }
137:
138: return cachedObject;
139: }
140:
141: /**
142: * Returns an object for the given class and <code>String</code> cache key.
143: *
144: * @param sClassname the name of class of the object to be returned
145: * @param sKey the cache key
146: * @return the object matching class and path
147: * @throws CacheException if an error occurs getting object from the cache
148: */
149: public Object getObject(String sClassname, String sKey)
150: throws CacheException {
151: Object cachedObject = null;
152:
153: if ((sKey != null) && (sKey.length() > 0)) {
154:
155: AbstractCache cache = getCache(sClassname);
156:
157: cachedObject = cache.getObject(sKey);
158: } else {
159: cachedObject = GeneralCache.createObject(m_dsi, sClassname,
160: sKey);
161: }
162:
163: return cachedObject;
164: }
165:
166: /**
167: * Adds the given object to the relevant cache.
168: *
169: * @param xobj the object to be cached
170: * @throws CacheException if there is an error either getting the correct
171: * cache or adding the object to the cache
172: */
173: public void addToCache(AbstractObject xobj) throws CacheException {
174: Object cachedObject = null;
175: int nId = xobj.getId();
176:
177: if (nId > 0) {
178: AbstractCache cache = getCache(xobj.getClass());
179:
180: cache.addToCache(String.valueOf(nId), xobj);
181: }
182: }
183:
184: /**
185: * Change object in the cache. This method notifies the appropriate cache
186: * that a change has to take place to the object referenced by
187: * <code>key</code> and possibly replaced by the new Object
188: * <code>newObj</code>, depending on the code <code>sType</code>.
189: *
190: * @param key the cache key of object in cache
191: * @param sType the type of change being made, see constants available
192: * @param newObj the new object to be placed in cache to replace object
193: * referenced by <code>key</code>, if appropriate
194: * @throws CacheException if there is an error either gettting the
195: * appropriate cache or changing the object in the cache
196: */
197: public void changeObject(String key, String sType, Object newObj)
198: throws CacheException {
199: AbstractCache cache = getCache(newObj.getClass());
200:
201: cache.changeObject(key, sType, newObj);
202: }
203:
204: /**
205: * Change object in the cache. This method notifies the appropriate
206: * cache that a change has to take place to the object <code>oldObj</code>
207: * and possibly replaced by the new Object <code>newObj</code>,
208: * depending on the code <code>sType</code>.
209: *
210: * @param oldObj the object which is in cache
211: * @param sType The type of change being made, see constants available
212: * @param newObj the new object to be placed in cache to replace
213: * <code>oldObj</code>
214: * @throws CacheException if there is an error either gettting the
215: * appropriate cache or changing the object in the cache
216: */
217: public void changeObject(Object oldObj, String sType, Object newObj)
218: throws CacheException {
219: AbstractCache cache = getCache(oldObj.getClass());
220:
221: cache.changeObject(String.valueOf(((AbstractObject) oldObj)
222: .getId()), sType, newObj);
223: }
224:
225: /**
226: * Returns the cache which corresponds to the specified class name.
227: *
228: * @param sClassname the class name
229: * @return the cache which corresponds to the specified class name
230: * @throws CacheException if there is an error creating the cache
231: */
232: public GeneralCache getCache(String sClassname)
233: throws CacheException {
234: GeneralCache cache = null;
235:
236: try {
237: m_lock.readLock().acquire();
238: cache = (GeneralCache) m_caches.get(sClassname);
239: m_lock.readLock().release();
240: } catch (InterruptedException e) {
241: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
242: throw new CacheException(e);
243: }
244:
245: if (cache == null) {
246: try {
247: cache = getCache(Class.forName(sClassname));
248: } catch (ClassNotFoundException e) {
249: throw new CacheException(e);
250: }
251: }
252:
253: return cache;
254: }
255:
256: /**
257: * Returns the appropriate cache for the specified object.
258: *
259: * @param obj the object to get cache for
260: * @return the appropriate cache for this object
261: * @throws CacheException if there is an error creating the cache
262: */
263: public GeneralCache getCache(AbstractObject obj)
264: throws CacheException {
265: return getCache(obj.getClass());
266: }
267:
268: /**
269: * Returns the appropriate cache for the specified <code>Class</code>.
270: *
271: * @param clss the <code>Class</code> to get cache for
272: * @return the appropriate cache for the <code>Class</code>
273: * @throws CacheException if there is an error creating the cache
274: */
275: public GeneralCache getCache(Class clss) throws CacheException {
276: GeneralCache cache = null;
277: String sClassname = clss.getName();
278:
279: try {
280: m_lock.readLock().acquire();
281: cache = (GeneralCache) m_caches.get(sClassname);
282: m_lock.readLock().release();
283:
284: if (cache == null) {
285: m_lock.writeLock().acquire();
286: //create cache for class
287: cache = new GeneralCache(this .m_dsi, sClassname);
288:
289: try {
290: Object obj = clss.newInstance();
291:
292: if (CacheDependant.class.isAssignableFrom(clss)) {
293: cache.setDependancyAware(true);
294: }
295:
296: //if there's an exception creating the instance we can assume
297: // that the cache shouldn't be dependant aware
298: } catch (InstantiationException e) {
299: m_logger.log(Level.WARNING,
300: e.getLocalizedMessage(), e);
301: } catch (IllegalAccessException e) {
302: m_logger.log(Level.WARNING,
303: e.getLocalizedMessage(), e);
304: }
305:
306: //store cache
307: m_caches.put(sClassname, cache);
308: m_lock.writeLock().release();
309: }
310: } catch (InterruptedException e) {
311: m_logger.log(Level.WARNING, e.getLocalizedMessage(), e);
312: throw new CacheException(e);
313: }
314:
315: return cache;
316: }
317:
318: /**
319: * Removes the specified object from the appropriate cache.
320: *
321: * @param obj the object to remove
322: *
323: * @throws CacheException if there is an error accessing the cache or
324: * removing the object from it
325: */
326: public void removeObjectFromCache(AbstractObject obj)
327: throws CacheException {
328: GeneralCache cache = getCache(obj);
329:
330: cache.removeObjectFromCache(String.valueOf(obj.getId()));
331: }
332:
333: /**
334: * Returns the cache pointer which will reference the specified
335: * object.
336: *
337: * @param obj the object
338: * @return the cache pointer which will reference the specified
339: * object
340: * @throws CacheException if an error occurs accessing the appropriate cache
341: */
342: public CachePointer getCachePointer(AbstractObject obj)
343: throws CacheException {
344: CachePointer pointer = null;
345:
346: if (obj != null) {
347: GeneralCache cache = getCache(obj.getClass());
348:
349: pointer = cache.getObjectPointer(String
350: .valueOf(obj.getId()));
351: }
352:
353: return pointer;
354: }
355:
356: /**
357: * Returns a list of the name of all caches this cache handler is
358: * currently managing.
359: *
360: * @return the list of all cache names
361: */
362: public List getCacheList() {
363: try {
364: m_lock.readLock().acquire();
365: } catch (InterruptedException e) {
366: m_logger.log(Level.WARNING, "Couldn't aquire lock", e);
367: }
368: Set keys = m_caches.keySet();
369: ArrayList vec = new ArrayList();
370: Iterator iter = keys.iterator();
371:
372: while (iter.hasNext()) {
373: vec.add(iter.next());
374: }
375: m_lock.readLock().release();
376:
377: return vec;
378: }
379:
380: /**
381: * Returns a list of all the caches this cache handler is
382: * currently managing.
383: *
384: * @return the list of all caches
385: */
386: public List getCaches() {
387: try {
388: m_lock.readLock().acquire();
389: } catch (InterruptedException e) {
390: m_logger.log(Level.WARNING, "Couldn't aquire lock", e);
391: }
392: Set keys = m_caches.keySet();
393: ArrayList vec = new ArrayList();
394: Iterator iter = keys.iterator();
395:
396: while (iter.hasNext()) {
397: vec.add(this .m_caches.get(iter.next()));
398: }
399:
400: m_lock.readLock().release();
401:
402: return vec;
403: }
404:
405: /* (non-Javadoc)
406: * @see java.lang.Object#toString()
407: */
408: public String toString() {
409: StringBuffer buffer = new StringBuffer();
410: List list = getCacheList();
411: buffer.append("[");
412:
413: Iterator iter = list.iterator();
414:
415: while (iter.hasNext()) {
416:
417: buffer.append((String) iter.next());
418: if (iter.hasNext()) {
419: buffer.append(",");
420: }
421: }
422:
423: buffer.append("]");
424:
425: return (buffer.toString());
426: }
427: }
|