001: package org.geotools.feature.iso.collection;
002:
003: import java.io.IOException;
004: import java.util.AbstractCollection;
005: import java.util.Collection;
006: import java.util.HashSet;
007: import java.util.Iterator;
008: import java.util.Set;
009:
010: import org.geotools.data.collection.ResourceCollection;
011:
012: /**
013: * Collection supporting close( Iterator ).
014: * <p>
015: * This implementation is a port of java.util.Collection with support for
016: * the use of close( Iterator ). This will allow subclasses that make use of
017: * resources during iterator() to be uses safely.
018: * </p>
019: * <p>
020: * Subclasses are reminded that they should construct their Iterator to
021: * return system resources once content has been exhuasted. While this class
022: * is safe, and we remind users, not all libraries that accept collections
023: * can be hacked.
024: * </p>
025: * <h2>How to Collectionify Resource Access</h2>
026: * <p>
027: * We need to do the same things as for use of AbstractCollection - namely:
028: * <ul>
029: * <li><b>Read-Only</b>:
030: * provide implementations for <code>size</code> and <tt>openIterator</tt> ( w/ <code>hasNext()</code> and <code>next()</code>.)
031: * and finally closeIteartor( iterator )<p>
032: * </li>
033: * <li><b>Modifiable collection</b>
034: * Do all of the above and supply <code>add( Object )</code>
035: * let that <code>Iterator</code> do <tt>remove()</tt>
036: * </li>
037: * </ul>
038: * And of course subclass, we are after all feelign <b>abstract</b> today :-)
039: * </p>
040: * <p>
041: * Why not play with <code>iterator()</code>? Because we are keeping track of them for
042: * later <code>purge()</code>...
043: * </p>
044: *
045: * @author Jody Garnett, Refractions Research, Inc.
046: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/community-schemas/fm/src/main/java/org/geotools/feature/iso/collection/AbstractResourceCollection.java $
047: */
048: public abstract class AbstractResourceCollection extends
049: AbstractCollection implements ResourceCollection {
050:
051: protected AbstractResourceCollection() {
052: }
053:
054: /**
055: * @return <tt>true</tt> if this collection contains no elements.
056: */
057: public boolean isEmpty() {
058: return size() == 0;
059: }
060:
061: /**
062: * Returns <tt>true</tt> if this collection contains the specified
063: * element.
064: * <tt></tt>.<p>
065: *
066: * This implementation iterates over the elements in the collection,
067: * checking each element in turn for equality with the specified element.
068: *
069: * @param o object to be checked for containment in this collection.
070: * @return <tt>true</tt> if this collection contains the specified element.
071: */
072: public boolean contains(Object o) {
073: Iterator e = null;
074: try {
075: e = iterator();
076: if (o == null) {
077: while (e.hasNext())
078: if (e.next() == null)
079: return true;
080: } else {
081: while (e.hasNext())
082: if (o.equals(e.next()))
083: return true;
084: }
085: return false;
086: } finally {
087: close(e);
088: }
089: }
090:
091: /**
092: * Array of all the elements.
093: *
094: * @return an array containing all of the elements in this collection.
095: */
096: public Object[] toArray() {
097: Object[] result = new Object[size()];
098: Iterator e = null;
099: try {
100: e = iterator();
101: for (int i = 0; e.hasNext(); i++)
102: result[i] = e.next();
103: return result;
104: } finally {
105: close(e);
106: }
107: }
108:
109: public Object[] toArray(Object[] a) {
110: int size = size();
111: if (a.length < size)
112: a = (Object[]) java.lang.reflect.Array.newInstance(a
113: .getClass().getComponentType(), size);
114:
115: Iterator it = iterator();
116: try {
117:
118: Object[] result = a;
119: for (int i = 0; i < size; i++)
120: result[i] = it.next();
121: if (a.length > size)
122: a[size] = null;
123: return a;
124: } finally {
125: close(it);
126: }
127: }
128:
129: // Modification Operations
130:
131: /**
132: * Implement to support modification.
133: *
134: * @param o element whose presence in this collection is to be ensured.
135: * @return <tt>true</tt> if the collection changed as a result of the call.
136: *
137: * @throws UnsupportedOperationException if the <tt>add</tt> method is not
138: * supported by this collection.
139: *
140: * @throws NullPointerException if this collection does not permit
141: * <tt>null</tt> elements, and the specified element is
142: * <tt>null</tt>.
143: *
144: * @throws ClassCastException if the class of the specified element
145: * prevents it from being added to this collection.
146: *
147: * @throws IllegalArgumentException if some aspect of this element
148: * prevents it from being added to this collection.
149: */
150: public boolean add(Object o) {
151: throw new UnsupportedOperationException();
152: }
153:
154: /**
155: * Removes a single instance of the specified element from this
156: * collection, if it is present (optional operation).
157: *
158: * @param o element to be removed from this collection, if present.
159: * @return <tt>true</tt> if the collection contained the specified
160: * element.
161: * @throws UnsupportedOperationException if the <tt>remove</tt> method is
162: * not supported by this collection.
163: */
164: public boolean remove(Object o) {
165: Iterator e = iterator();
166: try {
167: if (o == null) {
168: while (e.hasNext()) {
169: if (e.next() == null) {
170: e.remove();
171: return true;
172: }
173: }
174: } else {
175: while (e.hasNext()) {
176: if (o.equals(e.next())) {
177: e.remove();
178: return true;
179: }
180: }
181: }
182: return false;
183: } finally {
184: close(e);
185: }
186: }
187:
188: // Bulk Operations
189:
190: /**
191: * Returns <tt>true</tt> if this collection contains all of the elements
192: * in the specified collection. <p>
193: *
194: * @param c collection to be checked for containment in this collection.
195: * @return <tt>true</tt> if this collection contains all of the elements
196: * in the specified collection.
197: * @throws NullPointerException if the specified collection is null.
198: *
199: * @see #contains(Object)
200: */
201: public boolean containsAll(Collection c) {
202: Iterator e = c.iterator();
203: try {
204: while (e.hasNext())
205: if (!contains(e.next()))
206: return false;
207: return true;
208: } finally {
209: close(e);
210: }
211: }
212:
213: /**
214: * Adds all of the elements in the specified collection to this collection
215: * (optional operation).
216: *
217: * @param c collection whose elements are to be added to this collection.
218: * @return <tt>true</tt> if this collection changed as a result of the
219: * call.
220: * @throws UnsupportedOperationException if this collection does not
221: * support the <tt>addAll</tt> method.
222: * @throws NullPointerException if the specified collection is null.
223: *
224: * @see #add(Object)
225: */
226: public boolean addAll(Collection c) {
227: boolean modified = false;
228: Iterator e = c.iterator();
229: try {
230: while (e.hasNext()) {
231: if (add(e.next()))
232: modified = true;
233: }
234: } finally {
235: if (c instanceof ResourceCollection) {
236: ResourceCollection other = (ResourceCollection) c;
237: other.close(e);
238: }
239: }
240: return modified;
241: }
242:
243: /**
244: * Removes from this collection all of its elements that are contained in
245: * the specified collection (optional operation). <p>
246: *
247: * @param c elements to be removed from this collection.
248: * @return <tt>true</tt> if this collection changed as a result of the
249: * call.
250: * @throws UnsupportedOperationException if the <tt>removeAll</tt> method
251: * is not supported by this collection.
252: * @throws NullPointerException if the specified collection is null.
253: *
254: * @see #remove(Object)
255: * @see #contains(Object)
256: */
257: public boolean removeAll(Collection c) {
258: boolean modified = false;
259: Iterator e = iterator();
260: try {
261: while (e.hasNext()) {
262: if (c.contains(e.next())) {
263: e.remove();
264: modified = true;
265: }
266: }
267: return modified;
268: } finally {
269: close(e);
270: }
271: }
272:
273: /**
274: * Retains only the elements in this collection that are contained in the
275: * specified collection (optional operation).
276: *
277: * @param c elements to be retained in this collection.
278: * @return <tt>true</tt> if this collection changed as a result of the
279: * call.
280: * @throws UnsupportedOperationException if the <tt>retainAll</tt> method
281: * is not supported by this Collection.
282: * @throws NullPointerException if the specified collection is null.
283: *
284: * @see #remove(Object)
285: * @see #contains(Object)
286: */
287: public boolean retainAll(Collection c) {
288: boolean modified = false;
289: Iterator e = iterator();
290: try {
291: while (e.hasNext()) {
292: if (!c.contains(e.next())) {
293: e.remove();
294: modified = true;
295: }
296: }
297: return modified;
298: } finally {
299: close(e);
300: }
301: }
302:
303: /**
304: * Removes all of the elements from this collection (optional operation).
305: *
306: * @throws UnsupportedOperationException if the <tt>clear</tt> method is
307: * not supported by this collection.
308: */
309: public void clear() {
310: Iterator e = iterator();
311: try {
312: while (e.hasNext()) {
313: e.next();
314: e.remove();
315: }
316: } finally {
317: close(e);
318: }
319: }
320:
321: // String conversion
322:
323: /**
324: * Returns a string representation of this collection.
325: *
326: * @return a string representation of this collection.
327: */
328: public String toString() {
329: StringBuffer buf = new StringBuffer();
330: buf.append("[");
331: Iterator i = iterator();
332: try {
333: boolean hasNext = i.hasNext();
334: while (hasNext) {
335: Object o = i.next();
336: buf.append(o == this ? "(this Collection)" : String
337: .valueOf(o));
338: hasNext = i.hasNext();
339: if (hasNext)
340: buf.append(", ");
341: }
342: buf.append("]");
343: return buf.toString();
344: } finally {
345: close(i);
346: }
347: }
348:
349: //
350: // Contents
351: //
352: //
353: /** Set of open resource iterators */
354: protected final Set open = new HashSet();
355:
356: /**
357: * Please implement!
358: * <p>
359: * Note: If you return a ResourceIterator, the default implemntation of close( Iterator )
360: * will know what to do.
361: *
362: * @return
363: */
364: final public Iterator iterator() {
365: Iterator iterator = null;
366: try {
367: iterator = openIterator();
368: } catch (IOException io) {
369: throw new RuntimeException(io);
370: }
371:
372: open.add(iterator);
373: return iterator;
374: }
375:
376: /**
377: * Returns the number of elements in this collection.
378: *
379: * @return Number of items, or Interger.MAX_VALUE
380: */
381: public abstract int size();
382:
383: /**
384: * Clean up after any resources assocaited with this iteartor in a manner similar to JDO collections.
385: * </p>
386: * Example (safe) use:<pre><code>
387: * Iterator iterator = collection.iterator();
388: * try {
389: * for( Iterator i=collection.iterator(); i.hasNext();){
390: * Feature feature = (Feature) i.hasNext();
391: * System.out.println( feature.getID() );
392: * }
393: * }
394: * finally {
395: * collection.close( iterator );
396: * }
397: * </code></pre>
398: * </p>
399: * @param close
400: */
401: final public void close(Iterator close) {
402: if (close == null)
403: return;
404: try {
405: closeIterator(close);
406: } catch (Throwable e) {
407: // TODO Log e = ln
408: } finally {
409: open.remove(close);
410: }
411:
412: }
413:
414: /**
415: * Open a resource based Iterator, we will call close( iterator ).
416: * <p>
417: * Please subclass to provide your own iterator for the the ResourceCollection,
418: * note <code>iterator()</code> is implemented to call <code>open()</code>
419: * and track the results in for later <code>purge()</code>.
420: *
421: * @param close
422: * @return Iterator based on resource use
423: */
424: abstract protected Iterator openIterator() throws IOException;
425:
426: /**
427: * Please override to cleanup after your own iterators, and
428: * any used resources.
429: * <p>
430: * As an example if the iterator was working off a File then
431: * the inputstream should be closed.
432: * </p>
433: * <p>
434: * Subclass must call super.close( close ) to allow the list
435: * of open iterators to be adjusted.
436: * </p>
437: *
438: * @param close Iterator, will not be <code>null</code>
439: */
440: abstract protected void closeIterator(Iterator close)
441: throws IOException;
442:
443: /**
444: * Close any outstanding resources released by this resources.
445: * <p>
446: * This method should be used with great caution, it is however available
447: * to allow the use of the ResourceCollection with algorthims that are
448: * unaware of the need to close iterators after use.
449: * </p>
450: * <p>
451: * Example of using a normal Collections utility method:<pre><code>
452: * Collections.sort( collection );
453: * collection.purge();
454: * </code></pre>
455: */
456: public void purge() {
457: for (Iterator i = open.iterator(); i.hasNext();) {
458: Object resource = i.next();
459: if (resource instanceof Iterator) {
460: Iterator resourceIterator = (Iterator) resource;
461: try {
462: closeIterator(resourceIterator);
463: } catch (Throwable e) {
464: // TODO: Log e = ln
465: } finally {
466: i.remove();
467: }
468: }
469: }
470: }
471: }
|