Source Code Cross Referenced for MessageFormat.java in  » Apache-Harmony-Java-SE » java-package » java » text » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Apache Harmony Java SE » java package » java.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* 
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *     http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        package java.text;
0019:
0020:        import java.io.IOException;
0021:        import java.io.InvalidObjectException;
0022:        import java.io.ObjectInputStream;
0023:        import java.io.ObjectOutputStream;
0024:        import java.io.ObjectStreamField;
0025:        import java.util.Arrays;
0026:        import java.util.Date;
0027:        import java.util.Iterator;
0028:        import java.util.Locale;
0029:        import java.util.Vector;
0030:
0031:        import org.apache.harmony.text.internal.nls.Messages;
0032:
0033:        /**
0034:         * MessageFormat is used to format and parse arguments based on a pattern. The
0035:         * pattern specifies how each argument will be formatted and concatenated with
0036:         * other text to produce the formatted output.
0037:         */
0038:        public class MessageFormat extends Format {
0039:
0040:            private static final long serialVersionUID = 6479157306784022952L;
0041:
0042:            private Locale locale = Locale.getDefault();
0043:
0044:            transient private String[] strings;
0045:
0046:            private int[] argumentNumbers;
0047:
0048:            private Format[] formats;
0049:
0050:            private int maxOffset;
0051:
0052:            transient private int maxArgumentIndex;
0053:
0054:            /**
0055:             * Constructs a new MessageFormat using the specified pattern and the
0056:             * specified Locale for Formats.
0057:             * 
0058:             * @param template
0059:             *            the pattern
0060:             * @param locale
0061:             *            the locale
0062:             * 
0063:             * @exception IllegalArgumentException
0064:             *                when the pattern cannot be parsed
0065:             */
0066:            public MessageFormat(String template, Locale locale) {
0067:                this .locale = locale;
0068:                applyPattern(template);
0069:            }
0070:
0071:            /**
0072:             * Constructs a new MessageFormat using the specified pattern and the
0073:             * default Locale for Formats.
0074:             * 
0075:             * @param template
0076:             *            the pattern
0077:             * 
0078:             * @exception IllegalArgumentException
0079:             *                when the pattern cannot be parsed
0080:             */
0081:            public MessageFormat(String template) {
0082:                applyPattern(template);
0083:            }
0084:
0085:            /**
0086:             * Changes this MessageFormat to use the specified pattern.
0087:             * 
0088:             * @param template
0089:             *            the pattern
0090:             * 
0091:             * @exception IllegalArgumentException
0092:             *                when the pattern cannot be parsed
0093:             */
0094:            public void applyPattern(String template) {
0095:                int length = template.length();
0096:                StringBuffer buffer = new StringBuffer();
0097:                ParsePosition position = new ParsePosition(0);
0098:                Vector<String> localStrings = new Vector<String>();
0099:                int argCount = 0;
0100:                int[] args = new int[10];
0101:                int maxArg = -1;
0102:                Vector<Format> localFormats = new Vector<Format>();
0103:                while (position.getIndex() < length) {
0104:                    if (Format.upTo(template, position, buffer, '{')) {
0105:                        int arg = 0;
0106:                        int offset = position.getIndex();
0107:                        if (offset >= length) {
0108:                            // text.19=Invalid argument number
0109:                            throw new IllegalArgumentException(Messages
0110:                                    .getString("text.19")); //$NON-NLS-1$
0111:                        }
0112:                        // Get argument number
0113:                        char ch;
0114:                        while ((ch = template.charAt(offset++)) != '}'
0115:                                && ch != ',') {
0116:                            if (ch < '0' && ch > '9') {
0117:                                // text.19=Invalid argument number
0118:                                throw new IllegalArgumentException(Messages
0119:                                        .getString("text.19")); //$NON-NLS-1$
0120:                            }
0121:
0122:                            arg = arg * 10 + (ch - '0');
0123:
0124:                            if (arg < 0 || offset >= length) {
0125:                                // text.19=Invalid argument number
0126:                                throw new IllegalArgumentException(Messages
0127:                                        .getString("text.19")); //$NON-NLS-1$
0128:                            }
0129:                        }
0130:                        offset--;
0131:                        position.setIndex(offset);
0132:                        localFormats.addElement(parseVariable(template,
0133:                                position));
0134:                        if (argCount >= args.length) {
0135:                            int[] newArgs = new int[args.length * 2];
0136:                            System.arraycopy(args, 0, newArgs, 0, args.length);
0137:                            args = newArgs;
0138:                        }
0139:                        args[argCount++] = arg;
0140:                        if (arg > maxArg) {
0141:                            maxArg = arg;
0142:                        }
0143:                    }
0144:                    localStrings.addElement(buffer.toString());
0145:                    buffer.setLength(0);
0146:                }
0147:                this .strings = new String[localStrings.size()];
0148:                for (int i = 0; i < localStrings.size(); i++) {
0149:                    this .strings[i] = localStrings.elementAt(i);
0150:                }
0151:                argumentNumbers = args;
0152:                this .formats = new Format[argCount];
0153:                for (int i = 0; i < argCount; i++) {
0154:                    this .formats[i] = localFormats.elementAt(i);
0155:                }
0156:                maxOffset = argCount - 1;
0157:                maxArgumentIndex = maxArg;
0158:            }
0159:
0160:            /**
0161:             * Answers a new instance of MessageFormat with the same pattern and Formats
0162:             * as this MessageFormat.
0163:             * 
0164:             * @return a shallow copy of this MessageFormat
0165:             * 
0166:             * @see java.lang.Cloneable
0167:             */
0168:            @Override
0169:            public Object clone() {
0170:                MessageFormat clone = (MessageFormat) super .clone();
0171:                Format[] array = new Format[formats.length];
0172:                for (int i = formats.length; --i >= 0;) {
0173:                    if (formats[i] != null) {
0174:                        array[i] = (Format) formats[i].clone();
0175:                    }
0176:                }
0177:                clone.formats = array;
0178:                return clone;
0179:            }
0180:
0181:            /**
0182:             * Compares the specified object to this MessageFormat and answer if they
0183:             * are equal. The object must be an instance of MessageFormat and have the
0184:             * same pattern.
0185:             * 
0186:             * @param object
0187:             *            the object to compare with this object
0188:             * @return true if the specified object is equal to this MessageFormat,
0189:             *         false otherwise
0190:             * 
0191:             * @see #hashCode
0192:             */
0193:            @Override
0194:            public boolean equals(Object object) {
0195:                if (this  == object) {
0196:                    return true;
0197:                }
0198:                if (!(object instanceof  MessageFormat)) {
0199:                    return false;
0200:                }
0201:                MessageFormat format = (MessageFormat) object;
0202:                if (maxOffset != format.maxOffset) {
0203:                    return false;
0204:                }
0205:                // Must use a loop since the lengths may be different due
0206:                // to serialization cross-loading
0207:                for (int i = 0; i <= maxOffset; i++) {
0208:                    if (argumentNumbers[i] != format.argumentNumbers[i]) {
0209:                        return false;
0210:                    }
0211:                }
0212:                return locale.equals(format.locale)
0213:                        && Arrays.equals(strings, format.strings)
0214:                        && Arrays.equals(formats, format.formats);
0215:            }
0216:
0217:            /**
0218:             * Formats the specified object using the rules of this MessageFormat and
0219:             * returns an AttributedCharacterIterator with the formatted message and
0220:             * attributes. The AttributedCharacterIterator returned also includes the
0221:             * attributes from the formats of this MessageFormat.
0222:             * 
0223:             * @param object
0224:             *            the object to format
0225:             * @return an AttributedCharacterIterator with the formatted message and
0226:             *         attributes
0227:             * 
0228:             * @exception IllegalArgumentException
0229:             *                when the arguments in the object array cannot be formatted
0230:             *                by this Format
0231:             */
0232:            @Override
0233:            public AttributedCharacterIterator formatToCharacterIterator(
0234:                    Object object) {
0235:                if (object == null) {
0236:                    throw new NullPointerException();
0237:                }
0238:
0239:                StringBuffer buffer = new StringBuffer();
0240:                Vector<FieldContainer> fields = new Vector<FieldContainer>();
0241:
0242:                // format the message, and find fields
0243:                formatImpl((Object[]) object, buffer, new FieldPosition(0),
0244:                        fields);
0245:
0246:                // create an AttributedString with the formatted buffer
0247:                AttributedString as = new AttributedString(buffer.toString());
0248:
0249:                // add MessageFormat field attributes and values to the AttributedString
0250:                for (int i = 0; i < fields.size(); i++) {
0251:                    FieldContainer fc = fields.elementAt(i);
0252:                    as.addAttribute(fc.attribute, fc.value, fc.start, fc.end);
0253:                }
0254:
0255:                // return the CharacterIterator from AttributedString
0256:                return as.getIterator();
0257:            }
0258:
0259:            /**
0260:             * Formats the Object arguments into the specified StringBuffer using the
0261:             * pattern of this MessageFormat.
0262:             * <p>
0263:             * If Field Attribute of the FieldPosition supplied is
0264:             * MessageFormat.Field.ARGUMENT, then begin and end index of this field
0265:             * position is set to the location of the first occurrence of a message
0266:             * format argument. Otherwise the FieldPosition is ignored
0267:             * <p>
0268:             * 
0269:             * @param objects
0270:             *            the array of Objects to format
0271:             * @param buffer
0272:             *            the StringBuffer
0273:             * @param field
0274:             *            a FieldPosition.
0275:             * 
0276:             * @return the StringBuffer parameter <code>buffer</code>
0277:             */
0278:            public final StringBuffer format(Object[] objects,
0279:                    StringBuffer buffer, FieldPosition field) {
0280:                return formatImpl(objects, buffer, field, null);
0281:            }
0282:
0283:            private StringBuffer formatImpl(Object[] objects,
0284:                    StringBuffer buffer, FieldPosition position,
0285:                    Vector<FieldContainer> fields) {
0286:                FieldPosition passedField = new FieldPosition(0);
0287:                for (int i = 0; i <= maxOffset; i++) {
0288:                    buffer.append(strings[i]);
0289:                    int begin = buffer.length();
0290:                    Object arg;
0291:                    if (objects != null && argumentNumbers[i] < objects.length) {
0292:                        arg = objects[argumentNumbers[i]];
0293:                    } else {
0294:                        buffer.append('{');
0295:                        buffer.append(argumentNumbers[i]);
0296:                        buffer.append('}');
0297:                        handleArgumentField(begin, buffer.length(),
0298:                                argumentNumbers[i], position, fields);
0299:                        continue;
0300:                    }
0301:                    Format format = formats[i];
0302:                    if (format == null || arg == null) {
0303:                        if (arg instanceof  Number) {
0304:                            format = NumberFormat.getInstance();
0305:                        } else if (arg instanceof  Date) {
0306:                            format = DateFormat.getInstance();
0307:                        } else {
0308:                            buffer.append(arg);
0309:                            handleArgumentField(begin, buffer.length(),
0310:                                    argumentNumbers[i], position, fields);
0311:                            continue;
0312:                        }
0313:                    }
0314:                    if (format instanceof  ChoiceFormat) {
0315:                        String result = format.format(arg);
0316:                        MessageFormat mf = new MessageFormat(result);
0317:                        mf.setLocale(locale);
0318:                        mf.format(objects, buffer, passedField);
0319:                        handleArgumentField(begin, buffer.length(),
0320:                                argumentNumbers[i], position, fields);
0321:                        handleformat(format, arg, begin, fields);
0322:                    } else {
0323:                        format.format(arg, buffer, passedField);
0324:                        handleArgumentField(begin, buffer.length(),
0325:                                argumentNumbers[i], position, fields);
0326:                        handleformat(format, arg, begin, fields);
0327:                    }
0328:                }
0329:                if (maxOffset + 1 < strings.length) {
0330:                    buffer.append(strings[maxOffset + 1]);
0331:                }
0332:                return buffer;
0333:            }
0334:
0335:            /**
0336:             * Adds a new FieldContainer with MessageFormat.Field.ARGUMENT field,
0337:             * argnumber, begin and end index to the fields vector, or sets the
0338:             * position's begin and end index if it has MessageFormat.Field.ARGUMENT as
0339:             * its field attribute.
0340:             * 
0341:             * @param begin
0342:             * @param end
0343:             * @param argnumber
0344:             * @param position
0345:             * @param fields
0346:             */
0347:            private void handleArgumentField(int begin, int end, int argnumber,
0348:                    FieldPosition position, Vector<FieldContainer> fields) {
0349:                if (fields != null) {
0350:                    fields.add(new FieldContainer(begin, end, Field.ARGUMENT,
0351:                            new Integer(argnumber)));
0352:                } else {
0353:                    if (position != null
0354:                            && position.getFieldAttribute() == Field.ARGUMENT
0355:                            && position.getEndIndex() == 0) {
0356:                        position.setBeginIndex(begin);
0357:                        position.setEndIndex(end);
0358:                    }
0359:                }
0360:            }
0361:
0362:            /**
0363:             * An inner class to store attributes, values, start and end indices.
0364:             * Instances of this inner class are used as elements for the fields vector
0365:             */
0366:            private static class FieldContainer {
0367:                int start, end;
0368:
0369:                AttributedCharacterIterator.Attribute attribute;
0370:
0371:                Object value;
0372:
0373:                public FieldContainer(int start, int end,
0374:                        AttributedCharacterIterator.Attribute attribute,
0375:                        Object value) {
0376:                    this .start = start;
0377:                    this .end = end;
0378:                    this .attribute = attribute;
0379:                    this .value = value;
0380:                }
0381:            }
0382:
0383:            /**
0384:             * If fields vector is not null, find and add the fields of this format to
0385:             * the fields vector by iterating through its AttributedCharacterIterator
0386:             * 
0387:             * @param format
0388:             *            the format to find fields for
0389:             * @param arg
0390:             *            object to format
0391:             * @param begin
0392:             *            the index where the string this format has formatted begins
0393:             * @param fields
0394:             *            fields vector, each entry in this vector are of type
0395:             *            FieldContainer.
0396:             */
0397:            private void handleformat(Format format, Object arg, int begin,
0398:                    Vector<FieldContainer> fields) {
0399:                if (fields != null) {
0400:                    AttributedCharacterIterator iterator = format
0401:                            .formatToCharacterIterator(arg);
0402:                    while (iterator.getIndex() != iterator.getEndIndex()) {
0403:                        int start = iterator.getRunStart();
0404:                        int end = iterator.getRunLimit();
0405:
0406:                        Iterator<?> it = iterator.getAttributes().keySet()
0407:                                .iterator();
0408:                        while (it.hasNext()) {
0409:                            AttributedCharacterIterator.Attribute attribute = (AttributedCharacterIterator.Attribute) it
0410:                                    .next();
0411:                            Object value = iterator.getAttribute(attribute);
0412:                            fields.add(new FieldContainer(begin + start, begin
0413:                                    + end, attribute, value));
0414:                        }
0415:                        iterator.setIndex(end);
0416:                    }
0417:                }
0418:            }
0419:
0420:            /**
0421:             * Formats the specified object into the specified StringBuffer using the
0422:             * pattern of this MessageFormat.
0423:             * 
0424:             * @param object
0425:             *            the object to format, must be an array of Object
0426:             * @param buffer
0427:             *            the StringBuffer
0428:             * @param field
0429:             *            a FieldPosition which is ignored
0430:             * @return the StringBuffer parameter <code>buffer</code>
0431:             * 
0432:             * @exception ClassCastException
0433:             *                when <code>object</code> is not an array of Object
0434:             */
0435:            @Override
0436:            public final StringBuffer format(Object object,
0437:                    StringBuffer buffer, FieldPosition field) {
0438:                return format((Object[]) object, buffer, field);
0439:            }
0440:
0441:            /**
0442:             * Formats the Object arguments using the specified MessageFormat pattern.
0443:             * 
0444:             * @param template
0445:             *            the pattern
0446:             * @param objects
0447:             *            the array of Objects to format
0448:             * @return the formatted result
0449:             * 
0450:             * @exception IllegalArgumentException
0451:             *                when the pattern cannot be parsed
0452:             */
0453:            public static String format(String template, Object... objects) {
0454:                if (objects != null) {
0455:                    for (int i = 0; i < objects.length; i++) {
0456:                        if (objects[i] == null) {
0457:                            objects[i] = "null";
0458:                        }
0459:                    }
0460:                }
0461:                return com.ibm.icu.text.MessageFormat.format(template, objects);
0462:            }
0463:
0464:            /**
0465:             * Answers the Formats of this MessageFormat.
0466:             * 
0467:             * @return an array of Format
0468:             */
0469:            public Format[] getFormats() {
0470:                return formats.clone();
0471:            }
0472:
0473:            /**
0474:             * Answers the formats used for each argument index. If an argument is
0475:             * placed more than once in the pattern string, than returns the format of
0476:             * the last one.
0477:             * 
0478:             * @return an array of formats, ordered by argument index
0479:             */
0480:            public Format[] getFormatsByArgumentIndex() {
0481:                Format[] answer = new Format[maxArgumentIndex + 1];
0482:                for (int i = 0; i < maxOffset + 1; i++) {
0483:                    answer[argumentNumbers[i]] = formats[i];
0484:                }
0485:                return answer;
0486:            }
0487:
0488:            /**
0489:             * Sets the format used for argument at index <code>argIndex</code>to
0490:             * <code>format</code>
0491:             * 
0492:             * @param argIndex
0493:             * @param format
0494:             */
0495:            public void setFormatByArgumentIndex(int argIndex, Format format) {
0496:                for (int i = 0; i < maxOffset + 1; i++) {
0497:                    if (argumentNumbers[i] == argIndex) {
0498:                        formats[i] = format;
0499:                    }
0500:                }
0501:            }
0502:
0503:            /**
0504:             * Sets the formats used for each argument <code>The formats</code> array
0505:             * elements should be in the order of the argument indices.
0506:             * 
0507:             * @param formats
0508:             */
0509:            public void setFormatsByArgumentIndex(Format[] formats) {
0510:                for (int j = 0; j < formats.length; j++) {
0511:                    for (int i = 0; i < maxOffset + 1; i++) {
0512:                        if (argumentNumbers[i] == j) {
0513:                            this .formats[i] = formats[j];
0514:                        }
0515:                    }
0516:                }
0517:            }
0518:
0519:            /**
0520:             * Answers the Locale used when creating Formats.
0521:             * 
0522:             * @return the Locale used to create Formats
0523:             */
0524:            public Locale getLocale() {
0525:                return locale;
0526:            }
0527:
0528:            /**
0529:             * Answers an integer hash code for the receiver. Objects which are equal
0530:             * answer the same value for this method.
0531:             * 
0532:             * @return the receiver's hash
0533:             * 
0534:             * @see #equals
0535:             */
0536:            @Override
0537:            public int hashCode() {
0538:                int hashCode = 0;
0539:                for (int i = 0; i <= maxOffset; i++) {
0540:                    hashCode += argumentNumbers[i] + strings[i].hashCode();
0541:                    if (formats[i] != null) {
0542:                        hashCode += formats[i].hashCode();
0543:                    }
0544:                }
0545:                if (maxOffset + 1 < strings.length) {
0546:                    hashCode += strings[maxOffset + 1].hashCode();
0547:                }
0548:                if (locale != null) {
0549:                    return hashCode + locale.hashCode();
0550:                }
0551:                return hashCode;
0552:            }
0553:
0554:            /**
0555:             * Parse the message arguments from the specified String using the rules of
0556:             * this MessageFormat.
0557:             * 
0558:             * @param string
0559:             *            the String to parse
0560:             * @return the array of Object arguments resulting from the parse
0561:             * 
0562:             * @exception ParseException
0563:             *                when an error occurs during parsing
0564:             */
0565:            public Object[] parse(String string) throws ParseException {
0566:                ParsePosition position = new ParsePosition(0);
0567:                Object[] result = parse(string, position);
0568:                if (position.getErrorIndex() != -1 || position.getIndex() == 0) {
0569:                    throw new ParseException(null, position.getErrorIndex());
0570:                }
0571:                return result;
0572:            }
0573:
0574:            /**
0575:             * Parse the message argument from the specified String starting at the
0576:             * index specified by the ParsePosition. If the string is successfully
0577:             * parsed, the index of the ParsePosition is updated to the index following
0578:             * the parsed text.
0579:             * 
0580:             * @param string
0581:             *            the String to parse
0582:             * @param position
0583:             *            the ParsePosition, updated on return with the index following
0584:             *            the parsed text, or on error the index is unchanged and the
0585:             *            error index is set to the index where the error occurred
0586:             * @return the array of Object arguments resulting from the parse, or null
0587:             *         if there is an error
0588:             */
0589:            public Object[] parse(String string, ParsePosition position) {
0590:                if (string == null) {
0591:                    return new Object[0];
0592:                }
0593:                ParsePosition internalPos = new ParsePosition(0);
0594:                int offset = position.getIndex();
0595:                Object[] result = new Object[maxArgumentIndex + 1];
0596:                for (int i = 0; i <= maxOffset; i++) {
0597:                    String sub = strings[i];
0598:                    if (!string.startsWith(sub, offset)) {
0599:                        position.setErrorIndex(offset);
0600:                        return null;
0601:                    }
0602:                    offset += sub.length();
0603:                    Object parse;
0604:                    Format format = formats[i];
0605:                    if (format == null) {
0606:                        if (i + 1 < strings.length) {
0607:                            int next = string.indexOf(strings[i + 1], offset);
0608:                            if (next == -1) {
0609:                                position.setErrorIndex(offset);
0610:                                return null;
0611:                            }
0612:                            parse = string.substring(offset, next);
0613:                            offset = next;
0614:                        } else {
0615:                            parse = string.substring(offset);
0616:                            offset = string.length();
0617:                        }
0618:                    } else {
0619:                        internalPos.setIndex(offset);
0620:                        parse = format.parseObject(string, internalPos);
0621:                        if (internalPos.getErrorIndex() != -1) {
0622:                            position.setErrorIndex(offset);
0623:                            return null;
0624:                        }
0625:                        offset = internalPos.getIndex();
0626:                    }
0627:                    result[argumentNumbers[i]] = parse;
0628:                }
0629:                if (maxOffset + 1 < strings.length) {
0630:                    String sub = strings[maxOffset + 1];
0631:                    if (!string.startsWith(sub, offset)) {
0632:                        position.setErrorIndex(offset);
0633:                        return null;
0634:                    }
0635:                    offset += sub.length();
0636:                }
0637:                position.setIndex(offset);
0638:                return result;
0639:            }
0640:
0641:            /**
0642:             * Parse the message argument from the specified String starting at the
0643:             * index specified by the ParsePosition. If the string is successfully
0644:             * parsed, the index of the ParsePosition is updated to the index following
0645:             * the parsed text.
0646:             * 
0647:             * @param string
0648:             *            the String to parse
0649:             * @param position
0650:             *            the ParsePosition, updated on return with the index following
0651:             *            the parsed text, or on error the index is unchanged and the
0652:             *            error index is set to the index where the error occurred
0653:             * @return the array of Object arguments resulting from the parse, or null
0654:             *         if there is an error
0655:             */
0656:            @Override
0657:            public Object parseObject(String string, ParsePosition position) {
0658:                return parse(string, position);
0659:            }
0660:
0661:            private int match(String string, ParsePosition position,
0662:                    boolean last, String[] tokens) {
0663:                int length = string.length(), offset = position.getIndex(), token = -1;
0664:                while (offset < length
0665:                        && Character.isWhitespace(string.charAt(offset))) {
0666:                    offset++;
0667:                }
0668:                for (int i = tokens.length; --i >= 0;) {
0669:                    if (string.regionMatches(true, offset, tokens[i], 0,
0670:                            tokens[i].length())) {
0671:                        token = i;
0672:                        break;
0673:                    }
0674:                }
0675:                if (token == -1) {
0676:                    return -1;
0677:                }
0678:                offset += tokens[token].length();
0679:                while (offset < length
0680:                        && Character.isWhitespace(string.charAt(offset))) {
0681:                    offset++;
0682:                }
0683:                char ch;
0684:                if (offset < length
0685:                        && ((ch = string.charAt(offset)) == '}' || (!last && ch == ','))) {
0686:                    position.setIndex(offset + 1);
0687:                    return token;
0688:                }
0689:                return -1;
0690:            }
0691:
0692:            private Format parseVariable(String string, ParsePosition position) {
0693:                int length = string.length(), offset = position.getIndex();
0694:                char ch;
0695:                if (offset >= length
0696:                        || ((ch = string.charAt(offset++)) != '}' && ch != ',')) {
0697:                    // text.15=Missing element format
0698:                    throw new IllegalArgumentException(Messages
0699:                            .getString("text.15")); //$NON-NLS-1$
0700:                }
0701:                position.setIndex(offset);
0702:                if (ch == '}') {
0703:                    return null;
0704:                }
0705:                int type = match(string, position, false, new String[] {
0706:                        "time", //$NON-NLS-1$
0707:                        "date", "number", "choice" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0708:                if (type == -1) {
0709:                    // text.16=Unknown element format
0710:                    throw new IllegalArgumentException(Messages
0711:                            .getString("text.16")); //$NON-NLS-1$
0712:                }
0713:                StringBuffer buffer = new StringBuffer();
0714:                ch = string.charAt(position.getIndex() - 1);
0715:                switch (type) {
0716:                case 0: // time
0717:                case 1: // date
0718:                    if (ch == '}') {
0719:                        return type == 1 ? DateFormat.getDateInstance(
0720:                                DateFormat.DEFAULT, locale) : DateFormat
0721:                                .getTimeInstance(DateFormat.DEFAULT, locale);
0722:                    }
0723:                    int dateStyle = match(string, position, true, new String[] {
0724:                            "full", "long", "medium", "short" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
0725:                    if (dateStyle == -1) {
0726:                        Format.upToWithQuotes(string, position, buffer, '}',
0727:                                '{');
0728:                        return new SimpleDateFormat(buffer.toString(), locale);
0729:                    }
0730:                    switch (dateStyle) {
0731:                    case 0:
0732:                        dateStyle = DateFormat.FULL;
0733:                        break;
0734:                    case 1:
0735:                        dateStyle = DateFormat.LONG;
0736:                        break;
0737:                    case 2:
0738:                        dateStyle = DateFormat.MEDIUM;
0739:                        break;
0740:                    case 3:
0741:                        dateStyle = DateFormat.SHORT;
0742:                        break;
0743:                    }
0744:                    return type == 1 ? DateFormat.getDateInstance(dateStyle,
0745:                            locale) : DateFormat.getTimeInstance(dateStyle,
0746:                            locale);
0747:                case 2: // number
0748:                    if (ch == '}') {
0749:                        return NumberFormat.getInstance();
0750:                    }
0751:                    int numberStyle = match(string, position, true,
0752:                            new String[] { "currency", "percent", "integer" }); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
0753:                    if (numberStyle == -1) {
0754:                        Format.upToWithQuotes(string, position, buffer, '}',
0755:                                '{');
0756:                        return new DecimalFormat(buffer.toString(),
0757:                                new DecimalFormatSymbols(locale));
0758:                    }
0759:                    switch (numberStyle) {
0760:                    case 0: // currency
0761:                        return NumberFormat.getCurrencyInstance(locale);
0762:                    case 1: // percent
0763:                        return NumberFormat.getPercentInstance(locale);
0764:                    }
0765:                    return NumberFormat.getIntegerInstance(locale);
0766:                }
0767:                // choice
0768:                try {
0769:                    Format.upToWithQuotes(string, position, buffer, '}', '{');
0770:                } catch (IllegalArgumentException e) {
0771:                    // ignored
0772:                }
0773:                return new ChoiceFormat(buffer.toString());
0774:            }
0775:
0776:            /**
0777:             * Sets the specified Format used by this MessageFormat.
0778:             * 
0779:             * @param offset
0780:             *            the format to change
0781:             * @param format
0782:             *            the Format
0783:             */
0784:            public void setFormat(int offset, Format format) {
0785:                formats[offset] = format;
0786:            }
0787:
0788:            /**
0789:             * Sets the Formats used by this MessageFormat.
0790:             * 
0791:             * @param formats
0792:             *            an array of Format
0793:             */
0794:            public void setFormats(Format[] formats) {
0795:                int min = this .formats.length;
0796:                if (formats.length < min) {
0797:                    min = formats.length;
0798:                }
0799:                for (int i = 0; i < min; i++) {
0800:                    this .formats[i] = formats[i];
0801:                }
0802:            }
0803:
0804:            /**
0805:             * Sets the Locale to use when creating Formats.
0806:             * 
0807:             * @param locale
0808:             *            the Locale
0809:             */
0810:            public void setLocale(Locale locale) {
0811:                this .locale = locale;
0812:                for (int i = 0; i <= maxOffset; i++) {
0813:                    Format format = formats[i];
0814:                    if (format instanceof  DecimalFormat) {
0815:                        formats[i] = new DecimalFormat(((DecimalFormat) format)
0816:                                .toPattern(), new DecimalFormatSymbols(locale));
0817:                    } else if (format instanceof  SimpleDateFormat) {
0818:                        formats[i] = new SimpleDateFormat(
0819:                                ((SimpleDateFormat) format).toPattern(), locale);
0820:                    }
0821:
0822:                }
0823:            }
0824:
0825:            private String decodeDecimalFormat(StringBuffer buffer,
0826:                    Format format) {
0827:                buffer.append(",number"); //$NON-NLS-1$
0828:                if (format.equals(NumberFormat.getNumberInstance(locale))) {
0829:                    // Empty block
0830:                } else if (format.equals(NumberFormat
0831:                        .getIntegerInstance(locale))) {
0832:                    buffer.append(",integer"); //$NON-NLS-1$
0833:                } else if (format.equals(NumberFormat
0834:                        .getCurrencyInstance(locale))) {
0835:                    buffer.append(",currency"); //$NON-NLS-1$
0836:                } else if (format.equals(NumberFormat
0837:                        .getPercentInstance(locale))) {
0838:                    buffer.append(",percent"); //$NON-NLS-1$
0839:                } else {
0840:                    buffer.append(',');
0841:                    return ((DecimalFormat) format).toPattern();
0842:                }
0843:                return null;
0844:            }
0845:
0846:            private String decodeSimpleDateFormat(StringBuffer buffer,
0847:                    Format format) {
0848:                if (format.equals(DateFormat.getTimeInstance(
0849:                        DateFormat.DEFAULT, locale))) {
0850:                    buffer.append(",time"); //$NON-NLS-1$
0851:                } else if (format.equals(DateFormat.getDateInstance(
0852:                        DateFormat.DEFAULT, locale))) {
0853:                    buffer.append(",date"); //$NON-NLS-1$
0854:                } else if (format.equals(DateFormat.getTimeInstance(
0855:                        DateFormat.SHORT, locale))) {
0856:                    buffer.append(",time,short"); //$NON-NLS-1$
0857:                } else if (format.equals(DateFormat.getDateInstance(
0858:                        DateFormat.SHORT, locale))) {
0859:                    buffer.append(",date,short"); //$NON-NLS-1$
0860:                } else if (format.equals(DateFormat.getTimeInstance(
0861:                        DateFormat.LONG, locale))) {
0862:                    buffer.append(",time,long"); //$NON-NLS-1$
0863:                } else if (format.equals(DateFormat.getDateInstance(
0864:                        DateFormat.LONG, locale))) {
0865:                    buffer.append(",date,long"); //$NON-NLS-1$
0866:                } else if (format.equals(DateFormat.getTimeInstance(
0867:                        DateFormat.FULL, locale))) {
0868:                    buffer.append(",time,full"); //$NON-NLS-1$
0869:                } else if (format.equals(DateFormat.getDateInstance(
0870:                        DateFormat.FULL, locale))) {
0871:                    buffer.append(",date,full"); //$NON-NLS-1$
0872:                } else {
0873:                    buffer.append(",date,"); //$NON-NLS-1$
0874:                    return ((SimpleDateFormat) format).toPattern();
0875:                }
0876:                return null;
0877:            }
0878:
0879:            /**
0880:             * Answers the pattern of this MessageFormat.
0881:             * 
0882:             * @return the pattern
0883:             */
0884:            public String toPattern() {
0885:                StringBuffer buffer = new StringBuffer();
0886:                for (int i = 0; i <= maxOffset; i++) {
0887:                    appendQuoted(buffer, strings[i]);
0888:                    buffer.append('{');
0889:                    buffer.append(argumentNumbers[i]);
0890:                    Format format = formats[i];
0891:                    String pattern = null;
0892:                    if (format instanceof  ChoiceFormat) {
0893:                        buffer.append(",choice,"); //$NON-NLS-1$
0894:                        pattern = ((ChoiceFormat) format).toPattern();
0895:                    } else if (format instanceof  DecimalFormat) {
0896:                        pattern = decodeDecimalFormat(buffer, format);
0897:                    } else if (format instanceof  SimpleDateFormat) {
0898:                        pattern = decodeSimpleDateFormat(buffer, format);
0899:                    } else if (format != null) {
0900:                        // text.17=Unknown format
0901:                        throw new IllegalArgumentException(Messages
0902:                                .getString("text.17")); //$NON-NLS-1$
0903:                    }
0904:                    if (pattern != null) {
0905:                        boolean quote = false;
0906:                        int index = 0, length = pattern.length(), count = 0;
0907:                        while (index < length) {
0908:                            char ch = pattern.charAt(index++);
0909:                            if (ch == '\'') {
0910:                                quote = !quote;
0911:                            }
0912:                            if (!quote) {
0913:                                if (ch == '{') {
0914:                                    count++;
0915:                                }
0916:                                if (ch == '}') {
0917:                                    if (count > 0) {
0918:                                        count--;
0919:                                    } else {
0920:                                        buffer.append("'}"); //$NON-NLS-1$
0921:                                        ch = '\'';
0922:                                    }
0923:                                }
0924:                            }
0925:                            buffer.append(ch);
0926:                        }
0927:                    }
0928:                    buffer.append('}');
0929:                }
0930:                if (maxOffset + 1 < strings.length) {
0931:                    appendQuoted(buffer, strings[maxOffset + 1]);
0932:                }
0933:                return buffer.toString();
0934:            }
0935:
0936:            private void appendQuoted(StringBuffer buffer, String string) {
0937:                int length = string.length();
0938:                for (int i = 0; i < length; i++) {
0939:                    char ch = string.charAt(i);
0940:                    if (ch == '{' || ch == '}') {
0941:                        buffer.append('\'');
0942:                        buffer.append(ch);
0943:                        buffer.append('\'');
0944:                    } else {
0945:                        buffer.append(ch);
0946:                    }
0947:                }
0948:            }
0949:
0950:            private static final ObjectStreamField[] serialPersistentFields = {
0951:                    new ObjectStreamField("argumentNumbers", int[].class), //$NON-NLS-1$
0952:                    new ObjectStreamField("formats", Format[].class), //$NON-NLS-1$
0953:                    new ObjectStreamField("locale", Locale.class), //$NON-NLS-1$
0954:                    new ObjectStreamField("maxOffset", Integer.TYPE), //$NON-NLS-1$
0955:                    new ObjectStreamField("offsets", int[].class), //$NON-NLS-1$
0956:                    new ObjectStreamField("pattern", String.class), }; //$NON-NLS-1$
0957:
0958:            private void writeObject(ObjectOutputStream stream)
0959:                    throws IOException {
0960:                ObjectOutputStream.PutField fields = stream.putFields();
0961:                fields.put("argumentNumbers", argumentNumbers); //$NON-NLS-1$
0962:                Format[] compatibleFormats = formats;
0963:                fields.put("formats", compatibleFormats); //$NON-NLS-1$
0964:                fields.put("locale", locale); //$NON-NLS-1$
0965:                fields.put("maxOffset", maxOffset); //$NON-NLS-1$
0966:                int offset = 0;
0967:                int offsetsLength = maxOffset + 1;
0968:                int[] offsets = new int[offsetsLength];
0969:                StringBuffer pattern = new StringBuffer();
0970:                for (int i = 0; i <= maxOffset; i++) {
0971:                    offset += strings[i].length();
0972:                    offsets[i] = offset;
0973:                    pattern.append(strings[i]);
0974:                }
0975:                if (maxOffset + 1 < strings.length) {
0976:                    pattern.append(strings[maxOffset + 1]);
0977:                }
0978:                fields.put("offsets", offsets); //$NON-NLS-1$
0979:                fields.put("pattern", pattern.toString()); //$NON-NLS-1$
0980:                stream.writeFields();
0981:            }
0982:
0983:            private void readObject(ObjectInputStream stream)
0984:                    throws IOException, ClassNotFoundException {
0985:                ObjectInputStream.GetField fields = stream.readFields();
0986:                argumentNumbers = (int[]) fields.get("argumentNumbers", null); //$NON-NLS-1$
0987:                formats = (Format[]) fields.get("formats", null); //$NON-NLS-1$
0988:                locale = (Locale) fields.get("locale", null); //$NON-NLS-1$
0989:                maxOffset = fields.get("maxOffset", 0); //$NON-NLS-1$
0990:                int[] offsets = (int[]) fields.get("offsets", null); //$NON-NLS-1$
0991:                String pattern = (String) fields.get("pattern", null); //$NON-NLS-1$
0992:                int length;
0993:                if (maxOffset < 0) {
0994:                    length = pattern.length() > 0 ? 1 : 0;
0995:                } else {
0996:                    length = maxOffset
0997:                            + (offsets[maxOffset] == pattern.length() ? 1 : 2);
0998:                }
0999:                strings = new String[length];
1000:                int last = 0;
1001:                for (int i = 0; i <= maxOffset; i++) {
1002:                    strings[i] = pattern.substring(last, offsets[i]);
1003:                    last = offsets[i];
1004:                }
1005:                if (maxOffset + 1 < strings.length) {
1006:                    strings[strings.length - 1] = pattern.substring(last,
1007:                            pattern.length());
1008:                }
1009:            }
1010:
1011:            /**
1012:             * The instances of this inner class are used as attribute keys in
1013:             * AttributedCharacterIterator that
1014:             * MessageFormat.formatToCharacterIterator() method returns.
1015:             * <p>
1016:             * There is no public constructor to this class, the only instances are the
1017:             * constants defined here.
1018:             */
1019:            public static class Field extends Format.Field {
1020:
1021:                private static final long serialVersionUID = 7899943957617360810L;
1022:
1023:                public static final Field ARGUMENT = new Field(
1024:                        "message argument field"); //$NON-NLS-1$
1025:
1026:                /**
1027:                 * Constructs a new instance of MessageFormat.Field with the given field
1028:                 * name.
1029:                 */
1030:                protected Field(String fieldName) {
1031:                    super (fieldName);
1032:                }
1033:
1034:                /**
1035:                 * serialization method resolve instances to the constant
1036:                 * MessageFormat.Field values
1037:                 */
1038:                @Override
1039:                protected Object readResolve() throws InvalidObjectException {
1040:                    String name = this .getName();
1041:                    if (name == null) {
1042:                        // text.18=Not a valid {0}, subclass should override
1043:                        // readResolve()
1044:                        throw new InvalidObjectException(Messages.getString(
1045:                                "text.18", "MessageFormat.Field")); //$NON-NLS-1$ //$NON-NLS-2$
1046:                    }
1047:
1048:                    if (name.equals(ARGUMENT.getName())) {
1049:                        return ARGUMENT;
1050:                    }
1051:                    // text.18=Not a valid {0}, subclass should override readResolve()
1052:                    throw new InvalidObjectException(Messages.getString(
1053:                            "text.18", "MessageFormat.Field")); //$NON-NLS-1$ //$NON-NLS-2$
1054:                }
1055:            }
1056:
1057:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.