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