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