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: private Field()
168: {
169: super("");
170: }
171:
172: protected Field(String s)
173: {
174: super(s);
175: }
176:
177:
183: protected Object readResolve() throws InvalidObjectException
184: {
185: if (getName().equals(ARGUMENT.getName()))
186: return ARGUMENT;
187:
188: throw new InvalidObjectException("no such MessageFormat field called " + getName());
189: }
190:
191: }
192:
193:
194:
195:
196: private static int scanString(String pat, int index, CPStringBuilder buffer)
197: {
198: int max = pat.length();
199: buffer.setLength(0);
200: boolean quoted = false;
201: for (; index < max; ++index)
202: {
203: char c = pat.charAt(index);
204: if (quoted)
205: {
206:
207: if (c == '\'')
208: quoted = false;
209: else
210: buffer.append(c);
211: }
212:
213: else if (c == '\'' && index + 1 < max && pat.charAt(index + 1) == '\'')
214: {
215: buffer.append(c);
216: ++index;
217: }
218: else if (c == '\'')
219: {
220:
221: quoted = true;
222: }
223: else if (c == '{')
224: break;
225: else
226: buffer.append(c);
227: }
228:
229:
230: return index;
231: }
232:
233:
234:
235: private static int scanFormatElement(String pat, int index,
236: CPStringBuilder buffer, char term)
237: {
238: int max = pat.length();
239: buffer.setLength(0);
240: int brace_depth = 1;
241: boolean quoted = false;
242:
243: for (; index < max; ++index)
244: {
245: char c = pat.charAt(index);
246:
247: if (quoted)
248: {
249: if (c == '\'')
250: quoted = false;
251:
252:
253: }
254:
255: else if (c == '\'' && index + 1 < max
256: && pat.charAt(index + 1) == '\'')
257: {
258: buffer.append(c);
259: ++index;
260: }
261:
262: else if (c == '\'')
263: quoted = true;
264: else if (c == '{')
265: ++brace_depth;
266: else if (c == '}')
267: {
268: if (--brace_depth == 0)
269: break;
270: }
271:
272: else if (c == term)
273: break;
274:
275:
276: buffer.append(c);
277: }
278: return index;
279: }
280:
281:
282:
283: private static int scanFormat(String pat, int index, CPStringBuilder buffer,
284: List<MessageFormatElement> elts, Locale locale)
285: {
286: MessageFormatElement mfe = new MessageFormatElement ();
287: elts.add(mfe);
288:
289: int max = pat.length();
290:
291:
292: ++index;
293:
294:
295: index = scanFormatElement (pat, index, buffer, ',');
296: try
297: {
298: mfe.argNumber = Integer.parseInt(buffer.toString());
299: }
300: catch (NumberFormatException nfx)
301: {
302: IllegalArgumentException iae = new IllegalArgumentException(pat);
303: iae.initCause(nfx);
304: throw iae;
305: }
306:
307:
308: if (index < max && pat.charAt(index) == ',')
309: {
310: index = scanFormatElement (pat, index + 1, buffer, ',');
311: mfe.type = buffer.toString();
312:
313:
314: if (index < max && pat.charAt(index) == ',')
315: {
316: index = scanFormatElement (pat, index + 1, buffer, '}');
317: mfe.style = buffer.toString ();
318: }
319: }
320:
321:
322: if (index >= max || pat.charAt(index) != '}')
323: throw new IllegalArgumentException("Missing '}' at end of message format");
324: ++index;
325:
326:
327: index = scanString (pat, index, buffer);
328: mfe.trailer = buffer.toString ();
329:
330: mfe.setLocale(locale);
331:
332: return index;
333: }
334:
335:
340: public void applyPattern (String newPattern)
341: {
342: pattern = newPattern;
343:
344: CPStringBuilder tempBuffer = new CPStringBuilder ();
345:
346: int index = scanString (newPattern, 0, tempBuffer);
347: leader = tempBuffer.toString();
348:
349: List<MessageFormatElement> elts = new ArrayList<MessageFormatElement>();
350: while (index < newPattern.length())
351: index = scanFormat (newPattern, index, tempBuffer, elts, locale);
352:
353: elements = elts.toArray(new MessageFormatElement[elts.size()]);
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<MessageFormat.Field, Integer> hash_argument =
496: new HashMap<MessageFormat.Field, Integer>();
497: int position = output_iterator.getEndIndex();
498:
499: hash_argument.put (MessageFormat.Field.ARGUMENT,
500: Integer.valueOf(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: ArrayList<Object> results = new ArrayList<Object>(elements.length);
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 = 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: {
684:
685: results.ensureCapacity(elements[i].argNumber + 1);
686: for (int a = results.size(); a <= elements[i].argNumber; ++a)
687: results.add(a, null);
688: }
689: results.set(elements[i].argNumber, value);
690:
691: index += elements[i].trailer.length();
692: }
693:
694: return results.toArray(new Object[results.size()]);
695: }
696:
697: public Object[] parse (String sourceStr) throws ParseException
698: {
699: ParsePosition pp = new ParsePosition (0);
700: Object[] r = parse (sourceStr, pp);
701: if (r == null)
702: throw new ParseException ("couldn't parse string", pp.getErrorIndex());
703: return r;
704: }
705:
706: public Object parseObject (String sourceStr, ParsePosition pos)
707: {
708: return parse (sourceStr, pos);
709: }
710:
711:
718: public void setFormat (int variableNum, Format newFormat)
719: {
720: elements[variableNum].setFormat = newFormat;
721: }
722:
723:
728: public void setFormats (Format[] newFormats)
729: {
730: if (newFormats.length < elements.length)
731: throw new IllegalArgumentException("Not enough format objects");
732:
733: int len = Math.min(newFormats.length, elements.length);
734: for (int i = 0; i < len; ++i)
735: elements[i].setFormat = newFormats[i];
736: }
737:
738:
743: public void setLocale (Locale loc)
744: {
745: locale = loc;
746: if (elements != null)
747: {
748: for (int i = 0; i < elements.length; ++i)
749: elements[i].setLocale(loc);
750: }
751: }
752:
753:
756: public String toPattern ()
757: {
758: return pattern;
759: }
760:
761:
773: public Format[] getFormatsByArgumentIndex()
774: {
775: int argNumMax = 0;
776:
777: for (int i=0;i<elements.length;i++)
778: if (elements[i].argNumber > argNumMax)
779: argNumMax = elements[i].argNumber;
780:
781: Format[] formats = new Format[argNumMax];
782: for (int i=0;i<elements.length;i++)
783: {
784: if (elements[i].setFormat != null)
785: formats[elements[i].argNumber] = elements[i].setFormat;
786: else if (elements[i].format != null)
787: formats[elements[i].argNumber] = elements[i].format;
788: }
789: return formats;
790: }
791:
792:
798: public void setFormatByArgumentIndex(int argumentIndex,
799: Format newFormat)
800: {
801: for (int i=0;i<elements.length;i++)
802: {
803: if (elements[i].argNumber == argumentIndex)
804: elements[i].setFormat = newFormat;
805: }
806: }
807:
808:
818: public void setFormatsByArgumentIndex(Format[] newFormats)
819: {
820: for (int i=0;i<newFormats.length;i++)
821: {
822:
823: setFormatByArgumentIndex(i, newFormats[i]);
824: }
825: }
826:
827:
828: private String pattern;
829:
830: private Locale locale;
831:
832: private MessageFormatElement[] elements;
833:
834: private String leader;
835: }