1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48:
49: public class MessageFormat extends Format
50: {
51:
56:
61: private static final class MessageFormatElement
62: {
63:
64: int argNumber;
65:
66: Format setFormat;
67:
68: Format format;
69:
70:
71:
72: Class formatClass;
73:
74:
75: String type;
76:
77: String style;
78:
79:
80: String trailer;
81:
82:
83: void setLocale (Locale loc)
84: {
85: if (type != null)
86: {
87: if (type.equals("number"))
88: {
89: formatClass = java.lang.Number.class;
90:
91: if (style == null)
92: format = NumberFormat.getInstance(loc);
93: else if (style.equals("currency"))
94: format = NumberFormat.getCurrencyInstance(loc);
95: else if (style.equals("percent"))
96: format = NumberFormat.getPercentInstance(loc);
97: else if (style.equals("integer"))
98: {
99: NumberFormat nf = NumberFormat.getNumberInstance(loc);
100: nf.setMaximumFractionDigits(0);
101: nf.setGroupingUsed(false);
102: format = nf;
103: }
104: else
105: {
106: format = NumberFormat.getNumberInstance(loc);
107: DecimalFormat df = (DecimalFormat) format;
108: df.applyPattern(style);
109: }
110: }
111: else if (type.equals("time") || type.equals("date"))
112: {
113: formatClass = java.util.Date.class;
114:
115: int val = DateFormat.DEFAULT;
116: boolean styleIsPattern = false;
117: if (style != null)
118: {
119: if (style.equals("short"))
120: val = DateFormat.SHORT;
121: else if (style.equals("medium"))
122: val = DateFormat.MEDIUM;
123: else if (style.equals("long"))
124: val = DateFormat.LONG;
125: else if (style.equals("full"))
126: val = DateFormat.FULL;
127: else
128: styleIsPattern = true;
129: }
130:
131: if (type.equals("time"))
132: format = DateFormat.getTimeInstance(val, loc);
133: else
134: format = DateFormat.getDateInstance(val, loc);
135:
136: if (styleIsPattern)
137: {
138: SimpleDateFormat sdf = (SimpleDateFormat) format;
139: sdf.applyPattern(style);
140: }
141: }
142: else if (type.equals("choice"))
143: {
144: formatClass = java.lang.Number.class;
145:
146: if (style == null)
147: throw new
148: IllegalArgumentException ("style required for choice format");
149: format = new ChoiceFormat (style);
150: }
151: }
152: }
153: }
154:
155: private static final long serialVersionUID = 6479157306784022952L;
156:
157: public static class Field extends Format.Field
158: {
159: static final long serialVersionUID = 7899943957617360810L;
160:
161:
165: public static final MessageFormat.Field ARGUMENT = new MessageFormat.Field("argument");
166:
167:
168: private Field()
169: {
170: super("");
171: }
172:
173: protected Field(String s)
174: {
175: super(s);
176: }
177:
178:
184: protected Object readResolve() throws InvalidObjectException
185: {
186: if (getName().equals(ARGUMENT.getName()))
187: return ARGUMENT;
188:
189: throw new InvalidObjectException("no such MessageFormat field called " + getName());
190: }
191:
192: }
193:
194:
195:
196:
197: private static int scanString(String pat, int index, StringBuffer buffer)
198: {
199: int max = pat.length();
200: buffer.setLength(0);
201: boolean quoted = false;
202: for (; index < max; ++index)
203: {
204: char c = pat.charAt(index);
205: if (quoted)
206: {
207:
208: if (c == '\'')
209: quoted = false;
210: else
211: buffer.append(c);
212: }
213:
214: else if (c == '\'' && index + 1 < max && pat.charAt(index + 1) == '\'')
215: {
216: buffer.append(c);
217: ++index;
218: }
219: else if (c == '\'')
220: {
221:
222: quoted = true;
223: }
224: else if (c == '{')
225: break;
226: else
227: buffer.append(c);
228: }
229:
230:
231: return index;
232: }
233:
234:
235:
236: private static int scanFormatElement(String pat, int index,
237: StringBuffer buffer, char term)
238: {
239: int max = pat.length();
240: buffer.setLength(0);
241: int brace_depth = 1;
242: boolean quoted = false;
243:
244: for (; index < max; ++index)
245: {
246: char c = pat.charAt(index);
247:
248: if (quoted)
249: {
250: if (c == '\'')
251: quoted = false;
252:
253:
254: }
255:
256: else if (c == '\'' && index + 1 < max
257: && pat.charAt(index + 1) == '\'')
258: {
259: buffer.append(c);
260: ++index;
261: }
262:
263: else if (c == '\'')
264: quoted = true;
265: else if (c == '{')
266: ++brace_depth;
267: else if (c == '}')
268: {
269: if (--brace_depth == 0)
270: break;
271: }
272:
273: else if (c == term)
274: break;
275:
276:
277: buffer.append(c);
278: }
279: return index;
280: }
281:
282:
283:
284: private static int scanFormat(String pat, int index, StringBuffer buffer,
285: Vector elts, Locale locale)
286: {
287: MessageFormatElement mfe = new MessageFormatElement ();
288: elts.addElement(mfe);
289:
290: int max = pat.length();
291:
292:
293: ++index;
294:
295:
296: index = scanFormatElement (pat, index, buffer, ',');
297: try
298: {
299: mfe.argNumber = Integer.parseInt(buffer.toString());
300: }
301: catch (NumberFormatException nfx)
302: {
303: IllegalArgumentException iae = new IllegalArgumentException(pat);
304: iae.initCause(nfx);
305: throw iae;
306: }
307:
308:
309: if (index < max && pat.charAt(index) == ',')
310: {
311: index = scanFormatElement (pat, index + 1, buffer, ',');
312: mfe.type = buffer.toString();
313:
314:
315: if (index < max && pat.charAt(index) == ',')
316: {
317: index = scanFormatElement (pat, index + 1, buffer, '}');
318: mfe.style = buffer.toString ();
319: }
320: }
321:
322:
323: if (index >= max || pat.charAt(index) != '}')
324: throw new IllegalArgumentException("Missing '}' at end of message format");
325: ++index;
326:
327:
328: index = scanString (pat, index, buffer);
329: mfe.trailer = buffer.toString ();
330:
331: mfe.setLocale(locale);
332:
333: return index;
334: }
335:
336:
341: public void applyPattern (String newPattern)
342: {
343: pattern = newPattern;
344:
345: StringBuffer tempBuffer = new StringBuffer ();
346:
347: int index = scanString (newPattern, 0, tempBuffer);
348: leader = tempBuffer.toString();
349:
350: Vector elts = new Vector ();
351: while (index < newPattern.length())
352: index = scanFormat (newPattern, index, tempBuffer, elts, locale);
353:
354: elements = new MessageFormatElement[elts.size()];
355: elts.copyInto(elements);
356: }
357:
358:
361: public Object clone ()
362: {
363: MessageFormat c = (MessageFormat) super.clone ();
364: c.elements = (MessageFormatElement[]) elements.clone ();
365: return c;
366: }
367:
368:
371: public boolean equals (Object obj)
372: {
373: if (! (obj instanceof MessageFormat))
374: return false;
375: MessageFormat mf = (MessageFormat) obj;
376: return (pattern.equals(mf.pattern)
377: && locale.equals(mf.locale));
378: }
379:
380:
385: public AttributedCharacterIterator formatToCharacterIterator (Object arguments)
386: {
387: Object[] arguments_array = (Object[])arguments;
388: FormatCharacterIterator iterator = new FormatCharacterIterator();
389:
390: formatInternal(arguments_array, new StringBuffer(), null, iterator);
391:
392: return iterator;
393: }
394:
395:
401: public static String format (String pattern, Object... arguments)
402: {
403: MessageFormat mf = new MessageFormat (pattern);
404: StringBuffer sb = new StringBuffer ();
405: FieldPosition fp = new FieldPosition (NumberFormat.INTEGER_FIELD);
406: return mf.formatInternal(arguments, sb, fp, null).toString();
407: }
408:
409:
416: public final StringBuffer format (Object arguments[], StringBuffer appendBuf,
417: FieldPosition fp)
418: {
419: return formatInternal(arguments, appendBuf, fp, null);
420: }
421:
422: private StringBuffer formatInternal (Object arguments[],
423: StringBuffer appendBuf,
424: FieldPosition fp,
425: FormatCharacterIterator output_iterator)
426: {
427: appendBuf.append(leader);
428: if (output_iterator != null)
429: output_iterator.append(leader);
430:
431: for (int i = 0; i < elements.length; ++i)
432: {
433: Object thisArg = null;
434: boolean unavailable = false;
435: if (arguments == null || elements[i].argNumber >= arguments.length)
436: unavailable = true;
437: else
438: thisArg = arguments[elements[i].argNumber];
439:
440: AttributedCharacterIterator iterator = null;
441:
442: Format formatter = null;
443:
444: if (fp != null && i == fp.getField() && fp.getFieldAttribute() == Field.ARGUMENT)
445: fp.setBeginIndex(appendBuf.length());
446:
447: if (unavailable)
448: appendBuf.append("{" + elements[i].argNumber + "}");
449: else
450: {
451: if (elements[i].setFormat != null)
452: formatter = elements[i].setFormat;
453: else if (elements[i].format != null)
454: {
455: if (elements[i].formatClass != null
456: && ! elements[i].formatClass.isInstance(thisArg))
457: throw new IllegalArgumentException("Wrong format class");
458:
459: formatter = elements[i].format;
460: }
461: else if (thisArg instanceof Number)
462: formatter = NumberFormat.getInstance(locale);
463: else if (thisArg instanceof Date)
464: formatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
465: else
466: appendBuf.append(thisArg);
467: }
468:
469: if (fp != null && fp.getField() == i && fp.getFieldAttribute() == Field.ARGUMENT)
470: fp.setEndIndex(appendBuf.length());
471:
472: if (formatter != null)
473: {
474:
475: if (formatter instanceof ChoiceFormat)
476: {
477: StringBuffer buf = new StringBuffer ();
478: formatter.format(thisArg, buf, fp);
479: MessageFormat mf = new MessageFormat ();
480: mf.setLocale(locale);
481: mf.applyPattern(buf.toString());
482: mf.format(arguments, appendBuf, fp);
483: }
484: else
485: {
486: if (output_iterator != null)
487: iterator = formatter.formatToCharacterIterator(thisArg);
488: else
489: formatter.format(thisArg, appendBuf, fp);
490: }
491:
492: elements[i].format = formatter;
493: }
494:
495: if (output_iterator != null)
496: {
497: HashMap hash_argument = new HashMap();
498: int position = output_iterator.getEndIndex();
499:
500: hash_argument.put (MessageFormat.Field.ARGUMENT,
501: new Integer(elements[i].argNumber));
502:
503:
504: if (iterator != null)
505: {
506: output_iterator.append(iterator);
507: output_iterator.addAttributes(hash_argument, position,
508: output_iterator.getEndIndex());
509: }
510: else
511: output_iterator.append(thisArg.toString(), hash_argument);
512:
513: output_iterator.append(elements[i].trailer);
514: }
515:
516: appendBuf.append(elements[i].trailer);
517: }
518:
519: return appendBuf;
520: }
521:
522:
531: public final StringBuffer format (Object objectArray, StringBuffer appendBuf,
532: FieldPosition fpos)
533: {
534: return format ((Object[])objectArray, appendBuf, fpos);
535: }
536:
537:
541: public Format[] getFormats ()
542: {
543: Format[] f = new Format[elements.length];
544: for (int i = elements.length - 1; i >= 0; --i)
545: f[i] = elements[i].setFormat;
546: return f;
547: }
548:
549:
552: public Locale getLocale ()
553: {
554: return locale;
555: }
556:
557:
560: public int hashCode ()
561: {
562:
563: return pattern.hashCode() + locale.hashCode();
564: }
565:
566: private MessageFormat ()
567: {
568: }
569:
570:
576: public MessageFormat(String pattern)
577: {
578: this(pattern, Locale.getDefault());
579: }
580:
581:
590: public MessageFormat(String pattern, Locale locale)
591: {
592: this.locale = locale;
593: applyPattern (pattern);
594: }
595:
596:
605: public Object[] parse (String sourceStr, ParsePosition pos)
606: {
607:
608: int index = pos.getIndex();
609: if (! sourceStr.startsWith(leader, index))
610: {
611: pos.setErrorIndex(index);
612: return null;
613: }
614: index += leader.length();
615:
616: Vector results = new Vector (elements.length, 1);
617:
618: for (int i = 0; i < elements.length; ++i)
619: {
620: Format formatter = null;
621: if (elements[i].setFormat != null)
622: formatter = elements[i].setFormat;
623: else if (elements[i].format != null)
624: formatter = elements[i].format;
625:
626: Object value = null;
627: if (formatter instanceof ChoiceFormat)
628: {
629:
630:
631: ChoiceFormat cf = (ChoiceFormat) formatter;
632: String[] formats = (String[]) cf.getFormats();
633: double[] limits = (double[]) cf.getLimits();
634: MessageFormat subfmt = new MessageFormat ();
635: subfmt.setLocale(locale);
636: ParsePosition subpos = new ParsePosition (index);
637:
638: int j;
639: for (j = 0; value == null && j < limits.length; ++j)
640: {
641: subfmt.applyPattern(formats[j]);
642: subpos.setIndex(index);
643: value = subfmt.parse(sourceStr, subpos);
644: }
645: if (value != null)
646: {
647: index = subpos.getIndex();
648: value = new Double (limits[j]);
649: }
650: }
651: else if (formatter != null)
652: {
653: pos.setIndex(index);
654: value = formatter.parseObject(sourceStr, pos);
655: if (value != null)
656: index = pos.getIndex();
657: }
658: else
659: {
660:
661:
662: int next_index;
663: if (elements[i].trailer.length() > 0)
664: next_index = sourceStr.indexOf(elements[i].trailer, index);
665: else
666: next_index = sourceStr.length();
667: if (next_index == -1)
668: {
669: pos.setErrorIndex(index);
670: return null;
671: }
672: value = sourceStr.substring(index, next_index);
673: index = next_index;
674: }
675:
676: if (value == null
677: || ! sourceStr.startsWith(elements[i].trailer, index))
678: {
679: pos.setErrorIndex(index);
680: return null;
681: }
682:
683: if (elements[i].argNumber >= results.size())
684: results.setSize(elements[i].argNumber + 1);
685: results.setElementAt(value, elements[i].argNumber);
686:
687: index += elements[i].trailer.length();
688: }
689:
690: Object[] r = new Object[results.size()];
691: results.copyInto(r);
692: return r;
693: }
694:
695: public Object[] parse (String sourceStr) throws ParseException
696: {
697: ParsePosition pp = new ParsePosition (0);
698: Object[] r = parse (sourceStr, pp);
699: if (r == null)
700: throw new ParseException ("couldn't parse string", pp.getErrorIndex());
701: return r;
702: }
703:
704: public Object parseObject (String sourceStr, ParsePosition pos)
705: {
706: return parse (sourceStr, pos);
707: }
708:
709:
716: public void setFormat (int variableNum, Format newFormat)
717: {
718: elements[variableNum].setFormat = newFormat;
719: }
720:
721:
726: public void setFormats (Format[] newFormats)
727: {
728: if (newFormats.length < elements.length)
729: throw new IllegalArgumentException("Not enough format objects");
730:
731: int len = Math.min(newFormats.length, elements.length);
732: for (int i = 0; i < len; ++i)
733: elements[i].setFormat = newFormats[i];
734: }
735:
736:
741: public void setLocale (Locale loc)
742: {
743: locale = loc;
744: if (elements != null)
745: {
746: for (int i = 0; i < elements.length; ++i)
747: elements[i].setLocale(loc);
748: }
749: }
750:
751:
754: public String toPattern ()
755: {
756: return pattern;
757: }
758:
759:
771: public Format[] getFormatsByArgumentIndex()
772: {
773: int argNumMax = 0;
774:
775: for (int i=0;i<elements.length;i++)
776: if (elements[i].argNumber > argNumMax)
777: argNumMax = elements[i].argNumber;
778:
779: Format[] formats = new Format[argNumMax];
780: for (int i=0;i<elements.length;i++)
781: {
782: if (elements[i].setFormat != null)
783: formats[elements[i].argNumber] = elements[i].setFormat;
784: else if (elements[i].format != null)
785: formats[elements[i].argNumber] = elements[i].format;
786: }
787: return formats;
788: }
789:
790:
796: public void setFormatByArgumentIndex(int argumentIndex,
797: Format newFormat)
798: {
799: for (int i=0;i<elements.length;i++)
800: {
801: if (elements[i].argNumber == argumentIndex)
802: elements[i].setFormat = newFormat;
803: }
804: }
805:
806:
816: public void setFormatsByArgumentIndex(Format[] newFormats)
817: {
818: for (int i=0;i<newFormats.length;i++)
819: {
820:
821: setFormatByArgumentIndex(i, newFormats[i]);
822: }
823: }
824:
825:
826: private String pattern;
827:
828: private Locale locale;
829:
830: private MessageFormatElement[] elements;
831:
832: private String leader;
833: }