Source Code Cross Referenced for Formatter.java in  » Apache-Harmony-Java-SE » java-package » java » util » 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.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* Licensed to the Apache Software Foundation (ASF) under one or more
0002:         * contributor license agreements.  See the NOTICE file distributed with
0003:         * this work for additional information regarding copyright ownership.
0004:         * The ASF licenses this file to You under the Apache License, Version 2.0
0005:         * (the "License"); you may not use this file except in compliance with
0006:         * the License.  You may obtain a copy of the License at
0007:         * 
0008:         *     http://www.apache.org/licenses/LICENSE-2.0
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:        package java.util;
0017:
0018:        import java.io.BufferedWriter;
0019:        import java.io.Closeable;
0020:        import java.io.File;
0021:        import java.io.FileNotFoundException;
0022:        import java.io.FileOutputStream;
0023:        import java.io.Flushable;
0024:        import java.io.IOException;
0025:        import java.io.OutputStream;
0026:        import java.io.OutputStreamWriter;
0027:        import java.io.PrintStream;
0028:        import java.io.UnsupportedEncodingException;
0029:        import java.math.BigDecimal;
0030:        import java.math.BigInteger;
0031:        import java.nio.CharBuffer;
0032:        import java.nio.charset.Charset;
0033:        import java.security.AccessController;
0034:        import java.security.PrivilegedAction;
0035:        import java.text.DateFormatSymbols;
0036:        import java.text.DecimalFormat;
0037:        import java.text.DecimalFormatSymbols;
0038:        import java.text.NumberFormat;
0039:
0040:        /**
0041:         * Formatter provides the method to give out formatted string just like the
0042:         * printf-style. Layout,alignment and other format flags are provided to format
0043:         * numeric,string and date/time as well as locale-specified formats applied.
0044:         * Besides primitive types, formatter also support some java object types such
0045:         * as BigInteger,BigDecimal and Calendar. Customized formatting is provided
0046:         * through the Formattable interface.
0047:         * 
0048:         * The class is not multi-threaded safe. The responsibility to maintain thread
0049:         * safety is the user's job.
0050:         * 
0051:         * @since 1.5
0052:         */
0053:        public final class Formatter implements  Closeable, Flushable {
0054:
0055:            public enum BigDecimalLayoutForm {
0056:                SCIENTIFIC, DECIMAL_FLOAT
0057:            }
0058:
0059:            private Appendable out;
0060:
0061:            private Locale locale;
0062:
0063:            private boolean closed = false;
0064:
0065:            private IOException lastIOException;
0066:
0067:            /**
0068:             * Constructs a formatter.
0069:             * 
0070:             * The output is a StringBuilder which can be achieved by invoking the out
0071:             * method and whose contents can be attained by calling the toString method.
0072:             * 
0073:             * The locale for the formatter is the default locale of the JVM.
0074:             */
0075:            public Formatter() {
0076:                this (new StringBuilder(), Locale.getDefault());
0077:            }
0078:
0079:            /**
0080:             * Constructs a formatter of which the output is denoted.
0081:             * 
0082:             * The locale for the formatter is the default locale of the JVM.
0083:             * 
0084:             * @param a
0085:             *            The output of the formatter. If a is null, then a
0086:             *            StringBuilder will be used.
0087:             */
0088:            public Formatter(Appendable a) {
0089:                this (a, Locale.getDefault());
0090:            }
0091:
0092:            /**
0093:             * Constructs a formatter of which the locale is denoted.
0094:             * 
0095:             * The output destination is a StringBuilder which can be achieved by
0096:             * invoking the out method and whose contents can be attained by calling the
0097:             * toString method.
0098:             * 
0099:             * @param l
0100:             *            The locale of the formatter. If l is null, then no
0101:             *            localization will be used.
0102:             */
0103:            public Formatter(Locale l) {
0104:                this (new StringBuilder(), l);
0105:            }
0106:
0107:            /**
0108:             * Constructs a formatter of which the output and locale is denoted.
0109:             * 
0110:             * @param a
0111:             *            The output of the formatter. If a is null, then a
0112:             *            StringBuilder will be used.
0113:             * @param l
0114:             *            The locale of the formatter. If l is null, then no
0115:             *            localization will be used.
0116:             */
0117:            public Formatter(Appendable a, Locale l) {
0118:                if (null == a) {
0119:                    out = new StringBuilder();
0120:                } else {
0121:                    out = a;
0122:                }
0123:                locale = l;
0124:            }
0125:
0126:            /**
0127:             * Constructs a formatter of which the filename is denoted.
0128:             * 
0129:             * The charset of the formatter is the default charset of JVM.
0130:             * 
0131:             * The locale for the formatter is the default locale of the JVM.
0132:             * 
0133:             * @param fileName
0134:             *            The filename of the file that is used as the output
0135:             *            destination for the formatter. The file will be truncated to
0136:             *            zero size if the file exists, or else a new file will be
0137:             *            created. The output of the formatter is buffered.
0138:             * 
0139:             * @throws FileNotFoundException
0140:             *             If the filename does not denote a normal and writable file,
0141:             *             or a new file cannot be created or any error rises when
0142:             *             opening or creating the file.
0143:             * @throws SecurityException
0144:             *             If there is a security manager and it denies writing to the
0145:             *             file in checkWrite(file.getPath()).
0146:             */
0147:            public Formatter(String fileName) throws FileNotFoundException {
0148:                this (new File(fileName));
0149:
0150:            }
0151:
0152:            /**
0153:             * Constructs a formatter of which the filename and charset is denoted.
0154:             * 
0155:             * The locale for the formatter is the default locale of the JVM.
0156:             * 
0157:             * @param fileName
0158:             *            The filename of the file that is used as the output
0159:             *            destination for the formatter. The file will be truncated to
0160:             *            zero size if the file exists, or else a new file will be
0161:             *            created. The output of the formatter is buffered.
0162:             * @param csn
0163:             *            The name of the charset for the formatter.
0164:             * 
0165:             * @throws FileNotFoundException
0166:             *             If the filename does not denote a normal and writable file,
0167:             *             or a new file cannot be created or any error rises when
0168:             *             opening or creating the file.
0169:             * @throws SecurityException
0170:             *             If there is a security manager and it denies writing to the
0171:             *             file in checkWrite(file.getPath()).
0172:             * @throws UnsupportedEncodingException
0173:             *             If the charset with the specified name is not supported.
0174:             */
0175:            public Formatter(String fileName, String csn)
0176:                    throws FileNotFoundException, UnsupportedEncodingException {
0177:                this (new File(fileName), csn);
0178:            }
0179:
0180:            /**
0181:             * Constructs a formatter of which the filename, charset and locale is
0182:             * denoted.
0183:             * 
0184:             * @param fileName
0185:             *            The filename of the file that is used as the output
0186:             *            destination for the formatter. The file will be truncated to
0187:             *            zero size if the file exists, or else a new file will be
0188:             *            created. The output of the formatter is buffered.
0189:             * @param csn
0190:             *            The name of the charset for the formatter.
0191:             * @param l
0192:             *            The locale of the formatter. If l is null, then no
0193:             *            localization will be used.
0194:             * 
0195:             * @throws FileNotFoundException
0196:             *             If the filename does not denote a normal and writable file,
0197:             *             or a new file cannot be created or any error rises when
0198:             *             opening or creating the file.
0199:             * @throws SecurityException
0200:             *             If there is a security manager and it denies writing to the
0201:             *             file in checkWrite(file.getPath()).
0202:             * @throws UnsupportedEncodingException
0203:             *             If the charset with the specified name is not supported.
0204:             * 
0205:             */
0206:            public Formatter(String fileName, String csn, Locale l)
0207:                    throws FileNotFoundException, UnsupportedEncodingException {
0208:
0209:                this (new File(fileName), csn, l);
0210:            }
0211:
0212:            /**
0213:             * Constructs a formatter of which the file is denoted.
0214:             * 
0215:             * The charset of the formatter is the default charset of JVM.
0216:             * 
0217:             * The locale for the formatter is the default locale of the JVM.
0218:             * 
0219:             * @param file
0220:             *            The file that is used as the output destination for the
0221:             *            formatter. The file will be truncated to zero size if the file
0222:             *            exists, or else a new file will be created. The output of the
0223:             *            formatter is buffered.
0224:             * 
0225:             * @throws FileNotFoundException
0226:             *             If the file does not denote a normal and writable file, or a
0227:             *             new file cannot be created or any error rises when opening or
0228:             *             creating the file.
0229:             * @throws SecurityException
0230:             *             If there is a security manager and it denies writing to the
0231:             *             file in checkWrite(file.getPath()).
0232:             */
0233:            public Formatter(File file) throws FileNotFoundException {
0234:                this (new FileOutputStream(file));
0235:            }
0236:
0237:            /**
0238:             * Constructs a formatter of which the file and charset is denoted.
0239:             * 
0240:             * The locale for the formatter is the default locale of the JVM.
0241:             * 
0242:             * @param file
0243:             *            The file of the file that is used as the output destination
0244:             *            for the formatter. The file will be truncated to zero size if
0245:             *            the file exists, or else a new file will be created. The
0246:             *            output of the formatter is buffered.
0247:             * @param csn
0248:             *            The name of the charset for the formatter.
0249:             * @throws FileNotFoundException
0250:             *             If the file does not denote a normal and writable file, or a
0251:             *             new file cannot be created or any error rises when opening or
0252:             *             creating the file.
0253:             * @throws SecurityException
0254:             *             If there is a security manager and it denies writing to the
0255:             *             file in checkWrite(file.getPath()).
0256:             * @throws UnsupportedEncodingException
0257:             *             If the charset with the specified name is not supported.
0258:             */
0259:            public Formatter(File file, String csn)
0260:                    throws FileNotFoundException, UnsupportedEncodingException {
0261:                this (file, csn, Locale.getDefault());
0262:            }
0263:
0264:            /**
0265:             * Constructs a formatter of which the file, charset and locale is denoted.
0266:             * 
0267:             * @param file
0268:             *            file that is used as the output destination for the formatter.
0269:             *            The file will be truncated to zero size if the file exists, or
0270:             *            else a new file will be created. The output of the formatter
0271:             *            is buffered.
0272:             * @param csn
0273:             *            The name of the charset for the formatter.
0274:             * @param l
0275:             *            The locale of the formatter. If l is null, then no
0276:             *            localization will be used.
0277:             * @throws FileNotFoundException
0278:             *             If the file does not denote a normal and writable file, or a
0279:             *             new file cannot be created or any error rises when opening or
0280:             *             creating the file.
0281:             * @throws SecurityException
0282:             *             If there is a security manager and it denies writing to the
0283:             *             file in checkWrite(file.getPath()).
0284:             * @throws UnsupportedEncodingException
0285:             *             If the charset with the specified name is not supported.
0286:             */
0287:            public Formatter(File file, String csn, Locale l)
0288:                    throws FileNotFoundException, UnsupportedEncodingException {
0289:                FileOutputStream fout = null;
0290:                try {
0291:                    fout = new FileOutputStream(file);
0292:                    OutputStreamWriter writer = new OutputStreamWriter(fout,
0293:                            csn);
0294:                    out = new BufferedWriter(writer);
0295:                } catch (RuntimeException e) {
0296:                    closeOutputStream(fout);
0297:                    throw e;
0298:                } catch (UnsupportedEncodingException e) {
0299:                    closeOutputStream(fout);
0300:                    throw e;
0301:                }
0302:
0303:                locale = l;
0304:            }
0305:
0306:            /**
0307:             * Constructs a formatter of which the output destination is specified.
0308:             * 
0309:             * The charset of the formatter is the default charset of JVM.
0310:             * 
0311:             * The locale for the formatter is the default locale of the JVM.
0312:             * 
0313:             * @param os
0314:             *            The stream used as the destination of the formatter.
0315:             */
0316:            public Formatter(OutputStream os) {
0317:                OutputStreamWriter writer = new OutputStreamWriter(os, Charset
0318:                        .defaultCharset());
0319:                out = new BufferedWriter(writer);
0320:                locale = Locale.getDefault();
0321:            }
0322:
0323:            /**
0324:             * Constructs a formatter of which the output destination and the charset is
0325:             * specified.
0326:             * 
0327:             * The locale for the formatter is the default locale of the JVM.
0328:             * 
0329:             * @param os
0330:             *            The stream used as the destination of the formatter.
0331:             * @param csn
0332:             *            The name of the charset for the formatter.
0333:             * @throws UnsupportedEncodingException
0334:             *             If the charset with the specified name is not supported.
0335:             */
0336:            public Formatter(OutputStream os, String csn)
0337:                    throws UnsupportedEncodingException {
0338:
0339:                this (os, csn, Locale.getDefault());
0340:            }
0341:
0342:            /**
0343:             * Constructs a formatter of which the output destination, the charset and
0344:             * the locale is specified.
0345:             * 
0346:             * @param os
0347:             *            The stream used as the destination of the formatter.
0348:             * @param csn
0349:             *            The name of the charset for the formatter.
0350:             * @param l
0351:             *            The locale of the formatter. If l is null, then no
0352:             *            localization will be used.
0353:             * @throws UnsupportedEncodingException
0354:             *             If the charset with the specified name is not supported.
0355:             */
0356:            public Formatter(OutputStream os, String csn, Locale l)
0357:                    throws UnsupportedEncodingException {
0358:
0359:                OutputStreamWriter writer = new OutputStreamWriter(os, csn);
0360:                out = new BufferedWriter(writer);
0361:
0362:                locale = l;
0363:            }
0364:
0365:            /**
0366:             * Constructs a formatter of which the output destination is specified.
0367:             * 
0368:             * The charset of the formatter is the default charset of JVM.
0369:             * 
0370:             * The locale for the formatter is the default locale of the JVM.
0371:             * 
0372:             * @param ps
0373:             *            The print stream used as destination of the formatter. If ps
0374:             *            is null, then NullPointerExcepiton will be thrown out.
0375:             */
0376:            public Formatter(PrintStream ps) {
0377:                if (null == ps) {
0378:                    throw new NullPointerException();
0379:                }
0380:                out = ps;
0381:                locale = Locale.getDefault();
0382:            }
0383:
0384:            private void checkClosed() {
0385:                if (closed) {
0386:                    throw new FormatterClosedException();
0387:                }
0388:            }
0389:
0390:            /**
0391:             * Returns the locale of the formatter.
0392:             * 
0393:             * @return The locale for the formatter and null for no locale.
0394:             * @throws FormatterClosedException
0395:             *             If the formatter has been closed.
0396:             */
0397:            public Locale locale() {
0398:                checkClosed();
0399:                return locale;
0400:            }
0401:
0402:            /**
0403:             * Returns the output destination of the formatter.
0404:             * 
0405:             * @return The output destination of the formatter.
0406:             * @throws FormatterClosedException
0407:             *             If the formatter has been closed.
0408:             */
0409:            public Appendable out() {
0410:                checkClosed();
0411:                return out;
0412:            }
0413:
0414:            /**
0415:             * Returns the content by calling the toString() method of the output
0416:             * destination.
0417:             * 
0418:             * @return The content by calling the toString() method of the output
0419:             *         destination.
0420:             * @throws FormatterClosedException
0421:             *             If the formatter has been closed.
0422:             */
0423:            @Override
0424:            public String toString() {
0425:                checkClosed();
0426:                return out.toString();
0427:            }
0428:
0429:            /**
0430:             * Flushes the formatter. If the output destination is {@link Flushable},
0431:             * then the method flush() will be called on that destination.
0432:             * 
0433:             * @throws FormatterClosedException
0434:             *             If the formatter has been closed.
0435:             */
0436:            public void flush() {
0437:                checkClosed();
0438:                if (out instanceof  Flushable) {
0439:                    try {
0440:                        ((Flushable) out).flush();
0441:                    } catch (IOException e) {
0442:                        lastIOException = e;
0443:                    }
0444:                }
0445:            }
0446:
0447:            /**
0448:             * Closes the formatter. If the output destination is {@link Closeable},
0449:             * then the method close() will be called on that destination.
0450:             * 
0451:             * If the formatter has been closed, then calling the close will have no
0452:             * effect.
0453:             * 
0454:             * Any method but the ioException() that is called after the formatter has
0455:             * been closed will raise a FormatterClosedException.
0456:             */
0457:            public void close() {
0458:                closed = true;
0459:                try {
0460:                    if (out instanceof  Closeable) {
0461:                        ((Closeable) out).close();
0462:                    }
0463:                } catch (IOException e) {
0464:
0465:                    lastIOException = e;
0466:                }
0467:            }
0468:
0469:            /**
0470:             * Returns the last IOException thrown out by the formatter's output
0471:             * destination. If the append() method of the destination will not throw
0472:             * IOException, the ioException() method will always return null.
0473:             * 
0474:             * @return The last IOException thrown out by the formatter's output
0475:             *         destination.
0476:             */
0477:            public IOException ioException() {
0478:                return lastIOException;
0479:            }
0480:
0481:            /**
0482:             * Writes a formatted string to the output destination of the formatter.
0483:             * 
0484:             * @param format
0485:             *            A format string.
0486:             * @param args
0487:             *            The arguments list used in the format() method. If there are
0488:             *            more arguments than those specified by the format string, then
0489:             *            the additional arguments are ignored.
0490:             * @return This formatter.
0491:             * @throws IllegalFormatException
0492:             *             If the format string is illegal or incompatible with the
0493:             *             arguments or the arguments are less than those required by
0494:             *             the format string or any other illegal situation.
0495:             * @throws FormatterClosedException
0496:             *             If the formatter has been closed.
0497:             */
0498:            public Formatter format(String format, Object... args) {
0499:                return format(locale, format, args);
0500:            }
0501:
0502:            /**
0503:             * Writes a formatted string to the output destination of the formatter.
0504:             * 
0505:             * @param l
0506:             *            The locale used in the method. If locale is null, then no
0507:             *            localization will be applied. This parameter does not
0508:             *            influence the locale specified during construction.
0509:             * @param format
0510:             *            A format string.
0511:             * @param args
0512:             *            The arguments list used in the format() method. If there are
0513:             *            more arguments than those specified by the format string, then
0514:             *            the additional arguments are ignored.
0515:             * @return This formatter.
0516:             * @throws IllegalFormatException
0517:             *             If the format string is illegal or incompatible with the
0518:             *             arguments or the arguments are less than those required by
0519:             *             the format string or any other illegal situation.
0520:             * @throws FormatterClosedException
0521:             *             If the formatter has been closed.
0522:             */
0523:            public Formatter format(Locale l, String format, Object... args) {
0524:                checkClosed();
0525:                CharBuffer formatBuffer = CharBuffer.wrap(format);
0526:                ParserStateMachine parser = new ParserStateMachine(formatBuffer);
0527:                Transformer transformer = new Transformer(this , l);
0528:
0529:                int currentObjectIndex = 0;
0530:                Object lastArgument = null;
0531:                boolean hasLastArgumentSet = false;
0532:                while (formatBuffer.hasRemaining()) {
0533:                    parser.reset();
0534:                    FormatToken token = parser.getNextFormatToken();
0535:                    String result;
0536:                    String plainText = token.getPlainText();
0537:                    if (token.getConversionType() == (char) FormatToken.UNSET) {
0538:                        result = plainText;
0539:                    } else {
0540:                        plainText = plainText.substring(0, plainText
0541:                                .indexOf('%'));
0542:                        Object argument = null;
0543:                        if (token.requireArgument()) {
0544:                            int index = token.getArgIndex() == FormatToken.UNSET ? currentObjectIndex++
0545:                                    : token.getArgIndex();
0546:                            argument = getArgument(args, index, token,
0547:                                    lastArgument, hasLastArgumentSet);
0548:                            lastArgument = argument;
0549:                            hasLastArgumentSet = true;
0550:                        }
0551:                        result = transformer.transform(token, argument);
0552:                        result = (null == result ? plainText : plainText
0553:                                + result);
0554:                    }
0555:                    // if output is made by formattable callback
0556:                    if (null != result) {
0557:                        try {
0558:                            out.append(result);
0559:                        } catch (IOException e) {
0560:                            lastIOException = e;
0561:                        }
0562:                    }
0563:                }
0564:                return this ;
0565:            }
0566:
0567:            private Object getArgument(Object[] args, int index,
0568:                    FormatToken token, Object lastArgument,
0569:                    boolean hasLastArgumentSet) {
0570:                if (index == FormatToken.LAST_ARGUMENT_INDEX
0571:                        && !hasLastArgumentSet) {
0572:                    throw new MissingFormatArgumentException("<"); //$NON-NLS-1$
0573:                }
0574:
0575:                if (null == args) {
0576:                    return null;
0577:                }
0578:
0579:                if (index >= args.length) {
0580:                    throw new MissingFormatArgumentException(token
0581:                            .getPlainText());
0582:                }
0583:
0584:                if (index == FormatToken.LAST_ARGUMENT_INDEX) {
0585:                    return lastArgument;
0586:                }
0587:
0588:                return args[index];
0589:            }
0590:
0591:            private static void closeOutputStream(OutputStream os) {
0592:                if (null == os) {
0593:                    return;
0594:                }
0595:                try {
0596:                    os.close();
0597:
0598:                } catch (IOException e) {
0599:                    // silently
0600:                }
0601:            }
0602:
0603:            /*
0604:             * Information about the format string of a specified argument, which
0605:             * includes the conversion type, flags, width, precision and the argument
0606:             * index as well as the plainText that contains the whole format string used
0607:             * as the result for output if necessary. Besides, the string for flags is
0608:             * recorded to construct corresponding FormatExceptions if necessary.
0609:             */
0610:            private static class FormatToken {
0611:
0612:                static final int LAST_ARGUMENT_INDEX = -2;
0613:
0614:                static final int UNSET = -1;
0615:
0616:                static final int FLAGS_UNSET = 0;
0617:
0618:                static final int DEFAULT_PRECISION = 6;
0619:
0620:                static final int FLAG_MINUS = 1;
0621:
0622:                static final int FLAG_SHARP = 1 << 1;
0623:
0624:                static final int FLAG_ADD = 1 << 2;
0625:
0626:                static final int FLAG_SPACE = 1 << 3;
0627:
0628:                static final int FLAG_ZERO = 1 << 4;
0629:
0630:                static final int FLAG_COMMA = 1 << 5;
0631:
0632:                static final int FLAG_PARENTHESIS = 1 << 6;
0633:
0634:                private static final int FLAGT_TYPE_COUNT = 6;
0635:
0636:                private int formatStringStartIndex;
0637:
0638:                private String plainText;
0639:
0640:                private int argIndex = UNSET;
0641:
0642:                private int flags = 0;
0643:
0644:                private int width = UNSET;
0645:
0646:                private int precision = UNSET;
0647:
0648:                private StringBuilder strFlags = new StringBuilder(
0649:                        FLAGT_TYPE_COUNT);
0650:
0651:                private char dateSuffix;// will be used in new feature.
0652:
0653:                private char conversionType = (char) UNSET;
0654:
0655:                boolean isPrecisionSet() {
0656:                    return precision != UNSET;
0657:                }
0658:
0659:                boolean isWidthSet() {
0660:                    return width != UNSET;
0661:                }
0662:
0663:                boolean isFlagSet(int flag) {
0664:                    return 0 != (flags & flag);
0665:                }
0666:
0667:                int getArgIndex() {
0668:                    return argIndex;
0669:                }
0670:
0671:                void setArgIndex(int index) {
0672:                    argIndex = index;
0673:                }
0674:
0675:                String getPlainText() {
0676:                    return plainText;
0677:                }
0678:
0679:                void setPlainText(String plainText) {
0680:                    this .plainText = plainText;
0681:                }
0682:
0683:                int getWidth() {
0684:                    return width;
0685:                }
0686:
0687:                void setWidth(int width) {
0688:                    this .width = width;
0689:                }
0690:
0691:                int getPrecision() {
0692:                    return precision;
0693:                }
0694:
0695:                void setPrecision(int precise) {
0696:                    this .precision = precise;
0697:                }
0698:
0699:                String getStrFlags() {
0700:                    return strFlags.toString();
0701:                }
0702:
0703:                int getFlags() {
0704:                    return flags;
0705:                }
0706:
0707:                void setFlags(int flags) {
0708:                    this .flags = flags;
0709:                }
0710:
0711:                /*
0712:                 * Sets qualified char as one of the flags. If the char is qualified,
0713:                 * sets it as a flag and returns true. Or else returns false.
0714:                 */
0715:                boolean setFlag(char c) {
0716:                    int newFlag;
0717:                    switch (c) {
0718:                    case '-': {
0719:                        newFlag = FLAG_MINUS;
0720:                        break;
0721:                    }
0722:                    case '#': {
0723:                        newFlag = FLAG_SHARP;
0724:                        break;
0725:                    }
0726:                    case '+': {
0727:                        newFlag = FLAG_ADD;
0728:                        break;
0729:                    }
0730:                    case ' ': {
0731:                        newFlag = FLAG_SPACE;
0732:                        break;
0733:                    }
0734:                    case '0': {
0735:                        newFlag = FLAG_ZERO;
0736:                        break;
0737:                    }
0738:                    case ',': {
0739:                        newFlag = FLAG_COMMA;
0740:                        break;
0741:                    }
0742:                    case '(': {
0743:                        newFlag = FLAG_PARENTHESIS;
0744:                        break;
0745:                    }
0746:                    default:
0747:                        return false;
0748:                    }
0749:                    if (0 != (flags & newFlag)) {
0750:                        throw new DuplicateFormatFlagsException(String
0751:                                .valueOf(c));
0752:                    }
0753:                    flags = (flags | newFlag);
0754:                    strFlags.append(c);
0755:                    return true;
0756:
0757:                }
0758:
0759:                int getFormatStringStartIndex() {
0760:                    return formatStringStartIndex;
0761:                }
0762:
0763:                void setFormatStringStartIndex(int index) {
0764:                    formatStringStartIndex = index;
0765:                }
0766:
0767:                char getConversionType() {
0768:                    return conversionType;
0769:                }
0770:
0771:                void setConversionType(char c) {
0772:                    conversionType = c;
0773:                }
0774:
0775:                char getDateSuffix() {
0776:                    return dateSuffix;
0777:                }
0778:
0779:                void setDateSuffix(char c) {
0780:                    dateSuffix = c;
0781:                }
0782:
0783:                boolean requireArgument() {
0784:                    return conversionType != '%' && conversionType != 'n';
0785:                }
0786:            }
0787:
0788:            /*
0789:             * Transforms the argument to the formatted string according to the format
0790:             * information contained in the format token.
0791:             */
0792:            private static class Transformer {
0793:
0794:                private Formatter formatter;
0795:
0796:                private FormatToken formatToken;
0797:
0798:                private Object arg;
0799:
0800:                private Locale locale;
0801:
0802:                private static String lineSeparator;
0803:
0804:                private NumberFormat numberFormat;
0805:
0806:                private DecimalFormatSymbols decimalFormatSymbols;
0807:
0808:                private DateTimeUtil dateTimeUtil;
0809:
0810:                Transformer(Formatter formatter, Locale locale) {
0811:                    this .formatter = formatter;
0812:                    this .locale = (null == locale ? Locale.US : locale);
0813:                }
0814:
0815:                private NumberFormat getNumberFormat() {
0816:                    if (null == numberFormat) {
0817:                        numberFormat = NumberFormat.getInstance(locale);
0818:                    }
0819:                    return numberFormat;
0820:                }
0821:
0822:                private DecimalFormatSymbols getDecimalFormatSymbols() {
0823:                    if (null == decimalFormatSymbols) {
0824:                        decimalFormatSymbols = new DecimalFormatSymbols(locale);
0825:                    }
0826:                    return decimalFormatSymbols;
0827:                }
0828:
0829:                /*
0830:                 * Gets the formatted string according to the format token and the
0831:                 * argument.
0832:                 */
0833:                String transform(FormatToken token, Object argument) {
0834:
0835:                    /* init data member to print */
0836:                    this .formatToken = token;
0837:                    this .arg = argument;
0838:
0839:                    String result;
0840:                    switch (token.getConversionType()) {
0841:                    case 'B':
0842:                    case 'b': {
0843:                        result = transformFromBoolean();
0844:                        break;
0845:                    }
0846:                    case 'H':
0847:                    case 'h': {
0848:                        result = transformFromHashCode();
0849:                        break;
0850:                    }
0851:                    case 'S':
0852:                    case 's': {
0853:                        result = transformFromString();
0854:                        break;
0855:                    }
0856:                    case 'C':
0857:                    case 'c': {
0858:                        result = transformFromCharacter();
0859:                        break;
0860:                    }
0861:                    case 'd':
0862:                    case 'o':
0863:                    case 'x':
0864:                    case 'X': {
0865:                        if (null == arg || arg instanceof  BigInteger) {
0866:                            result = transformFromBigInteger();
0867:                        } else {
0868:                            result = transformFromInteger();
0869:                        }
0870:                        break;
0871:                    }
0872:                    case 'e':
0873:                    case 'E':
0874:                    case 'g':
0875:                    case 'G':
0876:                    case 'f':
0877:                    case 'a':
0878:                    case 'A': {
0879:                        result = transformFromFloat();
0880:                        break;
0881:                    }
0882:                    case '%': {
0883:                        result = transformFromPercent();
0884:                        break;
0885:                    }
0886:                    case 'n': {
0887:                        result = transformFromLineSeparator();
0888:                        break;
0889:                    }
0890:                    case 't':
0891:                    case 'T': {
0892:                        result = transformFromDateTime();
0893:                        break;
0894:                    }
0895:                    default: {
0896:                        throw new UnknownFormatConversionException(String
0897:                                .valueOf(token.getConversionType()));
0898:                    }
0899:                    }
0900:
0901:                    if (Character.isUpperCase(token.getConversionType())) {
0902:                        if (null != result) {
0903:                            result = result.toUpperCase(Locale.US);
0904:                        }
0905:                    }
0906:                    return result;
0907:                }
0908:
0909:                /*
0910:                 * Transforms the Boolean argument to a formatted string.
0911:                 */
0912:                private String transformFromBoolean() {
0913:                    StringBuilder result = new StringBuilder();
0914:                    int startIndex = 0;
0915:                    int flags = formatToken.getFlags();
0916:
0917:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
0918:                            && !formatToken.isWidthSet()) {
0919:                        throw new MissingFormatWidthException("-" //$NON-NLS-1$
0920:                                + formatToken.getConversionType());
0921:                    }
0922:
0923:                    // only '-' is valid for flags
0924:                    if (FormatToken.FLAGS_UNSET != flags
0925:                            && FormatToken.FLAG_MINUS != flags) {
0926:                        throw new FormatFlagsConversionMismatchException(
0927:                                formatToken.getStrFlags(), formatToken
0928:                                        .getConversionType());
0929:                    }
0930:
0931:                    if (null == arg) {
0932:                        result.append("false"); //$NON-NLS-1$
0933:                    } else if (arg instanceof  Boolean) {
0934:                        result.append(arg);
0935:                    } else {
0936:                        result.append("true"); //$NON-NLS-1$
0937:                    }
0938:                    return padding(result, startIndex);
0939:                }
0940:
0941:                /*
0942:                 * Transforms the hashcode of the argument to a formatted string.
0943:                 */
0944:                private String transformFromHashCode() {
0945:                    StringBuilder result = new StringBuilder();
0946:
0947:                    int startIndex = 0;
0948:                    int flags = formatToken.getFlags();
0949:
0950:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
0951:                            && !formatToken.isWidthSet()) {
0952:                        throw new MissingFormatWidthException("-" //$NON-NLS-1$
0953:                                + formatToken.getConversionType());
0954:                    }
0955:
0956:                    // only '-' is valid for flags
0957:                    if (FormatToken.FLAGS_UNSET != flags
0958:                            && FormatToken.FLAG_MINUS != flags) {
0959:                        throw new FormatFlagsConversionMismatchException(
0960:                                formatToken.getStrFlags(), formatToken
0961:                                        .getConversionType());
0962:                    }
0963:
0964:                    if (null == arg) {
0965:                        result.append("null"); //$NON-NLS-1$
0966:                    } else {
0967:                        result.append(Integer.toHexString(arg.hashCode()));
0968:                    }
0969:                    return padding(result, startIndex);
0970:                }
0971:
0972:                /*
0973:                 * Transforms the String to a formatted string.
0974:                 */
0975:                private String transformFromString() {
0976:                    StringBuilder result = new StringBuilder();
0977:                    int startIndex = 0;
0978:                    int flags = formatToken.getFlags();
0979:
0980:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
0981:                            && !formatToken.isWidthSet()) {
0982:                        throw new MissingFormatWidthException("-" //$NON-NLS-1$
0983:                                + formatToken.getConversionType());
0984:                    }
0985:
0986:                    if (arg instanceof  Formattable) {
0987:                        int flag = 0;
0988:                        // only minus and sharp flag is valid
0989:                        if (FormatToken.FLAGS_UNSET != (flags
0990:                                & ~FormatToken.FLAG_MINUS & ~FormatToken.FLAG_SHARP)) {
0991:                            throw new IllegalFormatFlagsException(formatToken
0992:                                    .getStrFlags());
0993:                        }
0994:                        if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)) {
0995:                            flag |= FormattableFlags.LEFT_JUSTIFY;
0996:                        }
0997:                        if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)) {
0998:                            flag |= FormattableFlags.ALTERNATE;
0999:                        }
1000:                        if (Character.isUpperCase(formatToken
1001:                                .getConversionType())) {
1002:                            flag |= FormattableFlags.UPPERCASE;
1003:                        }
1004:                        ((Formattable) arg).formatTo(formatter, flag,
1005:                                formatToken.getWidth(), formatToken
1006:                                        .getPrecision());
1007:                        // all actions have been taken out in the
1008:                        // Formattable.formatTo, thus there is nothing to do, just
1009:                        // returns null, which tells the Parser to add nothing to the
1010:                        // output.
1011:                        return null;
1012:                    }
1013:                    // only '-' is valid for flags if the argument is not an
1014:                    // instance of Formattable
1015:                    if (FormatToken.FLAGS_UNSET != flags
1016:                            && FormatToken.FLAG_MINUS != flags) {
1017:                        throw new FormatFlagsConversionMismatchException(
1018:                                formatToken.getStrFlags(), formatToken
1019:                                        .getConversionType());
1020:                    }
1021:
1022:                    result.append(arg);
1023:                    return padding(result, startIndex);
1024:                }
1025:
1026:                /*
1027:                 * Transforms the Character to a formatted string.
1028:                 */
1029:                private String transformFromCharacter() {
1030:                    StringBuilder result = new StringBuilder();
1031:
1032:                    int startIndex = 0;
1033:                    int flags = formatToken.getFlags();
1034:
1035:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
1036:                            && !formatToken.isWidthSet()) {
1037:                        throw new MissingFormatWidthException("-" //$NON-NLS-1$
1038:                                + formatToken.getConversionType());
1039:                    }
1040:
1041:                    // only '-' is valid for flags
1042:                    if (FormatToken.FLAGS_UNSET != flags
1043:                            && FormatToken.FLAG_MINUS != flags) {
1044:                        throw new FormatFlagsConversionMismatchException(
1045:                                formatToken.getStrFlags(), formatToken
1046:                                        .getConversionType());
1047:                    }
1048:
1049:                    if (formatToken.isPrecisionSet()) {
1050:                        throw new IllegalFormatPrecisionException(formatToken
1051:                                .getPrecision());
1052:                    }
1053:
1054:                    if (null == arg) {
1055:                        result.append("null"); //$NON-NLS-1$
1056:                    } else {
1057:                        if (arg instanceof  Character) {
1058:                            result.append(arg);
1059:                        } else if (arg instanceof  Byte) {
1060:                            byte b = ((Byte) arg).byteValue();
1061:                            if (!Character.isValidCodePoint(b)) {
1062:                                throw new IllegalFormatCodePointException(b);
1063:                            }
1064:                            result.append((char) b);
1065:                        } else if (arg instanceof  Short) {
1066:                            short s = ((Short) arg).shortValue();
1067:                            if (!Character.isValidCodePoint(s)) {
1068:                                throw new IllegalFormatCodePointException(s);
1069:                            }
1070:                            result.append((char) s);
1071:                        } else if (arg instanceof  Integer) {
1072:                            int codePoint = ((Integer) arg).intValue();
1073:                            if (!Character.isValidCodePoint(codePoint)) {
1074:                                throw new IllegalFormatCodePointException(
1075:                                        codePoint);
1076:                            }
1077:                            result.append(String.valueOf(Character
1078:                                    .toChars(codePoint)));
1079:                        } else {
1080:                            // argument of other class is not acceptable.
1081:                            throw new IllegalFormatConversionException(
1082:                                    formatToken.getConversionType(), arg
1083:                                            .getClass());
1084:                        }
1085:                    }
1086:                    return padding(result, startIndex);
1087:                }
1088:
1089:                /*
1090:                 * Transforms percent to a formatted string. Only '-' is legal flag.
1091:                 * Precision is illegal.
1092:                 */
1093:                private String transformFromPercent() {
1094:                    StringBuilder result = new StringBuilder("%"); //$NON-NLS-1$
1095:
1096:                    int startIndex = 0;
1097:                    int flags = formatToken.getFlags();
1098:
1099:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
1100:                            && !formatToken.isWidthSet()) {
1101:                        throw new MissingFormatWidthException("-" //$NON-NLS-1$
1102:                                + formatToken.getConversionType());
1103:                    }
1104:
1105:                    if (FormatToken.FLAGS_UNSET != flags
1106:                            && FormatToken.FLAG_MINUS != flags) {
1107:                        throw new FormatFlagsConversionMismatchException(
1108:                                formatToken.getStrFlags(), formatToken
1109:                                        .getConversionType());
1110:                    }
1111:                    if (formatToken.isPrecisionSet()) {
1112:                        throw new IllegalFormatPrecisionException(formatToken
1113:                                .getPrecision());
1114:                    }
1115:                    return padding(result, startIndex);
1116:                }
1117:
1118:                /*
1119:                 * Transforms line separator to a formatted string. Any flag, the width
1120:                 * or the precision is illegal.
1121:                 */
1122:                private String transformFromLineSeparator() {
1123:                    if (formatToken.isPrecisionSet()) {
1124:                        throw new IllegalFormatPrecisionException(formatToken
1125:                                .getPrecision());
1126:                    }
1127:
1128:                    if (formatToken.isWidthSet()) {
1129:                        throw new IllegalFormatWidthException(formatToken
1130:                                .getWidth());
1131:                    }
1132:
1133:                    int flags = formatToken.getFlags();
1134:                    if (FormatToken.FLAGS_UNSET != flags) {
1135:                        throw new IllegalFormatFlagsException(formatToken
1136:                                .getStrFlags());
1137:                    }
1138:
1139:                    if (null == lineSeparator) {
1140:                        lineSeparator = AccessController
1141:                                .doPrivileged(new PrivilegedAction<String>() {
1142:
1143:                                    public String run() {
1144:                                        return System
1145:                                                .getProperty("line.separator"); //$NON-NLS-1$
1146:                                    }
1147:                                });
1148:                    }
1149:                    return lineSeparator;
1150:                }
1151:
1152:                /*
1153:                 * Pads characters to the formatted string.
1154:                 */
1155:                private String padding(StringBuilder source, int startIndex) {
1156:                    int start = startIndex;
1157:                    boolean paddingRight = formatToken
1158:                            .isFlagSet(FormatToken.FLAG_MINUS);
1159:                    char paddingChar = '\u0020';// space as padding char.
1160:                    if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
1161:                        if ('d' == formatToken.getConversionType()) {
1162:                            paddingChar = getDecimalFormatSymbols()
1163:                                    .getZeroDigit();
1164:                        } else {
1165:                            paddingChar = '0';
1166:                        }
1167:                    } else {
1168:                        // if padding char is space, always padding from the head
1169:                        // location.
1170:                        start = 0;
1171:                    }
1172:                    int width = formatToken.getWidth();
1173:                    int precision = formatToken.getPrecision();
1174:
1175:                    int length = source.length();
1176:                    if (precision >= 0) {
1177:                        length = Math.min(length, precision);
1178:                        source.delete(length, source.length());
1179:                    }
1180:                    if (width > 0) {
1181:                        width = Math.max(source.length(), width);
1182:                    }
1183:                    if (length >= width) {
1184:                        return source.toString();
1185:                    }
1186:
1187:                    char[] paddings = new char[width - length];
1188:                    Arrays.fill(paddings, paddingChar);
1189:                    String insertString = new String(paddings);
1190:
1191:                    if (paddingRight) {
1192:                        source.append(insertString);
1193:                    } else {
1194:                        source.insert(start, insertString);
1195:                    }
1196:                    return source.toString();
1197:                }
1198:
1199:                /*
1200:                 * Transforms the Integer to a formatted string.
1201:                 */
1202:                private String transformFromInteger() {
1203:                    int startIndex = 0;
1204:                    boolean isNegative = false;
1205:                    StringBuilder result = new StringBuilder();
1206:                    char currentConversionType = formatToken
1207:                            .getConversionType();
1208:                    long value;
1209:
1210:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
1211:                            || formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
1212:                        if (!formatToken.isWidthSet()) {
1213:                            throw new MissingFormatWidthException(formatToken
1214:                                    .getStrFlags());
1215:                        }
1216:                    }
1217:                    // Combination of '+' & ' ' is illegal.
1218:                    if (formatToken.isFlagSet(FormatToken.FLAG_ADD)
1219:                            && formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
1220:                        throw new IllegalFormatFlagsException(formatToken
1221:                                .getStrFlags());
1222:                    }
1223:                    if (formatToken.isPrecisionSet()) {
1224:                        throw new IllegalFormatPrecisionException(formatToken
1225:                                .getPrecision());
1226:                    }
1227:                    if (arg instanceof  Long) {
1228:                        value = ((Long) arg).longValue();
1229:                    } else if (arg instanceof  Integer) {
1230:                        value = ((Integer) arg).longValue();
1231:                    } else if (arg instanceof  Short) {
1232:                        value = ((Short) arg).longValue();
1233:                    } else if (arg instanceof  Byte) {
1234:                        value = ((Byte) arg).longValue();
1235:                    } else {
1236:                        throw new IllegalFormatConversionException(formatToken
1237:                                .getConversionType(), arg.getClass());
1238:                    }
1239:                    if ('d' != currentConversionType) {
1240:                        if (formatToken.isFlagSet(FormatToken.FLAG_ADD)
1241:                                || formatToken
1242:                                        .isFlagSet(FormatToken.FLAG_SPACE)
1243:                                || formatToken
1244:                                        .isFlagSet(FormatToken.FLAG_COMMA)
1245:                                || formatToken
1246:                                        .isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
1247:                            throw new FormatFlagsConversionMismatchException(
1248:                                    formatToken.getStrFlags(), formatToken
1249:                                            .getConversionType());
1250:                        }
1251:                    }
1252:
1253:                    if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)) {
1254:                        if ('d' == currentConversionType) {
1255:                            throw new FormatFlagsConversionMismatchException(
1256:                                    formatToken.getStrFlags(), formatToken
1257:                                            .getConversionType());
1258:                        } else if ('o' == currentConversionType) {
1259:                            result.append("0"); //$NON-NLS-1$
1260:                            startIndex += 1;
1261:                        } else {
1262:                            result.append("0x"); //$NON-NLS-1$
1263:                            startIndex += 2;
1264:                        }
1265:                    }
1266:
1267:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
1268:                            && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
1269:                        throw new IllegalFormatFlagsException(formatToken
1270:                                .getStrFlags());
1271:                    }
1272:
1273:                    if (value < 0) {
1274:                        isNegative = true;
1275:                    }
1276:
1277:                    if ('d' == currentConversionType) {
1278:                        NumberFormat numberFormat = getNumberFormat();
1279:                        if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)) {
1280:                            numberFormat.setGroupingUsed(true);
1281:                        } else {
1282:                            numberFormat.setGroupingUsed(false);
1283:                        }
1284:                        result.append(numberFormat.format(arg));
1285:                    } else {
1286:                        long BYTE_MASK = 0x00000000000000FFL;
1287:                        long SHORT_MASK = 0x000000000000FFFFL;
1288:                        long INT_MASK = 0x00000000FFFFFFFFL;
1289:                        if (isNegative) {
1290:                            if (arg instanceof  Byte) {
1291:                                value &= BYTE_MASK;
1292:                            } else if (arg instanceof  Short) {
1293:                                value &= SHORT_MASK;
1294:                            } else if (arg instanceof  Integer) {
1295:                                value &= INT_MASK;
1296:                            }
1297:                        }
1298:                        if ('o' == currentConversionType) {
1299:                            result.append(Long.toOctalString(value));
1300:                        } else {
1301:                            result.append(Long.toHexString(value));
1302:                        }
1303:                        isNegative = false;
1304:                    }
1305:
1306:                    if (!isNegative) {
1307:                        if (formatToken.isFlagSet(FormatToken.FLAG_ADD)) {
1308:                            result.insert(0, '+');
1309:                            startIndex += 1;
1310:                        }
1311:                        if (formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
1312:                            result.insert(0, ' ');
1313:                            startIndex += 1;
1314:                        }
1315:                    }
1316:
1317:                    /* pad paddingChar to the output */
1318:                    if (isNegative
1319:                            && formatToken
1320:                                    .isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
1321:                        result = wrapParentheses(result);
1322:                        return result.toString();
1323:
1324:                    }
1325:                    if (isNegative
1326:                            && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
1327:                        startIndex++;
1328:                    }
1329:                    return padding(result, startIndex);
1330:                }
1331:
1332:                /*
1333:                 * add () to the output,if the value is negative and
1334:                 * formatToken.FLAG_PARENTHESIS is set. 'result' is used as an in-out
1335:                 * parameter.
1336:                 */
1337:                private StringBuilder wrapParentheses(StringBuilder result) {
1338:                    // delete the '-'
1339:                    result.deleteCharAt(0);
1340:                    result.insert(0, '(');
1341:                    if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
1342:                        formatToken.setWidth(formatToken.getWidth() - 1);
1343:                        padding(result, 1);
1344:                        result.append(')');
1345:                    } else {
1346:                        result.append(')');
1347:                        padding(result, 0);
1348:                    }
1349:                    return result;
1350:                }
1351:
1352:                private String transformFromSpecialNumber() {
1353:                    String source = null;
1354:
1355:                    if (!(arg instanceof  Number) || arg instanceof  BigDecimal) {
1356:                        return null;
1357:                    }
1358:
1359:                    Number number = (Number) arg;
1360:                    double d = number.doubleValue();
1361:                    if (Double.isNaN(d)) {
1362:                        source = "NaN"; //$NON-NLS-1$
1363:                    } else if (Double.isInfinite(d)) {
1364:                        if (d >= 0) {
1365:                            if (formatToken.isFlagSet(FormatToken.FLAG_ADD)) {
1366:                                source = "+Infinity"; //$NON-NLS-1$
1367:                            } else if (formatToken
1368:                                    .isFlagSet(FormatToken.FLAG_SPACE)) {
1369:                                source = " Infinity"; //$NON-NLS-1$
1370:                            } else {
1371:                                source = "Infinity"; //$NON-NLS-1$
1372:                            }
1373:                        } else {
1374:                            if (formatToken
1375:                                    .isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
1376:                                source = "(Infinity)"; //$NON-NLS-1$
1377:                            } else {
1378:                                source = "-Infinity"; //$NON-NLS-1$
1379:                            }
1380:                        }
1381:                    }
1382:
1383:                    if (null != source) {
1384:                        formatToken.setPrecision(FormatToken.UNSET);
1385:                        formatToken.setFlags(formatToken.getFlags()
1386:                                & (~FormatToken.FLAG_ZERO));
1387:                        source = padding(new StringBuilder(source), 0);
1388:                    }
1389:                    return source;
1390:                }
1391:
1392:                private String transformFromNull() {
1393:                    formatToken.setFlags(formatToken.getFlags()
1394:                            & (~FormatToken.FLAG_ZERO));
1395:                    return padding(new StringBuilder("null"), 0); //$NON-NLS-1$
1396:                }
1397:
1398:                /*
1399:                 * Transforms a BigInteger to a formatted string.
1400:                 */
1401:                private String transformFromBigInteger() {
1402:                    int startIndex = 0;
1403:                    boolean isNegative = false;
1404:                    StringBuilder result = new StringBuilder();
1405:                    BigInteger bigInt = (BigInteger) arg;
1406:                    char currentConversionType = formatToken
1407:                            .getConversionType();
1408:
1409:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
1410:                            || formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
1411:                        if (!formatToken.isWidthSet()) {
1412:                            throw new MissingFormatWidthException(formatToken
1413:                                    .getStrFlags());
1414:                        }
1415:                    }
1416:
1417:                    // Combination of '+' & ' ' is illegal.
1418:                    if (formatToken.isFlagSet(FormatToken.FLAG_ADD)
1419:                            && formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
1420:                        throw new IllegalFormatFlagsException(formatToken
1421:                                .getStrFlags());
1422:                    }
1423:
1424:                    // Combination of '-' & '0' is illegal.
1425:                    if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)
1426:                            && formatToken.isFlagSet(FormatToken.FLAG_MINUS)) {
1427:                        throw new IllegalFormatFlagsException(formatToken
1428:                                .getStrFlags());
1429:                    }
1430:
1431:                    if (formatToken.isPrecisionSet()) {
1432:                        throw new IllegalFormatPrecisionException(formatToken
1433:                                .getPrecision());
1434:                    }
1435:
1436:                    if ('d' != currentConversionType
1437:                            && formatToken.isFlagSet(FormatToken.FLAG_COMMA)) {
1438:                        throw new FormatFlagsConversionMismatchException(
1439:                                formatToken.getStrFlags(),
1440:                                currentConversionType);
1441:                    }
1442:
1443:                    if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)
1444:                            && 'd' == currentConversionType) {
1445:                        throw new FormatFlagsConversionMismatchException(
1446:                                formatToken.getStrFlags(),
1447:                                currentConversionType);
1448:                    }
1449:
1450:                    if (null == bigInt) {
1451:                        return transformFromNull();
1452:                    }
1453:
1454:                    isNegative = (bigInt.compareTo(BigInteger.ZERO) < 0);
1455:
1456:                    if ('d' == currentConversionType) {
1457:                        NumberFormat numberFormat = getNumberFormat();
1458:                        boolean readableName = formatToken
1459:                                .isFlagSet(FormatToken.FLAG_COMMA);
1460:                        numberFormat.setGroupingUsed(readableName);
1461:                        result.append(numberFormat.format(bigInt));
1462:                    } else if ('o' == currentConversionType) {
1463:                        // convert BigInteger to a string presentation using radix 8
1464:                        result.append(bigInt.toString(8));
1465:                    } else {
1466:                        // convert BigInteger to a string presentation using radix 16
1467:                        result.append(bigInt.toString(16));
1468:                    }
1469:                    if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)) {
1470:                        startIndex = isNegative ? 1 : 0;
1471:                        if ('o' == currentConversionType) {
1472:                            result.insert(startIndex, "0"); //$NON-NLS-1$
1473:                            startIndex += 1;
1474:                        } else if ('x' == currentConversionType
1475:                                || 'X' == currentConversionType) {
1476:                            result.insert(startIndex, "0x"); //$NON-NLS-1$
1477:                            startIndex += 2;
1478:                        }
1479:                    }
1480:
1481:                    if (!isNegative) {
1482:                        if (formatToken.isFlagSet(FormatToken.FLAG_ADD)) {
1483:                            result.insert(0, '+');
1484:                            startIndex += 1;
1485:                        }
1486:                        if (formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
1487:                            result.insert(0, ' ');
1488:                            startIndex += 1;
1489:                        }
1490:                    }
1491:
1492:                    /* pad paddingChar to the output */
1493:                    if (isNegative
1494:                            && formatToken
1495:                                    .isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
1496:                        result = wrapParentheses(result);
1497:                        return result.toString();
1498:
1499:                    }
1500:                    if (isNegative
1501:                            && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
1502:                        startIndex++;
1503:                    }
1504:                    return padding(result, startIndex);
1505:                }
1506:
1507:                /*
1508:                 * Transforms a Float,Double or BigDecimal to a formatted string.
1509:                 */
1510:                private String transformFromFloat() {
1511:                    StringBuilder result = new StringBuilder();
1512:                    int startIndex = 0;
1513:                    char currentConversionType = formatToken
1514:                            .getConversionType();
1515:
1516:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS
1517:                            | FormatToken.FLAG_ZERO)) {
1518:                        if (!formatToken.isWidthSet()) {
1519:                            throw new MissingFormatWidthException(formatToken
1520:                                    .getStrFlags());
1521:                        }
1522:                    }
1523:
1524:                    if (formatToken.isFlagSet(FormatToken.FLAG_ADD)
1525:                            && formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
1526:                        throw new IllegalFormatFlagsException(formatToken
1527:                                .getStrFlags());
1528:                    }
1529:
1530:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
1531:                            && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
1532:                        throw new IllegalFormatFlagsException(formatToken
1533:                                .getStrFlags());
1534:                    }
1535:
1536:                    if ('e' == Character.toLowerCase(currentConversionType)) {
1537:                        if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)) {
1538:                            throw new FormatFlagsConversionMismatchException(
1539:                                    formatToken.getStrFlags(),
1540:                                    currentConversionType);
1541:                        }
1542:                    }
1543:
1544:                    if ('g' == Character.toLowerCase(currentConversionType)) {
1545:                        if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)) {
1546:                            throw new FormatFlagsConversionMismatchException(
1547:                                    formatToken.getStrFlags(),
1548:                                    currentConversionType);
1549:                        }
1550:                    }
1551:
1552:                    if ('a' == Character.toLowerCase(currentConversionType)) {
1553:                        if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)
1554:                                || formatToken
1555:                                        .isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
1556:                            throw new FormatFlagsConversionMismatchException(
1557:                                    formatToken.getStrFlags(),
1558:                                    currentConversionType);
1559:                        }
1560:                    }
1561:
1562:                    if (null == arg) {
1563:                        return transformFromNull();
1564:                    }
1565:
1566:                    if (!(arg instanceof  Float || arg instanceof  Double || arg instanceof  BigDecimal)) {
1567:                        throw new IllegalFormatConversionException(
1568:                                currentConversionType, arg.getClass());
1569:                    }
1570:
1571:                    String specialNumberResult = transformFromSpecialNumber();
1572:                    if (null != specialNumberResult) {
1573:                        return specialNumberResult;
1574:                    }
1575:
1576:                    if ('a' != Character.toLowerCase(currentConversionType)) {
1577:                        formatToken
1578:                                .setPrecision(formatToken.isPrecisionSet() ? formatToken
1579:                                        .getPrecision()
1580:                                        : FormatToken.DEFAULT_PRECISION);
1581:                    }
1582:                    // output result
1583:                    FloatUtil floatUtil = new FloatUtil(result, formatToken,
1584:                            (DecimalFormat) NumberFormat.getInstance(locale),
1585:                            arg);
1586:                    floatUtil.transform(formatToken, result);
1587:
1588:                    formatToken.setPrecision(FormatToken.UNSET);
1589:
1590:                    if (getDecimalFormatSymbols().getMinusSign() == result
1591:                            .charAt(0)) {
1592:                        if (formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
1593:                            result = wrapParentheses(result);
1594:                            return result.toString();
1595:                        }
1596:                    } else {
1597:                        if (formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
1598:                            result.insert(0, ' ');
1599:                            startIndex++;
1600:                        }
1601:                        if (formatToken.isFlagSet(FormatToken.FLAG_ADD)) {
1602:                            result.insert(0, floatUtil.getAddSign());
1603:                            startIndex++;
1604:                        }
1605:                    }
1606:
1607:                    char firstChar = result.charAt(0);
1608:                    if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)
1609:                            && (firstChar == floatUtil.getAddSign() || firstChar == floatUtil
1610:                                    .getMinusSign())) {
1611:                        startIndex = 1;
1612:                    }
1613:
1614:                    if ('a' == Character.toLowerCase(currentConversionType)) {
1615:                        startIndex += 2;
1616:                    }
1617:                    return padding(result, startIndex);
1618:                }
1619:
1620:                /*
1621:                 * Transforms a Date to a formatted string.
1622:                 */
1623:                private String transformFromDateTime() {
1624:                    int startIndex = 0;
1625:                    char currentConversionType = formatToken
1626:                            .getConversionType();
1627:
1628:                    if (formatToken.isPrecisionSet()) {
1629:                        throw new IllegalFormatPrecisionException(formatToken
1630:                                .getPrecision());
1631:                    }
1632:
1633:                    if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)) {
1634:                        throw new FormatFlagsConversionMismatchException(
1635:                                formatToken.getStrFlags(),
1636:                                currentConversionType);
1637:                    }
1638:
1639:                    if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
1640:                            && FormatToken.UNSET == formatToken.getWidth()) {
1641:                        throw new MissingFormatWidthException("-" //$NON-NLS-1$
1642:                                + currentConversionType);
1643:                    }
1644:
1645:                    if (null == arg) {
1646:                        return transformFromNull();
1647:                    }
1648:
1649:                    Calendar calendar;
1650:                    if (arg instanceof  Calendar) {
1651:                        calendar = (Calendar) arg;
1652:                    } else {
1653:                        Date date = null;
1654:                        if (arg instanceof  Long) {
1655:                            date = new Date(((Long) arg).longValue());
1656:                        } else if (arg instanceof  Date) {
1657:                            date = (Date) arg;
1658:                        } else {
1659:                            throw new IllegalFormatConversionException(
1660:                                    currentConversionType, arg.getClass());
1661:                        }
1662:                        calendar = Calendar.getInstance(locale);
1663:                        calendar.setTime(date);
1664:                    }
1665:
1666:                    if (null == dateTimeUtil) {
1667:                        dateTimeUtil = new DateTimeUtil(locale);
1668:                    }
1669:                    StringBuilder result = new StringBuilder();
1670:                    // output result
1671:                    dateTimeUtil.transform(formatToken, calendar, result);
1672:                    return padding(result, startIndex);
1673:                }
1674:            }
1675:
1676:            private static class FloatUtil {
1677:                private StringBuilder result;
1678:
1679:                private DecimalFormat decimalFormat;
1680:
1681:                private FormatToken formatToken;
1682:
1683:                private Object argument;
1684:
1685:                private char minusSign;
1686:
1687:                FloatUtil(StringBuilder result, FormatToken formatToken,
1688:                        DecimalFormat decimalFormat, Object argument) {
1689:                    this .result = result;
1690:                    this .formatToken = formatToken;
1691:                    this .decimalFormat = decimalFormat;
1692:                    this .argument = argument;
1693:                    this .minusSign = decimalFormat.getDecimalFormatSymbols()
1694:                            .getMinusSign();
1695:                }
1696:
1697:                void transform(FormatToken aFormatToken, StringBuilder aResult) {
1698:                    this .result = aResult;
1699:                    this .formatToken = aFormatToken;
1700:                    switch (formatToken.getConversionType()) {
1701:                    case 'e':
1702:                    case 'E': {
1703:                        transform_e();
1704:                        break;
1705:                    }
1706:                    case 'f': {
1707:                        transform_f();
1708:                        break;
1709:                    }
1710:                    case 'g':
1711:                    case 'G': {
1712:                        transform_g();
1713:                        break;
1714:                    }
1715:                    case 'a':
1716:                    case 'A': {
1717:                        transform_a();
1718:                        break;
1719:                    }
1720:                    default: {
1721:                        throw new UnknownFormatConversionException(String
1722:                                .valueOf(formatToken.getConversionType()));
1723:                    }
1724:                    }
1725:                }
1726:
1727:                char getMinusSign() {
1728:                    return minusSign;
1729:                }
1730:
1731:                char getAddSign() {
1732:                    return '+';
1733:                }
1734:
1735:                void transform_e() {
1736:                    StringBuilder pattern = new StringBuilder();
1737:                    pattern.append('0');
1738:                    if (formatToken.getPrecision() > 0) {
1739:                        pattern.append('.');
1740:                        char[] zeros = new char[formatToken.getPrecision()];
1741:                        Arrays.fill(zeros, '0');
1742:                        pattern.append(zeros);
1743:                    }
1744:                    pattern.append('E');
1745:                    pattern.append("+00"); //$NON-NLS-1$
1746:                    decimalFormat.applyPattern(pattern.toString());
1747:                    String formattedString = decimalFormat.format(argument);
1748:                    result.append(formattedString.replace('E', 'e'));
1749:
1750:                    // if the flag is sharp and decimal seperator is always given
1751:                    // out.
1752:                    if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)
1753:                            && 0 == formatToken.getPrecision()) {
1754:                        int indexOfE = result.indexOf("e"); //$NON-NLS-1$
1755:                        char dot = decimalFormat.getDecimalFormatSymbols()
1756:                                .getDecimalSeparator();
1757:                        result.insert(indexOfE, dot);
1758:                    }
1759:                }
1760:
1761:                void transform_g() {
1762:                    int precision = formatToken.getPrecision();
1763:                    precision = (0 == precision ? 1 : precision);
1764:                    formatToken.setPrecision(precision);
1765:
1766:                    if (0.0 == ((Number) argument).doubleValue()) {
1767:                        precision--;
1768:                        formatToken.setPrecision(precision);
1769:                        transform_f();
1770:                        return;
1771:                    }
1772:
1773:                    boolean requireScientificRepresentation = true;
1774:                    double d = ((Number) argument).doubleValue();
1775:                    d = Math.abs(d);
1776:                    long l = Math.round(d);
1777:
1778:                    if (l >= 1) {
1779:                        if (l < Math.pow(10, precision)) {
1780:                            requireScientificRepresentation = false;
1781:                            precision -= String.valueOf(l).length();
1782:                            precision = precision < 0 ? 0 : precision;
1783:                            l = Math.round(d * Math.pow(10, precision + 1));
1784:                            if (String.valueOf(l).length() <= formatToken
1785:                                    .getPrecision()) {
1786:                                precision++;
1787:                            }
1788:                            formatToken.setPrecision(precision);
1789:                        }
1790:
1791:                    } else {
1792:                        l = Math.round(d * Math.pow(10, 4));
1793:                        if (l >= 1) {
1794:                            requireScientificRepresentation = false;
1795:                            precision += 4 - String.valueOf(l).length();
1796:                            l = Math.round(d * Math.pow(10, precision + 1));
1797:                            if (String.valueOf(l).length() <= formatToken
1798:                                    .getPrecision()) {
1799:                                precision++;
1800:                            }
1801:                            l = Math.round(d * Math.pow(10, precision));
1802:                            if (l < Math.pow(10, precision - 4)) {
1803:                                requireScientificRepresentation = true;
1804:                            } else {
1805:                                formatToken.setPrecision(precision);
1806:                            }
1807:                        }
1808:                    }
1809:                    if (requireScientificRepresentation) {
1810:                        precision = formatToken.getPrecision();
1811:                        precision--;
1812:                        formatToken.setPrecision(precision);
1813:                        transform_e();
1814:                    } else {
1815:                        transform_f();
1816:                    }
1817:
1818:                }
1819:
1820:                void transform_f() {
1821:                    StringBuilder pattern = new StringBuilder();
1822:                    if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)) {
1823:                        pattern.append(',');
1824:                        int groupingSize = decimalFormat.getGroupingSize();
1825:                        if (groupingSize > 1) {
1826:                            char[] sharps = new char[groupingSize - 1];
1827:                            Arrays.fill(sharps, '#');
1828:                            pattern.append(sharps);
1829:                        }
1830:                    }
1831:
1832:                    pattern.append(0);
1833:
1834:                    if (formatToken.getPrecision() > 0) {
1835:                        pattern.append('.');
1836:                        char[] zeros = new char[formatToken.getPrecision()];
1837:                        Arrays.fill(zeros, '0');
1838:                        pattern.append(zeros);
1839:                    }
1840:                    decimalFormat.applyPattern(pattern.toString());
1841:                    result.append(decimalFormat.format(argument));
1842:                    // if the flag is sharp and decimal seperator is always given
1843:                    // out.
1844:                    if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)
1845:                            && 0 == formatToken.getPrecision()) {
1846:                        char dot = decimalFormat.getDecimalFormatSymbols()
1847:                                .getDecimalSeparator();
1848:                        result.append(dot);
1849:                    }
1850:
1851:                }
1852:
1853:                void transform_a() {
1854:                    char currentConversionType = formatToken
1855:                            .getConversionType();
1856:
1857:                    if (argument instanceof  Float) {
1858:                        Float F = (Float) argument;
1859:                        result.append(Float.toHexString(F.floatValue()));
1860:
1861:                    } else if (argument instanceof  Double) {
1862:                        Double D = (Double) argument;
1863:                        result.append(Double.toHexString(D.doubleValue()));
1864:                    } else {
1865:                        // BigInteger is not supported.
1866:                        throw new IllegalFormatConversionException(
1867:                                currentConversionType, argument.getClass());
1868:                    }
1869:
1870:                    if (!formatToken.isPrecisionSet()) {
1871:                        return;
1872:                    }
1873:
1874:                    int precision = formatToken.getPrecision();
1875:                    precision = (0 == precision ? 1 : precision);
1876:                    int indexOfFirstFracitoanlDigit = result.indexOf(".") + 1; //$NON-NLS-1$
1877:                    int indexOfP = result.indexOf("p"); //$NON-NLS-1$
1878:                    int fractionalLength = indexOfP
1879:                            - indexOfFirstFracitoanlDigit;
1880:
1881:                    if (fractionalLength == precision) {
1882:                        return;
1883:                    }
1884:
1885:                    if (fractionalLength < precision) {
1886:                        char zeros[] = new char[precision - fractionalLength];
1887:                        Arrays.fill(zeros, '0');
1888:                        result.insert(indexOfP, zeros);
1889:                        return;
1890:                    }
1891:                    result.delete(indexOfFirstFracitoanlDigit + precision,
1892:                            indexOfP);
1893:                }
1894:            }
1895:
1896:            private static class DateTimeUtil {
1897:                private Calendar calendar;
1898:
1899:                private Locale locale;
1900:
1901:                private StringBuilder result;
1902:
1903:                private DateFormatSymbols dateFormatSymbols;
1904:
1905:                DateTimeUtil(Locale locale) {
1906:                    this .locale = locale;
1907:                }
1908:
1909:                void transform(FormatToken formatToken, Calendar aCalendar,
1910:                        StringBuilder aResult) {
1911:                    this .result = aResult;
1912:                    this .calendar = aCalendar;
1913:                    char suffix = formatToken.getDateSuffix();
1914:
1915:                    switch (suffix) {
1916:                    case 'H': {
1917:                        transform_H();
1918:                        break;
1919:                    }
1920:                    case 'I': {
1921:                        transform_I();
1922:                        break;
1923:                    }
1924:                    case 'M': {
1925:                        transform_M();
1926:                        break;
1927:                    }
1928:                    case 'S': {
1929:                        transform_S();
1930:                        break;
1931:                    }
1932:                    case 'L': {
1933:                        transform_L();
1934:                        break;
1935:                    }
1936:                    case 'N': {
1937:                        transform_N();
1938:                        break;
1939:                    }
1940:                    case 'k': {
1941:                        transform_k();
1942:                        break;
1943:                    }
1944:                    case 'l': {
1945:                        transform_l();
1946:                        break;
1947:                    }
1948:                    case 'p': {
1949:                        transform_p(true);
1950:                        break;
1951:                    }
1952:                    case 's': {
1953:                        transform_s();
1954:                        break;
1955:                    }
1956:                    case 'z': {
1957:                        transform_z();
1958:                        break;
1959:                    }
1960:                    case 'Z': {
1961:                        transform_Z();
1962:                        break;
1963:                    }
1964:                    case 'Q': {
1965:                        transform_Q();
1966:                        break;
1967:                    }
1968:                    case 'B': {
1969:                        transform_B();
1970:                        break;
1971:                    }
1972:                    case 'b':
1973:                    case 'h': {
1974:                        transform_b();
1975:                        break;
1976:                    }
1977:                    case 'A': {
1978:                        transform_A();
1979:                        break;
1980:                    }
1981:                    case 'a': {
1982:                        transform_a();
1983:                        break;
1984:                    }
1985:                    case 'C': {
1986:                        transform_C();
1987:                        break;
1988:                    }
1989:                    case 'Y': {
1990:                        transform_Y();
1991:                        break;
1992:                    }
1993:                    case 'y': {
1994:                        transform_y();
1995:                        break;
1996:                    }
1997:                    case 'j': {
1998:                        transform_j();
1999:                        break;
2000:                    }
2001:                    case 'm': {
2002:                        transform_m();
2003:                        break;
2004:                    }
2005:                    case 'd': {
2006:                        transform_d();
2007:                        break;
2008:                    }
2009:                    case 'e': {
2010:                        transform_e();
2011:                        break;
2012:                    }
2013:                    case 'R': {
2014:                        transform_R();
2015:                        break;
2016:                    }
2017:
2018:                    case 'T': {
2019:                        transform_T();
2020:                        break;
2021:                    }
2022:                    case 'r': {
2023:                        transform_r();
2024:                        break;
2025:                    }
2026:                    case 'D': {
2027:                        transform_D();
2028:                        break;
2029:                    }
2030:                    case 'F': {
2031:                        transform_F();
2032:                        break;
2033:                    }
2034:                    case 'c': {
2035:                        transform_c();
2036:                        break;
2037:                    }
2038:                    default: {
2039:                        throw new UnknownFormatConversionException(String
2040:                                .valueOf(formatToken.getConversionType())
2041:                                + formatToken.getDateSuffix());
2042:                    }
2043:                    }
2044:                }
2045:
2046:                private void transform_e() {
2047:                    int day = calendar.get(Calendar.DAY_OF_MONTH);
2048:                    result.append(day);
2049:                }
2050:
2051:                private void transform_d() {
2052:                    int day = calendar.get(Calendar.DAY_OF_MONTH);
2053:                    result.append(paddingZeros(day, 2));
2054:                }
2055:
2056:                private void transform_m() {
2057:                    int month = calendar.get(Calendar.MONTH);
2058:                    // The returned month starts from zero, which needs to be
2059:                    // incremented by 1.
2060:                    month++;
2061:                    result.append(paddingZeros(month, 2));
2062:                }
2063:
2064:                private void transform_j() {
2065:                    int day = calendar.get(Calendar.DAY_OF_YEAR);
2066:                    result.append(paddingZeros(day, 3));
2067:                }
2068:
2069:                private void transform_y() {
2070:                    int year = calendar.get(Calendar.YEAR);
2071:                    year %= 100;
2072:                    result.append(paddingZeros(year, 2));
2073:                }
2074:
2075:                private void transform_Y() {
2076:                    int year = calendar.get(Calendar.YEAR);
2077:                    result.append(paddingZeros(year, 4));
2078:                }
2079:
2080:                private void transform_C() {
2081:                    int year = calendar.get(Calendar.YEAR);
2082:                    year /= 100;
2083:                    result.append(paddingZeros(year, 2));
2084:                }
2085:
2086:                private void transform_a() {
2087:                    int day = calendar.get(Calendar.DAY_OF_WEEK);
2088:                    result
2089:                            .append(getDateFormatSymbols().getShortWeekdays()[day]);
2090:                }
2091:
2092:                private void transform_A() {
2093:                    int day = calendar.get(Calendar.DAY_OF_WEEK);
2094:                    result.append(getDateFormatSymbols().getWeekdays()[day]);
2095:                }
2096:
2097:                private void transform_b() {
2098:                    int month = calendar.get(Calendar.MONTH);
2099:                    result
2100:                            .append(getDateFormatSymbols().getShortMonths()[month]);
2101:                }
2102:
2103:                private void transform_B() {
2104:                    int month = calendar.get(Calendar.MONTH);
2105:                    result.append(getDateFormatSymbols().getMonths()[month]);
2106:                }
2107:
2108:                private void transform_Q() {
2109:                    long milliSeconds = calendar.getTimeInMillis();
2110:                    result.append(milliSeconds);
2111:                }
2112:
2113:                private void transform_s() {
2114:                    long milliSeconds = calendar.getTimeInMillis();
2115:                    milliSeconds /= 1000;
2116:                    result.append(milliSeconds);
2117:                }
2118:
2119:                private void transform_Z() {
2120:                    TimeZone timeZone = calendar.getTimeZone();
2121:                    result.append(timeZone.getDisplayName(true, TimeZone.SHORT,
2122:                            locale));
2123:                }
2124:
2125:                private void transform_z() {
2126:                    int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
2127:                    zoneOffset /= 3600000;
2128:                    zoneOffset *= 100;
2129:                    if (zoneOffset >= 0) {
2130:                        result.append('+');
2131:                    }
2132:                    result.append(paddingZeros(zoneOffset, 4));
2133:                }
2134:
2135:                private void transform_p(boolean isLowerCase) {
2136:                    int i = calendar.get(Calendar.AM_PM);
2137:                    String s = getDateFormatSymbols().getAmPmStrings()[i];
2138:                    if (isLowerCase) {
2139:                        s = s.toLowerCase(locale);
2140:                    }
2141:                    result.append(s);
2142:                }
2143:
2144:                private void transform_N() {
2145:                    // TODO System.nanoTime();
2146:                    long nanosecond = calendar.get(Calendar.MILLISECOND) * 1000000L;
2147:                    result.append(paddingZeros(nanosecond, 9));
2148:                }
2149:
2150:                private void transform_L() {
2151:                    int millisecond = calendar.get(Calendar.MILLISECOND);
2152:                    result.append(paddingZeros(millisecond, 3));
2153:                }
2154:
2155:                private void transform_S() {
2156:                    int second = calendar.get(Calendar.SECOND);
2157:                    result.append(paddingZeros(second, 2));
2158:                }
2159:
2160:                private void transform_M() {
2161:                    int minute = calendar.get(Calendar.MINUTE);
2162:                    result.append(paddingZeros(minute, 2));
2163:                }
2164:
2165:                private void transform_l() {
2166:                    int hour = calendar.get(Calendar.HOUR);
2167:                    if (0 == hour) {
2168:                        hour = 12;
2169:                    }
2170:                    result.append(hour);
2171:                }
2172:
2173:                private void transform_k() {
2174:                    int hour = calendar.get(Calendar.HOUR_OF_DAY);
2175:                    result.append(hour);
2176:                }
2177:
2178:                private void transform_I() {
2179:                    int hour = calendar.get(Calendar.HOUR);
2180:                    if (0 == hour) {
2181:                        hour = 12;
2182:                    }
2183:                    result.append(paddingZeros(hour, 2));
2184:                }
2185:
2186:                private void transform_H() {
2187:                    int hour = calendar.get(Calendar.HOUR_OF_DAY);
2188:                    result.append(paddingZeros(hour, 2));
2189:                }
2190:
2191:                private void transform_R() {
2192:                    transform_H();
2193:                    result.append(':');
2194:                    transform_M();
2195:                }
2196:
2197:                private void transform_T() {
2198:                    transform_H();
2199:                    result.append(':');
2200:                    transform_M();
2201:                    result.append(':');
2202:                    transform_S();
2203:                }
2204:
2205:                private void transform_r() {
2206:                    transform_I();
2207:                    result.append(':');
2208:                    transform_M();
2209:                    result.append(':');
2210:                    transform_S();
2211:                    result.append(' ');
2212:                    transform_p(false);
2213:                }
2214:
2215:                private void transform_D() {
2216:                    transform_m();
2217:                    result.append('/');
2218:                    transform_d();
2219:                    result.append('/');
2220:                    transform_y();
2221:                }
2222:
2223:                private void transform_F() {
2224:                    transform_Y();
2225:                    result.append('-');
2226:                    transform_m();
2227:                    result.append('-');
2228:                    transform_d();
2229:                }
2230:
2231:                private void transform_c() {
2232:                    transform_a();
2233:                    result.append(' ');
2234:                    transform_b();
2235:                    result.append(' ');
2236:                    transform_d();
2237:                    result.append(' ');
2238:                    transform_T();
2239:                    result.append(' ');
2240:                    transform_Z();
2241:                    result.append(' ');
2242:                    transform_Y();
2243:                }
2244:
2245:                private static String paddingZeros(long number, int length) {
2246:                    int len = length;
2247:                    StringBuilder result = new StringBuilder();
2248:                    result.append(number);
2249:                    int startIndex = 0;
2250:                    if (number < 0) {
2251:                        len++;
2252:                        startIndex = 1;
2253:                    }
2254:                    len -= result.length();
2255:                    if (len > 0) {
2256:                        char[] zeros = new char[len];
2257:                        Arrays.fill(zeros, '0');
2258:                        result.insert(startIndex, zeros);
2259:                    }
2260:                    return result.toString();
2261:                }
2262:
2263:                private DateFormatSymbols getDateFormatSymbols() {
2264:                    if (null == dateFormatSymbols) {
2265:                        dateFormatSymbols = new DateFormatSymbols(locale);
2266:                    }
2267:                    return dateFormatSymbols;
2268:                }
2269:            }
2270:
2271:            private static class ParserStateMachine {
2272:
2273:                private static final char EOS = (char) -1;
2274:
2275:                private static final int EXIT_STATE = 0;
2276:
2277:                private static final int ENTRY_STATE = 1;
2278:
2279:                private static final int START_CONVERSION_STATE = 2;
2280:
2281:                private static final int FLAGS_STATE = 3;
2282:
2283:                private static final int WIDTH_STATE = 4;
2284:
2285:                private static final int PRECISION_STATE = 5;
2286:
2287:                private static final int CONVERSION_TYPE_STATE = 6;
2288:
2289:                private static final int SUFFIX_STATE = 7;
2290:
2291:                private FormatToken token;
2292:
2293:                private int state = ENTRY_STATE;
2294:
2295:                private char currentChar = 0;
2296:
2297:                private CharBuffer format = null;
2298:
2299:                ParserStateMachine(CharBuffer format) {
2300:                    this .format = format;
2301:                }
2302:
2303:                void reset() {
2304:                    this .currentChar = (char) FormatToken.UNSET;
2305:                    this .state = ENTRY_STATE;
2306:                    this .token = null;
2307:                }
2308:
2309:                /*
2310:                 * Gets the information about the current format token. Information is
2311:                 * recorded in the FormatToken returned and the position of the stream
2312:                 * for the format string will be advanced till the next format token.
2313:                 */
2314:                FormatToken getNextFormatToken() {
2315:                    token = new FormatToken();
2316:                    token.setFormatStringStartIndex(format.position());
2317:
2318:                    // FINITE AUTOMATIC MACHINE
2319:                    while (true) {
2320:
2321:                        if (ParserStateMachine.EXIT_STATE != state) {
2322:                            // exit state does not need to get next char
2323:                            currentChar = getNextFormatChar();
2324:                            if (EOS == currentChar
2325:                                    && ParserStateMachine.ENTRY_STATE != state) {
2326:                                throw new UnknownFormatConversionException(
2327:                                        getFormatString());
2328:                            }
2329:                        }
2330:
2331:                        switch (state) {
2332:                        // exit state
2333:                        case ParserStateMachine.EXIT_STATE: {
2334:                            process_EXIT_STATE();
2335:                            return token;
2336:                        }
2337:                            // plain text state, not yet applied converter
2338:                        case ParserStateMachine.ENTRY_STATE: {
2339:                            process_ENTRY_STATE();
2340:                            break;
2341:                        }
2342:                            // begins converted string
2343:                        case ParserStateMachine.START_CONVERSION_STATE: {
2344:                            process_START_CONVERSION_STATE();
2345:                            break;
2346:                        }
2347:                        case ParserStateMachine.FLAGS_STATE: {
2348:                            process_FlAGS_STATE();
2349:                            break;
2350:                        }
2351:                        case ParserStateMachine.WIDTH_STATE: {
2352:                            process_WIDTH_STATE();
2353:                            break;
2354:                        }
2355:                        case ParserStateMachine.PRECISION_STATE: {
2356:                            process_PRECISION_STATE();
2357:                            break;
2358:                        }
2359:                        case ParserStateMachine.CONVERSION_TYPE_STATE: {
2360:                            process_CONVERSION_TYPE_STATE();
2361:                            break;
2362:                        }
2363:                        case ParserStateMachine.SUFFIX_STATE: {
2364:                            process_SUFFIX_STATE();
2365:                            break;
2366:                        }
2367:                        }
2368:                    }
2369:                }
2370:
2371:                /*
2372:                 * Gets next char from the format string.
2373:                 */
2374:                private char getNextFormatChar() {
2375:                    if (format.hasRemaining()) {
2376:                        return format.get();
2377:                    }
2378:                    return EOS;
2379:                }
2380:
2381:                private String getFormatString() {
2382:                    int end = format.position();
2383:                    format.rewind();
2384:                    String formatString = format.subSequence(
2385:                            token.getFormatStringStartIndex(), end).toString();
2386:                    format.position(end);
2387:                    return formatString;
2388:                }
2389:
2390:                private void process_ENTRY_STATE() {
2391:                    if (EOS == currentChar) {
2392:                        state = ParserStateMachine.EXIT_STATE;
2393:                    } else if ('%' == currentChar) {
2394:                        // change to conversion type state
2395:                        state = START_CONVERSION_STATE;
2396:                    }
2397:                    // else remains in ENTRY_STATE
2398:                }
2399:
2400:                private void process_START_CONVERSION_STATE() {
2401:                    if (Character.isDigit(currentChar)) {
2402:                        int position = format.position() - 1;
2403:                        int number = parseInt(format);
2404:                        char nextChar = 0;
2405:                        if (format.hasRemaining()) {
2406:                            nextChar = format.get();
2407:                        }
2408:                        if ('$' == nextChar) {
2409:                            // the digital sequence stands for the argument
2410:                            // index.
2411:                            int argIndex = number;
2412:                            // k$ stands for the argument whose index is k-1 except that
2413:                            // 0$ and 1$ both stands for the first element.
2414:                            if (argIndex > 0) {
2415:                                token.setArgIndex(argIndex - 1);
2416:                            } else if (argIndex == FormatToken.UNSET) {
2417:                                throw new MissingFormatArgumentException(
2418:                                        getFormatString());
2419:                            }
2420:                            state = FLAGS_STATE;
2421:                        } else {
2422:                            // the digital zero stands for one format flag.
2423:                            if ('0' == currentChar) {
2424:                                state = FLAGS_STATE;
2425:                                format.position(position);
2426:                            } else {
2427:                                // the digital sequence stands for the width.
2428:                                state = WIDTH_STATE;
2429:                                // do not get the next char.
2430:                                format.position(format.position() - 1);
2431:                                token.setWidth(number);
2432:                            }
2433:                        }
2434:                        currentChar = nextChar;
2435:                    } else if ('<' == currentChar) {
2436:                        state = FLAGS_STATE;
2437:                        token.setArgIndex(FormatToken.LAST_ARGUMENT_INDEX);
2438:                    } else {
2439:                        state = FLAGS_STATE;
2440:                        // do not get the next char.
2441:                        format.position(format.position() - 1);
2442:                    }
2443:
2444:                }
2445:
2446:                private void process_FlAGS_STATE() {
2447:                    if (token.setFlag(currentChar)) {
2448:                        // remains in FLAGS_STATE
2449:                    } else if (Character.isDigit(currentChar)) {
2450:                        token.setWidth(parseInt(format));
2451:                        state = WIDTH_STATE;
2452:                    } else if ('.' == currentChar) {
2453:                        state = PRECISION_STATE;
2454:                    } else {
2455:                        state = CONVERSION_TYPE_STATE;
2456:                        // do not get the next char.
2457:                        format.position(format.position() - 1);
2458:                    }
2459:                }
2460:
2461:                private void process_WIDTH_STATE() {
2462:                    if ('.' == currentChar) {
2463:                        state = PRECISION_STATE;
2464:                    } else {
2465:                        state = CONVERSION_TYPE_STATE;
2466:                        // do not get the next char.
2467:                        format.position(format.position() - 1);
2468:                    }
2469:                }
2470:
2471:                private void process_PRECISION_STATE() {
2472:                    if (Character.isDigit(currentChar)) {
2473:                        token.setPrecision(parseInt(format));
2474:                    } else {
2475:                        // the precision is required but not given by the
2476:                        // format string.
2477:                        throw new UnknownFormatConversionException(
2478:                                getFormatString());
2479:                    }
2480:                    state = CONVERSION_TYPE_STATE;
2481:                }
2482:
2483:                private void process_CONVERSION_TYPE_STATE() {
2484:                    token.setConversionType(currentChar);
2485:                    if ('t' == currentChar || 'T' == currentChar) {
2486:                        state = SUFFIX_STATE;
2487:                    } else {
2488:                        state = EXIT_STATE;
2489:                    }
2490:
2491:                }
2492:
2493:                private void process_SUFFIX_STATE() {
2494:                    token.setDateSuffix(currentChar);
2495:                    state = EXIT_STATE;
2496:                }
2497:
2498:                private void process_EXIT_STATE() {
2499:                    token.setPlainText(getFormatString());
2500:                }
2501:
2502:                /*
2503:                 * Parses integer value from the given buffer
2504:                 */
2505:                private int parseInt(CharBuffer buffer) {
2506:                    int start = buffer.position() - 1;
2507:                    int end = buffer.limit();
2508:                    while (buffer.hasRemaining()) {
2509:                        if (!Character.isDigit(buffer.get())) {
2510:                            end = buffer.position() - 1;
2511:                            break;
2512:                        }
2513:                    }
2514:                    buffer.position(0);
2515:                    String intStr = buffer.subSequence(start, end).toString();
2516:                    buffer.position(end);
2517:                    try {
2518:                        return Integer.parseInt(intStr);
2519:                    } catch (NumberFormatException e) {
2520:                        return FormatToken.UNSET;
2521:                    }
2522:                }
2523:            }
2524:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.