KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > go > trove > util > PropertyMap


1 /* ====================================================================
2  * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
3  * ====================================================================
4  * The Tea Software License, Version 1.1
5  *
6  * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Walt Disney Internet Group (http://opensource.go.com/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact opensource@dig.com.
31  *
32  * 5. Products derived from this software may not be called "Tea",
33  * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34  * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35  * written permission of the Walt Disney Internet Group.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * For more information about Tea, please see http://opensource.go.com/.
51  */

52
53 package com.go.trove.util;
54
55 import java.util.*;
56 import java.io.Serializable JavaDoc;
57
58 /******************************************************************************
59  * A class that is similar to {@link java.util.Properties} but preserves
60  * original property order and supports a special {@link #subMap} view
61  * operation. PropertyMap also has more convenience methods for getting
62  * properties as certain types.
63  *
64  * @author Brian S O'Neill
65  * @version
66  * <!--$$Revision:--> 13 <!-- $--> 4 <!-- $$JustDate:--> 01/02/26 <!-- $-->
67  */

68 public class PropertyMap extends AbstractMap {
69     public static final Class JavaDoc ELEMENT_TYPE = String JavaDoc.class;
70
71     private static String JavaDoc internStr(String JavaDoc str) {
72         return (String JavaDoc)Utils.intern(str);
73     }
74
75     private Map mMappings;
76     private String JavaDoc mSeparator;
77     private String JavaDoc mPrefix;
78
79     private transient Set mSubMapKeySet;
80     private transient Set mEntrySet;
81
82     /**
83      * Construct a PropetyMap using a dot (".") separator.
84      */

85     public PropertyMap() {
86         this(null, ".");
87     }
88
89     /**
90      * @param map Map of defaults.
91      */

92     public PropertyMap(Map map) {
93         this(map, ".");
94     }
95
96     /**
97      * @param separator Sub-key separator, i.e. ".".
98      */

99     public PropertyMap(String JavaDoc separator) {
100         this(null, separator);
101     }
102
103     /**
104      * @param map Optional map of defaults.
105      * @param separator Sub-key separator, i.e. ".".
106      *
107      * @see #putDefaults(Map)
108      */

109     public PropertyMap(Map map, String JavaDoc separator) {
110         UsageMap usageMap = new UsageMap();
111         usageMap.setReverseOrder(true);
112         mMappings = usageMap;
113         mSeparator = separator;
114         if (map != null) {
115             putAll(map);
116         }
117     }
118
119     private PropertyMap(String JavaDoc prefix, PropertyMap source) {
120         mMappings = source;
121         mSeparator = source.getSeparator();
122         mPrefix = prefix;
123     }
124
125     public String JavaDoc getSeparator() {
126         return mSeparator;
127     }
128
129     /**
130      * Returns a view of this map for keys that are the same as the given key,
131      * or start with it (and a separator). The names of the keys in the
132      * sub-map have their prefix truncated.
133      *
134      * <p>A sub-map of
135      *
136      * <pre>
137      * "x" = "a"
138      * "foo" = "b"
139      * "foo." = "c"
140      * "foo.bar" = "d"
141      * "foo.bar.splat" = "e"
142      * "foo..bar" = "f"
143      * ".foo" = "g"
144      * "" = "h"
145      * null = "i"
146      * </pre>
147      *
148      * using a key of "foo" results in
149      *
150      * <pre>
151      * null = "b"
152      * "" = "c"
153      * "bar" = "d"
154      * "bar.splat" = "e"
155      * ".bar" = "f"
156      * </pre>
157      *
158      * using a key of "x" results in
159      *
160      * <pre>
161      * null = "a"
162      * </pre>
163      *
164      * using a key of "" results in
165      *
166      * <pre>
167      * "foo" = "g"
168      * null = "h"
169      * </pre>
170      *
171      * and using a key of null results in the original map.
172      */

173     public PropertyMap subMap(String JavaDoc key) {
174         if (key == null) {
175             return this;
176         }
177         else {
178             return new PropertyMap(key, this);
179         }
180     }
181
182     /**
183      * Returns the key names of each sub-map in this PropertyMap. The returned
184      * set is unmodifiable.
185      */

186     public Set subMapKeySet() {
187         if (mSubMapKeySet == null) {
188             mSubMapKeySet = new SubMapKeySet();
189         }
190         return mSubMapKeySet;
191     }
192
193     public int size() {
194         if (mPrefix == null) {
195             return mMappings.size();
196         }
197         else {
198             return super.size();
199         }
200     }
201
202     public boolean isEmpty() {
203         if (mPrefix == null) {
204             return mMappings.isEmpty();
205         }
206         else {
207             return super.isEmpty();
208         }
209     }
210     
211     public boolean containsKey(Object JavaDoc key) {
212         if (key == null) {
213             return containsKey((String JavaDoc)null);
214         }
215         else {
216             return containsKey(key.toString());
217         }
218     }
219     
220     public boolean containsKey(String JavaDoc key) {
221         if (mPrefix == null) {
222             return mMappings.containsKey(internStr(key));
223         }
224         else {
225             return mMappings.containsKey(mPrefix + mSeparator + key);
226         }
227     }
228     
229     public Object JavaDoc get(Object JavaDoc key) {
230         if (key == null) {
231             return get((String JavaDoc)null);
232         }
233         else {
234             return get(key.toString());
235         }
236     }
237
238     public Object JavaDoc get(String JavaDoc key) {
239         if (mPrefix == null) {
240             return mMappings.get(internStr(key));
241         }
242         else {
243             return mMappings.get(mPrefix + mSeparator + key);
244         }
245     }
246
247     /**
248      * Returns null if the given key isn't in this PropertyMap.
249      *
250      * @param key Key of property to read
251      */

252     public String JavaDoc getString(String JavaDoc key) {
253         Object JavaDoc value = get(key);
254         if (value == null) {
255             return null;
256         }
257         else {
258             return value.toString();
259         }
260     }
261     
262     /**
263      * Returns the default value if the given key isn't in this PropertyMap.
264      *
265      * @param key Key of property to read
266      * @param def Default value
267      */

268     public String JavaDoc getString(String JavaDoc key, String JavaDoc def) {
269         Object JavaDoc value = get(key);
270         if (value == null) {
271             return def;
272         }
273         else {
274             return value.toString();
275         }
276     }
277     
278     /**
279      * Returns 0 if the given key isn't in this PropertyMap.
280      *
281      * @param key Key of property to read
282      */

283     public int getInt(String JavaDoc key) throws NumberFormatException JavaDoc {
284         String JavaDoc value = getString(key);
285         if (value == null) {
286             return 0;
287         }
288         else {
289             return Integer.parseInt(value);
290         }
291     }
292
293     /**
294      * Returns the default value if the given key isn't in this PropertyMap or
295      * isn't a valid integer.
296      *
297      * @param key Key of property to read
298      * @param def Default value
299      */

300     public int getInt(String JavaDoc key, int def) {
301         String JavaDoc value = getString(key);
302         if (value == null) {
303             return def;
304         }
305         else {
306             try {
307                 return Integer.parseInt(value);
308             }
309             catch (NumberFormatException JavaDoc e) {
310             }
311             return def;
312         }
313     }
314
315     /**
316      * Returns null if the given key isn't in this PropertyMap or it isn't a
317      * valid integer.
318      *
319      * @param key Key of property to read
320      */

321     public Integer JavaDoc getInteger(String JavaDoc key) {
322         return getInteger(key, null);
323     }
324
325     /**
326      * Returns the default value if the given key isn't in this PropertyMap or
327      * it isn't a valid integer.
328      *
329      * @param key Key of property to read
330      * @param def Default value
331      */

332     public Integer JavaDoc getInteger(String JavaDoc key, Integer JavaDoc def) {
333         String JavaDoc value = getString(key);
334         if (value == null) {
335             return def;
336         }
337         else {
338             try {
339                 return Integer.valueOf(value);
340             }
341             catch (NumberFormatException JavaDoc e) {
342             }
343             return def;
344         }
345     }
346
347     /**
348      * Returns null if the given key isn't in this PropertyMap.
349      *
350      * @param key Key of property to read
351      */

352     public Number JavaDoc getNumber(String JavaDoc key) throws NumberFormatException JavaDoc {
353         String JavaDoc value = getString(key);
354         if (value == null) {
355             return null;
356         }
357         else {
358             try {
359                 return Integer.valueOf(value);
360             }
361             catch (NumberFormatException JavaDoc e) {
362             }
363             try {
364                 return Long.valueOf(value);
365             }
366             catch (NumberFormatException JavaDoc e) {
367             }
368             return Double.valueOf(value);
369         }
370     }
371
372     /**
373      * Returns the default value if the given key isn't in this PropertyMap or
374      * isn't a valid number.
375      *
376      * @param key Key of property to read
377      * @param def Default value
378      */

379     public Number JavaDoc getNumber(String JavaDoc key, Number JavaDoc def) {
380         String JavaDoc value = getString(key);
381         if (value == null) {
382             return def;
383         }
384         else {
385             try {
386                 return Integer.valueOf(value);
387             }
388             catch (NumberFormatException JavaDoc e) {
389             }
390             try {
391                 return Long.valueOf(value);
392             }
393             catch (NumberFormatException JavaDoc e) {
394             }
395             try {
396                 return Double.valueOf(value);
397             }
398             catch (NumberFormatException JavaDoc e) {
399             }
400             return def;
401         }
402     }
403
404     /**
405      * Returns true only if value is "true", ignoring case.
406      *
407      * @param key Key of property to read
408      */

409     public boolean getBoolean(String JavaDoc key) {
410         return "true".equalsIgnoreCase(getString(key));
411     }
412
413     /**
414      * Returns the default value if the given key isn't in this PropertyMap or
415      * if the the value isn't equal to "true", ignoring case.
416      *
417      * @param key Key of property to read
418      * @param def Default value
419      */

420     public boolean getBoolean(String JavaDoc key, boolean def) {
421         String JavaDoc value = getString(key);
422         if (value == null) {
423             return def;
424         }
425         else {
426             return "true".equalsIgnoreCase(value);
427         }
428     }
429
430     public Set entrySet() {
431         if (mPrefix == null) {
432             return mMappings.entrySet();
433         }
434         else {
435             if (mEntrySet == null) {
436                 mEntrySet = new EntrySet();
437             }
438             return mEntrySet;
439         }
440     }
441
442     public Set keySet() {
443         if (mPrefix == null) {
444             return mMappings.keySet();
445         }
446         else {
447             return super.keySet();
448         }
449     }
450
451     public Collection values() {
452         if (mPrefix == null) {
453             return mMappings.values();
454         }
455         else {
456             return super.values();
457         }
458     }
459
460     /**
461      * The key is always converted to a String.
462      */

463     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
464         if (key == null) {
465             return put((String JavaDoc)null, value);
466         }
467         else {
468             return put(key.toString(), value);
469         }
470     }
471
472     public Object JavaDoc put(String JavaDoc key, Object JavaDoc value) {
473         if (mPrefix == null) {
474             return mMappings.put(internStr(key), value);
475         }
476         else {
477             return mMappings.put(mPrefix + mSeparator + key, value);
478         }
479     }
480
481     /**
482      * Copies the entries of the given map into this one only for keys that
483      * aren't contained in this map. Is equivalent to putAll if this map is
484      * empty.
485      */

486     public void putDefaults(Map map) {
487         Iterator it = map.entrySet().iterator();
488         while (it.hasNext()) {
489             Map.Entry entry = (Map.Entry)it.next();
490             Object JavaDoc key = entry.getKey();
491             if (!containsKey(key)) {
492                 put(key, entry.getValue());
493             }
494         }
495     }
496     
497     public Object JavaDoc remove(Object JavaDoc key) {
498         if (key == null) {
499             return remove((String JavaDoc)null);
500         }
501         else {
502             return remove(key.toString());
503         }
504     }
505     
506     public Object JavaDoc remove(String JavaDoc key) {
507         if (mPrefix == null) {
508             return mMappings.remove(internStr(key));
509         }
510         else {
511             return mMappings.remove(mPrefix + mSeparator + key);
512         }
513     }
514     
515     public void clear() {
516         if (mPrefix == null) {
517             mMappings.clear();
518         }
519         else {
520             super.clear();
521         }
522     }
523
524     private class SubMapKeySet extends AbstractSet {
525         public int size() {
526             int size = 0;
527             Iterator it = iterator();
528             while (it.hasNext()) {
529                 it.next();
530                 size++;
531             }
532             return size;
533         }
534         
535         public Iterator iterator() {
536             return new Iterator() {
537                 final Iterator mIterator = keySet().iterator();
538                 Set mSeen = new HashSet();
539                 String JavaDoc mNext;
540
541                 public boolean hasNext() {
542                     if (mNext != null) {
543                         return true;
544                     }
545
546                     String JavaDoc sep = mSeparator;
547
548                     while (mIterator.hasNext()) {
549                         String JavaDoc key = (String JavaDoc)mIterator.next();
550                         if (key != null) {
551                             int index = key.indexOf(sep);
552                             if (index >= 0) {
553                                 String JavaDoc subKey = key.substring(0, index);
554                                 if (!mSeen.contains(subKey)) {
555                                     mSeen.add(subKey);
556                                     mNext = subKey;
557                                     return true;
558                                 }
559                             }
560                         }
561                     }
562
563                     return false;
564                 }
565
566                 public Object JavaDoc next() {
567                     if (!hasNext()) {
568                         throw new NoSuchElementException();
569                     }
570                     else {
571                         Object JavaDoc next = mNext;
572                         mNext = null;
573                         return next;
574                     }
575                 }
576
577                 public void remove() {
578                     throw new UnsupportedOperationException JavaDoc();
579                 }
580             };
581         }
582     }
583
584     private class EntrySet extends AbstractSet {
585         public int size() {
586             int size = 0;
587             Iterator it = iterator();
588             while (it.hasNext()) {
589                 it.next();
590                 size++;
591             }
592             return size;
593         }
594         
595         public boolean remove(Object JavaDoc obj) {
596             if (obj instanceof Map.Entry) {
597                 Object JavaDoc key = ((Map.Entry)obj).getKey();
598                 Object JavaDoc value = ((Map.Entry)obj).getValue();
599
600                 if (PropertyMap.this.containsKey(key)) {
601                     Object JavaDoc v = PropertyMap.this.get(key);
602                     if (v == null) {
603                         if (value == null) {
604                             PropertyMap.this.remove(key);
605                             return true;
606                         }
607                     }
608                     else if (v.equals(value)) {
609                         PropertyMap.this.remove(key);
610                         return true;
611                     }
612                 }
613             }
614             return false;
615         }
616         
617         public void clear() {
618             Iterator it = iterator();
619             while (it.hasNext()) {
620                 it.next();
621                 it.remove();
622             }
623         }
624
625         public Iterator iterator() {
626             return new Iterator() {
627                 final Iterator mIterator = mMappings.entrySet().iterator();
628                 Map.Entry mNext;
629
630                 public boolean hasNext() {
631                     if (mNext != null) {
632                         return true;
633                     }
634
635                     String JavaDoc prefix = mPrefix;
636                     String JavaDoc sep = mSeparator;
637
638                     while (mIterator.hasNext()) {
639                         final Map.Entry entry = (Map.Entry)mIterator.next();
640                         String JavaDoc key = (String JavaDoc)entry.getKey();
641
642                         if (key != null && key.startsWith(prefix)) {
643                             final String JavaDoc subKey;
644                             if (key.length() == prefix.length()) {
645                                 subKey = null;
646                             }
647                             else {
648                                 if (key.startsWith(sep, prefix.length())) {
649                                     subKey = key.substring
650                                         (prefix.length() + sep.length());
651                                 }
652                                 else {
653                                     continue;
654                                 }
655                             }
656
657                             mNext = new AbstractMapEntry() {
658                                 public Object JavaDoc getKey() {
659                                     return subKey;
660                                 }
661
662                                 public Object JavaDoc getValue() {
663                                     return entry.getValue();
664                                 }
665                                 
666                                 public Object JavaDoc setValue(Object JavaDoc value) {
667                                     return put(subKey, value);
668                                 }
669                             };
670
671                             return true;
672                         }
673                     }
674
675                     return false;
676                 }
677
678                 public Object JavaDoc next() {
679                     if (!hasNext()) {
680                         throw new NoSuchElementException();
681                     }
682                     else {
683                         Object JavaDoc next = mNext;
684                         mNext = null;
685                         return next;
686                     }
687                 }
688
689                 public void remove() {
690                     mIterator.remove();
691                 }
692             };
693         }
694     }
695 }
696
Popular Tags