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: * XMLConfigurationException.java
020: *
021: * RMICache.java
022: *
023: * This class is responsible for temporarily caching of rmi factory objects.
024: * They will be cache until they have not been touched for a given period of
025: * time.
026: */
027:
028: // package path
029: package com.rift.coad.lib.deployment.rmi;
030:
031: // java imports
032: import java.util.Date;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.Map;
036: import java.util.Vector;
037: import javax.rmi.PortableRemoteObject;
038:
039: // logging import
040: import org.apache.log4j.Logger;
041:
042: // coad imports
043: import com.rift.coad.lib.cache.Cache;
044: import com.rift.coad.lib.cache.CacheEntry;
045: import com.rift.coad.lib.common.RandomGuid;
046: import com.rift.coad.lib.configuration.ConfigurationFactory;
047: import com.rift.coad.lib.configuration.Configuration;
048: import com.rift.coad.lib.thread.ThreadStateMonitor;
049:
050: /**
051: * This class is responsible for temporarily caching of rmi factory objects.
052: * They will be cache until they have not been touched for a given period of
053: * time.
054: *
055: * @author Brett Chaldecott
056: */
057: public class RMICache implements Cache {
058:
059: // class constants
060: private final static String CACHE_EXPIRY_TIME = "rmi_cache_expiry";
061: private final static long CACHE_EXPIRY_TIME_DEFAULT = 60 * 1000;
062:
063: // private member variables
064: protected static Logger log = Logger.getLogger(RMICache.class
065: .getName());
066:
067: // private member variables
068: private Map cacheEntries = new HashMap();
069: private long defaultCacheExpiryTime = 0;
070: private ThreadStateMonitor status = new ThreadStateMonitor();
071:
072: /**
073: * Creates a new instance of RMICache
074: *
075: * @exception RMIException
076: */
077: public RMICache() throws RMIException {
078: try {
079: Configuration config = ConfigurationFactory.getInstance()
080: .getConfig(RMICache.class);
081: defaultCacheExpiryTime = config.getLong(CACHE_EXPIRY_TIME,
082: CACHE_EXPIRY_TIME_DEFAULT);
083: } catch (Exception ex) {
084: log.error("Failed to start the RMICache object because : "
085: + ex.getMessage(), ex);
086: throw new RMIException(
087: "Failed to start the RMICache object because : "
088: + ex.getMessage(), ex);
089: }
090: }
091:
092: /**
093: * This method is called to perform garbage collection on the cache entries.
094: */
095: public void garbageCollect() {
096: Map currentEntryList = new HashMap();
097: synchronized (cacheEntries) {
098: currentEntryList.putAll(cacheEntries);
099: }
100: Date expiryDate = new Date();
101: for (Iterator iter = currentEntryList.keySet().iterator(); iter
102: .hasNext();) {
103: Object key = iter.next();
104: RMICacheEntry cacheEntry = (RMICacheEntry) currentEntryList
105: .get(key);
106: if (cacheEntry.isExpired(expiryDate)) {
107: try {
108: PortableRemoteObject.unexportObject(cacheEntry
109: .getRemoteInterface());
110: synchronized (cacheEntries) {
111: cacheEntries.remove(key);
112: }
113: cacheEntry.cacheRelease();
114: } catch (java.rmi.NoSuchObjectException ex) {
115: log.warn("The object was never exported : "
116: + ex.getMessage(), ex);
117: // remove from cache
118: synchronized (cacheEntries) {
119: cacheEntries.remove(key);
120: }
121: cacheEntry.cacheRelease();
122: } catch (Exception ex) {
123: log.error(
124: "Failed to remove a cache entry because : "
125: + ex.getMessage(), ex);
126: }
127: }
128: }
129: }
130:
131: /**
132: * This method is called to forcibly remove everything from the cache.
133: */
134: public void clear() {
135: status.terminate(false);
136: Map currentEntryList = new HashMap();
137: synchronized (cacheEntries) {
138: currentEntryList.putAll(cacheEntries);
139: cacheEntries.clear();
140: }
141: for (Iterator iter = currentEntryList.keySet().iterator(); iter
142: .hasNext();) {
143: Object key = iter.next();
144: RMICacheEntry cacheEntry = (RMICacheEntry) currentEntryList
145: .get(key);
146: try {
147: PortableRemoteObject.unexportObject(cacheEntry
148: .getRemoteInterface());
149: } catch (java.rmi.NoSuchObjectException ex) {
150: log.warn("The object was never exported : "
151: + ex.getMessage(), ex);
152: } catch (Exception ex) {
153: log.error("Failed to remove a cache entry because : "
154: + ex.getMessage(), ex);
155: }
156: cacheEntry.cacheRelease();
157: }
158: }
159:
160: /**
161: * This mehtod returns true if the cache contains the checked entry.
162: *
163: * @return TRUE if the cache contains the checked entry.
164: * @param cacheEntry The entry to perform the check for.
165: */
166: public boolean contains(Object cacheEntry) {
167: synchronized (cacheEntries) {
168: return cacheEntries.containsKey(cacheEntry);
169: }
170: }
171:
172: /**
173: * This method is responsible for adding an entry to the cache.
174: *
175: * @param entry The entry to add to the cache.
176: */
177: public void addCacheEntry(long timeout, CacheEntry entry)
178: throws RMIException {
179: synchronized (cacheEntries) {
180: checkStatus();
181: long cacheTimeout = timeout;
182: if (timeout == -1) {
183: cacheTimeout = defaultCacheExpiryTime;
184: }
185: cacheEntries.put(entry, new RMICacheEntry(cacheTimeout,
186: entry));
187: }
188: }
189:
190: /**
191: * This method will check to see if the cache has been terminated or not.
192: *
193: * @exception BeanException
194: */
195: private void checkStatus() throws RMIException {
196: if (status.isTerminated()) {
197: throw new RMIException("The RMI cache has been shut down.");
198: }
199: }
200: }
|