001: package net.sourceforge.squirrel_sql.fw.util;
002:
003: /*
004: * Copyright (C) 2001-2003 Colin Bell
005: * colbell@users.sourceforge.net
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: import java.util.ArrayList;
022: import java.util.Collection;
023: import java.util.HashMap;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027:
028: import javax.swing.event.EventListenerList;
029:
030: import net.sourceforge.squirrel_sql.fw.id.IHasIdentifier;
031: import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
032:
033: /**
034: * This class is a cache of objects. All objects stored must implement
035: * <CODE>IHasIdentifier</CODE>.<P>
036: *
037: * @author <A HREF="mailto:colbell@users.sourceforge.net">Colin Bell</A>
038: */
039: public class ObjectCache<E extends IHasIdentifier> implements
040: IObjectCache<E> {
041: /** This collection stores <CODE>CacheEntry</CODE> objects. */
042: private Map<Class<E>, CacheEntry<E>> _entries = new HashMap<Class<E>, CacheEntry<E>>();
043:
044: /**
045: * Default constructor.
046: */
047: public ObjectCache() {
048: super ();
049: }
050:
051: /**
052: * Retrieve a stored object.
053: *
054: * @param objClass The class of the object to be retrieved.
055: * @param id The <CODE>IIdentifier</CODE> that identifies
056: * the object to be retrieved.
057: *
058: * @return The <CODE>IHasIdentifier</CODE> retrieved or <CODE>null</CODE>
059: * if no object exists for <CODE>id</CODE>.
060: */
061: public synchronized IHasIdentifier get(Class<E> objClass,
062: IIdentifier id) {
063: return getCacheEntry(objClass).get(id);
064: }
065:
066: /**
067: * Store an object.
068: *
069: * @param obj Object to be stored.
070: *
071: * @exception DuplicateObjectException
072: * Thrown if an object of the same class as <CODE>obj</CODE>
073: * and with the same identifier is already in the cache.
074: */
075: @SuppressWarnings("unchecked")
076: public synchronized void add(E obj) throws DuplicateObjectException {
077: getCacheEntry((Class<E>) obj.getClass()).add(obj);
078: }
079:
080: /**
081: * Remove an object.
082: *
083: * @param objClass Class of object to be removed.
084: * @param id Identifier for object to be removed.
085: */
086: public synchronized void remove(Class<E> objClass, IIdentifier id) {
087: getCacheEntry(objClass).remove(id);
088: }
089:
090: /**
091: * Adds a listener for changes to the cache entry for the passed class.
092: *
093: * @param lis a IObjectCacheChangeListener that will be notified
094: * when objects are added or removed from this cache
095: * entry.
096: * @param objClass The class of objects whose cache we want to listen
097: * to.
098: */
099: public void addChangesListener(IObjectCacheChangeListener lis,
100: Class<E> objClass) {
101: getCacheEntry(objClass).addChangesListener(lis);
102: }
103:
104: /**
105: * Removes a listener for changes to the cache entry for the passed class.
106: *
107: * @param lis a IObjectCacheChangeListener that will be notified
108: * when objects are added or removed from this cache
109: * entry.
110: * @param objClass The class of objects whose cache we want to listen
111: * to.
112: */
113: public void removeChangesListener(IObjectCacheChangeListener lis,
114: Class<E> objClass) {
115: getCacheEntry(objClass).removeChangesListener(lis);
116: }
117:
118: /**
119: * Return an array of <CODE>Class</CODE objects that represent all the
120: * different types of objects stored.
121: *
122: * @return Class[] of all classes stored.
123: */
124: @SuppressWarnings("unchecked")
125: public synchronized Class<E>[] getAllClasses() {
126: List<Class<?>> classes = new ArrayList<Class<?>>();
127: for (Iterator<Class<E>> it = _entries.keySet().iterator(); it
128: .hasNext();) {
129: classes.add(it.next());
130: //classes.add(((CacheEntry)it.next())._objClass);
131: }
132: if (classes.size() > 0) {
133: return classes.toArray(new Class[classes.size()]);
134: }
135: return new Class[0];
136: }
137:
138: /**
139: * Return an <CODE>Iterator</CODE> of all objects stored for the
140: * passed class.
141: *
142: * @param objClass Class to return objects for.
143: *
144: * @return <CODE>Iterator</CODE> over all objects.
145: */
146: public synchronized Iterator<E> getAllForClass(Class<E> objClass) {
147: return getCacheEntry(objClass).values().iterator();
148: }
149:
150: /**
151: * Return a <CODE>CacheEntry</CODE> for the passed class. If one doesn't
152: * exist then create it and add to <CODE>_entries</CODE>.
153: *
154: * @param objClass Class to return <CODE>CacheEntry</CODE> for.
155: *
156: * @return <CODE>CacheEntry</CODE> which stores objects of type
157: * <CODE>objClass</CODE>.
158: */
159: private CacheEntry<E> getCacheEntry(Class<E> objClass) {
160: CacheEntry<E> entry = _entries.get(objClass);
161: if (entry == null) {
162: entry = new CacheEntry(objClass);
163: _entries.put(objClass, entry);
164: }
165: return entry;
166: }
167:
168: /**
169: * These objects are collections for a single class.
170: */
171: private final class CacheEntry<T extends E> {
172: /** Class of objects stored here. */
173: private Class<? extends T> _objClass;
174:
175: /** Collection of stored objects keyed by their <CODE>IIdentifier</CODE>. */
176: private Map<IIdentifier, T> _coll = new HashMap<IIdentifier, T>();
177:
178: /**
179: * Collection of listeners that are told of additions and removals
180: * from this collection.
181: */
182: private EventListenerList _listenerList = new EventListenerList();
183:
184: /**
185: * Ctor.
186: *
187: * @param objClass Class of objects to be stored in this collection.
188: */
189: CacheEntry(Class<? extends T> objClass) {
190: super ();
191: _objClass = objClass;
192: }
193:
194: /**
195: * Retrieve an object from this collection.
196: *
197: * @param id ID of object to be returned.
198: *
199: * @return The object stored for <CODE>id</CODE> or <CODE>null</CODE>
200: * if none exists.
201: */
202: IHasIdentifier get(IIdentifier id) {
203: return _coll.get(id);
204: }
205:
206: /**
207: * Store an object.
208: *
209: * @param obj Object to be stored.
210: *
211: * @exception DuplicateObjectException
212: * Thrown if an object of the same class as <CODE>obj</CODE>
213: * and with the same identifier is already in the cache.
214: *
215: * @exception IllegalArgumentException
216: * Thrown if <CODE>obj</CODE> is not of type <CODE>_objClass</CODE>.
217: */
218: void add(T obj) throws DuplicateObjectException,
219: IllegalArgumentException {
220: if (get(obj.getIdentifier()) != null) {
221: throw new DuplicateObjectException(obj);
222: }
223: if (!_objClass.isInstance(obj)) {
224: throw new IllegalArgumentException(
225: "IHasIdentifier is not an instance of "
226: + _objClass.getName()); //i18n
227: }
228: _coll.put(obj.getIdentifier(), obj);
229: fireObjectAdded(obj);
230: }
231:
232: /**
233: * Remove an object.
234: *
235: * @param id Identifier of object to be removed.
236: */
237: void remove(IIdentifier id) {
238: IHasIdentifier obj = get(id);
239: if (obj != null) {
240: _coll.remove(id);
241: fireObjectRemoved(obj);
242: }
243: }
244:
245: /**
246: * Return a <CODE>Collection</CODE> of all objects in this entry.
247: */
248: Collection<T> values() {
249: return _coll.values();
250: }
251:
252: /**
253: * Adds a listener for changes in this cache entry.
254: *
255: * @param lis a IObjectCacheChangeListener that will be notified when
256: * objects are added and removed from this cache entry.
257: */
258: void addChangesListener(IObjectCacheChangeListener lis) {
259: _listenerList.add(IObjectCacheChangeListener.class, lis);
260: }
261:
262: /**
263: * Removes a listener for changes in this cache entry.
264: *
265: * @param lis a IObjectCacheChangeListener that will be notified when
266: * objects are added and removed from this cache entry.
267: */
268: void removeChangesListener(IObjectCacheChangeListener lis) {
269: _listenerList.remove(IObjectCacheChangeListener.class, lis);
270: }
271:
272: /**
273: * Fire an "Object Added" event to all listeners.
274: *
275: * @param obj The object added.
276: */
277: private void fireObjectAdded(IHasIdentifier obj) {
278: // Guaranteed to be non-null.
279: Object[] listeners = _listenerList.getListenerList();
280: // Process the listeners last to first, notifying
281: // those that are interested in this event.
282: ObjectCacheChangeEvent evt = null;
283: for (int i = listeners.length - 2; i >= 0; i -= 2) {
284: if (listeners[i] == IObjectCacheChangeListener.class) {
285: // Lazily create the event.
286: if (evt == null) {
287: evt = new ObjectCacheChangeEvent(
288: ObjectCache.this , obj);
289: }
290: ((IObjectCacheChangeListener) listeners[i + 1])
291: .objectAdded(evt);
292: }
293: }
294: }
295:
296: /**
297: * Fire an "Object Removed" event to all listeners.
298: *
299: * @param obj The object added.
300: */
301: private void fireObjectRemoved(IHasIdentifier obj) {
302: // Guaranteed to be non-null.
303: Object[] listeners = _listenerList.getListenerList();
304: // Process the listeners last to first, notifying
305: // those that are interested in this event.
306: ObjectCacheChangeEvent evt = null;
307: for (int i = listeners.length - 2; i >= 0; i -= 2) {
308: if (listeners[i] == IObjectCacheChangeListener.class) {
309: // Lazily create the event:
310: if (evt == null) {
311: evt = new ObjectCacheChangeEvent(
312: ObjectCache.this , obj);
313: }
314: ((IObjectCacheChangeListener) listeners[i + 1])
315: .objectRemoved(evt);
316: }
317: }
318: }
319: }
320: }
|