001: /*
002: * CoadunationLib: The coaduntion implementation library.
003: * Copyright (C) 2006 Rift IT Contracting
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018: *
019: * CacheRegistry.java
020: *
021: * The cache registery is responsible for managing the cache information for
022: * the deployments. Each deployment gets its own class loader.
023: */
024:
025: // package path
026: package com.rift.coad.lib.cache;
027:
028: // java imports
029: import java.util.HashMap;
030: import java.util.HashSet;
031: import java.util.Iterator;
032: import java.util.Map;
033: import java.util.Set;
034:
035: // logging import
036: import org.apache.log4j.Logger;
037:
038: // coadunation imports
039: import com.rift.coad.lib.configuration.ConfigurationFactory;
040: import com.rift.coad.lib.configuration.Configuration;
041: import com.rift.coad.lib.thread.BasicThread;
042: import com.rift.coad.lib.thread.ThreadStateMonitor;
043: import com.rift.coad.lib.thread.CoadunationThreadGroup;
044:
045: /**
046: * The cache registery is responsible for managing the cache information for
047: * the deployments. Each deployment gets its own class loader and own cache
048: * entry.
049: *
050: * @author Brett Chaldecott
051: */
052: public class CacheRegistry {
053:
054: /**
055: * This object is responsible for managing a list of cache entries.
056: */
057: public class CacheListManager extends BasicThread {
058:
059: // private member variables
060: private ClassLoader loader = null;
061: private Map caches = new HashMap();
062: private ThreadStateMonitor threadStateMonitor = null;
063:
064: /**
065: * The constructor of the CacheListManager
066: *
067: * @param loader The reference to the class loader.
068: */
069: public CacheListManager(ClassLoader loader) throws Exception {
070: this .loader = loader;
071: threadStateMonitor = new ThreadStateMonitor(delay);
072: }
073:
074: /**
075: * This method replaces the run method in the BasicThread.
076: *
077: * @exception Exception
078: */
079: public void process() throws Exception {
080: while (!threadStateMonitor.isTerminated()) {
081: threadStateMonitor.monitor();
082: Set keySet = new HashSet();
083: synchronized (caches) {
084: keySet.addAll(caches.keySet());
085: }
086: Iterator iter = keySet.iterator();
087: while (iter.hasNext()) {
088: Object key = iter.next();
089: Cache cache = null;
090: synchronized (caches) {
091: cache = (Cache) caches.get(key);
092: }
093: try {
094: cache.garbageCollect();
095: } catch (Exception ex) {
096: log.error(
097: "Failed to clear the garbage collect : "
098: + ex.getMessage(), ex);
099: }
100: if (threadStateMonitor.isTerminated()) {
101: break;
102: }
103: }
104: }
105:
106: // clean up the cache
107: Iterator iter = caches.keySet().iterator();
108: while (iter.hasNext()) {
109: Object key = iter.next();
110: Cache cache = (Cache) caches.get(key);
111: try {
112: cache.clear();
113: } catch (Exception ex) {
114: log.error("Failed to clear the cache : "
115: + ex.getMessage(), ex);
116: }
117: }
118: }
119:
120: /**
121: * This method terminates the processing being performed by the cache
122: * list manager object.
123: */
124: public void terminate() {
125: threadStateMonitor.terminate(false);
126: }
127:
128: /**
129: * This method retrieves a cache entry.
130: *
131: * @return The cache entry to return.
132: * @param cacheClass The cache class being requested.
133: * @exception CacheException
134: */
135: public Cache getCache(Class cacheClass) throws CacheException {
136: if (threadStateMonitor.isTerminated()) {
137: throw new CacheException(
138: "The cache has been closed cannot add anymore entries.");
139: }
140: // synchronize access to the caches
141: try {
142: synchronized (caches) {
143: if (caches.containsKey(cacheClass)) {
144: return (Cache) caches.get(cacheClass);
145: }
146: Cache cache = (Cache) cacheClass.newInstance();
147: caches.put(cacheClass, cache);
148: return cache;
149: }
150: } catch (Exception ex) {
151:
152: throw new CacheException(
153: "Failed to retrieve the cache entry");
154: }
155: }
156: }
157:
158: // the classes constants
159: private static final String DELAY = "cache_process_delay";
160: private static final long DELAY_DEFAULT = 500;
161: private static final String USER = "cache_user";
162:
163: // the class log variable
164: protected Logger log = Logger.getLogger(CacheRegistry.class
165: .getName());
166:
167: // class member variables
168: private static CacheRegistry singleton = null;
169: private CoadunationThreadGroup threadGroup = null;
170: private String threadUser = null;
171: private Map cacheManagers = new HashMap();
172: private Configuration config = null;
173: private long delay = 0;
174: private ThreadStateMonitor stateMonitor = new ThreadStateMonitor();
175:
176: /**
177: * Creates a new instance of CacheRegistry
178: *
179: * @param threadGroup The thread group used to greate a sub thread group.
180: * @exception CacheException
181: */
182: private CacheRegistry(CoadunationThreadGroup threadGroup)
183: throws CacheException {
184: try {
185: this .threadGroup = threadGroup.createThreadGroup();
186: config = ConfigurationFactory.getInstance().getConfig(
187: CacheRegistry.class);
188: delay = config.getLong(DELAY, DELAY_DEFAULT);
189: threadUser = config.getString(USER);
190: } catch (Exception ex) {
191: log.error("Failed to instanciate the cache registry : "
192: + ex.getMessage(), ex);
193: throw new CacheException(
194: "Failed to instanciate the cache registry : "
195: + ex.getMessage(), ex);
196: }
197: }
198:
199: /**
200: * This method returns an instance of the cache registry object. Do not call
201: * more than once.
202: *
203: * @return The reference to the cache registry object.
204: * @param threadGroup The thread group used for initialization purposes.
205: * @exception CacheException
206: */
207: public static synchronized CacheRegistry init(
208: CoadunationThreadGroup threadGroup) throws CacheException {
209: // this method overrides the existing cache registry
210: if (singleton == null) {
211: singleton = new CacheRegistry(threadGroup);
212: }
213: return singleton;
214: }
215:
216: /**
217: * This method returns an instance of the cache registry object.
218: *
219: * @return The reference to the cache registry object.
220: * @exception CacheException
221: */
222: public static synchronized CacheRegistry getInstance()
223: throws CacheException {
224: if (singleton == null) {
225: throw new CacheException(
226: "The cache registry has not been initialized");
227: }
228: return singleton;
229: }
230:
231: /**
232: * This method inits the cache for a given class loader. This is based on
233: * the class loader that attached to the calling thread.
234: */
235: public void initCache() throws CacheException {
236: if (stateMonitor.isTerminated()) {
237: throw new CacheException("Cache is terminated");
238: }
239: ClassLoader loader = Thread.currentThread()
240: .getContextClassLoader();
241: CacheListManager cacheListManager = null;
242: synchronized (cacheManagers) {
243: if (cacheManagers.containsKey(loader)) {
244: throw new CacheException(
245: "There is already a cache entry for "
246: + "this loader");
247: }
248: try {
249: cacheListManager = new CacheListManager(loader);
250: } catch (Exception ex) {
251: throw new CacheException(
252: "Failed to instanciate the cace list manager : "
253: + ex.getMessage(), ex);
254: }
255: cacheManagers.put(loader, cacheListManager);
256: }
257: try {
258: threadGroup.addThread(cacheListManager, threadUser);
259: cacheListManager.start();
260: cacheListManager.setContextClassLoader(loader);
261: } catch (Exception ex) {
262: // if fails to start remove cache entry
263: synchronized (cacheManagers) {
264: cacheManagers.remove(loader);
265: }
266: log.error("Failed to start the cache list manager : "
267: + ex.getMessage(), ex);
268: throw new CacheException("Failed to init the cache : "
269: + ex.getMessage(), ex);
270: }
271:
272: }
273:
274: /**
275: * This method inits the cache for a given class loader. This is based on
276: * the class loader that attached to the calling thread.
277: *
278: * @return The reference to the requested cache class.
279: * @param cacheClass The cache class to retrieve.
280: * @exception CacheException
281: */
282: public Cache getCache(Class cacheClass) throws CacheException {
283: if (stateMonitor.isTerminated()) {
284: throw new CacheException("Cache is terminated");
285: }
286: ClassLoader loader = Thread.currentThread()
287: .getContextClassLoader();
288: CacheListManager cacheListManager = null;
289: synchronized (cacheManagers) {
290: if (!cacheManagers.containsKey(loader)) {
291: throw new CacheException(
292: "The is no cache list manager for "
293: + "this loader");
294: }
295: cacheListManager = (CacheListManager) cacheManagers
296: .get(loader);
297: }
298: return cacheListManager.getCache(cacheClass);
299: }
300:
301: /**
302: * This method terminates the cache for the class loader making the request.
303: *
304: * @exception CacheException
305: */
306: public void terminateCache() throws CacheException {
307: ClassLoader loader = Thread.currentThread()
308: .getContextClassLoader();
309: CacheListManager cacheListManager = null;
310: synchronized (cacheManagers) {
311: if (!cacheManagers.containsKey(loader)) {
312: log
313: .info("The is no cache list manager for this loader. "
314: + "The deploy was not completed successfully");
315: return;
316: }
317: cacheListManager = (CacheListManager) cacheManagers
318: .get(loader);
319: cacheManagers.remove(loader);
320: }
321: cacheListManager.terminate();
322: }
323:
324: /**
325: * This method shuts down the cache registry
326: *
327: * @exception CacheException
328: */
329: public void shutdown() throws CacheException {
330: stateMonitor.terminate(false);
331: try {
332: threadGroup.terminate();
333: } catch (Exception ex) {
334: log.error(
335: "Failed to terminate the cache thread managers : "
336: + ex.getMessage(), ex);
337: }
338: synchronized (cacheManagers) {
339: cacheManagers.clear();
340: }
341: }
342: }
|