KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > util > HashNMap


1 /* ========================================================================
2  * JCommon : a free general purpose class library for the Java(tm) platform
3  * ========================================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jcommon/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * -------------
28  * HashNMap.java
29  * -------------
30  * (C)opyright 2002-2005, by Thomas Morgner and Contributors.
31  *
32  * Original Author: Thomas Morgner;
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  *
35  * $Id: HashNMap.java,v 1.7 2005/10/18 13:24:19 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 20-May-2002 : Initial version
40  * 10-Dec-2002 : Minor Javadoc updates (DG);
41  * 29-Jul-2004 : Replaced 'enum' variable name (reserved word in JDK 1.5) (DG);
42  * 12-Mar-2005 : Some performance improvements, this implementation is no
43  * longer forced to use ArrayLists, add/put behaviour changed to
44  * fit the common behaviour of collections.
45  *
46  */

47
48 package org.jfree.util;
49
50 import java.io.Serializable JavaDoc;
51 import java.util.ArrayList JavaDoc;
52 import java.util.HashMap JavaDoc;
53 import java.util.Iterator JavaDoc;
54 import java.util.List JavaDoc;
55 import java.util.NoSuchElementException JavaDoc;
56 import java.util.Set JavaDoc;
57
58 /**
59  * The HashNMap can be used to store multiple values by a single key value. The
60  * values stored can be retrieved using a direct query or by creating an
61  * enumeration over the stored elements.
62  *
63  * @author Thomas Morgner
64  */

65 public class HashNMap implements Serializable JavaDoc, Cloneable JavaDoc {
66
67     /** Serialization support. */
68     private static final long serialVersionUID = -670924844536074826L;
69
70     /**
71      * An helper class to implement an empty iterator. This iterator will always
72      * return false when <code>hasNext</code> is called.
73      */

74     private static final class EmptyIterator implements Iterator JavaDoc {
75
76         /**
77          * DefaultConstructor.
78          */

79         private EmptyIterator() {
80             super();
81         }
82
83         /**
84          * Returns <tt>true</tt> if the iteration has more elements. (In other
85          * words, returns <tt>true</tt> if <tt>next</tt> would return an element
86          * rather than throwing an exception.)
87          *
88          * @return <tt>true</tt> if the iterator has more elements.
89          */

90         public boolean hasNext() {
91             return false;
92         }
93
94         /**
95          * Returns the next element in the iteration.
96          *
97          * @return the next element in the iteration.
98          * @throws NoSuchElementException iteration has no more elements.
99          */

100         public Object JavaDoc next() {
101             throw new NoSuchElementException JavaDoc("This iterator is empty.");
102         }
103
104         /**
105          * Removes from the underlying collection the last element returned by the
106          * iterator (optional operation). This method can be called only once per
107          * call to <tt>next</tt>. The behavior of an iterator is unspecified if
108          * the underlying collection is modified while the iteration is in
109          * progress in any way other than by calling this method.
110          *
111          * @throws UnsupportedOperationException if the <tt>remove</tt>
112          * operation is not supported by this Iterator.
113          * @throws IllegalStateException if the <tt>next</tt> method has not
114          * yet been called, or the <tt>remove</tt> method has already
115          * been called after the last call to the <tt>next</tt>
116          * method.
117          */

118         public void remove() {
119             throw new UnsupportedOperationException JavaDoc("This iterator is empty, no remove supported.");
120         }
121     }
122
123     /**
124      * A singleton instance of the empty iterator. This object can be safely
125      * shared.
126      */

127     private static final Iterator JavaDoc EMPTY_ITERATOR = new EmptyIterator();
128
129     /**
130      * The underlying storage.
131      */

132     private HashMap JavaDoc table;
133
134     /**
135      * An empty array.
136      */

137     private static final Object JavaDoc[] EMPTY_ARRAY = new Object JavaDoc[0];
138
139     /**
140      * Default constructor.
141      */

142     public HashNMap() {
143         this.table = new HashMap JavaDoc();
144     }
145
146     /**
147      * Returns a new empty list.
148      *
149      * @return A new empty list.
150      */

151     protected List JavaDoc createList() {
152         return new ArrayList JavaDoc();
153     }
154
155     /**
156      * Inserts a new key/value pair into the map. If such a pair already
157      * exists, it gets replaced with the given values.
158      *
159      * @param key the key.
160      * @param val the value.
161      * @return A boolean.
162      */

163     public boolean put(final Object JavaDoc key, final Object JavaDoc val) {
164         final List JavaDoc v = (List JavaDoc) this.table.get(key);
165         if (v == null) {
166             final List JavaDoc newList = createList();
167             newList.add(val);
168             this.table.put(key, newList);
169             return true;
170         }
171         else {
172             v.clear();
173             return v.add(val);
174         }
175     }
176
177     /**
178      * Adds a new key/value pair into this map. If the key is not yet in the
179      * map, it gets added to the map and the call is equal to
180      * put(Object,Object).
181      *
182      * @param key the key.
183      * @param val the value.
184      * @return true, if the value has been added, false otherwise
185      */

186     public boolean add(final Object JavaDoc key, final Object JavaDoc val) {
187         final List JavaDoc v = (List JavaDoc) this.table.get(key);
188         if (v == null) {
189             put(key, val);
190             return true;
191         }
192         else {
193             return v.add(val);
194         }
195     }
196
197     /**
198      * Retrieves the first value registered for an key or null if there was no
199      * such key in the list.
200      *
201      * @param key the key.
202      * @return the value.
203      */

204     public Object JavaDoc getFirst(final Object JavaDoc key) {
205         return get(key, 0);
206     }
207
208     /**
209      * Retrieves the n-th value registered for an key or null if there was no
210      * such key in the list. An index out of bounds exception is thrown if
211      * there are less than n elements registered to this key.
212      *
213      * @param key the key.
214      * @param n the index.
215      * @return the object.
216      */

217     public Object JavaDoc get(final Object JavaDoc key, final int n) {
218         final List JavaDoc v = (List JavaDoc) this.table.get(key);
219         if (v == null) {
220             return null;
221         }
222         return v.get(n);
223     }
224
225     /**
226      * Returns an iterator over all elements registered to the given key.
227      *
228      * @param key the key.
229      * @return an iterator.
230      */

231     public Iterator JavaDoc getAll(final Object JavaDoc key) {
232         final List JavaDoc v = (List JavaDoc) this.table.get(key);
233         if (v == null) {
234             return EMPTY_ITERATOR;
235         }
236         return v.iterator();
237     }
238
239     /**
240      * Returns all registered keys as an enumeration.
241      *
242      * @return an enumeration of the keys.
243      */

244     public Iterator JavaDoc keys() {
245         return this.table.keySet().iterator();
246     }
247
248     /**
249      * Returns all registered keys as set.
250      *
251      * @return a set of keys.
252      */

253     public Set JavaDoc keySet() {
254         return this.table.keySet();
255     }
256
257     /**
258      * Removes the key/value pair from the map. If the removed entry was the
259      * last entry for this key, the key gets also removed.
260      *
261      * @param key the key.
262      * @param value the value.
263      * @return true, if removing the element was successfull, false otherwise.
264      */

265     public boolean remove(final Object JavaDoc key, final Object JavaDoc value) {
266         final List JavaDoc v = (List JavaDoc) this.table.get(key);
267         if (v == null) {
268             return false;
269         }
270
271         if (!v.remove(value)) {
272             return false;
273         }
274         if (v.size() == 0) {
275             this.table.remove(key);
276         }
277         return true;
278     }
279
280     /**
281      * Removes all elements for the given key.
282      *
283      * @param key the key.
284      */

285     public void removeAll(final Object JavaDoc key) {
286         this.table.remove(key);
287     }
288
289     /**
290      * Clears all keys and values of this map.
291      */

292     public void clear() {
293         this.table.clear();
294     }
295
296     /**
297      * Tests whether this map contains the given key.
298      *
299      * @param key the key.
300      * @return true if the key is contained in the map
301      */

302     public boolean containsKey(final Object JavaDoc key) {
303         return this.table.containsKey(key);
304     }
305
306     /**
307      * Tests whether this map contains the given value.
308      *
309      * @param value the value.
310      * @return true if the value is registered in the map for an key.
311      */

312     public boolean containsValue(final Object JavaDoc value) {
313         final Iterator JavaDoc e = this.table.values().iterator();
314         boolean found = false;
315         while (e.hasNext() && !found) {
316             final List JavaDoc v = (List JavaDoc) e.next();
317             found = v.contains(value);
318         }
319         return found;
320     }
321
322     /**
323      * Tests whether this map contains the given value.
324      *
325      * @param value the value.
326      * @param key the key under which to find the value
327      * @return true if the value is registered in the map for an key.
328      */

329     public boolean containsValue(final Object JavaDoc key, final Object JavaDoc value) {
330         final List JavaDoc v = (List JavaDoc) this.table.get(key);
331         if (v == null) {
332             return false;
333         }
334         return v.contains(value);
335     }
336
337     /**
338      * Tests whether this map contains the given key or value.
339      *
340      * @param value the value.
341      * @return true if the key or value is contained in the map
342      */

343     public boolean contains(final Object JavaDoc value) {
344         if (containsKey(value)) {
345             return true;
346         }
347         return containsValue(value);
348     }
349
350     /**
351      * Creates a deep copy of this HashNMap.
352      *
353      * @return a clone.
354      * @throws CloneNotSupportedException this should never happen.
355      */

356     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
357         final HashNMap map = (HashNMap) super.clone();
358         map.table = new HashMap JavaDoc();
359         final Iterator JavaDoc iterator = keys();
360         while (iterator.hasNext()) {
361             final Object JavaDoc key = iterator.next();
362             final List JavaDoc list = (List JavaDoc) map.table.get(key);
363             if (list != null) {
364                 map.table.put(key, ObjectUtilities.clone(list));
365             }
366         }
367         return map;
368     }
369
370     /**
371      * Returns the contents for the given key as object array. If there were
372      * no objects registered with that key, an empty object array is returned.
373      *
374      * @param key the key.
375      * @param data the object array to receive the contents.
376      * @return the contents.
377      */

378     public Object JavaDoc[] toArray(final Object JavaDoc key, final Object JavaDoc[] data) {
379         if (key == null) {
380             throw new NullPointerException JavaDoc("Key must not be null.");
381         }
382         final List JavaDoc list = (List JavaDoc) this.table.get(key);
383         if (list != null) {
384             return list.toArray(data);
385         }
386         if (data.length > 0) {
387             data[0] = null;
388         }
389         return data;
390     }
391
392     /**
393      * Returns the contents for the given key as object array. If there were
394      * no objects registered with that key, an empty object array is returned.
395      *
396      * @param key the key.
397      * @return the contents.
398      */

399     public Object JavaDoc[] toArray(final Object JavaDoc key) {
400         if (key == null) {
401             throw new NullPointerException JavaDoc("Key must not be null.");
402         }
403         final List JavaDoc list = (List JavaDoc) this.table.get(key);
404         if (list != null) {
405             return list.toArray();
406         }
407         return EMPTY_ARRAY;
408     }
409
410     /**
411      * Returns the number of elements registered with the given key.
412      *
413      * @param key the key.
414      * @return the number of element for this key, or 0 if there are no elements
415      * registered.
416      */

417     public int getValueCount(final Object JavaDoc key) {
418         if (key == null) {
419             throw new NullPointerException JavaDoc("Key must not be null.");
420         }
421         final List JavaDoc list = (List JavaDoc) this.table.get(key);
422         if (list != null) {
423             return list.size();
424         }
425         return 0;
426     }
427 }
428
Popular Tags