1 7 8 20 21 package java.text; 22 23 import java.io.InvalidObjectException ; 24 import java.io.IOException ; 25 import java.io.ObjectInputStream ; 26 import java.text.DecimalFormat ; 27 import java.util.ArrayList ; 28 import java.util.Date ; 29 import java.util.List ; 30 import java.util.Locale ; 31 import sun.text.Utility; 32 33 34 332 333 public class MessageFormat extends Format { 334 335 private static final long serialVersionUID = 6479157306784022952L; 336 337 348 public MessageFormat(String pattern) { 349 this.locale = Locale.getDefault(); 350 applyPattern(pattern); 351 } 352 353 366 public MessageFormat(String pattern, Locale locale) { 367 this.locale = locale; 368 applyPattern(pattern); 369 } 370 371 380 public void setLocale(Locale locale) { 381 this.locale = locale; 382 } 383 384 389 public Locale getLocale() { 390 return locale; 391 } 392 393 394 404 public void applyPattern(String pattern) { 405 StringBuffer [] segments = new StringBuffer [4]; 406 for (int i = 0; i < segments.length; ++i) { 407 segments[i] = new StringBuffer (); 408 } 409 int part = 0; 410 int formatNumber = 0; 411 boolean inQuote = false; 412 int braceStack = 0; 413 maxOffset = -1; 414 for (int i = 0; i < pattern.length(); ++i) { 415 char ch = pattern.charAt(i); 416 if (part == 0) { 417 if (ch == '\'') { 418 if (i + 1 < pattern.length() 419 && pattern.charAt(i+1) == '\'') { 420 segments[part].append(ch); ++i; 422 } else { 423 inQuote = !inQuote; 424 } 425 } else if (ch == '{' && !inQuote) { 426 part = 1; 427 } else { 428 segments[part].append(ch); 429 } 430 } else if (inQuote) { segments[part].append(ch); 432 if (ch == '\'') { 433 inQuote = false; 434 } 435 } else { 436 switch (ch) { 437 case ',': 438 if (part < 3) 439 part += 1; 440 else 441 segments[part].append(ch); 442 break; 443 case '{': 444 ++braceStack; 445 segments[part].append(ch); 446 break; 447 case '}': 448 if (braceStack == 0) { 449 part = 0; 450 makeFormat(i, formatNumber, segments); 451 formatNumber++; 452 } else { 453 --braceStack; 454 segments[part].append(ch); 455 } 456 break; 457 case '\'': 458 inQuote = true; 459 default: 461 segments[part].append(ch); 462 break; 463 } 464 } 465 } 466 if (braceStack == 0 && part != 0) { 467 maxOffset = -1; 468 throw new IllegalArgumentException ("Unmatched braces in the pattern."); 469 } 470 this.pattern = segments[0].toString(); 471 } 472 473 474 481 public String toPattern() { 482 int lastOffset = 0; 484 StringBuffer result = new StringBuffer (); 485 for (int i = 0; i <= maxOffset; ++i) { 486 copyAndFixQuotes(pattern, lastOffset, offsets[i],result); 487 lastOffset = offsets[i]; 488 result.append('{'); 489 result.append(argumentNumbers[i]); 490 if (formats[i] == null) { 491 } else if (formats[i] instanceof DecimalFormat ) { 493 if (formats[i].equals(NumberFormat.getInstance(locale))) { 494 result.append(",number"); 495 } else if (formats[i].equals(NumberFormat.getCurrencyInstance(locale))) { 496 result.append(",number,currency"); 497 } else if (formats[i].equals(NumberFormat.getPercentInstance(locale))) { 498 result.append(",number,percent"); 499 } else if (formats[i].equals(NumberFormat.getIntegerInstance(locale))) { 500 result.append(",number,integer"); 501 } else { 502 result.append(",number," + 503 ((DecimalFormat )formats[i]).toPattern()); 504 } 505 } else if (formats[i] instanceof SimpleDateFormat ) { 506 if (formats[i].equals(DateFormat.getDateInstance( 507 DateFormat.DEFAULT,locale))) { 508 result.append(",date"); 509 } else if (formats[i].equals(DateFormat.getDateInstance( 510 DateFormat.SHORT,locale))) { 511 result.append(",date,short"); 512 } else if (formats[i].equals(DateFormat.getDateInstance( 513 DateFormat.DEFAULT,locale))) { 514 result.append(",date,medium"); 515 } else if (formats[i].equals(DateFormat.getDateInstance( 516 DateFormat.LONG,locale))) { 517 result.append(",date,long"); 518 } else if (formats[i].equals(DateFormat.getDateInstance( 519 DateFormat.FULL,locale))) { 520 result.append(",date,full"); 521 } else if (formats[i].equals(DateFormat.getTimeInstance( 522 DateFormat.DEFAULT,locale))) { 523 result.append(",time"); 524 } else if (formats[i].equals(DateFormat.getTimeInstance( 525 DateFormat.SHORT,locale))) { 526 result.append(",time,short"); 527 } else if (formats[i].equals(DateFormat.getTimeInstance( 528 DateFormat.DEFAULT,locale))) { 529 result.append(",time,medium"); 530 } else if (formats[i].equals(DateFormat.getTimeInstance( 531 DateFormat.LONG,locale))) { 532 result.append(",time,long"); 533 } else if (formats[i].equals(DateFormat.getTimeInstance( 534 DateFormat.FULL,locale))) { 535 result.append(",time,full"); 536 } else { 537 result.append(",date," 538 + ((SimpleDateFormat )formats[i]).toPattern()); 539 } 540 } else if (formats[i] instanceof ChoiceFormat ) { 541 result.append(",choice," 542 + ((ChoiceFormat )formats[i]).toPattern()); 543 } else { 544 } 546 result.append('}'); 547 } 548 copyAndFixQuotes(pattern, lastOffset, pattern.length(), result); 549 return result.toString(); 550 } 551 552 575 public void setFormatsByArgumentIndex(Format [] newFormats) { 576 for (int i = 0; i <= maxOffset; i++) { 577 int j = argumentNumbers[i]; 578 if (j < newFormats.length) { 579 formats[i] = newFormats[j]; 580 } 581 } 582 } 583 584 606 public void setFormats(Format [] newFormats) { 607 int runsToCopy = newFormats.length; 608 if (runsToCopy > maxOffset + 1) { 609 runsToCopy = maxOffset + 1; 610 } 611 for (int i = 0; i < runsToCopy; i++) { 612 formats[i] = newFormats[i]; 613 } 614 } 615 616 634 public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) { 635 for (int j = 0; j <= maxOffset; j++) { 636 if (argumentNumbers[j] == argumentIndex) { 637 formats[j] = newFormat; 638 } 639 } 640 } 641 642 659 public void setFormat(int formatElementIndex, Format newFormat) { 660 formats[formatElementIndex] = newFormat; 661 } 662 663 683 public Format [] getFormatsByArgumentIndex() { 684 int maximumArgumentNumber = -1; 685 for (int i = 0; i <= maxOffset; i++) { 686 if (argumentNumbers[i] > maximumArgumentNumber) { 687 maximumArgumentNumber = argumentNumbers[i]; 688 } 689 } 690 Format [] resultArray = new Format [maximumArgumentNumber + 1]; 691 for (int i = 0; i <= maxOffset; i++) { 692 resultArray[argumentNumbers[i]] = formats[i]; 693 } 694 return resultArray; 695 } 696 697 713 public Format [] getFormats() { 714 Format [] resultArray = new Format [maxOffset + 1]; 715 System.arraycopy(formats, 0, resultArray, 0, maxOffset + 1); 716 return resultArray; 717 } 718 719 784 public final StringBuffer format(Object [] arguments, StringBuffer result, 785 FieldPosition pos) 786 { 787 return subformat(arguments, result, pos, null); 788 } 789 790 802 public static String format(String pattern, Object ... arguments) { 803 MessageFormat temp = new MessageFormat (pattern); 804 return temp.format(arguments); 805 } 806 807 825 public final StringBuffer format(Object arguments, StringBuffer result, 826 FieldPosition pos) 827 { 828 return subformat((Object []) arguments, result, pos, null); 829 } 830 831 866 public AttributedCharacterIterator formatToCharacterIterator(Object arguments) { 867 StringBuffer result = new StringBuffer (); 868 ArrayList iterators = new ArrayList (); 869 870 if (arguments == null) { 871 throw new NullPointerException ( 872 "formatToCharacterIterator must be passed non-null object"); 873 } 874 subformat((Object []) arguments, result, null, iterators); 875 if (iterators.size() == 0) { 876 return createAttributedCharacterIterator(""); 877 } 878 return createAttributedCharacterIterator( 879 (AttributedCharacterIterator [])iterators.toArray( 880 new AttributedCharacterIterator [iterators.size()])); 881 } 882 883 910 public Object [] parse(String source, ParsePosition pos) { 911 if (source == null) { 912 Object [] empty = {}; 913 return empty; 914 } 915 916 int maximumArgumentNumber = -1; 917 for (int i = 0; i <= maxOffset; i++) { 918 if (argumentNumbers[i] > maximumArgumentNumber) { 919 maximumArgumentNumber = argumentNumbers[i]; 920 } 921 } 922 Object [] resultArray = new Object [maximumArgumentNumber + 1]; 923 924 int patternOffset = 0; 925 int sourceOffset = pos.index; 926 ParsePosition tempStatus = new ParsePosition (0); 927 for (int i = 0; i <= maxOffset; ++i) { 928 int len = offsets[i] - patternOffset; 930 if (len == 0 || pattern.regionMatches(patternOffset, 931 source, sourceOffset, len)) { 932 sourceOffset += len; 933 patternOffset += len; 934 } else { 935 pos.errorIndex = sourceOffset; 936 return null; } 938 939 if (formats[i] == null) { int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length(); 945 946 int next; 947 if (patternOffset >= tempLength) { 948 next = source.length(); 949 }else{ 950 next = source.indexOf( pattern.substring(patternOffset,tempLength), sourceOffset); 951 } 952 953 if (next < 0) { 954 pos.errorIndex = sourceOffset; 955 return null; } else { 957 String strValue= source.substring(sourceOffset,next); 958 if (!strValue.equals("{"+argumentNumbers[i]+"}")) 959 resultArray[argumentNumbers[i]] 960 = source.substring(sourceOffset,next); 961 sourceOffset = next; 962 } 963 } else { 964 tempStatus.index = sourceOffset; 965 resultArray[argumentNumbers[i]] 966 = formats[i].parseObject(source,tempStatus); 967 if (tempStatus.index == sourceOffset) { 968 pos.errorIndex = sourceOffset; 969 return null; } 971 sourceOffset = tempStatus.index; } 973 } 974 int len = pattern.length() - patternOffset; 975 if (len == 0 || pattern.regionMatches(patternOffset, 976 source, sourceOffset, len)) { 977 pos.index = sourceOffset + len; 978 } else { 979 pos.errorIndex = sourceOffset; 980 return null; } 982 return resultArray; 983 } 984 985 998 public Object [] parse(String source) throws ParseException { 999 ParsePosition pos = new ParsePosition (0); 1000 Object [] result = parse(source, pos); 1001 if (pos.index == 0) throw new ParseException ("MessageFormat parse error!", pos.errorIndex); 1003 1004 return result; 1005 } 1006 1007 1031 public Object parseObject(String source, ParsePosition pos) { 1032 return parse(source, pos); 1033 } 1034 1035 1040 public Object clone() { 1041 MessageFormat other = (MessageFormat ) super.clone(); 1042 1043 other.formats = (Format []) formats.clone(); for (int i = 0; i < formats.length; ++i) { 1046 if (formats[i] != null) 1047 other.formats[i] = (Format )formats[i].clone(); 1048 } 1049 other.offsets = (int[]) offsets.clone(); 1051 other.argumentNumbers = (int[]) argumentNumbers.clone(); 1052 1053 return other; 1054 } 1055 1056 1059 public boolean equals(Object obj) { 1060 if (this == obj) return true; 1062 if (obj == null || getClass() != obj.getClass()) 1063 return false; 1064 MessageFormat other = (MessageFormat ) obj; 1065 return (maxOffset == other.maxOffset 1066 && pattern.equals(other.pattern) 1067 && Utility.objectEquals(locale, other.locale) && Utility.arrayEquals(offsets,other.offsets) 1069 && Utility.arrayEquals(argumentNumbers,other.argumentNumbers) 1070 && Utility.arrayEquals(formats,other.formats)); 1071 } 1072 1073 1076 public int hashCode() { 1077 return pattern.hashCode(); } 1079 1080 1081 1088 public static class Field extends Format.Field { 1089 1090 private static final long serialVersionUID = 7899943957617360810L; 1092 1093 1098 protected Field(String name) { 1099 super(name); 1100 } 1101 1102 1109 protected Object readResolve() throws InvalidObjectException { 1110 if (this.getClass() != MessageFormat.Field .class) { 1111 throw new InvalidObjectException ("subclass didn't correctly implement readResolve"); 1112 } 1113 1114 return ARGUMENT; 1115 } 1116 1117 1121 1128 public final static Field ARGUMENT = 1129 new Field("message argument field"); 1130 } 1131 1132 1134 1138 private Locale locale; 1139 1140 1145 private String pattern = ""; 1146 1147 1148 private static final int INITIAL_FORMATS = 10; 1149 1150 1154 private Format [] formats = new Format [INITIAL_FORMATS]; 1155 1156 1161 private int[] offsets = new int[INITIAL_FORMATS]; 1162 1163 1169 private int[] argumentNumbers = new int[INITIAL_FORMATS]; 1170 1171 1178 private int maxOffset = -1; 1179 1180 1192 private StringBuffer subformat(Object [] arguments, StringBuffer result, 1193 FieldPosition fp, List characterIterators) { 1194 int lastOffset = 0; 1197 int last = result.length(); 1198 for (int i = 0; i <= maxOffset; ++i) { 1199 result.append(pattern.substring(lastOffset, offsets[i])); 1200 lastOffset = offsets[i]; 1201 int argumentNumber = argumentNumbers[i]; 1202 if (arguments == null || argumentNumber >= arguments.length) { 1203 result.append("{" + argumentNumber + "}"); 1204 continue; 1205 } 1206 if (false) { result.append('\uFFFD'); 1210 } else { 1211 Object obj = arguments[argumentNumber]; 1212 String arg = null; 1213 Format subFormatter = null; 1214 if (obj == null) { 1215 arg = "null"; 1216 } else if (formats[i] != null) { 1217 subFormatter = formats[i]; 1218 if (subFormatter instanceof ChoiceFormat ) { 1219 arg = formats[i].format(obj); 1220 if (arg.indexOf('{') >= 0) { 1221 subFormatter = new MessageFormat (arg, locale); 1222 obj = arguments; 1223 arg = null; 1224 } 1225 } 1226 } else if (obj instanceof Number ) { 1227 subFormatter = NumberFormat.getInstance(locale); 1229 } else if (obj instanceof Date ) { 1230 subFormatter = DateFormat.getDateTimeInstance( 1232 DateFormat.SHORT, DateFormat.SHORT, locale); } else if (obj instanceof String ) { 1234 arg = (String ) obj; 1235 1236 } else { 1237 arg = obj.toString(); 1238 if (arg == null) arg = "null"; 1239 } 1240 1241 1245 if (characterIterators != null) { 1246 if (last != result.length()) { 1249 characterIterators.add( 1250 createAttributedCharacterIterator(result.substring 1251 (last))); 1252 last = result.length(); 1253 } 1254 if (subFormatter != null) { 1255 AttributedCharacterIterator subIterator = 1256 subFormatter.formatToCharacterIterator(obj); 1257 1258 append(result, subIterator); 1259 if (last != result.length()) { 1260 characterIterators.add( 1261 createAttributedCharacterIterator( 1262 subIterator, Field.ARGUMENT, 1263 new Integer (argumentNumber))); 1264 last = result.length(); 1265 } 1266 arg = null; 1267 } 1268 if (arg != null && arg.length() > 0) { 1269 result.append(arg); 1270 characterIterators.add( 1271 createAttributedCharacterIterator( 1272 arg, Field.ARGUMENT, 1273 new Integer (argumentNumber))); 1274 last = result.length(); 1275 } 1276 } 1277 else { 1278 if (subFormatter != null) { 1279 arg = subFormatter.format(obj); 1280 } 1281 last = result.length(); 1282 result.append(arg); 1283 if (i == 0 && fp != null && Field.ARGUMENT.equals( 1284 fp.getFieldAttribute())) { 1285 fp.setBeginIndex(last); 1286 fp.setEndIndex(result.length()); 1287 } 1288 last = result.length(); 1289 } 1290 } 1291 } 1292 result.append(pattern.substring(lastOffset, pattern.length())); 1293 if (characterIterators != null && last != result.length()) { 1294 characterIterators.add(createAttributedCharacterIterator( 1295 result.substring(last))); 1296 } 1297 return result; 1298 } 1299 1300 1304 private void append(StringBuffer result, CharacterIterator iterator) { 1305 if (iterator.first() != CharacterIterator.DONE) { 1306 char aChar; 1307 1308 result.append(iterator.first()); 1309 while ((aChar = iterator.next()) != CharacterIterator.DONE) { 1310 result.append(aChar); 1311 } 1312 } 1313 } 1314 1315 private static final String [] typeList = 1316 {"", "", "number", "", "date", "", "time", "", "choice"}; 1317 private static final String [] modifierList = 1318 {"", "", "currency", "", "percent", "", "integer"}; 1319 private static final String [] dateModifierList = 1320 {"", "", "short", "", "medium", "", "long", "", "full"}; 1321 1322 private void makeFormat(int position, int offsetNumber, 1323 StringBuffer [] segments) 1324 { 1325 int argumentNumber; 1327 try { 1328 argumentNumber = Integer.parseInt(segments[1].toString()); } catch (NumberFormatException e) { 1330 throw new IllegalArgumentException ("can't parse argument number " + segments[1]); 1331 } 1332 if (argumentNumber < 0) { 1333 throw new IllegalArgumentException ("negative argument number " + argumentNumber); 1334 } 1335 1336 if (offsetNumber >= formats.length) { 1338 int newLength = formats.length * 2; 1339 Format [] newFormats = new Format [newLength]; 1340 int[] newOffsets = new int[newLength]; 1341 int[] newArgumentNumbers = new int[newLength]; 1342 System.arraycopy(formats, 0, newFormats, 0, maxOffset + 1); 1343 System.arraycopy(offsets, 0, newOffsets, 0, maxOffset + 1); 1344 System.arraycopy(argumentNumbers, 0, newArgumentNumbers, 0, maxOffset + 1); 1345 formats = newFormats; 1346 offsets = newOffsets; 1347 argumentNumbers = newArgumentNumbers; 1348 } 1349 int oldMaxOffset = maxOffset; 1350 maxOffset = offsetNumber; 1351 offsets[offsetNumber] = segments[0].length(); 1352 argumentNumbers[offsetNumber] = argumentNumber; 1353 1354 Format newFormat = null; 1356 switch (findKeyword(segments[2].toString(), typeList)) { 1357 case 0: 1358 break; 1359 case 1: case 2: switch (findKeyword(segments[3].toString(), modifierList)) { 1361 case 0: newFormat = NumberFormat.getInstance(locale); 1363 break; 1364 case 1: case 2: newFormat = NumberFormat.getCurrencyInstance(locale); 1366 break; 1367 case 3: case 4: newFormat = NumberFormat.getPercentInstance(locale); 1369 break; 1370 case 5: case 6: newFormat = NumberFormat.getIntegerInstance(locale); 1372 break; 1373 default: newFormat = new DecimalFormat (segments[3].toString(), new DecimalFormatSymbols (locale)); 1375 break; 1376 } 1377 break; 1378 case 3: case 4: switch (findKeyword(segments[3].toString(), dateModifierList)) { 1380 case 0: newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale); 1382 break; 1383 case 1: case 2: newFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale); 1385 break; 1386 case 3: case 4: newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale); 1388 break; 1389 case 5: case 6: newFormat = DateFormat.getDateInstance(DateFormat.LONG, locale); 1391 break; 1392 case 7: case 8: newFormat = DateFormat.getDateInstance(DateFormat.FULL, locale); 1394 break; 1395 default: 1396 newFormat = new SimpleDateFormat (segments[3].toString(), locale); 1397 break; 1398 } 1399 break; 1400 case 5: case 6: switch (findKeyword(segments[3].toString(), dateModifierList)) { 1402 case 0: newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale); 1404 break; 1405 case 1: case 2: newFormat = DateFormat.getTimeInstance(DateFormat.SHORT, locale); 1407 break; 1408 case 3: case 4: newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale); 1410 break; 1411 case 5: case 6: newFormat = DateFormat.getTimeInstance(DateFormat.LONG, locale); 1413 break; 1414 case 7: case 8: newFormat = DateFormat.getTimeInstance(DateFormat.FULL, locale); 1416 break; 1417 default: 1418 newFormat = new SimpleDateFormat (segments[3].toString(), locale); 1419 break; 1420 } 1421 break; 1422 case 7: case 8: try { 1424 newFormat = new ChoiceFormat (segments[3].toString()); 1425 } catch (Exception e) { 1426 maxOffset = oldMaxOffset; 1427 throw new IllegalArgumentException ( 1428 "Choice Pattern incorrect"); 1429 } 1430 break; 1431 default: 1432 maxOffset = oldMaxOffset; 1433 throw new IllegalArgumentException ("unknown format type at "); 1434 } 1435 formats[offsetNumber] = newFormat; 1436 segments[1].setLength(0); segments[2].setLength(0); 1438 segments[3].setLength(0); 1439 } 1440 1441 private static final int findKeyword(String s, String [] list) { 1442 s = s.trim().toLowerCase(); 1443 for (int i = 0; i < list.length; ++i) { 1444 if (s.equals(list[i])) 1445 return i; 1446 } 1447 return -1; 1448 } 1449 1450 private static final void copyAndFixQuotes( 1451 String source, int start, int end, StringBuffer target) { 1452 for (int i = start; i < end; ++i) { 1453 char ch = source.charAt(i); 1454 if (ch == '{') { 1455 target.append("'{'"); 1456 } else if (ch == '}') { 1457 target.append("'}'"); 1458 } else if (ch == '\'') { 1459 target.append("''"); 1460 } else { 1461 target.append(ch); 1462 } 1463 } 1464 } 1465 1466 1471 private void readObject(ObjectInputStream in) throws IOException , ClassNotFoundException { 1472 in.defaultReadObject(); 1473 boolean isValid = maxOffset >= -1 1474 && formats.length > maxOffset 1475 && offsets.length > maxOffset 1476 && argumentNumbers.length > maxOffset; 1477 if (isValid) { 1478 int lastOffset = pattern.length() + 1; 1479 for (int i = maxOffset; i >= 0; --i) { 1480 if ((offsets[i] < 0) || (offsets[i] > lastOffset)) { 1481 isValid = false; 1482 break; 1483 } else { 1484 lastOffset = offsets[i]; 1485 } 1486 } 1487 } 1488 if (!isValid) { 1489 throw new InvalidObjectException ("Could not reconstruct MessageFormat from corrupt stream."); 1490 } 1491 } 1492} 1493 | Popular Tags |