KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > collections > map > SingletonMap


1 /*
2  * Copyright 2003-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.commons.collections.map;
17
18 import java.io.Serializable JavaDoc;
19 import java.util.AbstractSet JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.NoSuchElementException JavaDoc;
25 import java.util.Set JavaDoc;
26
27 import org.apache.commons.collections.BoundedMap;
28 import org.apache.commons.collections.KeyValue;
29 import org.apache.commons.collections.MapIterator;
30 import org.apache.commons.collections.OrderedMap;
31 import org.apache.commons.collections.OrderedMapIterator;
32 import org.apache.commons.collections.ResettableIterator;
33 import org.apache.commons.collections.iterators.SingletonIterator;
34 import org.apache.commons.collections.keyvalue.TiedMapEntry;
35
36 /**
37  * A <code>Map</code> implementation that holds a single item and is fixed size.
38  * <p>
39  * The single key/value pair is specified at creation.
40  * The map is fixed size so any action that would change the size is disallowed.
41  * However, the <code>put</code> or <code>setValue</code> methods can <i>change</i>
42  * the value associated with the key.
43  * <p>
44  * If trying to remove or clear the map, an UnsupportedOperationException is thrown.
45  * If trying to put a new mapping into the map, an IllegalArgumentException is thrown.
46  * The put method will only suceed if the key specified is the same as the
47  * singleton key.
48  * <p>
49  * The key and value can be obtained by:
50  * <ul>
51  * <li>normal Map methods and views
52  * <li>the <code>MapIterator</code>, see {@link #mapIterator()}
53  * <li>the <code>KeyValue</code> interface (just cast - no object creation)
54  * </ul>
55  *
56  * @since Commons Collections 3.1
57  * @version $Revision: 1.1 $ $Date: 2004/04/09 14:46:35 $
58  *
59  * @author Stephen Colebourne
60  */

61 public class SingletonMap
62         implements OrderedMap, BoundedMap, KeyValue, Serializable JavaDoc, Cloneable JavaDoc {
63
64     /** Serialization version */
65     private static final long serialVersionUID = -8931271118676803261L;
66
67     /** Singleton key */
68     private final Object JavaDoc key;
69     /** Singleton value */
70     private Object JavaDoc value;
71
72     /**
73      * Constructor that creates a map of <code>null</code> to <code>null</code>.
74      */

75     public SingletonMap() {
76         super();
77         this.key = null;
78     }
79
80     /**
81      * Constructor specifying the key and value.
82      *
83      * @param key the key to use
84      * @param value the value to use
85      */

86     public SingletonMap(Object JavaDoc key, Object JavaDoc value) {
87         super();
88         this.key = key;
89         this.value = value;
90     }
91
92     /**
93      * Constructor specifying the key and value as a <code>KeyValue</code>.
94      *
95      * @param keyValue the key value pair to use
96      */

97     public SingletonMap(KeyValue keyValue) {
98         super();
99         this.key = keyValue.getKey();
100         this.value = keyValue.getValue();
101     }
102
103     /**
104      * Constructor specifying the key and value as a <code>MapEntry</code>.
105      *
106      * @param keyValue the key value pair to use
107      */

108     public SingletonMap(Map.Entry JavaDoc entry) {
109         super();
110         this.key = entry.getKey();
111         this.value = entry.getValue();
112     }
113
114     /**
115      * Constructor copying elements from another map.
116      *
117      * @param map the map to copy, must be size 1
118      * @throws NullPointerException if the map is null
119      * @throws IllegalArgumentException if the size is not 1
120      */

121     public SingletonMap(Map JavaDoc map) {
122         super();
123         if (map.size() != 1) {
124             throw new IllegalArgumentException JavaDoc("The map size must be 1");
125         }
126         Map.Entry JavaDoc entry = (Map.Entry JavaDoc) map.entrySet().iterator().next();
127         this.key = entry.getKey();
128         this.value = entry.getValue();
129     }
130
131     // KeyValue
132
//-----------------------------------------------------------------------
133
/**
134      * Gets the key.
135      *
136      * @return the key
137      */

138     public Object JavaDoc getKey() {
139         return key;
140     }
141
142     /**
143      * Gets the value.
144      *
145      * @return the value
146      */

147     public Object JavaDoc getValue() {
148         return value;
149     }
150
151     /**
152      * Sets the value.
153      *
154      * @param value the new value to set
155      * @return the old value
156      */

157     public Object JavaDoc setValue(Object JavaDoc value) {
158         Object JavaDoc old = this.value;
159         this.value = value;
160         return old;
161     }
162
163     // BoundedMap
164
//-----------------------------------------------------------------------
165
/**
166      * Is the map currently full, always true.
167      *
168      * @return true always
169      */

170     public boolean isFull() {
171         return true;
172     }
173
174     /**
175      * Gets the maximum size of the map, always 1.
176      *
177      * @return 1 always
178      */

179     public int maxSize() {
180         return 1;
181     }
182
183     // Map
184
//-----------------------------------------------------------------------
185
/**
186      * Gets the value mapped to the key specified.
187      *
188      * @param key the key
189      * @return the mapped value, null if no match
190      */

191     public Object JavaDoc get(Object JavaDoc key) {
192         if (isEqualKey(key)) {
193             return value;
194         }
195         return null;
196     }
197
198     /**
199      * Gets the size of the map, always 1.
200      *
201      * @return the size of 1
202      */

203     public int size() {
204         return 1;
205     }
206
207     /**
208      * Checks whether the map is currently empty, which it never is.
209      *
210      * @return false always
211      */

212     public boolean isEmpty() {
213         return false;
214     }
215
216     //-----------------------------------------------------------------------
217
/**
218      * Checks whether the map contains the specified key.
219      *
220      * @param key the key to search for
221      * @return true if the map contains the key
222      */

223     public boolean containsKey(Object JavaDoc key) {
224         return (isEqualKey(key));
225     }
226
227     /**
228      * Checks whether the map contains the specified value.
229      *
230      * @param value the value to search for
231      * @return true if the map contains the key
232      */

233     public boolean containsValue(Object JavaDoc value) {
234         return (isEqualValue(value));
235     }
236
237     //-----------------------------------------------------------------------
238
/**
239      * Puts a key-value mapping into this map where the key must match the existing key.
240      * <p>
241      * An IllegalArgumentException is thrown if the key does not match as the map
242      * is fixed size.
243      *
244      * @param key the key to set, must be the key of the map
245      * @param value the value to set
246      * @return the value previously mapped to this key, null if none
247      * @throws IllegalArgumentException if the key does not match
248      */

249     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
250         if (isEqualKey(key)) {
251             return setValue(value);
252         }
253         throw new IllegalArgumentException JavaDoc("Cannot put new key/value pair - Map is fixed size singleton");
254     }
255
256     /**
257      * Puts the values from the specified map into this map.
258      * <p>
259      * The map must be of size 0 or size 1.
260      * If it is size 1, the key must match the key of this map otherwise an
261      * IllegalArgumentException is thrown.
262      *
263      * @param map the map to add, must be size 0 or 1, and the key must match
264      * @throws NullPointerException if the map is null
265      * @throws IllegalArgumentException if the key does not match
266      */

267     public void putAll(Map JavaDoc map) {
268         switch (map.size()) {
269             case 0:
270                 return;
271             
272             case 1:
273                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) map.entrySet().iterator().next();
274                 put(entry.getKey(), entry.getValue());
275                 return;
276             
277             default:
278                 throw new IllegalArgumentException JavaDoc("The map size must be 0 or 1");
279         }
280     }
281
282     /**
283      * Unsupported operation.
284      *
285      * @param key the mapping to remove
286      * @return the value mapped to the removed key, null if key not in map
287      * @throws UnsupportedOperationException always
288      */

289     public Object JavaDoc remove(Object JavaDoc key) {
290         throw new UnsupportedOperationException JavaDoc();
291     }
292
293     /**
294      * Unsupported operation.
295      */

296     public void clear() {
297         throw new UnsupportedOperationException JavaDoc();
298     }
299
300     //-----------------------------------------------------------------------
301
/**
302      * Gets the entrySet view of the map.
303      * Changes made via <code>setValue</code> affect this map.
304      * To simply iterate through the entries, use {@link #mapIterator()}.
305      *
306      * @return the entrySet view
307      */

308     public Set JavaDoc entrySet() {
309         Map.Entry JavaDoc entry = new TiedMapEntry(this, getKey());
310         return Collections.singleton(entry);
311     }
312     
313     /**
314      * Gets the unmodifiable keySet view of the map.
315      * Changes made to the view affect this map.
316      * To simply iterate through the keys, use {@link #mapIterator()}.
317      *
318      * @return the keySet view
319      */

320     public Set JavaDoc keySet() {
321         return Collections.singleton(key);
322     }
323
324     /**
325      * Gets the unmodifiable values view of the map.
326      * Changes made to the view affect this map.
327      * To simply iterate through the values, use {@link #mapIterator()}.
328      *
329      * @return the values view
330      */

331     public Collection JavaDoc values() {
332         return new SingletonValues(this);
333     }
334
335     /**
336      * Gets an iterator over the map.
337      * Changes made to the iterator using <code>setValue</code> affect this map.
338      * The <code>remove</code> method is unsupported.
339      * <p>
340      * A MapIterator returns the keys in the map. It also provides convenient
341      * methods to get the key and value, and set the value.
342      * It avoids the need to create an entrySet/keySet/values object.
343      * It also avoids creating the Map Entry object.
344      *
345      * @return the map iterator
346      */

347     public MapIterator mapIterator() {
348         return new SingletonMapIterator(this);
349     }
350
351     // OrderedMap
352
//-----------------------------------------------------------------------
353
/**
354      * Obtains an <code>OrderedMapIterator</code> over the map.
355      * <p>
356      * A ordered map iterator is an efficient way of iterating over maps
357      * in both directions.
358      *
359      * @return an ordered map iterator
360      */

361     public OrderedMapIterator orderedMapIterator() {
362         return new SingletonMapIterator(this);
363     }
364
365     /**
366      * Gets the first (and only) key in the map.
367      *
368      * @return the key
369      */

370     public Object JavaDoc firstKey() {
371         return getKey();
372     }
373
374     /**
375      * Gets the last (and only) key in the map.
376      *
377      * @return the key
378      */

379     public Object JavaDoc lastKey() {
380         return getKey();
381     }
382
383     /**
384      * Gets the next key after the key specified, always null.
385      *
386      * @param key the next key
387      * @return null always
388      */

389     public Object JavaDoc nextKey(Object JavaDoc key) {
390         return null;
391     }
392
393     /**
394      * Gets the previous key before the key specified, always null.
395      *
396      * @param key the next key
397      * @return null always
398      */

399     public Object JavaDoc previousKey(Object JavaDoc key) {
400         return null;
401     }
402
403     //-----------------------------------------------------------------------
404
/**
405      * Compares the specified key to the stored key.
406      *
407      * @param key the key to compare
408      * @return true if equal
409      */

410     protected boolean isEqualKey(Object JavaDoc key) {
411         return (key == null ? getKey() == null : key.equals(getKey()));
412     }
413
414     /**
415      * Compares the specified value to the stored value.
416      *
417      * @param value the value to compare
418      * @return true if equal
419      */

420     protected boolean isEqualValue(Object JavaDoc value) {
421         return (value == null ? getValue() == null : value.equals(getValue()));
422     }
423
424     //-----------------------------------------------------------------------
425
/**
426      * SingletonMapIterator.
427      */

428     static class SingletonMapIterator implements OrderedMapIterator, ResettableIterator {
429         private final SingletonMap parent;
430         private boolean hasNext = true;
431         private boolean canGetSet = false;
432         
433         SingletonMapIterator(SingletonMap parent) {
434             super();
435             this.parent = parent;
436         }
437
438         public boolean hasNext() {
439             return hasNext;
440         }
441
442         public Object JavaDoc next() {
443             if (hasNext == false) {
444                 throw new NoSuchElementException JavaDoc(AbstractHashedMap.NO_NEXT_ENTRY);
445             }
446             hasNext = false;
447             canGetSet = true;
448             return parent.getKey();
449         }
450
451         public boolean hasPrevious() {
452             return (hasNext == false);
453         }
454
455         public Object JavaDoc previous() {
456             if (hasNext == true) {
457                 throw new NoSuchElementException JavaDoc(AbstractHashedMap.NO_PREVIOUS_ENTRY);
458             }
459             hasNext = true;
460             return parent.getKey();
461         }
462
463         public void remove() {
464             throw new UnsupportedOperationException JavaDoc();
465         }
466
467         public Object JavaDoc getKey() {
468             if (canGetSet == false) {
469                 throw new IllegalStateException JavaDoc(AbstractHashedMap.GETKEY_INVALID);
470             }
471             return parent.getKey();
472         }
473
474         public Object JavaDoc getValue() {
475             if (canGetSet == false) {
476                 throw new IllegalStateException JavaDoc(AbstractHashedMap.GETVALUE_INVALID);
477             }
478             return parent.getValue();
479         }
480
481         public Object JavaDoc setValue(Object JavaDoc value) {
482             if (canGetSet == false) {
483                 throw new IllegalStateException JavaDoc(AbstractHashedMap.SETVALUE_INVALID);
484             }
485             return parent.setValue(value);
486         }
487         
488         public void reset() {
489             hasNext = true;
490         }
491         
492         public String JavaDoc toString() {
493             if (hasNext) {
494                 return "Iterator[]";
495             } else {
496                 return "Iterator[" + getKey() + "=" + getValue() + "]";
497             }
498         }
499     }
500     
501     /**
502      * Values implementation for the SingletonMap.
503      * This class is needed as values is a view that must update as the map updates.
504      */

505     static class SingletonValues extends AbstractSet JavaDoc implements Serializable JavaDoc {
506         private static final long serialVersionUID = -3689524741863047872L;
507         private final SingletonMap parent;
508
509         SingletonValues(SingletonMap parent) {
510             super();
511             this.parent = parent;
512         }
513
514         public int size() {
515             return 1;
516         }
517         public boolean isEmpty() {
518             return false;
519         }
520         public boolean contains(Object JavaDoc object) {
521             return parent.containsValue(object);
522         }
523         public void clear() {
524             throw new UnsupportedOperationException JavaDoc();
525         }
526         public Iterator JavaDoc iterator() {
527             return new SingletonIterator(parent.getValue(), false);
528         }
529     }
530     
531     //-----------------------------------------------------------------------
532
/**
533      * Clones the map without cloning the key or value.
534      *
535      * @return a shallow clone
536      */

537     public Object JavaDoc clone() {
538         try {
539             SingletonMap cloned = (SingletonMap) super.clone();
540             return cloned;
541         } catch (CloneNotSupportedException JavaDoc ex) {
542             throw new InternalError JavaDoc();
543         }
544     }
545
546     /**
547      * Compares this map with another.
548      *
549      * @param obj the object to compare to
550      * @return true if equal
551      */

552     public boolean equals(Object JavaDoc obj) {
553         if (obj == this) {
554             return true;
555         }
556         if (obj instanceof Map JavaDoc == false) {
557             return false;
558         }
559         Map JavaDoc other = (Map JavaDoc) obj;
560         if (other.size() != 1) {
561             return false;
562         }
563         Map.Entry JavaDoc entry = (Map.Entry JavaDoc) other.entrySet().iterator().next();
564         return isEqualKey(entry.getKey()) && isEqualValue(entry.getValue());
565     }
566
567     /**
568      * Gets the standard Map hashCode.
569      *
570      * @return the hash code defined in the Map interface
571      */

572     public int hashCode() {
573         return (getKey() == null ? 0 : getKey().hashCode()) ^
574                (getValue() == null ? 0 : getValue().hashCode());
575     }
576
577     /**
578      * Gets the map as a String.
579      *
580      * @return a string version of the map
581      */

582     public String JavaDoc toString() {
583         return new StringBuffer JavaDoc(128)
584             .append('{')
585             .append((getKey() == this ? "(this Map)" : getKey()))
586             .append('=')
587             .append((getValue() == this ? "(this Map)" : getValue()))
588             .append('}')
589             .toString();
590     }
591
592 }
593
Popular Tags