001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2004, Institut de Recherche pour le Développement
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: package org.geotools.util;
018:
019: // J2SE dependencies
020: import java.io.Serializable;
021: import java.util.AbstractSet;
022: import java.util.Iterator;
023: import java.util.Set;
024:
025: /**
026: * A set whose values are derived from an other set. The values are derived only when
027: * requested, which make it possible to backup potentially large sets. Implementations
028: * need only to overrides {@link #baseToDerived} and {@link #derivedToBase} methods.
029: * This set do not supports {@code null} value, since {@code null} is used
030: * when no mapping from {@linkplain #base} to {@code this} exists.
031: * This class is serializable if the underlying {@linkplain #base} set is serializable
032: * too.
033: *
034: * @since 2.0
035: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/util/DerivedSet.java $
036: * @version $Id: DerivedSet.java 22443 2006-10-27 20:47:22Z desruisseaux $
037: * @author Martin Desruisseaux
038: */
039: public abstract class DerivedSet/*<BaseType, DerivedType>*/extends
040: AbstractSet/*<DerivedType>*/
041: implements Serializable {
042: /**
043: * Serial number for interoperability with different versions.
044: */
045: private static final long serialVersionUID = -4662336508586424581L;
046:
047: /**
048: * The base set whose values are derived from.
049: *
050: * @see #baseToDerived
051: * @see #derivedToBase
052: */
053: protected final Set/*<BaseType>*/base;
054:
055: /**
056: * Creates a new derived set from the specified base set.
057: *
058: * @param base The base set.
059: */
060: public DerivedSet(final Set/*<BaseType>*/base) {
061: this .base = base;
062: }
063:
064: /**
065: * Transforms a value in the {@linkplain #base} set to a value in this set.
066: * If there is no mapping in the derived set for the specified element,
067: * then this method returns {@code null}.
068: *
069: * @param element A value in the {@linkplain #base} set.
070: * @return The value that this view should contains instead of {@code element},
071: * or {@code null}.
072: */
073: protected abstract/*DerivedType*/Object baseToDerived(
074: final/*BaseType*/Object element);
075:
076: /**
077: * Transforms a value in this set to a value in the {@linkplain #base} set.
078: *
079: * @param element A value in this set.
080: * @return The value stored in the {@linkplain #base} set.
081: */
082: protected abstract/*BaseType*/Object derivedToBase(
083: final/*DerivedType*/Object element);
084:
085: /**
086: * Returns an iterator over the elements contained in this set.
087: * The iterator will invokes {@link #baseToDerived} for each element.
088: *
089: * @return an iterator over the elements contained in this set.
090: */
091: public Iterator/*<DerivedType>*/iterator() {
092: return new Iter(base.iterator());
093: }
094:
095: /**
096: * Returns the number of elements in this set. The default implementation counts
097: * the number of elements returned by the {@link #iterator iterator}.
098: *
099: * @return the number of elements in this set.
100: */
101: public int size() {
102: int count = 0;
103: for (final Iterator it = iterator(); it.hasNext();) {
104: it.next();
105: count++;
106: }
107: return count;
108: }
109:
110: /**
111: * Returns {@code true} if this set contains no elements.
112: *
113: * @return {@code true} if this set contains no elements.
114: */
115: public boolean isEmpty() {
116: return base.isEmpty() || super .isEmpty();
117: }
118:
119: /**
120: * Returns {@code true} if this set contains the specified element.
121: * The default implementation invokes
122: * <code>{@linkplain #base}.contains({@linkplain #derivedToBase derivedToBase}(element))</code>.
123: *
124: * @param element object to be checked for containment in this set.
125: * @return {@code true} if this set contains the specified element.
126: */
127: public boolean contains(final/*DerivedType*/Object element) {
128: return base.contains(derivedToBase(element));
129: }
130:
131: /**
132: * Ensures that this set contains the specified element.
133: * The default implementation invokes
134: * <code>{@linkplain #base}.add({@linkplain #derivedToBase derivedToBase}(element))</code>.
135: *
136: * @param element element whose presence in this set is to be ensured.
137: * @return {@code true} if the set changed as a result of the call.
138: * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't
139: * supports the {@code add} operation.
140: */
141: public boolean add(final/*DerivedType*/Object element)
142: throws UnsupportedOperationException {
143: return base.add(derivedToBase(element));
144: }
145:
146: /**
147: * Removes a single instance of the specified element from this set.
148: * The default implementation invokes
149: * <code>{@linkplain #base}.remove({@linkplain #derivedToBase derivedToBase}(element))</code>.
150: *
151: * @param element element to be removed from this set, if present.
152: * @return {@code true} if the set contained the specified element.
153: * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't
154: * supports the {@code remove} operation.
155: */
156: public boolean remove(final/*DerivedType*/Object element)
157: throws UnsupportedOperationException {
158: return base.remove(derivedToBase(element));
159: }
160:
161: /**
162: * Iterates through the elements in the set.
163: */
164: private final class Iter implements Iterator/*<DerivedType>*/{
165: /**
166: * The iterator from the {@linkplain #base} set.
167: */
168: private final Iterator/*<BaseType>*/iterator;
169:
170: /**
171: * The next element to be returned, or {@code null}.
172: */
173: private transient/*DerivedType*/Object next;
174:
175: /**
176: * The iterator from the {@linkplain #base} set.
177: */
178: public Iter(final Iterator/*<BaseType>*/iterator) {
179: this .iterator = iterator;
180: }
181:
182: /**
183: * Returns {@code true} if the iteration has more elements.
184: */
185: public boolean hasNext() {
186: while (next == null) {
187: if (!iterator.hasNext()) {
188: return false;
189: }
190: next = baseToDerived(iterator.next());
191: }
192: return true;
193: }
194:
195: /**
196: * Returns the next element in the iteration.
197: */
198: public/*DerivedType*/Object next() {
199: while (next == null) {
200: next = baseToDerived(iterator.next());
201: }
202: final Object value = next;
203: next = null;
204: return value;
205: }
206:
207: /**
208: * Removes from the underlying set the last element returned by the iterator.
209: *
210: * @throws UnsupportedOperationException if the {@linkplain #base} set doesn't
211: * supports the {@code remove} operation.
212: */
213: public void remove() {
214: iterator.remove();
215: }
216: }
217: }
|