1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44:
45: import ;
46:
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52:
53: public class MessageFormat extends Format
54: {
55:
60:
65: private static final class MessageFormatElement
66: {
67:
68: int argNumber;
69:
70: Format setFormat;
71:
72: Format format;
73:
74:
75:
76: Class<?> formatClass;
77:
78:
79: String type;
80:
81: String style;
82:
83:
84: String trailer;
85:
86:
87: void setLocale (Locale loc)
88: {
89: if (type != null)
90: {
91: if (type.equals("number"))
92: {
93: formatClass = java.lang.Number.class;
94:
95: if (style == null)
96: format = NumberFormat.getInstance(loc);
97: else if (style.equals("currency"))
98: format = NumberFormat.getCurrencyInstance(loc);
99: else if (style.equals("percent"))
100: format = NumberFormat.getPercentInstance(loc);
101: else if (style.equals("integer"))
102: format = NumberFormat.getIntegerInstance(loc);
103: else
104: {
105: format = NumberFormat.getNumberInstance(loc);
106: DecimalFormat df = (DecimalFormat) format;
107: df.applyPattern(style);
108: }
109: }
110: else if (type.equals("time") || type.equals("date"))
111: {
112: formatClass = java.util.Date.class;
113:
114: int val = DateFormat.DEFAULT;
115: boolean styleIsPattern = false;
116: if (style != null)
117: {
118: if (style.equals("short"))
119: val = DateFormat.SHORT;
120: else if (style.equals("medium"))
121: val = DateFormat.MEDIUM;
122: else if (style.equals("long"))
123: val = DateFormat.LONG;
124: else if (style.equals("full"))
125: val = DateFormat.FULL;
126: else
127: styleIsPattern = true;
128: }
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:
154: private static final long serialVersionUID = 6479157306784022952L;
155:
156: public static class Field extends Format.Field
157: {
158: static final long serialVersionUID = 7899943957617360810L;
159:
160:
164: public static final MessageFormat.Field ARGUMENT = new MessageFormat.Field("argument");
165:
166:
167: @SuppressWarnings("unused")
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, CPStringBuilder 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: CPStringBuilder 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, CPStringBuilder buffer,
285: List<MessageFormatElement> elts, Locale locale)
286: {
287: MessageFormatElement mfe = new MessageFormatElement ();
288: elts.add(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: CPStringBuilder tempBuffer = new CPStringBuilder ();
346:
347: int index = scanString (newPattern, 0, tempBuffer);
348: leader = tempBuffer.toString();
349:
350: List<MessageFormatElement> elts = new ArrayList<MessageFormatElement>();
351: while (index < newPattern.length())
352: index = scanFormat (newPattern, index, tempBuffer, elts, locale);
353:
354: elements = elts.toArray(new MessageFormatElement[elts.size()]);
355: }
356:
357:
360: public Object clone ()
361: {
362: MessageFormat c = (MessageFormat) super.clone ();
363: c.elements = (MessageFormatElement[]) elements.clone ();
364: return c;
365: }
366:
367:
370: public boolean equals (Object obj)
371: {
372: if (! (obj instanceof MessageFormat))
373: return false;
374: MessageFormat mf = (MessageFormat) obj;
375: return (pattern.equals(mf.pattern)
376: && locale.equals(mf.locale));
377: }
378:
379:
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<MessageFormat.Field, Integer> hash_argument =
497: new HashMap<MessageFormat.Field, Integer>();
498: int position = output_iterator.getEndIndex();
499:
500: hash_argument.put (MessageFormat.Field.ARGUMENT,
501: Integer.valueOf(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: ArrayList<Object> results = new ArrayList<Object>(elements.length);
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 = 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: {
685:
686: results.ensureCapacity(elements[i].argNumber + 1);
687: for (int a = results.size(); a <= elements[i].argNumber; ++a)
688: results.add(a, null);
689: }
690: results.set(elements[i].argNumber, value);
691:
692: index += elements[i].trailer.length();
693: }
694:
695: return results.toArray(new Object[results.size()]);
696: }
697:
698: public Object[] parse (String sourceStr) throws ParseException
699: {
700: ParsePosition pp = new ParsePosition (0);
701: Object[] r = parse (sourceStr, pp);
702: if (r == null)
703: throw new ParseException ("couldn't parse string", pp.getErrorIndex());
704: return r;
705: }
706:
707: public Object parseObject (String sourceStr, ParsePosition pos)
708: {
709: return parse (sourceStr, pos);
710: }
711:
712:
719: public void setFormat (int variableNum, Format newFormat)
720: {
721: elements[variableNum].setFormat = newFormat;
722: }
723:
724:
729: public void setFormats (Format[] newFormats)
730: {
731: if (newFormats.length < elements.length)
732: throw new IllegalArgumentException("Not enough format objects");
733:
734: int len = Math.min(newFormats.length, elements.length);
735: for (int i = 0; i < len; ++i)
736: elements[i].setFormat = newFormats[i];
737: }
738:
739:
744: public void setLocale (Locale loc)
745: {
746: locale = loc;
747: if (elements != null)
748: {
749: for (int i = 0; i < elements.length; ++i)
750: elements[i].setLocale(loc);
751: }
752: }
753:
754:
757: public String toPattern ()
758: {
759: return pattern;
760: }
761:
762:
774: public Format[] getFormatsByArgumentIndex()
775: {
776: int argNumMax = 0;
777:
778: for (int i=0;i<elements.length;i++)
779: if (elements[i].argNumber > argNumMax)
780: argNumMax = elements[i].argNumber;
781:
782: Format[] formats = new Format[argNumMax];
783: for (int i=0;i<elements.length;i++)
784: {
785: if (elements[i].setFormat != null)
786: formats[elements[i].argNumber] = elements[i].setFormat;
787: else if (elements[i].format != null)
788: formats[elements[i].argNumber] = elements[i].format;
789: }
790: return formats;
791: }
792:
793:
799: public void setFormatByArgumentIndex(int argumentIndex,
800: Format newFormat)
801: {
802: for (int i=0;i<elements.length;i++)
803: {
804: if (elements[i].argNumber == argumentIndex)
805: elements[i].setFormat = newFormat;
806: }
807: }
808:
809:
819: public void setFormatsByArgumentIndex(Format[] newFormats)
820: {
821: for (int i=0;i<newFormats.length;i++)
822: {
823:
824: setFormatByArgumentIndex(i, newFormats[i]);
825: }
826: }
827:
828:
829: private String pattern;
830:
831: private Locale locale;
832:
833: private MessageFormatElement[] elements;
834:
835: private String leader;
836: }