001: package net.sourceforge.squirrel_sql.fw.xml;
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.io.FileNotFoundException;
022: import java.io.IOException;
023: import java.io.Reader;
024: import java.util.Iterator;
025:
026: import net.sourceforge.squirrel_sql.fw.id.IHasIdentifier;
027: import net.sourceforge.squirrel_sql.fw.id.IIdentifier;
028: import net.sourceforge.squirrel_sql.fw.util.DuplicateObjectException;
029: import net.sourceforge.squirrel_sql.fw.util.IObjectCache;
030: import net.sourceforge.squirrel_sql.fw.util.IObjectCacheChangeListener;
031: import net.sourceforge.squirrel_sql.fw.util.ObjectCache;
032: import net.sourceforge.squirrel_sql.fw.util.StringManager;
033: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
034:
035: /**
036: * This class is a cache of objects that can be read from/written to an XML
037: * document. All objects stored must implement <CODE>IHasIdentifier</CODE>.<P>
038: *
039: * It is implemented using <CODE>ObjectCache</CODE>.
040: *
041: * @author <A HREF="mailto:colbell@users.sourceforge.net">Colin Bell</A>
042: */
043: public class XMLObjectCache<E extends IHasIdentifier> implements
044: IObjectCache<E> {
045: /** Internationalized strings for this class. */
046: private static final StringManager s_stringMgr = StringManagerFactory
047: .getStringManager(XMLObjectCache.class);
048:
049: /** Cache of stored objects. */
050: private ObjectCache<E> _cache = new ObjectCache<E>();
051:
052: /**
053: * Default ctor.
054: */
055: public XMLObjectCache() {
056: super ();
057: }
058:
059: /**
060: * Retrieve a stored object.
061: *
062: * @param objClass The class of the object to be retrieved.
063: * @param id The <CODE>IIdentifier</CODE> that identifies
064: * the object to be retrieved.
065: *
066: * @return The <CODE>IHasIdentifier</CODE> retrieved or <CODE>null</CODE>
067: * if no object exists for <CODE>id</CODE>.
068: */
069: public IHasIdentifier get(Class<E> objClass, IIdentifier id) {
070: return _cache.get(objClass, id);
071: }
072:
073: /**
074: * Store an object.
075: *
076: * @param obj Object to be stored.
077: *
078: * @exception DuplicateObjectException
079: * Thrown if an object of the same class as <CODE>obj</CODE>
080: * and with the same identifier is already in the cache.
081: */
082: public void add(E obj) throws DuplicateObjectException {
083: _cache.add(obj);
084: }
085:
086: /**
087: * Remove an object.
088: *
089: * @param objClass Class of object to be removed.
090: * @param id Identifier for object to be removed.
091: */
092: public void remove(Class<E> objClass, IIdentifier id) {
093: _cache.remove(objClass, id);
094: }
095:
096: /**
097: * Return an array of <CODE>Class</CODE objects that represent all the
098: * different types of objects stored.
099: *
100: * @return Class[] of all classes stored.
101: */
102: public Class<E>[] getAllClasses() {
103: return _cache.getAllClasses();
104: }
105:
106: /**
107: * Return an <CODE>Iterator</CODE> of all objects stored for the
108: * passed class.
109: *
110: * @param objClass Class to return objects for.
111: *
112: * @return <CODE>Iterator</CODE> over all objects.
113: */
114: public Iterator<E> getAllForClass(Class<E> objClass) {
115: return _cache.getAllForClass(objClass);
116: }
117:
118: /**
119: * Adds a listener for changes to the cache entry for the passed class.
120: *
121: * @param lis an IObjectCacheChangeListener that will be notified
122: * when objects are added and removed from this cache
123: * entry.
124: * @param objClass The class of objects whose cache we want to listen
125: * to.
126: */
127: public void addChangesListener(IObjectCacheChangeListener lis,
128: Class<E> objClass) {
129: _cache.addChangesListener(lis, objClass);
130: }
131:
132: /**
133: * Removes a listener for changes to the cache entry for the passed class.
134: *
135: * @param lis an IObjectCacheChangeListener that will be notified
136: * when objects are added and removed from this cache
137: * entry.
138: * @param objClass The class of objects whose cache we want to listen
139: * to.
140: */
141: public void removeChangesListener(IObjectCacheChangeListener lis,
142: Class<E> objClass) {
143: _cache.removeChangesListener(lis, objClass);
144: }
145:
146: /**
147: * Load from an XML document.
148: *
149: * @param xmlFileName Name of XML file to load from.
150: *
151: * @exception FileNotFoundException
152: * Thrown if file not found.
153: *
154: * @exception XMLException
155: * Thrown if an XML error occurs.
156: *
157: * @exception DuplicateObjectException
158: * Thrown if two objects of the same class
159: * and with the same identifier are added to the cache.
160: */
161: public void load(String xmlFileName) throws FileNotFoundException,
162: XMLException, DuplicateObjectException {
163: load(xmlFileName, null);
164: }
165:
166: /**
167: * Load from an XML document but don't ignore duplicate objects.
168: *
169: * @param xmlFileName Name of XML file to load from.
170: * @param cl Class loader to use for object creation.
171: *
172: * @exception FileNotFoundException
173: * Thrown if file not found.
174: *
175: * @exception XMLException
176: * Thrown if an XML error occurs.
177: *
178: * @exception DuplicateObjectException
179: * Thrown if two objects of the same class
180: * and with the same identifier are added to the cache.
181: */
182: public void load(String xmlFileName, ClassLoader cl)
183: throws FileNotFoundException, XMLException,
184: DuplicateObjectException {
185: XMLBeanReader rdr = new XMLBeanReader();
186: rdr.load(xmlFileName, cl);
187: for (Iterator<Object> it = rdr.iterator(); it.hasNext();) {
188: final Object obj = it.next();
189: if (!(obj instanceof IHasIdentifier)) {
190: throw new XMLException(
191: s_stringMgr
192: .getString("XMLObjectCache.error.notimplemented"));
193: }
194: add((E) obj);
195: }
196: }
197:
198: /**
199: * Load from a reader over an XML document. Use the system classloader and
200: * don't ignore duplicate objects.
201: *
202: * @param rdr Reader over the XML document.
203: *
204: * @exception XMLException
205: * Thrown if an XML error occurs.
206: *
207: * @exception DuplicateObjectException
208: * Thrown if two objects of the same class
209: * and with the same identifier are added to the cache.
210: */
211: public void load(Reader rdr) throws XMLException,
212: DuplicateObjectException {
213: load(rdr, null, false);
214: }
215:
216: /**
217: * Load from a reader over an XML document.
218: *
219: * @param rdr Reader over the XML document.
220: * @param cl Class loader to use for object creation. Pass
221: * <TT>null</TT> to use the system classloader.
222: * @param ignoreDuplicates If <tt>true</TT> don't throw a
223: * <TT>DuplicateObjectException</TT> but rather
224: * ignore the attempt to add a duplicate, in
225: * this case there will be only one object added to
226: * the cache.
227: *
228: * @exception XMLException
229: * Thrown if an XML error occurs.
230: *
231: * @exception DuplicateObjectException
232: * Thrown if two objects of the same class
233: * and with the same identifier are added to the cache.
234: */
235: public void load(Reader rdr, ClassLoader cl,
236: boolean ignoreDuplicates) throws XMLException,
237: DuplicateObjectException {
238: XMLBeanReader xmlRdr = new XMLBeanReader();
239: xmlRdr.load(rdr, cl);
240: for (Iterator<?> it = xmlRdr.iterator(); it.hasNext();) {
241: final Object obj = it.next();
242: if (!(obj instanceof IHasIdentifier)) {
243: throw new XMLException(
244: s_stringMgr
245: .getString("XMLObjectCache.error.notimplemented"));
246: }
247: try {
248: add((E) obj);
249: } catch (DuplicateObjectException ex) {
250: if (!ignoreDuplicates) {
251: throw ex;
252: }
253: }
254: }
255: }
256:
257: /**
258: * Save all objects in this cache to an XML document.
259: *
260: * @param xmlFileName Name of XML file to save to.
261: *
262: * @exception IOException
263: * Thrown if an IO error occurs.
264: *
265: * @exception XMLException
266: * Thrown if an XML error occurs.
267: */
268: public synchronized void save(String xmlFilename)
269: throws IOException, XMLException {
270: XMLBeanWriter wtr = new XMLBeanWriter();
271: Class<E>[] classes = _cache.getAllClasses();
272: for (int i = 0; i < classes.length; ++i) {
273: for (Iterator<E> it = _cache.getAllForClass(classes[i]); it
274: .hasNext();) {
275: wtr.addToRoot(it.next());
276: }
277: }
278: wtr.save(xmlFilename);
279: }
280:
281: /**
282: * Save all objects of type <CODE>objClass</CODE> to an XML document.
283: *
284: * @param xmlFileName Name of XML file to save to.
285: * @param forClass Class of objects to be saved.
286: *
287: * @exception IOException
288: * Thrown if an IO error occurs.
289: *
290: * @exception XMLException
291: * Thrown if an XML error occurs.
292: */
293: public synchronized void saveAllForClass(String xmlFilename,
294: Class<E> forClass) throws IOException, XMLException {
295: XMLBeanWriter wtr = new XMLBeanWriter();
296: for (Iterator<E> it = _cache.getAllForClass(forClass); it
297: .hasNext();) {
298: wtr.addToRoot(it.next());
299: }
300: wtr.save(xmlFilename);
301: }
302: }
|