Source Code Cross Referenced for Utility.java in  » XML » jibx-1.1.5 » org » jibx » runtime » 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 » XML » jibx 1.1.5 » org.jibx.runtime 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:        Copyright (c) 2002-2005, Dennis M. Sosnoski.
0003:        All rights reserved.
0004:
0005:        Redistribution and use in source and binary forms, with or without modification,
0006:        are permitted provided that the following conditions are met:
0007:
0008:         * Redistributions of source code must retain the above copyright notice, this
0009:           list of conditions and the following disclaimer.
0010:         * Redistributions in binary form must reproduce the above copyright notice,
0011:           this list of conditions and the following disclaimer in the documentation
0012:           and/or other materials provided with the distribution.
0013:         * Neither the name of JiBX nor the names of its contributors may be used
0014:           to endorse or promote products derived from this software without specific
0015:           prior written permission.
0016:
0017:        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
0018:        ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0019:        WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0020:        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
0021:        ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0022:        (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0023:        LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
0024:        ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0025:        (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0026:        SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0027:         */
0028:
0029:        package org.jibx.runtime;
0030:
0031:        import java.lang.reflect.Array; //#!j2me{
0032:        import java.sql.Time;
0033:        import java.sql.Timestamp; //#j2me}
0034:        import java.util.ArrayList;
0035:        import java.util.Calendar;
0036:        import java.util.Date;
0037:        import java.util.GregorianCalendar;
0038:        import java.util.List;
0039:
0040:        /**
0041:         * Utility class supplying static methods. Date serialization is based on the
0042:         * algorithms published by Peter Baum (http://www.capecod.net/~pbaum). All date
0043:         * handling is done according to the W3C Schema specification, which uses a
0044:         * proleptic Gregorian calendar with no year 0. Note that this differs from the
0045:         * Java date handling, which uses a discontinuous Gregorian calendar.
0046:         *
0047:         * @author Dennis M. Sosnoski
0048:         * @version 1.0
0049:         */
0050:        public abstract class Utility {
0051:            /** Minimum size for array returned by {@link #growArray}. */
0052:            public static final int MINIMUM_GROWN_ARRAY_SIZE = 16;
0053:
0054:            /** Number of milliseconds in a minute. */
0055:            private static final int MSPERMINUTE = 60000;
0056:
0057:            /** Number of milliseconds in an hour. */
0058:            private static final int MSPERHOUR = MSPERMINUTE * 60;
0059:
0060:            /** Number of milliseconds in a day. */
0061:            private static final int MSPERDAY = MSPERHOUR * 24;
0062:
0063:            /** Number of milliseconds in a day as a long. */
0064:            private static final long LMSPERDAY = (long) MSPERDAY;
0065:
0066:            /** Number of milliseconds in a (non-leap) year. */
0067:            private static final long MSPERYEAR = LMSPERDAY * 365;
0068:
0069:            /** Average number of milliseconds in a year within century. */
0070:            private static final long MSPERAVGYEAR = (long) (MSPERDAY * 365.25);
0071:
0072:            /** Number of milliseconds in a normal century. */
0073:            private static final long MSPERCENTURY = (long) (MSPERDAY * 36524.25);
0074:
0075:            /** Millisecond value of base time for internal representation. This gives
0076:             the bias relative to January 1 of the year 1 C.E. */
0077:            private static final long TIME_BASE = 1969 * MSPERYEAR
0078:                    + (1969 / 4 - 19 + 4) * LMSPERDAY;
0079:
0080:            /** Day number for start of month in non-leap year. */
0081:            private static final int[] MONTHS_NONLEAP = { 0, 31, 59, 90, 120,
0082:                    151, 181, 212, 243, 273, 304, 334, 365 };
0083:
0084:            /** Day number for start of month in non-leap year. */
0085:            private static final int[] MONTHS_LEAP = { 0, 31, 60, 91, 121, 152,
0086:                    182, 213, 244, 274, 305, 335, 366 };
0087:
0088:            /** Millisecond count prior to start of month in March 1-biased year. */
0089:            private static final long[] BIAS_MONTHMS = { 0 * LMSPERDAY,
0090:                    0 * LMSPERDAY, 0 * LMSPERDAY, 0 * LMSPERDAY,
0091:                    31 * LMSPERDAY, 61 * LMSPERDAY, 92 * LMSPERDAY,
0092:                    122 * LMSPERDAY, 153 * LMSPERDAY, 184 * LMSPERDAY,
0093:                    214 * LMSPERDAY, 245 * LMSPERDAY, 275 * LMSPERDAY,
0094:                    306 * LMSPERDAY, 337 * LMSPERDAY };
0095:
0096:            /** Date for setting change to Gregorian calendar. */
0097:            private static Date BEGINNING_OF_TIME = new Date(Long.MIN_VALUE);
0098:
0099:            /** Pad character for base64 encoding. */
0100:            private static final char PAD_CHAR = '=';
0101:
0102:            /** Characters used in base64 encoding. */
0103:            private static final char[] s_base64Chars = { 'A', 'B', 'C', 'D',
0104:                    'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
0105:                    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
0106:                    'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
0107:                    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
0108:                    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
0109:
0110:            /** Values corresponding to characters used in bas64 encoding. */
0111:            private static final byte[] s_base64Values = new byte[128];
0112:            static {
0113:                for (int i = 0; i < s_base64Values.length; i++) {
0114:                    s_base64Values[i] = -1;
0115:                }
0116:                s_base64Values[PAD_CHAR] = 0;
0117:                for (int i = 0; i < s_base64Chars.length; i++) {
0118:                    s_base64Values[s_base64Chars[i]] = (byte) i;
0119:                }
0120:            }
0121:
0122:            /**
0123:             * Parse digits in text as integer value. This internal method is used
0124:             * for number values embedded within lexical structures. Only decimal
0125:             * digits can be included in the text range parsed.
0126:             *
0127:             * @param text text to be parsed
0128:             * @param offset starting offset in text
0129:             * @param length number of digits to be parsed
0130:             * @return converted positive integer value
0131:             * @throws JiBXException on parse error
0132:             */
0133:            private static int parseDigits(String text, int offset, int length)
0134:                    throws JiBXException {
0135:
0136:                // check if overflow a potential problem
0137:                int value = 0;
0138:                if (length > 9) {
0139:
0140:                    // use library parse code for potential overflow
0141:                    try {
0142:                        value = Integer.parseInt(text.substring(offset, offset
0143:                                + length));
0144:                    } catch (NumberFormatException ex) {
0145:                        throw new JiBXException(ex.getMessage());
0146:                    }
0147:
0148:                } else {
0149:
0150:                    // parse with no overflow worries
0151:                    int limit = offset + length;
0152:                    while (offset < limit) {
0153:                        char chr = text.charAt(offset++);
0154:                        if (chr >= '0' && chr <= '9') {
0155:                            value = value * 10 + (chr - '0');
0156:                        } else {
0157:                            throw new JiBXException("Non-digit in number value");
0158:                        }
0159:                    }
0160:
0161:                }
0162:                return value;
0163:            }
0164:
0165:            /**
0166:             * Parse integer value from text. Integer values are parsed with optional
0167:             * leading sign flag, followed by any number of digits.
0168:             *
0169:             * @param text text to be parsed
0170:             * @return converted integer value
0171:             * @throws JiBXException on parse error
0172:             */
0173:            public static int parseInt(String text) throws JiBXException {
0174:
0175:                // make sure there's text to be processed
0176:                text = text.trim();
0177:                int offset = 0;
0178:                int limit = text.length();
0179:                if (limit == 0) {
0180:                    throw new JiBXException("Empty number value");
0181:                }
0182:
0183:                // check leading sign present in text
0184:                boolean negate = false;
0185:                char chr = text.charAt(0);
0186:                if (chr == '-') {
0187:                    if (limit > 9) {
0188:
0189:                        // special case to make sure maximum negative value handled
0190:                        try {
0191:                            return Integer.parseInt(text);
0192:                        } catch (NumberFormatException ex) {
0193:                            throw new JiBXException(ex.getMessage());
0194:                        }
0195:
0196:                    } else {
0197:                        negate = true;
0198:                        offset++;
0199:                    }
0200:                } else if (chr == '+') {
0201:                    offset++;
0202:                }
0203:                if (offset >= limit) {
0204:                    throw new JiBXException("Invalid number format");
0205:                }
0206:
0207:                // handle actual value conversion
0208:                int value = parseDigits(text, offset, limit - offset);
0209:                if (negate) {
0210:                    return -value;
0211:                } else {
0212:                    return value;
0213:                }
0214:            }
0215:
0216:            /**
0217:             * Serialize int value to text.
0218:             *
0219:             * @param value int value to be serialized
0220:             * @return text representation of value
0221:             */
0222:            public static String serializeInt(int value) {
0223:                return Integer.toString(value);
0224:            }
0225:
0226:            /**
0227:             * Parse long value from text. Long values are parsed with optional
0228:             * leading sign flag, followed by any number of digits.
0229:             *
0230:             * @param text text to be parsed
0231:             * @return converted long value
0232:             * @throws JiBXException on parse error
0233:             */
0234:            public static long parseLong(String text) throws JiBXException {
0235:
0236:                // make sure there's text to be processed
0237:                text = text.trim();
0238:                int offset = 0;
0239:                int limit = text.length();
0240:                if (limit == 0) {
0241:                    throw new JiBXException("Empty number value");
0242:                }
0243:
0244:                // check leading sign present in text
0245:                boolean negate = false;
0246:                char chr = text.charAt(0);
0247:                if (chr == '-') {
0248:                    negate = true;
0249:                    offset++;
0250:                } else if (chr == '+') {
0251:                    offset++;
0252:                }
0253:                if (offset >= limit) {
0254:                    throw new JiBXException("Invalid number format");
0255:                }
0256:
0257:                // check if overflow a potential problem
0258:                long value = 0;
0259:                if (limit - offset > 18) {
0260:
0261:                    // pass text to library parse code (less leading +)
0262:                    if (chr == '+') {
0263:                        text = text.substring(1);
0264:                    }
0265:                    try {
0266:                        value = Long.parseLong(text);
0267:                    } catch (NumberFormatException ex) {
0268:                        throw new JiBXException(ex.getMessage());
0269:                    }
0270:
0271:                } else {
0272:
0273:                    // parse with no overflow worries
0274:                    while (offset < limit) {
0275:                        chr = text.charAt(offset++);
0276:                        if (chr >= '0' && chr <= '9') {
0277:                            value = value * 10 + (chr - '0');
0278:                        } else {
0279:                            throw new JiBXException("Non-digit in number value");
0280:                        }
0281:                    }
0282:                    if (negate) {
0283:                        value = -value;
0284:                    }
0285:
0286:                }
0287:                return value;
0288:            }
0289:
0290:            /**
0291:             * Serialize long value to text.
0292:             *
0293:             * @param value long value to be serialized
0294:             * @return text representation of value
0295:             */
0296:            public static String serializeLong(long value) {
0297:                return Long.toString(value);
0298:            }
0299:
0300:            /**
0301:             * Convert gYear text to Java date. Date values are expected to be in
0302:             * W3C XML Schema standard format as CCYY, with optional leading sign.
0303:             *
0304:             * @param text text to be parsed
0305:             * @return start of year date as millisecond value from 1 C.E.
0306:             * @throws JiBXException on parse error
0307:             */
0308:            public static long parseYear(String text) throws JiBXException {
0309:
0310:                // start by validating the length
0311:                text = text.trim();
0312:                boolean valid = true;
0313:                int minc = 4;
0314:                char chr = text.charAt(0);
0315:                if (chr == '-') {
0316:                    minc = 5;
0317:                } else if (chr == '+') {
0318:                    valid = false;
0319:                }
0320:                if (text.length() < minc) {
0321:                    valid = false;
0322:                }
0323:                if (!valid) {
0324:                    throw new JiBXException("Invalid year format");
0325:                }
0326:
0327:                // handle year conversion
0328:                int year = parseInt(text);
0329:                if (year == 0) {
0330:                    throw new JiBXException("Year value 0 is not allowed");
0331:                }
0332:                if (year > 0) {
0333:                    year--;
0334:                }
0335:                long day = ((long) year) * 365 + year / 4 - year / 100 + year
0336:                        / 400;
0337:                return day * MSPERDAY - TIME_BASE;
0338:            }
0339:
0340:            /**
0341:             * Parse short value from text. Short values are parsed with optional
0342:             * leading sign flag, followed by any number of digits.
0343:             *
0344:             * @param text text to be parsed
0345:             * @return converted short value
0346:             * @throws JiBXException on parse error
0347:             */
0348:            public static short parseShort(String text) throws JiBXException {
0349:                int value = parseInt(text);
0350:                if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
0351:                    throw new JiBXException("Value out of range");
0352:                }
0353:                return (short) value;
0354:            }
0355:
0356:            /**
0357:             * Serialize short value to text.
0358:             *
0359:             * @param value short value to be serialized
0360:             * @return text representation of value
0361:             */
0362:            public static String serializeShort(short value) {
0363:                return Short.toString(value);
0364:            }
0365:
0366:            /**
0367:             * Parse byte value from text. Byte values are parsed with optional
0368:             * leading sign flag, followed by any number of digits.
0369:             *
0370:             * @param text text to be parsed
0371:             * @return converted byte value
0372:             * @throws JiBXException on parse error
0373:             */
0374:            public static byte parseByte(String text) throws JiBXException {
0375:                int value = parseInt(text);
0376:                if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
0377:                    throw new JiBXException("Value out of range");
0378:                }
0379:                return (byte) value;
0380:            }
0381:
0382:            /**
0383:             * Serialize byte value to text.
0384:             *
0385:             * @param value byte value to be serialized
0386:             * @return text representation of value
0387:             */
0388:            public static String serializeByte(byte value) {
0389:                return Byte.toString(value);
0390:            }
0391:
0392:            /**
0393:             * Parse boolean value from text. Boolean values are parsed as either text
0394:             * "true" and "false", or "1" and "0" numeric equivalents.
0395:             *
0396:             * @param text text to be parsed
0397:             * @return converted boolean value
0398:             * @throws JiBXException on parse error
0399:             */
0400:            public static boolean parseBoolean(String text)
0401:                    throws JiBXException {
0402:                text = text.trim();
0403:                if ("true".equals(text) || "1".equals(text)) {
0404:                    return true;
0405:                } else if ("false".equals(text) || "0".equals(text)) {
0406:                    return false;
0407:                } else {
0408:                    throw new JiBXException("Invalid boolean value");
0409:                }
0410:            }
0411:
0412:            /**
0413:             * Serialize boolean value to text. This serializes the value using the
0414:             * text representation as "true" or "false".
0415:             *
0416:             * @param value boolean value to be serialized
0417:             * @return text representation of value
0418:             */
0419:            public static String serializeBoolean(boolean value) {
0420:                return value ? "true" : "false";
0421:            }
0422:
0423:            /**
0424:             * Parse char value from text as unsigned 16-bit integer. Char values are
0425:             * parsed with optional leading sign flag, followed by any number of digits.
0426:             *
0427:             * @param text text to be parsed
0428:             * @return converted char value
0429:             * @throws JiBXException on parse error
0430:             */
0431:            public static char parseChar(String text) throws JiBXException {
0432:                int value = parseInt(text);
0433:                if (value < Character.MIN_VALUE || value > Character.MAX_VALUE) {
0434:                    throw new JiBXException("Value out of range");
0435:                }
0436:                return (char) value;
0437:            }
0438:
0439:            /**
0440:             * Serialize char value to text as unsigned 16-bit integer.
0441:             *
0442:             * @param value char value to be serialized
0443:             * @return text representation of value
0444:             */
0445:            public static String serializeChar(char value) {
0446:                return Integer.toString(value);
0447:            }
0448:
0449:            /**
0450:             * Parse char value from text as character value. This requires that the
0451:             * string must be of length one.
0452:             *
0453:             * @param text text to be parsed
0454:             * @return converted char value
0455:             * @throws JiBXException on parse error
0456:             */
0457:            public static char parseCharString(String text)
0458:                    throws JiBXException {
0459:                if (text.length() == 1) {
0460:                    return text.charAt(0);
0461:                } else {
0462:                    throw new JiBXException("Input must be a single character");
0463:                }
0464:            }
0465:
0466:            /**
0467:             * Deserialize char value from text as character value. This requires that
0468:             * the string must be null or of length one.
0469:             *
0470:             * @param text text to be parsed (may be <code>null</code>)
0471:             * @return converted char value
0472:             * @throws JiBXException on parse error
0473:             */
0474:            public static char deserializeCharString(String text)
0475:                    throws JiBXException {
0476:                if (text == null) {
0477:                    return 0;
0478:                } else {
0479:                    return parseCharString(text);
0480:                }
0481:            }
0482:
0483:            /**
0484:             * Serialize char value to text as string of length one.
0485:             *
0486:             * @param value char value to be serialized
0487:             * @return text representation of value
0488:             */
0489:            public static String serializeCharString(char value) {
0490:                return String.valueOf(value);
0491:            }
0492:
0493:            /**
0494:             * Parse float value from text. This uses the W3C XML Schema format for
0495:             * floats, with the exception that it will accept "+NaN" and "-NaN" as
0496:             * valid formats. This is not in strict compliance with the specification,
0497:             * but is included for interoperability with other Java XML processing.
0498:             *
0499:             * @param text text to be parsed
0500:             * @return converted float value
0501:             * @throws JiBXException on parse error
0502:             */
0503:            public static float parseFloat(String text) throws JiBXException {
0504:                text = text.trim();
0505:                if ("-INF".equals(text)) {
0506:                    return Float.NEGATIVE_INFINITY;
0507:                } else if ("INF".equals(text)) {
0508:                    return Float.POSITIVE_INFINITY;
0509:                } else {
0510:                    try {
0511:                        return Float.parseFloat(text);
0512:                    } catch (NumberFormatException ex) {
0513:                        throw new JiBXException(ex.getMessage());
0514:                    }
0515:                }
0516:            }
0517:
0518:            /**
0519:             * Serialize float value to text.
0520:             *
0521:             * @param value float value to be serialized
0522:             * @return text representation of value
0523:             */
0524:            public static String serializeFloat(float value) {
0525:                if (Float.isInfinite(value)) {
0526:                    return (value < 0.0f) ? "-INF" : "INF";
0527:                } else {
0528:                    return Float.toString(value);
0529:                }
0530:            }
0531:
0532:            /**
0533:             * Parse double value from text. This uses the W3C XML Schema format for
0534:             * doubles, with the exception that it will accept "+NaN" and "-NaN" as
0535:             * valid formats. This is not in strict compliance with the specification,
0536:             * but is included for interoperability with other Java XML processing.
0537:             *
0538:             * @param text text to be parsed
0539:             * @return converted double value
0540:             * @throws JiBXException on parse error
0541:             */
0542:            public static double parseDouble(String text) throws JiBXException {
0543:                text = text.trim();
0544:                if ("-INF".equals(text)) {
0545:                    return Double.NEGATIVE_INFINITY;
0546:                } else if ("INF".equals(text)) {
0547:                    return Double.POSITIVE_INFINITY;
0548:                } else {
0549:                    try {
0550:                        return Double.parseDouble(text);
0551:                    } catch (NumberFormatException ex) {
0552:                        throw new JiBXException(ex.getMessage());
0553:                    }
0554:                }
0555:            }
0556:
0557:            /**
0558:             * Serialize double value to text.
0559:             *
0560:             * @param value double value to be serialized
0561:             * @return text representation of value
0562:             */
0563:            public static String serializeDouble(double value) {
0564:                if (Double.isInfinite(value)) {
0565:                    return (value < 0.0f) ? "-INF" : "INF";
0566:                } else {
0567:                    return Double.toString(value);
0568:                }
0569:            }
0570:
0571:            /**
0572:             * Convert gYearMonth text to Java date. Date values are expected to be in
0573:             * W3C XML Schema standard format as CCYY-MM, with optional
0574:             * leading sign.
0575:             *
0576:             * @param text text to be parsed
0577:             * @return start of month in year date as millisecond value
0578:             * @throws JiBXException on parse error
0579:             */
0580:            public static long parseYearMonth(String text) throws JiBXException {
0581:
0582:                // start by validating the length and basic format
0583:                text = text.trim();
0584:                boolean valid = true;
0585:                int minc = 7;
0586:                char chr = text.charAt(0);
0587:                if (chr == '-') {
0588:                    minc = 8;
0589:                } else if (chr == '+') {
0590:                    valid = false;
0591:                }
0592:                int split = text.length() - 3;
0593:                if (text.length() < minc) {
0594:                    valid = false;
0595:                } else {
0596:                    if (text.charAt(split) != '-') {
0597:                        valid = false;
0598:                    }
0599:                }
0600:                if (!valid) {
0601:                    throw new JiBXException("Invalid date format");
0602:                }
0603:
0604:                // handle year and month conversion
0605:                int year = parseInt(text.substring(0, split));
0606:                if (year == 0) {
0607:                    throw new JiBXException("Year value 0 is not allowed");
0608:                }
0609:                int month = parseDigits(text, split + 1, 2) - 1;
0610:                if (month < 0 || month > 11) {
0611:                    throw new JiBXException("Month value out of range");
0612:                }
0613:                boolean leap = (year % 4 == 0)
0614:                        && !((year % 100 == 0) && (year % 400 != 0));
0615:                if (year > 0) {
0616:                    year--;
0617:                }
0618:                long day = ((long) year) * 365 + year / 4 - year / 100 + year
0619:                        / 400 + (leap ? MONTHS_LEAP : MONTHS_NONLEAP)[month];
0620:                return day * MSPERDAY - TIME_BASE;
0621:            }
0622:
0623:            /**
0624:             * Convert date text to Java date. Date values are expected to be in
0625:             * W3C XML Schema standard format as CCYY-MM-DD, with optional
0626:             * leading sign and trailing time zone (though the time zone is ignored
0627:             * in this case).
0628:             *
0629:             * @param text text to be parsed
0630:             * @return start of day in month and year date as millisecond value
0631:             * @throws JiBXException on parse error
0632:             */
0633:            public static long parseDate(String text) throws JiBXException {
0634:
0635:                // start by validating the length and basic format
0636:                int split = validateDate(text);
0637:
0638:                // handle year, month, and day conversion
0639:                int year = parseInt(text.substring(0, split));
0640:                if (year == 0) {
0641:                    throw new JiBXException("Year value 0 is not allowed");
0642:                }
0643:                int month = parseDigits(text, split + 1, 2) - 1;
0644:                if (month < 0 || month > 11) {
0645:                    throw new JiBXException("Month value out of range");
0646:                }
0647:                long day = parseDigits(text, split + 4, 2) - 1;
0648:                boolean leap = (year % 4 == 0)
0649:                        && !((year % 100 == 0) && (year % 400 != 0));
0650:                int[] starts = leap ? MONTHS_LEAP : MONTHS_NONLEAP;
0651:                if (day < 0 || day >= (starts[month + 1] - starts[month])) {
0652:                    throw new JiBXException("Day value out of range");
0653:                }
0654:                if (year > 0) {
0655:                    year--;
0656:                }
0657:                day += ((long) year) * 365 + year / 4 - year / 100 + year / 400
0658:                        + starts[month];
0659:                return day * MSPERDAY - TIME_BASE;
0660:            }
0661:
0662:            /**
0663:             * Deserialize date from text. Date values are expected to match W3C XML
0664:             * Schema standard format as CCYY-MM-DD, with optional leading minus sign
0665:             * if necessary. This method follows standard JiBX deserializer usage
0666:             * requirements by accepting a <code>null</code> input.
0667:             *
0668:             * @param text text to be parsed (may be <code>null</code>)
0669:             * @return converted date, or <code>null</code> if passed <code>null</code>
0670:             * input
0671:             * @throws JiBXException on parse error
0672:             */
0673:            public static Date deserializeDate(String text)
0674:                    throws JiBXException {
0675:                if (text == null) {
0676:                    return null;
0677:                } else {
0678:                    return new Date(parseDate(text));
0679:                }
0680:            }
0681:
0682:            /**
0683:             * Validate a date text string.
0684:             * 
0685:             * @param text
0686:             * @return offset past end of year in text
0687:             * @throws JiBXException on validation error
0688:             */
0689:            private static int validateDate(String text) throws JiBXException {
0690:
0691:                // start by validating the length and basic format
0692:                boolean valid = true;
0693:                int minc = 10;
0694:                char chr = text.charAt(0);
0695:                if (chr == '-') {
0696:                    minc = 11;
0697:                } else if (chr == '+') {
0698:                    valid = false;
0699:                }
0700:                int split = text.length() - 6;
0701:                if (text.length() < minc) {
0702:                    valid = false;
0703:                } else {
0704:                    if (text.charAt(split) != '-'
0705:                            || text.charAt(split + 3) != '-') {
0706:                        valid = false;
0707:                    }
0708:                }
0709:                if (!valid) {
0710:                    throw new JiBXException("Invalid date format");
0711:                }
0712:                return split;
0713:            }
0714:
0715:            //#!j2me{
0716:            /**
0717:             * Deserialize SQL date from text. Date values are expected to match W3C XML
0718:             * Schema standard format as CCYY-MM-DD, with optional leading minus sign
0719:             * if necessary. This method follows standard JiBX deserializer usage
0720:             * requirements by accepting a <code>null</code> input.
0721:             *
0722:             * @param text text to be parsed (may be <code>null</code>)
0723:             * @return converted date, or <code>null</code> if passed <code>null</code>
0724:             * input
0725:             * @throws JiBXException on parse error
0726:             */
0727:            public static java.sql.Date deserializeSqlDate(String text)
0728:                    throws JiBXException {
0729:                if (text == null) {
0730:                    return null;
0731:                } else {
0732:
0733:                    // make sure date is avlid
0734:                    int split = validateDate(text);
0735:
0736:                    // handle year, month, and day conversion
0737:                    int year = parseInt(text.substring(0, split));
0738:                    if (year == 0) {
0739:                        throw new JiBXException("Year value 0 is not allowed");
0740:                    }
0741:                    int month = parseDigits(text, split + 1, 2) - 1;
0742:                    if (month < 0 || month > 11) {
0743:                        throw new JiBXException("Month value out of range");
0744:                    }
0745:                    int day = parseDigits(text, split + 4, 2) - 1;
0746:                    boolean leap = (year % 4 == 0)
0747:                            && !((year % 100 == 0) && (year % 400 != 0));
0748:                    int[] starts = leap ? MONTHS_LEAP : MONTHS_NONLEAP;
0749:                    if (day < 0 || day >= (starts[month + 1] - starts[month])) {
0750:                        throw new JiBXException("Day value out of range");
0751:                    }
0752:                    if (year < 0) {
0753:                        year++;
0754:                    }
0755:
0756:                    // set it into a calendar
0757:                    GregorianCalendar cal;
0758:                    if (year < 1800) {
0759:                        cal = new GregorianCalendar();
0760:                        cal.setGregorianChange(BEGINNING_OF_TIME);
0761:                        cal.clear();
0762:                        cal.set(year, month, day + 1);
0763:                    } else {
0764:                        cal = new GregorianCalendar(year, month, day + 1);
0765:                    }
0766:                    return new java.sql.Date(cal.getTime().getTime());
0767:                }
0768:            }
0769:
0770:            //#j2me}
0771:
0772:            /**
0773:             * Parse general time value from text. Time values are expected to be in W3C
0774:             * XML Schema standard format as hh:mm:ss.fff, with optional leading sign
0775:             * and trailing time zone.
0776:             *
0777:             * @param text text to be parsed
0778:             * @param start offset of first character of time value
0779:             * @param length number of characters in time value
0780:             * @return converted time as millisecond value
0781:             * @throws JiBXException on parse error
0782:             */
0783:            public static long parseTime(String text, int start, int length)
0784:                    throws JiBXException {
0785:
0786:                // validate time value following date
0787:                long milli = 0;
0788:                boolean valid = length > (start + 7)
0789:                        && (text.charAt(start + 2) == ':')
0790:                        && (text.charAt(start + 5) == ':');
0791:                if (valid) {
0792:                    int hour = parseDigits(text, start, 2);
0793:                    int minute = parseDigits(text, start + 3, 2);
0794:                    int second = parseDigits(text, start + 6, 2);
0795:                    if (hour > 23 || minute > 59 || second > 60) {
0796:                        valid = false;
0797:                    } else {
0798:
0799:                        // convert to base millisecond in day
0800:                        milli = (((hour * 60) + minute) * 60 + second) * 1000;
0801:                        start += 8;
0802:                        if (length > start) {
0803:
0804:                            // adjust for time zone
0805:                            if (text.charAt(length - 1) == 'Z') {
0806:                                length--;
0807:                            } else {
0808:                                char chr = text.charAt(length - 6);
0809:                                if (chr == '-' || chr == '+') {
0810:                                    hour = parseDigits(text, length - 5, 2);
0811:                                    minute = parseDigits(text, length - 2, 2);
0812:                                    if (hour > 23 || minute > 59) {
0813:                                        valid = false;
0814:                                    } else {
0815:                                        int offset = ((hour * 60) + minute) * 60 * 1000;
0816:                                        if (chr == '-') {
0817:                                            milli += offset;
0818:                                        } else {
0819:                                            milli -= offset;
0820:                                        }
0821:                                    }
0822:                                    length -= 6;
0823:                                }
0824:                            }
0825:
0826:                            // check for trailing fractional second
0827:                            if (text.charAt(start) == '.') {
0828:                                double fraction = Double.parseDouble(text
0829:                                        .substring(start, length));
0830:                                milli += fraction * 1000.0;
0831:                            } else if (length > start) {
0832:                                valid = false;
0833:                            }
0834:                        }
0835:                    }
0836:                }
0837:
0838:                // check for valid result
0839:                if (valid) {
0840:                    return milli;
0841:                } else {
0842:                    throw new JiBXException("Invalid dateTime format");
0843:                }
0844:            }
0845:
0846:            /**
0847:             * Parse general dateTime value from text. Date values are expected to be in
0848:             * W3C XML Schema standard format as CCYY-MM-DDThh:mm:ss.fff, with optional
0849:             * leading sign and trailing time zone.
0850:             *
0851:             * @param text text to be parsed
0852:             * @return converted date as millisecond value
0853:             * @throws JiBXException on parse error
0854:             */
0855:            public static long parseDateTime(String text) throws JiBXException {
0856:
0857:                // split text to convert portions separately
0858:                int split = text.indexOf('T');
0859:                if (split < 0) {
0860:                    throw new JiBXException("Missing 'T' separator in dateTime");
0861:                }
0862:                return parseDate(text.substring(0, split))
0863:                        + parseTime(text, split + 1, text.length());
0864:            }
0865:
0866:            /**
0867:             * Deserialize date from general dateTime text. Date values are expected to
0868:             * match W3C XML Schema standard format as CCYY-MM-DDThh:mm:ss, with
0869:             * optional leading minus sign and trailing seconds decimal, as necessary.
0870:             * This method follows standard JiBX deserializer usage requirements by
0871:             * accepting a <code>null</code> input.
0872:             *
0873:             * @param text text to be parsed (may be <code>null</code>)
0874:             * @return converted date, or <code>null</code> if passed <code>null</code>
0875:             * input
0876:             * @throws JiBXException on parse error
0877:             */
0878:            public static Date deserializeDateTime(String text)
0879:                    throws JiBXException {
0880:                if (text == null) {
0881:                    return null;
0882:                } else {
0883:                    return new Date(parseDateTime(text));
0884:                }
0885:            }
0886:
0887:            //#!j2me{
0888:            /**
0889:             * Deserialize timestamp from general dateTime text. Timestamp values are
0890:             * represented in the same way as regular dates, but allow more precision in
0891:             * the fractional second value (down to nanoseconds). This method follows
0892:             * standard JiBX deserializer usage requirements by accepting a
0893:             * <code>null</code> input.
0894:             *
0895:             * @param text text to be parsed (may be <code>null</code>)
0896:             * @return converted timestamp, or <code>null</code> if passed
0897:             * <code>null</code> input
0898:             * @throws JiBXException on parse error
0899:             */
0900:            public static Timestamp deserializeTimestamp(String text)
0901:                    throws JiBXException {
0902:                if (text == null) {
0903:                    return null;
0904:                } else {
0905:
0906:                    // check for fractional second value present
0907:                    int split = text.indexOf('.');
0908:                    int nano = 0;
0909:                    if (split > 0) {
0910:
0911:                        // make sure there aren't multiple decimal points
0912:                        if (text.indexOf('.', split + 1) > 0) {
0913:                            throw new JiBXException(
0914:                                    "Not a valid timestamp value");
0915:                        }
0916:
0917:                        // scan through all digits following decimal point
0918:                        int limit = text.length();
0919:                        int scan = split;
0920:                        while (++scan < limit) {
0921:                            char chr = text.charAt(scan);
0922:                            if (chr < '0' || chr > '9') {
0923:                                break;
0924:                            }
0925:                        }
0926:
0927:                        // parse digits following decimal point
0928:                        int length = scan - split - 1;
0929:                        if (length > 9) {
0930:                            length = 9;
0931:                        }
0932:                        nano = parseDigits(text, split + 1, length);
0933:
0934:                        // convert to number of nanoseconds
0935:                        while (length < 9) {
0936:                            nano *= 10;
0937:                            length++;
0938:                        }
0939:
0940:                        // strip fractional second off text
0941:                        if (scan < limit) {
0942:                            text = text.substring(0, split)
0943:                                    + text.substring(scan);
0944:                        } else {
0945:                            text = text.substring(0, split);
0946:                        }
0947:                    }
0948:
0949:                    // return timestamp value with nanoseconds
0950:                    Timestamp stamp = new Timestamp(parseDateTime(text));
0951:                    stamp.setNanos(nano);
0952:                    return stamp;
0953:                }
0954:            }
0955:
0956:            /**
0957:             * Deserialize time from text. Time values obey the rules of the time
0958:             * portion of a dataTime value. This method follows standard JiBX
0959:             * deserializer usage requirements by accepting a <code>null</code> input.
0960:             *
0961:             * @param text text to be parsed (may be <code>null</code>)
0962:             * @return converted time, or <code>null</code> if passed <code>null</code>
0963:             * input
0964:             * @throws JiBXException on parse error
0965:             */
0966:            public static Time deserializeSqlTime(String text)
0967:                    throws JiBXException {
0968:                if (text == null) {
0969:                    return null;
0970:                } else {
0971:                    return new Time(parseTime(text, 0, text.length()));
0972:                }
0973:            }
0974:
0975:            //#j2me}
0976:
0977:            /**
0978:             * Format year number consistent with W3C XML Schema definitions, using a
0979:             * minimum of four digits padded with zeros if necessary. A leading minus
0980:             * sign is included for years prior to 1 C.E.
0981:             *
0982:             * @param year number to be formatted
0983:             * @param buff text formatting buffer
0984:             */
0985:            protected static void formatYearNumber(long year, StringBuffer buff) {
0986:
0987:                // start with minus sign for dates prior to 1 C.E.
0988:                if (year <= 0) {
0989:                    buff.append('-');
0990:                    year = -(year - 1);
0991:                }
0992:
0993:                // add padding if needed to bring to length of four
0994:                if (year < 1000) {
0995:                    buff.append('0');
0996:                    if (year < 100) {
0997:                        buff.append('0');
0998:                        if (year < 10) {
0999:                            buff.append('0');
1000:                        }
1001:                    }
1002:                }
1003:
1004:                // finish by converting the actual year number
1005:                buff.append(year);
1006:            }
1007:
1008:            /**
1009:             * Format a positive number as two digits. This uses an optional leading
1010:             * zero digit for values less than ten.
1011:             *
1012:             * @param value number to be formatted (<code>0</code> to <code>99</code>)
1013:             * @param buff text formatting buffer
1014:             */
1015:            protected static void formatTwoDigits(int value, StringBuffer buff) {
1016:                if (value < 10) {
1017:                    buff.append('0');
1018:                }
1019:                buff.append(value);
1020:            }
1021:
1022:            /**
1023:             * Format time in milliseconds to year number. The resulting year number
1024:             * format is consistent with W3C XML Schema definitions, using a minimum
1025:             * of four digits padded with zeros if necessary. A leading minus sign is
1026:             * included for years prior to 1 C.E.
1027:             *
1028:             * @param value time in milliseconds to be converted (from 1 C.E.)
1029:             * @param buff text formatting buffer
1030:             */
1031:            protected static void formatYear(long value, StringBuffer buff) {
1032:
1033:                // find the actual year and month number; this uses a integer arithmetic
1034:                //  conversion based on Baum, first making the millisecond count
1035:                //  relative to March 1 of the year 0 C.E., then using simple arithmetic
1036:                //  operations to compute century, year, and month; it's slightly
1037:                //  different for pre-C.E. values because of Java's handling of divisions.
1038:                long time = value + 306 * LMSPERDAY + LMSPERDAY * 3 / 4;
1039:                long century = time / MSPERCENTURY; // count of centuries
1040:                long adjusted = time + (century - (century / 4)) * MSPERDAY;
1041:                int year = (int) (adjusted / MSPERAVGYEAR); // year in March 1 terms
1042:                if (adjusted < 0) {
1043:                    year--;
1044:                }
1045:                long yms = adjusted + LMSPERDAY / 4 - (year * 365 + year / 4)
1046:                        * LMSPERDAY;
1047:                int yday = (int) (yms / LMSPERDAY); // day number in year
1048:                int month = (5 * yday + 456) / 153; // (biased) month number
1049:                if (month > 12) { // convert start of year
1050:                    year++;
1051:                }
1052:
1053:                // format year to text
1054:                formatYearNumber(year, buff);
1055:            }
1056:
1057:            /**
1058:             * Format time in milliseconds to year number and month number. The 
1059:             * resulting year number format is consistent with W3C XML Schema
1060:             * definitions, using a minimum of four digits for the year and exactly
1061:             * two digits for the month.
1062:             *
1063:             * @param value time in milliseconds to be converted (from 1 C.E.)
1064:             * @param buff text formatting buffer
1065:             * @return number of milliseconds into month
1066:             */
1067:            protected static long formatYearMonth(long value, StringBuffer buff) {
1068:
1069:                // find the actual year and month number; this uses a integer arithmetic
1070:                //  conversion based on Baum, first making the millisecond count
1071:                //  relative to March 1 of the year 0 C.E., then using simple arithmetic
1072:                //  operations to compute century, year, and month; it's slightly
1073:                //  different for pre-C.E. values because of Java's handling of divisions.
1074:                long time = value + 306 * LMSPERDAY + LMSPERDAY * 3 / 4;
1075:                long century = time / MSPERCENTURY; // count of centuries
1076:                long adjusted = time + (century - (century / 4)) * MSPERDAY;
1077:                int year = (int) (adjusted / MSPERAVGYEAR); // year in March 1 terms
1078:                if (adjusted < 0) {
1079:                    year--;
1080:                }
1081:                long yms = adjusted + LMSPERDAY / 4 - (year * 365 + year / 4)
1082:                        * LMSPERDAY;
1083:                int yday = (int) (yms / LMSPERDAY); // day number in year
1084:                if (yday == 0) { // special for negative
1085:                    boolean bce = year < 0;
1086:                    if (bce) {
1087:                        year--;
1088:                    }
1089:                    int dcnt = year % 4 == 0 ? 366 : 365;
1090:                    if (!bce) {
1091:                        year--;
1092:                    }
1093:                    yms += dcnt * LMSPERDAY;
1094:                    yday += dcnt;
1095:                }
1096:                int month = (5 * yday + 456) / 153; // (biased) month number
1097:                long rem = yms - BIAS_MONTHMS[month] - LMSPERDAY; // ms into month
1098:                if (month > 12) { // convert start of year
1099:                    year++;
1100:                    month -= 12;
1101:                }
1102:
1103:                // format year and month as text
1104:                formatYearNumber(year, buff);
1105:                buff.append('-');
1106:                formatTwoDigits(month, buff);
1107:
1108:                // return extra milliseconds into month
1109:                return rem;
1110:            }
1111:
1112:            /**
1113:             * Format time in milliseconds to year number, month number, and day
1114:             * number. The resulting year number format is consistent with W3C XML
1115:             * Schema definitions, using a minimum of four digits for the year and
1116:             * exactly two digits each for the month and day.
1117:             *
1118:             * @param value time in milliseconds to be converted (from 1 C.E.)
1119:             * @param buff text formatting buffer
1120:             * @return number of milliseconds into day
1121:             */
1122:            protected static int formatYearMonthDay(long value,
1123:                    StringBuffer buff) {
1124:
1125:                // convert year and month
1126:                long extra = formatYearMonth(value, buff);
1127:
1128:                // append the day of month
1129:                int day = (int) (extra / MSPERDAY) + 1;
1130:                buff.append('-');
1131:                formatTwoDigits(day, buff);
1132:
1133:                // return excess of milliseconds into day
1134:                return (int) (extra % MSPERDAY);
1135:            }
1136:
1137:            /**
1138:             * Serialize time to general gYear text. Date values are formatted in
1139:             * W3C XML Schema standard format as CCYY, with optional
1140:             * leading sign included if necessary.
1141:             *
1142:             * @param time time to be converted, as milliseconds from January 1, 1970
1143:             * @return converted gYear text
1144:             */
1145:            public static String serializeYear(long time) {
1146:                StringBuffer buff = new StringBuffer(6);
1147:                formatYear(time + TIME_BASE, buff);
1148:                return buff.toString();
1149:            }
1150:
1151:            /**
1152:             * Serialize date to general gYear text. Date values are formatted in
1153:             * W3C XML Schema standard format as CCYY, with optional
1154:             * leading sign included if necessary.
1155:             *
1156:             * @param date date to be converted
1157:             * @return converted gYear text
1158:             */
1159:            public static String serializeYear(Date date) {
1160:                return serializeYear(date.getTime());
1161:            }
1162:
1163:            /**
1164:             * Serialize time to general gYearMonth text. Date values are formatted in
1165:             * W3C XML Schema standard format as CCYY-MM, with optional
1166:             * leading sign included if necessary.
1167:             *
1168:             * @param time time to be converted, as milliseconds from January 1, 1970
1169:             * @return converted gYearMonth text
1170:             */
1171:            public static String serializeYearMonth(long time) {
1172:                StringBuffer buff = new StringBuffer(12);
1173:                formatYearMonth(time + TIME_BASE, buff);
1174:                return buff.toString();
1175:            }
1176:
1177:            /**
1178:             * Serialize date to general gYearMonth text. Date values are formatted in
1179:             * W3C XML Schema standard format as CCYY-MM, with optional
1180:             * leading sign included if necessary.
1181:             *
1182:             * @param date date to be converted
1183:             * @return converted gYearMonth text
1184:             */
1185:            public static String serializeYearMonth(Date date) {
1186:                return serializeYearMonth(date.getTime());
1187:            }
1188:
1189:            /**
1190:             * Serialize time to general date text. Date values are formatted in
1191:             * W3C XML Schema standard format as CCYY-MM-DD, with optional
1192:             * leading sign included if necessary.
1193:             *
1194:             * @param time time to be converted, as milliseconds from January 1, 1970
1195:             * @return converted date text
1196:             */
1197:            public static String serializeDate(long time) {
1198:                StringBuffer buff = new StringBuffer(12);
1199:                formatYearMonthDay(time + TIME_BASE, buff);
1200:                return buff.toString();
1201:            }
1202:
1203:            /**
1204:             * Serialize date to general date text. Date values are formatted in
1205:             * W3C XML Schema standard format as CCYY-MM-DD, with optional
1206:             * leading sign included if necessary.
1207:             *
1208:             * @param date date to be converted
1209:             * @return converted date text
1210:             */
1211:            public static String serializeDate(Date date) {
1212:                return serializeDate(date.getTime());
1213:            }
1214:
1215:            //#!j2me{
1216:            /**
1217:             * Serialize SQL date to general date text. Date values are formatted in
1218:             * W3C XML Schema standard format as CCYY-MM-DD, with optional
1219:             * leading sign included if necessary.
1220:             *
1221:             * @param date date to be converted
1222:             * @return converted date text
1223:             */
1224:            public static String serializeSqlDate(java.sql.Date date) {
1225:
1226:                // values should be normalized to midnight in zone, but no guarantee
1227:                //  so convert using the lame calendar approach
1228:                GregorianCalendar cal = new GregorianCalendar();
1229:                cal.setGregorianChange(BEGINNING_OF_TIME);
1230:                cal.setTime(date);
1231:                StringBuffer buff = new StringBuffer(12);
1232:                int year = cal.get(Calendar.YEAR);
1233:                if (date.getTime() < 0) {
1234:                    if (cal.get(Calendar.ERA) == GregorianCalendar.BC) {
1235:                        year = -year + 1;
1236:                    }
1237:                }
1238:                formatYearNumber(year, buff);
1239:                buff.append('-');
1240:                formatTwoDigits(cal.get(Calendar.MONTH) + 1, buff);
1241:                buff.append('-');
1242:                formatTwoDigits(cal.get(Calendar.DAY_OF_MONTH), buff);
1243:                return buff.toString();
1244:            }
1245:
1246:            //#j2me}
1247:
1248:            /**
1249:             * Serialize time to general time text in buffer. Time values are formatted
1250:             * in W3C XML Schema standard format as hh:mm:ss, with optional trailing
1251:             * seconds decimal, as necessary. This form uses a supplied buffer to
1252:             * support flexible use, including with dateTime combination values.
1253:             *
1254:             * @param time time to be converted, as milliseconds in day
1255:             * @param buff buffer for appending time text
1256:             */
1257:            public static void serializeTime(int time, StringBuffer buff) {
1258:
1259:                // append the hour, minute, and second
1260:                formatTwoDigits(time / MSPERHOUR, buff);
1261:                time = time % MSPERHOUR;
1262:                buff.append(':');
1263:                formatTwoDigits(time / MSPERMINUTE, buff);
1264:                time = time % MSPERMINUTE;
1265:                buff.append(':');
1266:                formatTwoDigits(time / 1000, buff);
1267:                time = time % 1000;
1268:
1269:                // check if decimals needed on second
1270:                if (time > 0) {
1271:                    buff.append('.');
1272:                    buff.append(time / 100);
1273:                    time = time % 100;
1274:                    if (time > 0) {
1275:                        buff.append(time / 10);
1276:                        time = time % 10;
1277:                        if (time > 0) {
1278:                            buff.append(time);
1279:                        }
1280:                    }
1281:                }
1282:            }
1283:
1284:            /**
1285:             * Serialize time to general dateTime text. Date values are formatted in
1286:             * W3C XML Schema standard format as CCYY-MM-DDThh:mm:ss, with optional
1287:             * leading sign and trailing seconds decimal, as necessary.
1288:             *
1289:             * @param time time to be converted, as milliseconds from January 1, 1970
1290:             * @param zone flag for trailing 'Z' to be appended to indicate UTC
1291:             * @return converted dateTime text
1292:             */
1293:            public static String serializeDateTime(long time, boolean zone) {
1294:
1295:                // start with the year, month, and day
1296:                StringBuffer buff = new StringBuffer(25);
1297:                int extra = formatYearMonthDay(time + TIME_BASE, buff);
1298:
1299:                // append the time for full form
1300:                buff.append('T');
1301:                serializeTime(extra, buff);
1302:
1303:                // return full text with optional trailing zone indicator
1304:                if (zone) {
1305:                    buff.append('Z');
1306:                }
1307:                return buff.toString();
1308:            }
1309:
1310:            /**
1311:             * Serialize time to general dateTime text. This method is provided for
1312:             * backward compatibility. It generates the dateTime text without the
1313:             * trailing 'Z' to indicate UTC.
1314:             *
1315:             * @param time time to be converted, as milliseconds from January 1, 1970
1316:             * @return converted dateTime text
1317:             */
1318:            public static String serializeDateTime(long time) {
1319:                return serializeDateTime(time, false);
1320:            }
1321:
1322:            /**
1323:             * Serialize date to general dateTime text. Date values are formatted in
1324:             * W3C XML Schema standard format as CCYY-MM-DDThh:mm:ssZ, with optional
1325:             * leading sign and trailing seconds decimal, as necessary.
1326:             *
1327:             * @param date date to be converted
1328:             * @return converted dateTime text
1329:             */
1330:            public static String serializeDateTime(Date date) {
1331:                return serializeDateTime(date.getTime(), true);
1332:            }
1333:
1334:            //#!j2me{
1335:            /**
1336:             * Serialize timestamp to general dateTime text. Timestamp values are
1337:             * represented in the same way as regular dates, but allow more precision in
1338:             * the fractional second value (down to nanoseconds).
1339:             *
1340:             * @param stamp timestamp to be converted
1341:             * @return converted dateTime text
1342:             */
1343:            public static String serializeTimestamp(Timestamp stamp) {
1344:
1345:                // check for nanosecond value to be included
1346:                int nano = stamp.getNanos();
1347:                if (nano > 0) {
1348:
1349:                    // convert the number of nanoseconds to text
1350:                    String value = serializeInt(nano);
1351:
1352:                    // pad with leading zeros if less than 9 digits
1353:                    StringBuffer digits = new StringBuffer(9);
1354:                    if (value.length() < 9) {
1355:                        int lead = 9 - value.length();
1356:                        for (int i = 0; i < lead; i++) {
1357:                            digits.append('0');
1358:                        }
1359:                    }
1360:                    digits.append(value);
1361:
1362:                    // strip trailing zeros from value
1363:                    int last = 9;
1364:                    while (--last >= 0) {
1365:                        if (digits.charAt(last) != '0') {
1366:                            break;
1367:                        }
1368:                    }
1369:                    digits.setLength(last + 1);
1370:
1371:                    // finish by appending to rounded time with decimal separator
1372:                    long time = stamp.getTime();
1373:                    return serializeDateTime(time - time % 1000, false) + '.'
1374:                            + digits + 'Z';
1375:
1376:                } else {
1377:                    return serializeDateTime(stamp.getTime(), true);
1378:                }
1379:            }
1380:
1381:            /**
1382:             * Serialize time to standard text. Time values are formatted in W3C XML
1383:             * Schema standard format as hh:mm:ss, with optional trailing seconds
1384:             * decimal, as necessary. The standard conversion does not append a time
1385:             * zone indication.
1386:             *
1387:             * @param time time to be converted
1388:             * @return converted time text
1389:             */
1390:            public static String serializeSqlTime(Time time) {
1391:                StringBuffer buff = new StringBuffer(12);
1392:                serializeTime((int) time.getTime(), buff);
1393:                return buff.toString();
1394:            }
1395:
1396:            //#j2me}
1397:
1398:            /**
1399:             * General object comparison method. Don't know why Sun hasn't seen fit to
1400:             * include this somewhere, but at least it's easy to write (over and over
1401:             * again).
1402:             * 
1403:             * @param a first object to be compared
1404:             * @param b second object to be compared
1405:             * @return <code>true</code> if both objects are <code>null</code>, or if
1406:             * <code>a.equals(b)</code>; <code>false</code> otherwise
1407:             */
1408:            public static boolean isEqual(Object a, Object b) {
1409:                return (a == null) ? b == null : a.equals(b);
1410:            }
1411:
1412:            /**
1413:             * Find text value in enumeration. This first does a binary search through
1414:             * an array of allowed text matches. If a separate array of corresponding
1415:             * values is supplied, the value at the matched position is returned;
1416:             * otherwise the match index is returned directly.
1417:             *
1418:             * @param target text to be found in enumeration
1419:             * @param enums ordered array of texts included in enumeration
1420:             * @param vals array of values to be returned for corresponding text match
1421:             * positions (position returned directly if this is <code>null</code>)
1422:             * @return enumeration value for target text
1423:             * @throws JiBXException if target text not found in enumeration
1424:             */
1425:            public static int enumValue(String target, String[] enums,
1426:                    int[] vals) throws JiBXException {
1427:                int base = 0;
1428:                int limit = enums.length - 1;
1429:                while (base <= limit) {
1430:                    int cur = (base + limit) >> 1;
1431:                    int diff = target.compareTo(enums[cur]);
1432:                    if (diff < 0) {
1433:                        limit = cur - 1;
1434:                    } else if (diff > 0) {
1435:                        base = cur + 1;
1436:                    } else if (vals != null) {
1437:                        return vals[cur];
1438:                    } else {
1439:                        return cur;
1440:                    }
1441:                }
1442:                throw new JiBXException("Target value \"" + target
1443:                        + "\" not found in enumeration");
1444:            }
1445:
1446:            /**
1447:             * Decode a chunk of data from base64 encoding. The length of a chunk is
1448:             * always 4 characters in the base64 representation, but may be 1, 2, or 3
1449:             * bytes of data, as determined by whether there are any pad characters at
1450:             * the end of the base64 representation 
1451:             *
1452:             * @param base starting offset within base64 character array
1453:             * @param chrs character array for base64 text representation
1454:             * @param fill starting offset within byte data array
1455:             * @param byts byte data array
1456:             * @return number of decoded bytes
1457:             */
1458:            private static int decodeChunk(int base, char[] chrs, int fill,
1459:                    byte[] byts) {
1460:
1461:                // find the byte count to be decoded
1462:                int length = 3;
1463:                if (chrs[base + 3] == PAD_CHAR) {
1464:                    length = 2;
1465:                    if (chrs[base + 2] == PAD_CHAR) {
1466:                        length = 1;
1467:                    }
1468:                }
1469:
1470:                // get 6-bit values
1471:                int v0 = s_base64Values[chrs[base + 0]];
1472:                int v1 = s_base64Values[chrs[base + 1]];
1473:                int v2 = s_base64Values[chrs[base + 2]];
1474:                int v3 = s_base64Values[chrs[base + 3]];
1475:
1476:                // convert and store bytes of data
1477:                switch (length) {
1478:                case 3:
1479:                    byts[fill + 2] = (byte) (v2 << 6 | v3);
1480:                case 2:
1481:                    byts[fill + 1] = (byte) (v1 << 4 | v2 >> 2);
1482:                case 1:
1483:                    byts[fill] = (byte) (v0 << 2 | v1 >> 4);
1484:                    break;
1485:                }
1486:                return length;
1487:            }
1488:
1489:            /**
1490:             * Parse base64 data from text. This converts the base64 data into a byte
1491:             * array of the appopriate length. In keeping with the recommendations,
1492:             *
1493:             * @param text text to be parsed (may include extra characters)
1494:             * @return byte array of data
1495:             * @throws JiBXException if invalid character in base64 representation
1496:             */
1497:            public static byte[] parseBase64(String text) throws JiBXException {
1498:
1499:                // convert raw text to base64 character array
1500:                char[] chrs = new char[text.length()];
1501:                int length = 0;
1502:                for (int i = 0; i < text.length(); i++) {
1503:                    char chr = text.charAt(i);
1504:                    if (chr < 128 && s_base64Values[chr] >= 0) {
1505:                        chrs[length++] = chr;
1506:                    }
1507:                }
1508:
1509:                // check the text length
1510:                if (length % 4 != 0) {
1511:                    throw new JiBXException(
1512:                            "Text length for base64 must be a multiple of 4");
1513:                } else if (length == 0) {
1514:                    return new byte[0];
1515:                }
1516:
1517:                // find corresponding byte count for data
1518:                int blength = length / 4 * 3;
1519:                if (chrs[length - 1] == PAD_CHAR) {
1520:                    blength--;
1521:                    if (chrs[length - 2] == PAD_CHAR) {
1522:                        blength--;
1523:                    }
1524:                }
1525:
1526:                // convert text to actual bytes of data
1527:                byte[] byts = new byte[blength];
1528:                int fill = 0;
1529:                for (int i = 0; i < length; i += 4) {
1530:                    fill += decodeChunk(i, chrs, fill, byts);
1531:                }
1532:                if (fill != blength) {
1533:                    throw new JiBXException(
1534:                            "Embedded padding characters in byte64 text");
1535:                }
1536:                return byts;
1537:            }
1538:
1539:            /**
1540:             * Parse base64 data from text. This converts the base64 data into a byte
1541:             * array of the appopriate length. In keeping with the recommendations,
1542:             *
1543:             * @param text text to be parsed (may be null, or include extra characters)
1544:             * @return byte array of data
1545:             * @throws JiBXException if invalid character in base64 representation
1546:             */
1547:            public static byte[] deserializeBase64(String text)
1548:                    throws JiBXException {
1549:                if (text == null) {
1550:                    return null;
1551:                } else {
1552:                    return parseBase64(text);
1553:                }
1554:            }
1555:
1556:            /**
1557:             * Encode a chunk of data to base64 encoding. Converts the next three bytes
1558:             * of data into four characters of text representation, using padding at the
1559:             * end of less than three bytes of data remain.
1560:             *
1561:             * @param base starting offset within byte array
1562:             * @param byts byte data array
1563:             * @param buff buffer for encoded text
1564:             */
1565:            public static void encodeChunk(int base, byte[] byts,
1566:                    StringBuffer buff) {
1567:
1568:                // get actual byte data length to be encoded
1569:                int length = 3;
1570:                if (base + length > byts.length) {
1571:                    length = byts.length - base;
1572:                }
1573:
1574:                // convert up to three bytes of data to four characters of text
1575:                int b0 = byts[base];
1576:                int value = (b0 >> 2) & 0x3F;
1577:                buff.append(s_base64Chars[value]);
1578:                if (length > 1) {
1579:                    int b1 = byts[base + 1];
1580:                    value = ((b0 & 3) << 4) + ((b1 >> 4) & 0x0F);
1581:                    buff.append(s_base64Chars[value]);
1582:                    if (length > 2) {
1583:                        int b2 = byts[base + 2];
1584:                        value = ((b1 & 0x0F) << 2) + ((b2 >> 6) & 3);
1585:                        buff.append(s_base64Chars[value]);
1586:                        value = b2 & 0x3F;
1587:                        buff.append(s_base64Chars[value]);
1588:                    } else {
1589:                        value = (b1 & 0x0F) << 2;
1590:                        buff.append(s_base64Chars[value]);
1591:                        buff.append(PAD_CHAR);
1592:                    }
1593:                } else {
1594:                    value = (b0 & 3) << 4;
1595:                    buff.append(s_base64Chars[value]);
1596:                    buff.append(PAD_CHAR);
1597:                    buff.append(PAD_CHAR);
1598:                }
1599:            }
1600:
1601:            /**
1602:             * Serialize byte array to base64 text. In keeping with the specification,
1603:             * this adds a line break every 76 characters in the encoded representation.
1604:             *
1605:             * @param byts byte data array
1606:             * @return base64 encoded text
1607:             */
1608:            public static String serializeBase64(byte[] byts) {
1609:                StringBuffer buff = new StringBuffer((byts.length + 2) / 3 * 4);
1610:                for (int i = 0; i < byts.length; i += 3) {
1611:                    encodeChunk(i, byts, buff);
1612:                    if (i > 0 && i % 57 == 0 && (i + 3) < byts.length) {
1613:                        buff.append("\r\n");
1614:                    }
1615:                }
1616:                return buff.toString();
1617:            }
1618:
1619:            /**
1620:             * Resize array of arbitrary type.
1621:             *
1622:             * @param size new aray size
1623:             * @param base array to be resized
1624:             * @return resized array, with all data to minimum of the two sizes copied
1625:             */
1626:            public static Object resizeArray(int size, Object base) {
1627:                int prior = Array.getLength(base);
1628:                if (size == prior) {
1629:                    return base;
1630:                } else {
1631:                    Class type = base.getClass().getComponentType();
1632:                    Object copy = Array.newInstance(type, size);
1633:                    int count = Math.min(size, prior);
1634:                    System.arraycopy(base, 0, copy, 0, count);
1635:                    return copy;
1636:                }
1637:            }
1638:
1639:            /**
1640:             * Grow array of arbitrary type. The returned array is double the size of
1641:             * the original array, providing this is at least the defined minimum size.
1642:             *
1643:             * @param base array to be grown
1644:             * @return array of twice the size as original array, with all data copied
1645:             */
1646:            public static Object growArray(Object base) {
1647:                int length = Array.getLength(base);
1648:                Class type = base.getClass().getComponentType();
1649:                int newlen = Math.max(length * 2, MINIMUM_GROWN_ARRAY_SIZE);
1650:                Object copy = Array.newInstance(type, newlen);
1651:                System.arraycopy(base, 0, copy, 0, length);
1652:                return copy;
1653:            }
1654:
1655:            /**
1656:             * Factory method to create a <code>java.util.ArrayList</code> as the
1657:             * implementation of a <code>java.util.List</code>.
1658:             *
1659:             * @return new <code>java.util.ArrayList</code>
1660:             */
1661:            public static List arrayListFactory() {
1662:                return new ArrayList();
1663:            }
1664:
1665:            /**
1666:             * Convert whitespace-separated list of values. This implements the
1667:             * whitespace skipping, calling the supplied item deserializer for handling
1668:             * each individual value.
1669:             * 
1670:             * @param text value to be converted
1671:             * @param ideser list item deserializer
1672:             * @return list of deserialized items (<code>null</code> if input
1673:             * <code>null</code>, or if nonrecoverable error)
1674:             * @throws JiBXException if error in deserializing text
1675:             */
1676:            public static ArrayList deserializeList(String text,
1677:                    IListItemDeserializer ideser) throws JiBXException {
1678:                if (text == null) {
1679:                    return null;
1680:                } else {
1681:
1682:                    // scan text to find whitespace breaks between items
1683:                    ArrayList items = new ArrayList();
1684:                    int length = text.length();
1685:                    int base = 0;
1686:                    boolean space = true;
1687:                    for (int i = 0; i < length; i++) {
1688:                        char chr = text.charAt(i);
1689:                        switch (chr) {
1690:
1691:                        case 0x09:
1692:                        case 0x0A:
1693:                        case 0x0D:
1694:                        case ' ':
1695:                            // ignore if preceded by space
1696:                            if (!space) {
1697:                                String itext = text.substring(base, i);
1698:                                items.add(ideser.deserialize(itext));
1699:                                space = true;
1700:                            }
1701:                            base = i + 1;
1702:                            break;
1703:
1704:                        default:
1705:                            space = false;
1706:                            break;
1707:                        }
1708:                    }
1709:
1710:                    // finish last item
1711:                    if (base < length) {
1712:                        String itext = text.substring(base);
1713:                        items.add(ideser.deserialize(itext));
1714:                    }
1715:
1716:                    // check if any items found
1717:                    if (items.size() > 0) {
1718:                        return items;
1719:                    } else {
1720:                        return null;
1721:                    }
1722:                }
1723:            }
1724:
1725:            /**
1726:             * Deserialize a list of whitespace-separated tokens into an array of
1727:             * strings.
1728:             * 
1729:             * @param text value text
1730:             * @return created class instance
1731:             * @throws JiBXException on error in marshalling
1732:             */
1733:            public static String[] deserializeTokenList(String text)
1734:                    throws JiBXException {
1735:
1736:                // use basic qualified name deserializer to handle items
1737:                IListItemDeserializer ldser = new IListItemDeserializer() {
1738:                    public Object deserialize(String text) throws JiBXException {
1739:                        return text;
1740:                    }
1741:                };
1742:                ArrayList list = Utility.deserializeList(text, ldser);
1743:                if (list == null) {
1744:                    return null;
1745:                } else {
1746:                    return (String[]) list.toArray(new String[list.size()]);
1747:                }
1748:            }
1749:
1750:            /**
1751:             * Serialize an array of strings into a whitespace-separated token list.
1752:             * 
1753:             * @param tokens array of strings to be serialized
1754:             * @return list text
1755:             */
1756:            public static String serializeTokenList(String[] tokens) {
1757:                StringBuffer buff = new StringBuffer();
1758:                for (int i = 0; i < tokens.length; i++) {
1759:                    if (buff.length() > 0) {
1760:                        buff.append(' ');
1761:                    }
1762:                    buff.append(tokens[i]);
1763:                }
1764:                return buff.toString();
1765:            }
1766:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.