KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > MapFormat


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.util;
20
21 import java.text.DateFormat JavaDoc;
22 import java.text.FieldPosition JavaDoc;
23 import java.text.Format JavaDoc;
24 import java.text.MessageFormat JavaDoc;
25 import java.text.NumberFormat JavaDoc;
26 import java.text.ParsePosition JavaDoc;
27
28 import java.util.Date JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.Locale JavaDoc;
31 import java.util.Map JavaDoc;
32
33
34 /** A text format similar to <code>MessageFormat</code>
35  * but using string rather than numeric keys.
36  * You might use use this formatter like this:
37  * <pre>MapFormat.format("Hello {name}", map);</pre>
38  * Or to have more control over it:
39  * <pre>
40  * Map m = new HashMap ();
41  * m.put ("KEY", "value");
42  * MapFormat f = new MapFormat (m);
43  * f.setLeftBrace ("__");
44  * f.setRightBrace ("__");
45  * String result = f.format ("the __KEY__ here");
46  * </pre>
47  *
48  * @author Slavek Psenicka
49  * @see MessageFormat
50  */

51 public class MapFormat extends Format JavaDoc {
52     private static final int BUFSIZE = 255;
53
54     /** Array with to-be-skipped blocks */
55
56     //private RangeList skipped;
57
static final long serialVersionUID = -7695811542873819435L;
58
59     /** Locale region settings used for number and date formatting */
60     private Locale JavaDoc locale = Locale.getDefault();
61
62     /** Left delimiter */
63     private String JavaDoc ldel = "{"; // NOI18N
64

65     /** Right delimiter */
66     private String JavaDoc rdel = "}"; // NOI18N
67

68     /** Used formatting map */
69     private Map JavaDoc argmap;
70
71     /** Offsets to {} expressions */
72     private int[] offsets;
73
74     /** Keys enclosed by {} brackets */
75     private String JavaDoc[] arguments;
76
77     /** Max used offset */
78     private int maxOffset;
79
80     /** Should be thrown an exception if key was not found? */
81     private boolean throwex = false;
82
83     /** Exactly match brackets? */
84     private boolean exactmatch = true;
85
86     /**
87     * Constructor.
88     * For common work use <code>format(pattern, arguments) </code>.
89     * @param arguments keys and values to use in the format
90     */

91     public MapFormat(Map JavaDoc arguments) {
92         super();
93         setMap(arguments);
94     }
95
96     /**
97     * Designated method. It gets the string, initializes HashFormat object
98     * and returns converted string. It scans <code>pattern</code>
99     * for {} brackets, then parses enclosed string and replaces it
100     * with argument's <code>get()</code> value.
101     * @param pattern String to be parsed.
102     * @param arguments Map with key-value pairs to replace.
103     * @return Formatted string
104     */

105     public static String JavaDoc format(String JavaDoc pattern, Map JavaDoc arguments) {
106         MapFormat temp = new MapFormat(arguments);
107
108         return temp.format(pattern);
109     }
110
111     // unused so removed --jglick
112

113     /**
114     * Search for comments and quotation marks.
115     * Prepares internal structures.
116     * @param pattern String to be parsed.
117     * @param lmark Left mark of to-be-skipped block.
118     * @param rmark Right mark of to-be-skipped block or null if does not exist (// comment).
119     private void process(String pattern, String lmark, String rmark)
120     {
121         int idx = 0;
122         while (true) {
123             int ridx = -1, lidx = pattern.indexOf(lmark,idx);
124             if (lidx >= 0) {
125                 if (rmark != null) {
126                     ridx = pattern.indexOf(rmark,lidx + lmark.length());
127                 } else ridx = pattern.length();
128             } else break;
129             if (ridx >= 0) {
130                 skipped.put(new Range(lidx, ridx-lidx));
131                 if (rmark != null) idx = ridx+rmark.length();
132                 else break;
133             } else break;
134         }
135     }
136     */

137     /** Returns the value for given key. Subclass may define its own beahvior of
138     * this method. For example, if key is not defined, subclass can return <not defined>
139     * string.
140     *
141     * @param key Key.
142     * @return Value for this key.
143     */

144     protected Object JavaDoc processKey(String JavaDoc key) {
145         return argmap.get(key);
146     }
147
148     /**
149     * Scans the pattern and prepares internal variables.
150     * @param newPattern String to be parsed.
151     * @exception IllegalArgumentException if number of arguments exceeds BUFSIZE or
152     * parser found unmatched brackets (this exception should be switched off
153     * using setExactMatch(false)).
154     */

155     public String JavaDoc processPattern(String JavaDoc newPattern) throws IllegalArgumentException JavaDoc {
156         int idx = 0;
157         int offnum = -1;
158         StringBuffer JavaDoc outpat = new StringBuffer JavaDoc();
159         offsets = new int[BUFSIZE];
160         arguments = new String JavaDoc[BUFSIZE];
161         maxOffset = -1;
162
163         //skipped = new RangeList();
164
// What was this for??
165
//process(newPattern, "\"", "\""); // NOI18N
166
while (true) {
167             int ridx = -1;
168             int lidx = newPattern.indexOf(ldel, idx);
169
170             /*
171             Range ran = skipped.getRangeContainingOffset(lidx);
172             if (ran != null) {
173                 outpat.append(newPattern.substring(idx, ran.getEnd()));
174                 idx = ran.getEnd(); continue;
175             }
176              */

177             if (lidx >= 0) {
178                 ridx = newPattern.indexOf(rdel, lidx + ldel.length());
179             } else {
180                 break;
181             }
182
183             if (++offnum >= BUFSIZE) {
184                 throw new IllegalArgumentException JavaDoc(
185                     NbBundle.getBundle(MapFormat.class).getString("MSG_TooManyArguments")
186                 );
187             }
188
189             if (ridx < 0) {
190                 if (exactmatch) {
191                     throw new IllegalArgumentException JavaDoc(
192                         NbBundle.getBundle(MapFormat.class).getString("MSG_UnmatchedBraces") + " " + lidx
193                     );
194                 } else {
195                     break;
196                 }
197             }
198
199             outpat.append(newPattern.substring(idx, lidx));
200             offsets[offnum] = outpat.length();
201             arguments[offnum] = newPattern.substring(lidx + ldel.length(), ridx);
202             idx = ridx + rdel.length();
203             maxOffset++;
204         }
205
206         outpat.append(newPattern.substring(idx));
207
208         return outpat.toString();
209     }
210
211     /**
212     * Formats object.
213     * @param obj Object to be formatted into string
214     * @return Formatted object
215     */

216     private String JavaDoc formatObject(Object JavaDoc obj) {
217         if (obj == null) {
218             return null;
219         }
220
221         if (obj instanceof Number JavaDoc) {
222             return NumberFormat.getInstance(locale).format(obj); // fix
223
} else if (obj instanceof Date JavaDoc) {
224             return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale).format(obj); //fix
225
} else if (obj instanceof String JavaDoc) {
226             return (String JavaDoc) obj;
227         }
228
229         return obj.toString();
230     }
231
232     /**
233     * Formats the parsed string by inserting table's values.
234     * @param pat a string pattern
235     * @param result Buffer to be used for result.
236      * @param fpos position
237     * @return Formatted string
238     */

239     public StringBuffer JavaDoc format(Object JavaDoc pat, StringBuffer JavaDoc result, FieldPosition JavaDoc fpos) {
240         String JavaDoc pattern = processPattern((String JavaDoc) pat);
241         int lastOffset = 0;
242
243         for (int i = 0; i <= maxOffset; ++i) {
244             int offidx = offsets[i];
245             result.append(pattern.substring(lastOffset, offsets[i]));
246             lastOffset = offidx;
247
248             String JavaDoc key = arguments[i];
249             String JavaDoc obj;
250             if (key.length() > 0) {
251                 obj = formatObject(processKey(key));
252             } else {
253                 // else just copy the left and right braces
254
result.append(this.ldel);
255                 result.append(this.rdel);
256                 continue;
257             }
258
259             if (obj == null) {
260                 // try less-greedy match; useful for e.g. PROP___PROPNAME__ where
261
// 'PROPNAME' is a key and delims are both '__'
262
// this does not solve all possible cases, surely, but it should catch
263
// the most common ones
264
String JavaDoc lessgreedy = ldel + key;
265                 int fromright = lessgreedy.lastIndexOf(ldel);
266
267                 if (fromright > 0) {
268                     String JavaDoc newkey = lessgreedy.substring(fromright + ldel.length());
269                     String JavaDoc newsubst = formatObject(processKey(newkey));
270
271                     if (newsubst != null) {
272                         obj = lessgreedy.substring(0, fromright) + newsubst;
273                     }
274                 }
275             }
276
277             if (obj == null) {
278                 if (throwex) {
279                     throw new IllegalArgumentException JavaDoc(
280                         MessageFormat.format(
281                             NbBundle.getBundle(MapFormat.class).getString("MSG_FMT_ObjectForKey"),
282                             new Object JavaDoc[] { new Integer JavaDoc(key) }
283                         )
284                     );
285                 } else {
286                     obj = ldel + key + rdel;
287                 }
288             }
289
290             result.append(obj);
291         }
292
293         result.append(pattern.substring(lastOffset, pattern.length()));
294
295         return result;
296     }
297
298     /**
299     * Parses the string. Does not yet handle recursion (where
300     * the substituted strings contain %n references.)
301     */

302     public Object JavaDoc parseObject(String JavaDoc text, ParsePosition JavaDoc status) {
303         return parse(text);
304     }
305
306     /**
307     * Parses the string. Does not yet handle recursion (where
308     * the substituted strings contain {n} references.)
309     * @return New format.
310     */

311     public String JavaDoc parse(String JavaDoc source) {
312         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(source);
313         Iterator JavaDoc key_it = argmap.keySet().iterator();
314
315         //skipped = new RangeList();
316
// What was this for??
317
//process(source, "\"", "\""); // NOI18N
318
while (key_it.hasNext()) {
319             String JavaDoc it_key = (String JavaDoc) key_it.next();
320             String JavaDoc it_obj = formatObject(argmap.get(it_key));
321             int it_idx = -1;
322
323             do {
324                 it_idx = sbuf.toString().indexOf(it_obj, ++it_idx);
325
326                 if (it_idx >= 0 /* && !skipped.containsOffset(it_idx) */ ) {
327                     sbuf.replace(it_idx, it_idx + it_obj.length(), ldel + it_key + rdel);
328
329                     //skipped = new RangeList();
330
// What was this for??
331
//process(sbuf.toString(), "\"", "\""); // NOI18N
332
}
333             } while (it_idx != -1);
334         }
335
336         return sbuf.toString();
337     }
338
339     /** Test whether formatter will throw exception if object for key was not found.
340     * If given map does not contain object for key specified, it could
341     * throw an exception. Returns true if throws. If not, key is left unchanged.
342     */

343     public boolean willThrowExceptionIfKeyWasNotFound() {
344         return throwex;
345     }
346
347     /** Specify whether formatter will throw exception if object for key was not found.
348     * If given map does not contain object for key specified, it could
349     * throw an exception. If does not throw, key is left unchanged.
350     * @param flag If true, formatter throws IllegalArgumentException.
351     */

352     public void setThrowExceptionIfKeyWasNotFound(boolean flag) {
353         throwex = flag;
354     }
355
356     /** Test whether both brackets are required in the expression.
357     * If not, use setExactMatch(false) and formatter will ignore missing right
358     * bracket. Advanced feature.
359     */

360     public boolean isExactMatch() {
361         return exactmatch;
362     }
363
364     /** Specify whether both brackets are required in the expression.
365     * If not, use setExactMatch(false) and formatter will ignore missing right
366     * bracket. Advanced feature.
367     * @param flag If true, formatter will ignore missing right bracket (default = false)
368     */

369     public void setExactMatch(boolean flag) {
370         exactmatch = flag;
371     }
372
373     /** Returns string used as left brace */
374     public String JavaDoc getLeftBrace() {
375         return ldel;
376     }
377
378     /** Sets string used as left brace
379     * @param delimiter Left brace.
380     */

381     public void setLeftBrace(String JavaDoc delimiter) {
382         ldel = delimiter;
383     }
384
385     /** Returns string used as right brace */
386     public String JavaDoc getRightBrace() {
387         return rdel;
388     }
389
390     /** Sets string used as right brace
391     * @param delimiter Right brace.
392     */

393     public void setRightBrace(String JavaDoc delimiter) {
394         rdel = delimiter;
395     }
396
397     /** Returns argument map */
398     public Map JavaDoc getMap() {
399         return argmap;
400     }
401
402     /** Sets argument map
403     * This map should contain key-value pairs with key values used in
404     * formatted string expression. If value for key was not found, formatter leave
405     * key unchanged (except if you've set setThrowExceptionIfKeyWasNotFound(true),
406     * then it fires IllegalArgumentException.
407     *
408     * @param map the argument map
409     */

410     public void setMap(Map JavaDoc map) {
411         argmap = map;
412     }
413
414     // commented out because unused --jglick
415

416     /**
417     * Range of expression in string.
418     * Used internally to store information about quotation marks and comments
419     * in formatted string.
420     *
421     * @author Slavek Psenicka
422     * @version 1.0, March 11. 1999
423     *
424     class Range extends Object
425     {
426         /** Offset of expression *
427         private int offset;
428
429         /** Length of expression *
430         private int length;
431
432         /** Constructor *
433         public Range(int off, int len)
434         {
435             offset = off;
436             length = len;
437         }
438
439         /** Returns offset *
440         public int getOffset()
441         {
442             return offset;
443         }
444
445         /** Returns length of expression *
446         public int getLength()
447         {
448             return length;
449         }
450
451         /** Returns final position of expression *
452         public int getEnd()
453         {
454             return offset+length;
455         }
456
457         public String toString()
458         {
459             return "("+offset+", "+length+")"; // NOI18N
460         }
461     }
462
463     /**
464     * List of ranges.
465     * Used internally to store information about quotation marks and comments
466     * in formatted string.
467     *
468     * @author Slavek Psenicka
469     * @version 1.0, March 11. 1999
470     *
471     class RangeList
472     {
473         /** Map with Ranges *
474         private HashMap hmap;
475
476         /** Constructor *
477         public RangeList()
478         {
479             hmap = new HashMap();
480         }
481
482         /** Returns true if offset is enclosed by any Range object in list *
483         public boolean containsOffset(int offset)
484         {
485             return (getRangeContainingOffset(offset) != null);
486         }
487
488         /** Returns enclosing Range object in list for given offset *
489         public Range getRangeContainingOffset(int offset)
490         {
491             if (hmap.size() == 0) return null;
492             int offit = offset;
493             while (offit-- >= 0) {
494                 Integer off = new Integer(offit);
495                 if (hmap.containsKey(off)) {
496                     Range ran = (Range)hmap.get(off);
497                     if (ran.getEnd() - offset > 0) return ran;
498                 }
499             }
500
501             return null;
502         }
503
504         /** Puts new range into list *
505         public void put(Range range)
506         {
507             hmap.put(new Integer(range.getOffset()), range);
508         }
509
510         public String toString()
511         {
512             return hmap.toString();
513         }
514     }
515      */

516 }
517
Popular Tags