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:
383: public AttributedCharacterIterator formatToCharacterIterator (Object arguments)
384: {
385: Object[] arguments_array = (Object[])arguments;
386: FormatCharacterIterator iterator = new FormatCharacterIterator();
387:
388: formatInternal(arguments_array, new StringBuffer(), null, iterator);
389:
390: return iterator;
391: }
392:
393:
399: public static String format (String pattern, Object arguments[])
400: {
401: MessageFormat mf = new MessageFormat (pattern);
402: StringBuffer sb = new StringBuffer ();
403: FieldPosition fp = new FieldPosition (NumberFormat.INTEGER_FIELD);
404: return mf.formatInternal(arguments, sb, fp, null).toString();
405: }
406:
407:
414: public final StringBuffer format (Object arguments[], StringBuffer appendBuf,
415: FieldPosition fp)
416: {
417: return formatInternal(arguments, appendBuf, fp, null);
418: }
419:
420: private StringBuffer formatInternal (Object arguments[],
421: StringBuffer appendBuf,
422: FieldPosition fp,
423: FormatCharacterIterator output_iterator)
424: {
425: appendBuf.append(leader);
426: if (output_iterator != null)
427: output_iterator.append(leader);
428:
429: for (int i = 0; i < elements.length; ++i)
430: {
431: Object thisArg = null;
432: boolean unavailable = false;
433: if (arguments == null || elements[i].argNumber >= arguments.length)
434: unavailable = true;
435: else
436: thisArg = arguments[elements[i].argNumber];
437:
438: AttributedCharacterIterator iterator = null;
439:
440: Format formatter = null;
441:
442: if (fp != null && i == fp.getField() && fp.getFieldAttribute() == Field.ARGUMENT)
443: fp.setBeginIndex(appendBuf.length());
444:
445: if (unavailable)
446: appendBuf.append("{" + elements[i].argNumber + "}");
447: else
448: {
449: if (elements[i].setFormat != null)
450: formatter = elements[i].setFormat;
451: else if (elements[i].format != null)
452: {
453: if (elements[i].formatClass != null
454: && ! elements[i].formatClass.isInstance(thisArg))
455: throw new IllegalArgumentException("Wrong format class");
456:
457: formatter = elements[i].format;
458: }
459: else if (thisArg instanceof Number)
460: formatter = NumberFormat.getInstance(locale);
461: else if (thisArg instanceof Date)
462: formatter = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
463: else
464: appendBuf.append(thisArg);
465: }
466:
467: if (fp != null && fp.getField() == i && fp.getFieldAttribute() == Field.ARGUMENT)
468: fp.setEndIndex(appendBuf.length());
469:
470: if (formatter != null)
471: {
472:
473: if (formatter instanceof ChoiceFormat)
474: {
475: StringBuffer buf = new StringBuffer ();
476: formatter.format(thisArg, buf, fp);
477: MessageFormat mf = new MessageFormat ();
478: mf.setLocale(locale);
479: mf.applyPattern(buf.toString());
480: mf.format(arguments, appendBuf, fp);
481: }
482: else
483: {
484: if (output_iterator != null)
485: iterator = formatter.formatToCharacterIterator(thisArg);
486: else
487: formatter.format(thisArg, appendBuf, fp);
488: }
489:
490: elements[i].format = formatter;
491: }
492:
493: if (output_iterator != null)
494: {
495: HashMap hash_argument = new HashMap();
496: int position = output_iterator.getEndIndex();
497:
498: hash_argument.put (MessageFormat.Field.ARGUMENT,
499: new Integer(elements[i].argNumber));
500:
501:
502: if (iterator != null)
503: {
504: output_iterator.append(iterator);
505: output_iterator.addAttributes(hash_argument, position,
506: output_iterator.getEndIndex());
507: }
508: else
509: output_iterator.append(thisArg.toString(), hash_argument);
510:
511: output_iterator.append(elements[i].trailer);
512: }
513:
514: appendBuf.append(elements[i].trailer);
515: }
516:
517: return appendBuf;
518: }
519:
520:
529: public final StringBuffer format (Object objectArray, StringBuffer appendBuf,
530: FieldPosition fpos)
531: {
532: return format ((Object[])objectArray, appendBuf, fpos);
533: }
534:
535:
539: public Format[] getFormats ()
540: {
541: Format[] f = new Format[elements.length];
542: for (int i = elements.length - 1; i >= 0; --i)
543: f[i] = elements[i].setFormat;
544: return f;
545: }
546:
547:
550: public Locale getLocale ()
551: {
552: return locale;
553: }
554:
555:
558: public int hashCode ()
559: {
560:
561: return pattern.hashCode() + locale.hashCode();
562: }
563:
564: private MessageFormat ()
565: {
566: }
567:
568:
574: public MessageFormat(String pattern)
575: {
576: this(pattern, Locale.getDefault());
577: }
578:
579:
588: public MessageFormat(String pattern, Locale locale)
589: {
590: this.locale = locale;
591: applyPattern (pattern);
592: }
593:
594:
603: public Object[] parse (String sourceStr, ParsePosition pos)
604: {
605:
606: int index = pos.getIndex();
607: if (! sourceStr.startsWith(leader, index))
608: {
609: pos.setErrorIndex(index);
610: return null;
611: }
612: index += leader.length();
613:
614: Vector results = new Vector (elements.length, 1);
615:
616: for (int i = 0; i < elements.length; ++i)
617: {
618: Format formatter = null;
619: if (elements[i].setFormat != null)
620: formatter = elements[i].setFormat;
621: else if (elements[i].format != null)
622: formatter = elements[i].format;
623:
624: Object value = null;
625: if (formatter instanceof ChoiceFormat)
626: {
627:
628:
629: ChoiceFormat cf = (ChoiceFormat) formatter;
630: String[] formats = (String[]) cf.getFormats();
631: double[] limits = (double[]) cf.getLimits();
632: MessageFormat subfmt = new MessageFormat ();
633: subfmt.setLocale(locale);
634: ParsePosition subpos = new ParsePosition (index);
635:
636: int j;
637: for (j = 0; value == null && j < limits.length; ++j)
638: {
639: subfmt.applyPattern(formats[j]);
640: subpos.setIndex(index);
641: value = subfmt.parse(sourceStr, subpos);
642: }
643: if (value != null)
644: {
645: index = subpos.getIndex();
646: value = new Double (limits[j]);
647: }
648: }
649: else if (formatter != null)
650: {
651: pos.setIndex(index);
652: value = formatter.parseObject(sourceStr, pos);
653: if (value != null)
654: index = pos.getIndex();
655: }
656: else
657: {
658:
659:
660: int next_index;
661: if (elements[i].trailer.length() > 0)
662: next_index = sourceStr.indexOf(elements[i].trailer, index);
663: else
664: next_index = sourceStr.length();
665: if (next_index == -1)
666: {
667: pos.setErrorIndex(index);
668: return null;
669: }
670: value = sourceStr.substring(index, next_index);
671: index = next_index;
672: }
673:
674: if (value == null
675: || ! sourceStr.startsWith(elements[i].trailer, index))
676: {
677: pos.setErrorIndex(index);
678: return null;
679: }
680:
681: if (elements[i].argNumber >= results.size())
682: results.setSize(elements[i].argNumber + 1);
683: results.setElementAt(value, elements[i].argNumber);
684:
685: index += elements[i].trailer.length();
686: }
687:
688: Object[] r = new Object[results.size()];
689: results.copyInto(r);
690: return r;
691: }
692:
693: public Object[] parse (String sourceStr) throws ParseException
694: {
695: ParsePosition pp = new ParsePosition (0);
696: Object[] r = parse (sourceStr, pp);
697: if (r == null)
698: throw new ParseException ("couldn't parse string", pp.getErrorIndex());
699: return r;
700: }
701:
702: public Object parseObject (String sourceStr, ParsePosition pos)
703: {
704: return parse (sourceStr, pos);
705: }
706:
707:
714: public void setFormat (int variableNum, Format newFormat)
715: {
716: elements[variableNum].setFormat = newFormat;
717: }
718:
719:
724: public void setFormats (Format[] newFormats)
725: {
726: if (newFormats.length < elements.length)
727: throw new IllegalArgumentException("Not enough format objects");
728:
729: int len = Math.min(newFormats.length, elements.length);
730: for (int i = 0; i < len; ++i)
731: elements[i].setFormat = newFormats[i];
732: }
733:
734:
739: public void setLocale (Locale loc)
740: {
741: locale = loc;
742: if (elements != null)
743: {
744: for (int i = 0; i < elements.length; ++i)
745: elements[i].setLocale(loc);
746: }
747: }
748:
749:
752: public String toPattern ()
753: {
754: return pattern;
755: }
756:
757:
769: public Format[] getFormatsByArgumentIndex()
770: {
771: int argNumMax = 0;
772:
773: for (int i=0;i<elements.length;i++)
774: if (elements[i].argNumber > argNumMax)
775: argNumMax = elements[i].argNumber;
776:
777: Format[] formats = new Format[argNumMax];
778: for (int i=0;i<elements.length;i++)
779: {
780: if (elements[i].setFormat != null)
781: formats[elements[i].argNumber] = elements[i].setFormat;
782: else if (elements[i].format != null)
783: formats[elements[i].argNumber] = elements[i].format;
784: }
785: return formats;
786: }
787:
788:
794: public void setFormatByArgumentIndex(int argumentIndex,
795: Format newFormat)
796: {
797: for (int i=0;i<elements.length;i++)
798: {
799: if (elements[i].argNumber == argumentIndex)
800: elements[i].setFormat = newFormat;
801: }
802: }
803:
804:
814: public void setFormatsByArgumentIndex(Format[] newFormats)
815: {
816: for (int i=0;i<newFormats.length;i++)
817: {
818:
819: setFormatByArgumentIndex(i, newFormats[i]);
820: }
821: }
822:
823:
824: private String pattern;
825:
826: private Locale locale;
827:
828: private MessageFormatElement[] elements;
829:
830: private String leader;
831: }