001: package org.geotools.feature.iso.collection;
002:
003: import java.util.AbstractList;
004: import java.util.Collection;
005: import java.util.ConcurrentModificationException;
006: import java.util.Iterator;
007: import java.util.List;
008: import java.util.ListIterator;
009: import java.util.NoSuchElementException;
010: import java.util.RandomAccess;
011:
012: import org.geotools.data.collection.ResourceCollection;
013: import org.geotools.data.collection.ResourceList;
014:
015: /**
016: * Starter for resource based list implementations.
017: * <p>
018: * Same deal as ResouceCollections - iterators that need to be closed. This implementation is
019: * set up for random access happy content, like an array list.
020: * </p>
021: * <p>
022: * Read-only:
023: * <ul>
024: * <li><code>get(int index)</code>
025: * <li><code>size()</code>
026: * </ul>
027: * </p>
028: * <p>
029: * For read/write:
030: * <ul>
031: * <li><code>set(index, element)</code> - for fixed length
032: * <li><code>add(index, element)</tt> and <code>remove(index)</code> for dynamic length
033: * </ul>
034: * As usual override anything if you have a faster implementation, say based
035: * on a shapefile index.
036: * </p>
037: *
038: * @author Jody Garnett, Refractions Research, Inc.
039: * @see AbstractList
040: * @since GeoTools 2.2
041: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/community-schemas/fm/src/main/java/org/geotools/feature/iso/collection/AbstractResourceList.java $
042: */
043:
044: public abstract class AbstractResourceList extends
045: AbstractResourceCollection implements ResourceList {
046:
047: protected AbstractResourceList() {
048: }
049:
050: /**
051: * Appends element.
052: * <p>
053: * This implementation calls <tt>add(size(), o)</tt>.
054: * <p>
055: * Note that this implementation throws an <tt>UnsupportedOperationException</tt> unless
056: * <tt>add(int, Object)</tt> is overridden.
057: *
058: * @param o element to be appended to this list.
059: * @return <tt>true</tt> (as per the general contract of <tt>Collection.add</tt>).
060: * @throws UnsupportedOperationException if the <tt>add</tt> method is not supported by
061: * this Set.
062: * @throws ClassCastException if the class of the specified element prevents it from being
063: * added to this set.
064: * @throws IllegalArgumentException some aspect of this element prevents it from being added
065: * to this collection.
066: */
067: public boolean add(Object item) {
068: add(size(), item);
069: return true;
070: }
071:
072: /**
073: * item at the specified index.
074: *
075: * @param index index of item
076: * @return the item at the specified index.
077: * @throws IndexOutOfBoundsException if index is not between 0 and size
078: */
079: abstract public Object get(int index);
080:
081: /**
082: * Replaces item in position index (optional operation).
083: * <p>
084: * This implementation always throws an <tt>UnsupportedOperationException</tt>.
085: *
086: * @param index index of element to replace.
087: * @param element element to be stored at the specified position.
088: * @return the element previously at the specified position.
089: * @throws UnsupportedOperationException if the <tt>set</tt> method is not supported by
090: * this List.
091: * @throws ClassCastException if the class of the specified element prevents it from being
092: * added to this list.
093: * @throws IllegalArgumentException if some aspect of the specified element prevents it from
094: * being added to this list.
095: * @throws IndexOutOfBoundsException if the specified index is out of range (<tt>index < 0 || index >= size()</tt>).
096: */
097:
098: public Object set(int index, Object item) {
099: throw new UnsupportedOperationException();
100: }
101:
102: /**
103: * Inserts the specified element at the specified position in this list (optional
104: * operation). Shifts the element currently at that position (if any) and any subsequent
105: * elements to the right (adds one to their indices).
106: * <p>
107: * This implementation always throws an UnsupportedOperationException.
108: *
109: * @param index index at which the specified element is to be inserted.
110: * @param element element to be inserted.
111: * @throws UnsupportedOperationException if the <tt>add</tt> method is not supported by
112: * this list.
113: * @throws ClassCastException if the class of the specified element prevents it from being
114: * added to this list.
115: * @throws IllegalArgumentException if some aspect of the specified element prevents it from
116: * being added to this list.
117: * @throws IndexOutOfBoundsException index is out of range (<tt>index <
118: * 0 || index > size()</tt>).
119: */
120: public void add(int index, Object element) {
121: throw new UnsupportedOperationException();
122: }
123:
124: /**
125: * Removes the element at the specified position in this list (optional operation). Shifts
126: * any subsequent elements to the left (subtracts one from their indices). Returns the
127: * element that was removed from the list.
128: * <p>
129: * This implementation always throws an <tt>UnsupportedOperationException</tt>.
130: *
131: * @param index the index of the element to remove.
132: * @return the element previously at the specified position.
133: * @throws UnsupportedOperationException if the <tt>remove</tt> method is not supported by
134: * this list.
135: * @throws IndexOutOfBoundsException if the specified index is out of range (<tt>index < 0 || index >= size()</tt>).
136: */
137: public Object remove(int index) {
138: throw new UnsupportedOperationException();
139: }
140:
141: // Search Operations
142:
143: /**
144: * Returns the index in this list of the first occurence of the specified element, or -1 if
145: * the list does not contain this element. More formally, returns the lowest index
146: * <tt>i</tt> such that <tt>(o==null ?
147: * get(i)==null : o.equals(get(i)))</tt>, or -1 if
148: * there is no such index.
149: * <p>
150: * This implementation first gets a list iterator (with <tt>listIterator()</tt>). Then,
151: * it iterates over the list until the specified element is found or the end of the list is
152: * reached.
153: *
154: * @param o element to search for.
155: * @return the index in this List of the first occurence of the specified element, or -1 if
156: * the List does not contain this element.
157: */
158: public int indexOf(Object o) {
159: ListIterator e = listIterator();
160: try {
161:
162: if (o == null) {
163: while (e.hasNext())
164: if (e.next() == null)
165: return e.previousIndex();
166: } else {
167: while (e.hasNext())
168: if (o.equals(e.next()))
169: return e.previousIndex();
170: }
171: return -1;
172: } finally {
173: close(e);
174: }
175: }
176:
177: /**
178: * Returns the index in this list of the last occurence of the specified element, or -1 if
179: * the list does not contain this element. More formally, returns the highest index
180: * <tt>i</tt> such that <tt>(o==null ?
181: * get(i)==null : o.equals(get(i)))</tt>, or -1 if
182: * there is no such index.
183: * <p>
184: * This implementation first gets a list iterator that points to the end of the list (with
185: * listIterator(size())). Then, it iterates backwards over the list until the specified
186: * element is found, or the beginning of the list is reached.
187: *
188: * @param o element to search for.
189: * @return the index in this list of the last occurence of the specified element, or -1 if
190: * the list does not contain this element.
191: */
192: public int lastIndexOf(Object o) {
193: ListIterator e = listIterator(size());
194: try {
195: if (o == null) {
196: while (e.hasPrevious())
197: if (e.previous() == null)
198: return e.nextIndex();
199: } else {
200: while (e.hasPrevious())
201: if (o.equals(e.previous()))
202: return e.nextIndex();
203: }
204: return -1;
205: } finally {
206: close(e);
207: }
208: }
209:
210: // Bulk Operations
211: /**
212: * Removes all of the elements from this collection (optional operation).
213: * <p>
214: * This implementation calls <tt>removeRange(0, size())</tt>.
215: * <p>
216: * Note that this implementation throws an <tt>UnsupportedOperationException</tt> unless
217: * <tt>remove(int
218: * index)</tt> or <tt>removeRange(int fromIndex, int toIndex)</tt> is
219: * overridden.
220: *
221: * @throws UnsupportedOperationException if the <tt>clear</tt> method is not supported by
222: * this Collection.
223: */
224: public void clear() {
225: removeRange(0, size());
226: }
227:
228: /**
229: * Inserts all of the elements in the specified collection into this list at the specified
230: * position (optional operation).
231: * <p>
232: * Note that this implementation throws an <tt>UnsupportedOperationException</tt> unless
233: * <tt>add(int, Object)</tt> is overridden.
234: *
235: * @return <tt>true</tt> if this list changed as a result of the call.
236: * @param index index at which to insert the first element from the specified collection.
237: * @param c elements to be inserted into this List.
238: * @throws UnsupportedOperationException if the <tt>addAll</tt> method is not supported by
239: * this list.
240: * @throws ClassCastException if the class of an element of the specified collection
241: * prevents it from being added to this List.
242: * @throws IllegalArgumentException some aspect an element of the specified collection
243: * prevents it from being added to this List.
244: * @throws IndexOutOfBoundsException index out of range (<tt>index < 0
245: * || index > size()</tt>).
246: * @throws NullPointerException if the specified collection is null.
247: */
248: public boolean addAll(int index, Collection c) {
249: boolean modified = false;
250: Iterator e = c.iterator();
251: try {
252: while (e.hasNext()) {
253: add(index++, e.next());
254: modified = true;
255: }
256: return modified;
257: } finally {
258: if (c instanceof ResourceCollection) {
259: ((ResourceCollection) c).close(e);
260: }
261: }
262: }
263:
264: // Iterators
265: /**
266: * Returns <tt>listIterator(0)</tt>.
267: *
268: * @return listIterator(0)
269: * @see #listIterator(int)
270: */
271: public ListIterator listIterator() {
272: return listIterator(0);
273: }
274:
275: /**
276: * Returns a list iterator of the elements in this list from index on.
277: *
278: * @param index
279: * @return a list iterator from index *
280: * @throws IndexOutOfBoundsException if the specified index is out of range
281: * @see #modCount
282: */
283: public ListIterator listIterator(final int index) {
284: if (index < 0 || index > size())
285: throw new IndexOutOfBoundsException("Index: " + index);
286: ListIterator iterator = openIterator(index);
287: open.add(iterator);
288: return iterator;
289: }
290:
291: public ListIterator openIterator(final int index) {
292: return new ListItr(index);
293: }
294:
295: /**
296: * Returns a quick iterator that uses get and size methods.
297: * <p>
298: * As with all resource collections it is assumed that the iterator will
299: * be closed after use.
300: * </p>
301: *
302: * @return an iterator over the elements in this list in proper sequence.
303: * @see #modCount
304: */
305: protected Iterator openIterator() {
306: return new ListItr(0);
307: }
308:
309: protected void closeIterator(Iterator close) {
310: // no resources used by default I
311: }
312:
313: private class ListItr implements ListIterator {
314: int index = 0;
315: int lastRet = -1;
316: /**
317: * detecte concurrent modification.
318: */
319: int expectedModCount = modCount;
320:
321: ListItr(int index) {
322: this .index = index;
323: }
324:
325: final void checkForComodification() {
326: if (modCount != expectedModCount)
327: throw new ConcurrentModificationException();
328: }
329:
330: public boolean hasNext() {
331: return index != size();
332: }
333:
334: public Object next() {
335: checkForComodification();
336: try {
337: Object next = get(index);
338: lastRet = index++;
339: return next;
340: } catch (IndexOutOfBoundsException e) {
341: checkForComodification();
342: throw new NoSuchElementException();
343: }
344: }
345:
346: public void remove() {
347: if (lastRet == -1)
348: throw new IllegalStateException();
349: checkForComodification();
350:
351: try {
352: AbstractResourceList.this .remove(lastRet);
353: if (lastRet < index)
354: index--;
355: lastRet = -1;
356: expectedModCount = modCount;
357: } catch (IndexOutOfBoundsException e) {
358: throw new ConcurrentModificationException();
359: }
360: }
361:
362: public boolean hasPrevious() {
363: return index != 0;
364: }
365:
366: public Object previous() {
367: checkForComodification();
368: try {
369: int i = index - 1;
370: Object previous = get(i);
371: lastRet = index = i;
372: return previous;
373: } catch (IndexOutOfBoundsException e) {
374: checkForComodification();
375: throw new NoSuchElementException();
376: }
377: }
378:
379: public int nextIndex() {
380: return index;
381: }
382:
383: public int previousIndex() {
384: return index - 1;
385: }
386:
387: public void set(Object o) {
388: if (lastRet == -1) {
389: throw new IllegalStateException();
390: }
391: checkForComodification();
392:
393: try {
394: AbstractResourceList.this .set(lastRet, o);
395: expectedModCount = modCount;
396: } catch (IndexOutOfBoundsException e) {
397: throw new ConcurrentModificationException();
398: }
399: }
400:
401: public void add(Object o) {
402: checkForComodification();
403:
404: try {
405: AbstractResourceList.this .add(index++, o);
406: lastRet = -1;
407: expectedModCount = modCount;
408: } catch (IndexOutOfBoundsException e) {
409: throw new ConcurrentModificationException();
410: }
411: }
412: }
413:
414: /**
415: * view of the portion of this list between fromIndex up to toIndex.
416: *
417: * @param fromIndex
418: * @param toIndex
419: * @return a view of the specified range within this list.
420: * @throws IndexOutOfBoundsException
421: * @throws IllegalArgumentException endpoint indices out of order
422: */
423: public List subList(int fromIndex, int toIndex) {
424: return new SubList(this , fromIndex, toIndex);
425: }
426:
427: // Comparison and hashing
428:
429: /**
430: * Compares the specified object with this list for equality. Returns <tt>true</tt> if and
431: * only if the specified object is also a list, both lists have the same size, and all
432: * corresponding pairs of elements in the two lists are <i>equal</i>. (Two elements
433: * <tt>e1</tt> and <tt>e2</tt> are <i>equal</i> if <tt>(e1==null ? e2==null :
434: * e1.equals(e2))</tt>.)
435: * In other words, two lists are defined to be equal if they contain the same elements in
436: * the same order.
437: * <p>
438: * This implementation first checks if the specified object is this list. If so, it returns
439: * <tt>true</tt>; if not, it checks if the specified object is a list. If not, it returns
440: * <tt>false</tt>; if so, it iterates over both lists, comparing corresponding pairs of
441: * elements. If any comparison returns <tt>false</tt>, this method returns <tt>false</tt>.
442: * If either iterator runs out of elements before the other it returns <tt>false</tt> (as
443: * the lists are of unequal length); otherwise it returns <tt>true</tt> when the
444: * iterations complete.
445: *
446: * @param o the object to be compared for equality with this list.
447: * @return <tt>true</tt> if the specified object is equal to this list.
448: */
449: public boolean equals(Object o) {
450: if (o == this )
451: return true;
452: if (!(o instanceof List))
453: return false;
454:
455: ListIterator e1 = listIterator();
456: ListIterator e2 = ((List) o).listIterator();
457: try {
458: while (e1.hasNext() && e2.hasNext()) {
459: Object o1 = e1.next();
460: Object o2 = e2.next();
461: if (!(o1 == null ? o2 == null : o1.equals(o2))) {
462: return false;
463: }
464: }
465: return !(e1.hasNext() || e2.hasNext());
466: } finally {
467: close(e1);
468: if (o instanceof ResourceCollection) {
469: ((ResourceCollection) o).close(e2);
470: }
471: }
472: }
473:
474: /**
475: * Returns the hash code value for this list.
476: * <p>
477: * This implementation uses exactly the code that is used to define the list hash function
478: * in the documentation for the <tt>List.hashCode</tt> method.
479: *
480: * @return the hash code value for this list.
481: */
482: public int hashCode() {
483: int hashCode = 1;
484: Iterator i = iterator();
485: try {
486: while (i.hasNext()) {
487: Object obj = i.next();
488: hashCode = 31 * hashCode
489: + (obj == null ? 0 : obj.hashCode());
490: }
491: return hashCode;
492: } finally {
493: close(i);
494: }
495: }
496:
497: /**
498: * Removes from this list all of the elements whose index is between fromIndex upto toIndex
499: *
500: * @param fromIndex index of first element to be removed.
501: * @param toIndex index after last element to be removed.
502: */
503: public void removeRange(int fromIndex, int toIndex) {
504: ListIterator it = listIterator(fromIndex);
505: try {
506: for (int i = 0, n = toIndex - fromIndex; i < n; i++) {
507: it.next();
508: it.remove();
509: }
510: } finally {
511: close(it);
512: }
513: }
514:
515: /**
516: * The number of times this list has been modified.
517: */
518: protected transient int modCount = 0;
519:
520: }
521:
522: class SubList extends AbstractResourceList implements ResourceList {
523:
524: private final class SubListIterator implements ListIterator {
525: private ListIterator i;
526:
527: private SubListIterator(int index) {
528: super ();
529: i = l.listIterator(index + offset);
530: i = l.listIterator(index + offset);
531: }
532:
533: public boolean hasNext() {
534: return nextIndex() < size;
535: }
536:
537: public Object next() {
538: if (hasNext())
539: return i.next();
540: else
541: throw new NoSuchElementException();
542: }
543:
544: public boolean hasPrevious() {
545: return previousIndex() >= 0;
546: }
547:
548: public Object previous() {
549: if (hasPrevious())
550: return i.previous();
551: else
552: throw new NoSuchElementException();
553: }
554:
555: public int nextIndex() {
556: return i.nextIndex() - offset;
557: }
558:
559: public int previousIndex() {
560: return i.previousIndex() - offset;
561: }
562:
563: public void remove() {
564: i.remove();
565: expectedModCount = l.modCount;
566: size--;
567: modCount++;
568: }
569:
570: public void set(Object o) {
571: i.set(o);
572: }
573:
574: public void add(Object o) {
575: i.add(o);
576: expectedModCount = l.modCount;
577: size++;
578: modCount++;
579: }
580: }
581:
582: private AbstractResourceList l;
583: private int offset;
584: private int size;
585: private int expectedModCount;
586:
587: SubList(AbstractResourceList list, int fromIndex, int toIndex) {
588: if (fromIndex < 0)
589: throw new IndexOutOfBoundsException("fromIndex = "
590: + fromIndex);
591: if (toIndex > list.size())
592: throw new IndexOutOfBoundsException("toIndex = " + toIndex);
593: if (fromIndex > toIndex)
594: throw new IllegalArgumentException("fromIndex(" + fromIndex
595: + ") > toIndex(" + toIndex + ")");
596: l = list;
597: offset = fromIndex;
598: size = toIndex - fromIndex;
599: expectedModCount = l.modCount;
600: }
601:
602: public Object set(int index, Object element) {
603: rangeCheck(index);
604: checkForComodification();
605: return l.set(index + offset, element);
606: }
607:
608: public Object get(int index) {
609: rangeCheck(index);
610: checkForComodification();
611: return l.get(index + offset);
612: }
613:
614: public int size() {
615: checkForComodification();
616: return size;
617: }
618:
619: public void add(int index, Object element) {
620: if (index < 0 || index > size)
621: throw new IndexOutOfBoundsException();
622: checkForComodification();
623: l.add(index + offset, element);
624: expectedModCount = l.modCount;
625: size++;
626: modCount++;
627: }
628:
629: public Object remove(int index) {
630: rangeCheck(index);
631: checkForComodification();
632: Object result = l.remove(index + offset);
633: expectedModCount = l.modCount;
634: size--;
635: modCount++;
636: return result;
637: }
638:
639: public void removeRange(int fromIndex, int toIndex) {
640: checkForComodification();
641: l.removeRange(fromIndex + offset, toIndex + offset);
642: expectedModCount = l.modCount;
643: size -= (toIndex - fromIndex);
644: modCount++;
645: }
646:
647: public boolean addAll(Collection c) {
648: return addAll(size, c);
649: }
650:
651: public boolean addAll(int index, Collection c) {
652: if (index < 0 || index > size)
653: throw new IndexOutOfBoundsException("Index: " + index
654: + ", Size: " + size);
655: int cSize = c.size();
656: if (cSize == 0)
657: return false;
658:
659: checkForComodification();
660: l.addAll(offset + index, c);
661: expectedModCount = l.modCount;
662: size += cSize;
663: modCount++;
664: return true;
665: }
666:
667: public void closeIterator(Iterator close) {
668: SubListIterator it = (SubListIterator) close;
669: l.close(it.i);
670: }
671:
672: public void purge() {
673: for (Iterator i = open.iterator(); i.hasNext();) {
674: SubListIterator it = (SubListIterator) i.next();
675: l.close(it.i);
676: i.remove();
677: }
678: }
679:
680: public ListIterator listIterator(final int index) {
681: checkForComodification();
682: if (index < 0 || index > size)
683: throw new IndexOutOfBoundsException("Index: " + index
684: + ", Size: " + size);
685:
686: ListIterator listIterator = new SubListIterator(index);
687: open.add(listIterator);
688: return listIterator;
689: }
690:
691: public List subList(int fromIndex, int toIndex) {
692: return new SubList(this , fromIndex, toIndex);
693: }
694:
695: private void rangeCheck(int index) {
696: if (index < 0 || index >= size)
697: throw new IndexOutOfBoundsException("Index: " + index
698: + ",Size: " + size);
699: }
700:
701: private void checkForComodification() {
702: if (l.modCount != expectedModCount)
703: throw new ConcurrentModificationException();
704: }
705: }
706:
707: class RandomAccessSubList extends SubList implements RandomAccess {
708: RandomAccessSubList(AbstractResourceList list, int fromIndex,
709: int toIndex) {
710: super (list, fromIndex, toIndex);
711: }
712:
713: public List subList(int fromIndex, int toIndex) {
714: return new RandomAccessSubList(this, fromIndex, toIndex);
715: }
716: }
|