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.AbstractMap;
022: import java.util.Collection;
023: import java.util.Map;
024: import java.util.Set;
025:
026: /**
027: * A map whose keys are derived from an other map. The keys are derived only when
028: * requested, which make it possible to backup potentially large maps. Implementations
029: * need only to overrides {@link #baseToDerived} and {@link #derivedToBase} methods.
030: * This set do not supports {@code null} key, since {@code null} is used
031: * when no mapping from {@linkplain #base} to {@code this} exists.
032: * This class is serializable if the underlying {@linkplain #base} set is serializable
033: * too.
034: *
035: * @since 2.0
036: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/util/DerivedMap.java $
037: * @version $Id: DerivedMap.java 22443 2006-10-27 20:47:22Z desruisseaux $
038: * @author Martin Desruisseaux
039: */
040: public abstract class DerivedMap extends AbstractMap implements
041: Serializable {
042: /**
043: * Serial number for interoperability with different versions.
044: */
045: private static final long serialVersionUID = -6994867383669885934L;
046:
047: /**
048: * The base map whose keys are derived from.
049: *
050: * @see #baseToDerived
051: * @see #derivedToBase
052: */
053: protected final Map base;
054:
055: /**
056: * Key set. Will be constructed only when first needed.
057: *
058: * @see #keySet
059: */
060: private transient Set keySet;
061:
062: /**
063: * Entry set. Will be constructed only when first needed.
064: *
065: * @see #entrySet
066: */
067: private transient Set entrySet;
068:
069: /**
070: * Creates a new derived map from the specified base map.
071: *
072: * @param base The base map.
073: */
074: public DerivedMap(final Map base) {
075: this .base = base;
076: }
077:
078: /**
079: * Transforms a key from the {@linkplain #base} map to a key in this map.
080: * If there is no key in the derived map for the specified base key,
081: * then this method returns {@code null}.
082: *
083: * @param key A ley from the {@linkplain #base} map.
084: * @return The key that this view should contains instead of {@code key},
085: * or {@code null}.
086: */
087: protected abstract Object baseToDerived(final Object key);
088:
089: /**
090: * Transforms a key from this derived map to a key in the {@linkplain #base} map.
091: *
092: * @param key A key in this map.
093: * @return The key stored in the {@linkplain #base} map.
094: */
095: protected abstract Object derivedToBase(final Object key);
096:
097: /**
098: * Returns the number of key-value mappings in this map.
099: *
100: * @return the number of key-value mappings in this map.
101: */
102: public int size() {
103: return super .size();
104: }
105:
106: /**
107: * Returns {@code true} if this map contains no key-value mappings.
108: *
109: * @return {@code true} if this map contains no key-value mappings.
110: */
111: public boolean isEmpty() {
112: return base.isEmpty() || super .isEmpty();
113: }
114:
115: /**
116: * Returns {@code true} if this map maps one or more keys to this value.
117: * The default implementation invokes
118: * <code>{@linkplain #base}.containsValue(value)</code>.
119: *
120: * @return {@code true} if this map maps one or more keys to this value.
121: */
122: public boolean containsValue(final Object value) {
123: return base.containsValue(value);
124: }
125:
126: /**
127: * Returns {@code true} if this map contains a mapping for the specified key.
128: * The default implementation invokes
129: * <code>{@linkplain #base}.containsKey({@linkplain #derivedToBase derivedToBase}(key))</code>.
130: *
131: * @param key key whose presence in this map is to be tested.
132: * @return {@code true} if this map contains a mapping for the specified key.
133: */
134: public boolean containsKey(final Object key) {
135: return base.containsKey(derivedToBase(key));
136: }
137:
138: /**
139: * Returns the value to which this map maps the specified key.
140: * The default implementation invokes
141: * <code>{@linkplain #base}.get({@linkplain #derivedToBase derivedToBase}(key))</code>.
142: *
143: * @param key key whose associated value is to be returned.
144: * @return the value to which this map maps the specified key.
145: */
146: public Object get(final Object key) {
147: return base.get(derivedToBase(key));
148: }
149:
150: /**
151: * Associates the specified value with the specified key in this map.
152: * The default implementation invokes
153: * <code>{@linkplain #base}.put({@linkplain #derivedToBase derivedToBase}(key), value)</code>.
154: *
155: * @param key key with which the specified value is to be associated.
156: * @param value value to be associated with the specified key.
157: * @return previous value associated with specified key, or {@code null}
158: * if there was no mapping for key.
159: * @throws UnsupportedOperationException if the {@linkplain #base} map doesn't
160: * supports the {@code put} operation.
161: */
162: public Object put(final Object key, final Object value)
163: throws UnsupportedOperationException {
164: return base.put(derivedToBase(key), value);
165: }
166:
167: /**
168: * Removes the mapping for this key from this map if present.
169: * The default implementation invokes
170: * <code>{@linkplain #base}.remove({@linkplain #derivedToBase derivedToBase}(key))</code>.
171: *
172: * @param key key whose mapping is to be removed from the map.
173: * @return previous value associated with specified key, or {@code null}
174: * if there was no entry for key.
175: * @throws UnsupportedOperationException if the {@linkplain #base} map doesn't
176: * supports the {@code remove} operation.
177: */
178: public Object remove(final Object key)
179: throws UnsupportedOperationException {
180: return base.remove(derivedToBase(key));
181: }
182:
183: /**
184: * Returns a set view of the keys contained in this map.
185: *
186: * @return a set view of the keys contained in this map.
187: */
188: public Set keySet() {
189: if (keySet == null) {
190: keySet = new KeySet(base.keySet());
191: }
192: return keySet;
193: }
194:
195: /**
196: * Returns a collection view of the values contained in this map.
197: *
198: * @return a collection view of the values contained in this map.
199: */
200: public Collection values() {
201: return base.values();
202: }
203:
204: /**
205: * Returns a set view of the mappings contained in this map.
206: *
207: * @return a set view of the mappings contained in this map.
208: */
209: public Set entrySet() {
210: if (entrySet == null) {
211: entrySet = new EntrySet(base.entrySet());
212: }
213: return entrySet;
214: }
215:
216: /**
217: * The key set.
218: */
219: private final class KeySet extends DerivedSet {
220: private static final long serialVersionUID = -2931806200277420177L;
221:
222: public KeySet(final Set base) {
223: super (base);
224: }
225:
226: protected Object baseToDerived(final Object element) {
227: return DerivedMap.this .baseToDerived(element);
228: }
229:
230: protected Object derivedToBase(final Object element) {
231: return DerivedMap.this .derivedToBase(element);
232: }
233: }
234:
235: /**
236: * The entry set.
237: */
238: private final class EntrySet extends DerivedSet {
239: private static final long serialVersionUID = -2931806200277420177L;
240:
241: public EntrySet(final Set base) {
242: super (base);
243: }
244:
245: protected Object baseToDerived(final Object element) {
246: final Map.Entry entry = (Map.Entry) element;
247: final Object derived = DerivedMap.this .baseToDerived(entry
248: .getKey());
249: return derived != null ? new Entry(entry, derived) : null;
250: }
251:
252: protected Object derivedToBase(final Object element) {
253: return ((Entry) element).entry;
254: }
255: }
256:
257: /**
258: * The entry element.
259: */
260: private static final class Entry implements Map.Entry {
261: public final Map.Entry entry;
262: private final Object derived;
263:
264: public Entry(final Map.Entry entry, final Object derived) {
265: this .entry = entry;
266: this .derived = derived;
267: }
268:
269: public Object getKey() {
270: return derived;
271: }
272:
273: public Object getValue() {
274: return entry.getValue();
275: }
276:
277: public Object setValue(Object value) {
278: return entry.setValue(value);
279: }
280: }
281: }
|