--- old/jaxp/src/com/sun/org/apache/xerces/internal/jaxp/datatype/XMLGregorianCalendarImpl.java Tue Feb 18 09:40:14 2014 +++ new/jaxp/src/com/sun/org/apache/xerces/internal/jaxp/datatype/XMLGregorianCalendarImpl.java Tue Feb 18 09:40:14 2014 @@ -25,6 +25,8 @@ package com.sun.org.apache.xerces.internal.jaxp.datatype; +import java.io.IOException; +import java.io.ObjectInputStream; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; @@ -194,6 +196,17 @@ public class XMLGregorianCalendarImpl extends XMLGregorianCalendar implements Serializable, Cloneable { + + /** Backup values **/ + transient private BigInteger orig_eon; + transient private int orig_year = DatatypeConstants.FIELD_UNDEFINED; + transient private int orig_month = DatatypeConstants.FIELD_UNDEFINED; + transient private int orig_day = DatatypeConstants.FIELD_UNDEFINED; + transient private int orig_hour = DatatypeConstants.FIELD_UNDEFINED; + transient private int orig_minute = DatatypeConstants.FIELD_UNDEFINED; + transient private int orig_second = DatatypeConstants.FIELD_UNDEFINED; + transient private BigDecimal orig_fracSeconds; + transient private int orig_timezone = DatatypeConstants.FIELD_UNDEFINED; /** *

Eon of this XMLGregorianCalendar.

@@ -241,11 +254,16 @@ private BigDecimal fractionalSecond = null; /** - *

Constant to represent a billion.

+ *

BigInteger constant; representing a billion.

*/ - private static final BigInteger BILLION = new BigInteger("1000000000"); - + private static final BigInteger BILLION_B = new BigInteger("1000000000"); + /** + *

int constant; representing a billion.

+ */ + private static final int BILLION_I = 1000000000; + + /** *

Obtain a pure Gregorian Calendar by calling * GregorianCalendar.setChange(PURE_GREGORIAN_CHANGE).

*/ @@ -441,9 +459,26 @@ //"\"" + lexicalRepresentation + "\" is not a valid representation of an XML Gregorian Calendar value." ); } + + save(); } /** + * save original values + */ + private void save() { + orig_eon = eon; + orig_year = year; + orig_month = month; + orig_day = day; + orig_hour = hour; + orig_minute = minute; + orig_second = second; + orig_fracSeconds = fractionalSecond; + orig_timezone = timezone; + } + + /** *

Create an instance with all date/time datatype fields set to * {@link DatatypeConstants#FIELD_UNDEFINED} or null respectively.

*/ @@ -479,14 +514,14 @@ BigDecimal fractionalSecond, int timezone) { - setYear(year); + setYear(year); setMonth(month); setDay(day); setTime(hour, minute, second, fractionalSecond); - setTimezone(timezone); + setTimezone(timezone); - // check for validity - if (!isValid()) { + // check for validity + if (!isValid()) { throw new IllegalArgumentException( DatatypeMessageFormatter.formatMessage(null, @@ -519,8 +554,9 @@ ); */ - } - + } + + save(); } /** @@ -547,17 +583,21 @@ int hour, int minute, int second, - int millisecond, + int millisecond, int timezone) { - setYear(year); + setYear(year); setMonth(month); setDay(day); setTime(hour, minute, second); - setTimezone(timezone); - setMillisecond(millisecond); + setTimezone(timezone); + BigDecimal realMilliseconds = null; + if (millisecond != DatatypeConstants.FIELD_UNDEFINED) { + realMilliseconds = BigDecimal.valueOf(millisecond, 3); + } + setFractionalSecond(realMilliseconds); - if (!isValid()) { + if (!isValid()) { throw new IllegalArgumentException( DatatypeMessageFormatter.formatMessage(null, @@ -580,7 +620,9 @@ ); */ - } + } + + save(); } /** @@ -661,6 +703,7 @@ // Calendar ZONE_OFFSET and DST_OFFSET fields are in milliseconds. int offsetInMinutes = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000); this.setTimezone(offsetInMinutes); + save(); } // Factories @@ -1164,7 +1207,7 @@ this.eon = null; this.year = DatatypeConstants.FIELD_UNDEFINED; } else { - BigInteger temp = year.remainder(BILLION); + BigInteger temp = year.remainder(BILLION_B); this.year = temp.intValue(); setEon(year.subtract(temp)); } @@ -1187,12 +1230,13 @@ if (year == DatatypeConstants.FIELD_UNDEFINED) { this.year = DatatypeConstants.FIELD_UNDEFINED; this.eon = null; - } else if (Math.abs(year) < BILLION.intValue()) { + } + else if (Math.abs(year) < BILLION_I) { this.year = year; this.eon = null; } else { BigInteger theYear = BigInteger.valueOf((long) year); - BigInteger remainder = theYear.remainder(BILLION); + BigInteger remainder = theYear.remainder(BILLION_B); this.year = remainder.intValue(); setEon(theYear.subtract(remainder)); } @@ -1684,10 +1728,13 @@ * @return true when compare(this,(XMLGregorianCalendar)obj) == EQUAL.. */ public boolean equals(Object obj) { - + if (obj == null || !(obj instanceof XMLGregorianCalendar)) { return false; } + if (obj == this) { + return true; + } return compare((XMLGregorianCalendar) obj) == DatatypeConstants.EQUAL; } @@ -1945,56 +1992,41 @@ * @return true if data values are valid. */ public boolean isValid() { - // since setters do not allow for invalid values, + // since setters do not allow for invalid values, // (except for exceptional case of year field of zero), // no need to check for anything except for constraints - // between fields. + // between fields. - //check if days in month is valid. Can be dependent on leap year. - if (getMonth() == DatatypeConstants.FEBRUARY) { - // years could not be set - int maxDays = 29; - - if (eon == null) { - if(year!=DatatypeConstants.FIELD_UNDEFINED) - maxDays = maximumDayInMonthFor(year,getMonth()); - } else { - BigInteger years = getEonAndYear(); - if (years != null) { - maxDays = maximumDayInMonthFor(getEonAndYear(), DatatypeConstants.FEBRUARY); + // check if days in month is valid. Can be dependent on leap year. + if (month != DatatypeConstants.FIELD_UNDEFINED && day != DatatypeConstants.FIELD_UNDEFINED) { + if (year != DatatypeConstants.FIELD_UNDEFINED) { + if (eon == null) { + if (day > maximumDayInMonthFor(year, month)) { + return false; + } } + else if (day > maximumDayInMonthFor(getEonAndYear(), month)) { + return false; + } } - if (getDay() > maxDays) { + // Use 2000 as a default since it's a leap year. + else if (day > maximumDayInMonthFor(2000, month)) { return false; } } // http://www.w3.org/2001/05/xmlschema-errata#e2-45 - if (getHour() == 24) { - if(getMinute() != 0) { - return false; - } else if (getSecond() != 0) { - return false; - } + if (hour == 24 && (minute != 0 || second != 0 || + (fractionalSecond != null && fractionalSecond.compareTo(DECIMAL_ZERO) != 0))) { + return false; } // XML Schema 1.0 specification defines year value of zero as // invalid. Allow this class to set year field to zero - // since XML Schema 1.0 errata states that lexical zero will + // since XML Schema 1.0 errata states that lexical zero will // be allowed in next version and treated as 1 B.C.E. - if (eon == null) { - // optimize check. - if (year == 0) { - return false; - } - } else { - BigInteger yearField = getEonAndYear(); - if (yearField != null) { - int result = compareField(yearField, BigInteger.ZERO); - if (result == DatatypeConstants.EQUAL) { - return false; - } - } + if (eon == null && year == 0) { + return false; } return true; } @@ -2213,7 +2245,7 @@ int quotient; if (endMonth < 0) { endMonth = (13 - 1) + endMonth + 1; - quotient = new BigDecimal(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue(); + quotient = BigDecimal.valueOf(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue(); } else { quotient = (intTemp - 1) / (13 - 1); endMonth += 1; @@ -2259,18 +2291,20 @@ private static final BigInteger SIXTY = BigInteger.valueOf(60); private static final BigInteger TWENTY_FOUR = BigInteger.valueOf(24); private static final BigInteger TWELVE = BigInteger.valueOf(12); - private static final BigDecimal DECIMAL_ZERO = new BigDecimal("0"); - private static final BigDecimal DECIMAL_ONE = new BigDecimal("1"); - private static final BigDecimal DECIMAL_SIXTY = new BigDecimal("60"); + private static final BigDecimal DECIMAL_ZERO = BigDecimal.valueOf(0); + private static final BigDecimal DECIMAL_ONE = BigDecimal.valueOf(1); + private static final BigDecimal DECIMAL_SIXTY = BigDecimal.valueOf(60); - private static int daysInMonth[] = { 0, // XML Schema months start at 1. - 31, 28, 31, 30, 31, 30, - 31, 31, 30, 31, 30, 31}; + private static class DaysInMonth { + private static final int [] table = { 0, // XML Schema months start at 1. + 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31}; + } private static int maximumDayInMonthFor(BigInteger year, int month) { if (month != DatatypeConstants.FEBRUARY) { - return daysInMonth[month]; + return DaysInMonth.table[month]; } else { if (year.mod(FOUR_HUNDRED).equals(BigInteger.ZERO) || (!year.mod(HUNDRED).equals(BigInteger.ZERO) && @@ -2278,7 +2312,7 @@ // is a leap year. return 29; } else { - return daysInMonth[month]; + return DaysInMonth.table[month]; } } } @@ -2285,7 +2319,7 @@ private static int maximumDayInMonthFor(int year, int month) { if (month != DatatypeConstants.FEBRUARY) { - return daysInMonth[month]; + return DaysInMonth.table[month]; } else { if (((year % 400) == 0) || (((year % 100) != 0) && ((year % 4) == 0))) { @@ -2292,7 +2326,7 @@ // is a leap year. return 29; } else { - return daysInMonth[DatatypeConstants.FEBRUARY]; + return DaysInMonth.table[DatatypeConstants.FEBRUARY]; } } } @@ -2404,10 +2438,16 @@ result.setGregorianChange(PURE_GREGORIAN_CHANGE); // if year( and eon) are undefined, leave default Calendar values - BigInteger year = getEonAndYear(); - if (year != null) { - result.set(Calendar.ERA, year.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); - result.set(Calendar.YEAR, year.abs().intValue()); + if (year != DatatypeConstants.FIELD_UNDEFINED) { + if (eon == null) { + result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, Math.abs(year)); + } + else { + BigInteger eonAndYear = getEonAndYear(); + result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, eonAndYear.abs().intValue()); + } } // only set month if it is set @@ -2543,16 +2583,31 @@ result.setGregorianChange(PURE_GREGORIAN_CHANGE); // if year( and eon) are undefined, leave default Calendar values - BigInteger year = getEonAndYear(); - if (year != null) { - result.set(Calendar.ERA, year.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); - result.set(Calendar.YEAR, year.abs().intValue()); + if (year != DatatypeConstants.FIELD_UNDEFINED) { + if (eon == null) { + result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, Math.abs(year)); + } + else { + final BigInteger eonAndYear = getEonAndYear(); + result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, eonAndYear.abs().intValue()); + } } else { // use default if set - BigInteger defaultYear = (defaults != null) ? defaults.getEonAndYear() : null; - if (defaultYear != null) { - result.set(Calendar.ERA, defaultYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); - result.set(Calendar.YEAR, defaultYear.abs().intValue()); + if (defaults != null) { + final int defaultYear = defaults.getYear(); + if (defaultYear != DatatypeConstants.FIELD_UNDEFINED) { + if (defaults.getEon() == null) { + result.set(Calendar.ERA, defaultYear < 0 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, Math.abs(defaultYear)); + } + else { + final BigInteger defaultEonAndYear = defaults.getEonAndYear(); + result.set(Calendar.ERA, defaultEonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD); + result.set(Calendar.YEAR, defaultEonAndYear.abs().intValue()); + } + } } } @@ -2562,7 +2617,7 @@ result.set(Calendar.MONTH, month - 1); } else { // use default if set - int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED; + final int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED; if (defaultMonth != DatatypeConstants.FIELD_UNDEFINED) { // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not. result.set(Calendar.MONTH, defaultMonth - 1); @@ -2574,7 +2629,7 @@ result.set(Calendar.DAY_OF_MONTH, day); } else { // use default if set - int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED; + final int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED; if (defaultDay != DatatypeConstants.FIELD_UNDEFINED) { result.set(Calendar.DAY_OF_MONTH, defaultDay); } @@ -2596,7 +2651,7 @@ result.set(Calendar.MINUTE, minute); } else { // use default if set - int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED; + final int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED; if (defaultMinute != DatatypeConstants.FIELD_UNDEFINED) { result.set(Calendar.MINUTE, defaultMinute); } @@ -2607,7 +2662,7 @@ result.set(Calendar.SECOND, second); } else { // use default if set - int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED; + final int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED; if (defaultSecond != DatatypeConstants.FIELD_UNDEFINED) { result.set(Calendar.SECOND, defaultSecond); } @@ -2618,7 +2673,7 @@ result.set(Calendar.MILLISECOND, getMillisecond()); } else { // use default if set - BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null; + final BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null; if (defaultFractionalSecond != null) { result.set(Calendar.MILLISECOND, defaults.getMillisecond()); } @@ -2671,6 +2726,9 @@ customTimezoneId.append(sign); customTimezoneId.append(hour); if (minutes != 0) { + if (minutes < 10) { + customTimezoneId.append('0'); + } customTimezoneId.append(minutes); } result = TimeZone.getTimeZone(customTimezoneId.toString()); @@ -2718,7 +2776,7 @@ if(millisecond<0 || 999 - * I wrote a custom format method for a particular format string to - * see if it improves the performance, but it didn't. So this interpreting - * approach isn't too bad. - * - *

* StringBuffer -> StringBuilder change had a very visible impact. - * It almost cut the execution time to half, but unfortunately we can't use it - * because we need to run on JDK 1.3 + * It almost cut the execution time to half. + * Diff from Xerces: + * Xerces use StringBuffer due to the requirement to support + * JDKs older than JDK 1.5 */ private String format( String format ) { - char[] buf = new char[32]; - int bufPtr = 0; - + StringBuilder buf = new StringBuilder(); int fidx=0,flen=format.length(); while(fidx= 0) { - String zeros = frac.substring(pos+2); - frac = frac.substring(0,pos); - pos = frac.indexOf("."); - if (pos >= 0) { - frac = frac.substring(0,pos) + frac.substring(pos+1); + case 'Y': + if (eon == null) { + int absYear = year; + if (absYear < 0) { + buf.append('-'); + absYear = -year; } - int count = Integer.parseInt(zeros); - if (count < 40) { - frac = "00000000000000000000000000000000000000000".substring(0,count-1) + frac; - } else { - // do it the hard way - while (count > 1) { - frac = "0" + frac; - count--; - } - } - frac = "0." + frac; + printNumber(buf, absYear, 4); } - - // reallocate the buffer now so that it has enough space - char[] n = new char[buf.length+frac.length()]; - System.arraycopy(buf,0,n,0,bufPtr); - buf = n; - //skip leading zero. - frac.getChars(1, frac.length(), buf, bufPtr); - bufPtr += frac.length()-1; - } - break; - case 'z': - int offset = getTimezone(); - if (offset == 0) { - buf[bufPtr++] = 'Z'; - } else - if (offset != DatatypeConstants.FIELD_UNDEFINED) { - if (offset < 0) { - buf[bufPtr++] = '-'; - offset *= -1; - } else { - buf[bufPtr++] = '+'; + else { + printNumber(buf, getEonAndYear(), 4); } - bufPtr = print2Number(buf, bufPtr, offset / 60); - buf[bufPtr++] = ':'; - bufPtr = print2Number(buf, bufPtr, offset % 60); - } - break; - default: - throw new InternalError(); // impossible + break; + case 'M': + printNumber(buf,getMonth(),2); + break; + case 'D': + printNumber(buf,getDay(),2); + break; + case 'h': + printNumber(buf,getHour(),2); + break; + case 'm': + printNumber(buf,getMinute(),2); + break; + case 's': + printNumber(buf,getSecond(),2); + if (getFractionalSecond() != null) { + //Xerces uses a custom method toString instead of + //toPlainString() since it needs to support JDKs older than 1.5 + String frac = getFractionalSecond().toPlainString(); + //skip leading zero. + buf.append(frac.substring(1, frac.length())); + } + break; + case 'z': + int offset = getTimezone(); + if (offset == 0) { + buf.append('Z'); + } + else if (offset != DatatypeConstants.FIELD_UNDEFINED) { + if (offset < 0) { + buf.append('-'); + offset *= -1; + } + else { + buf.append('+'); + } + printNumber(buf,offset/60,2); + buf.append(':'); + printNumber(buf,offset%60,2); + } + break; + default: + throw new InternalError(); // impossible } } - return new String(buf,0,bufPtr); + return buf.toString(); } /** - * Prints an int as two digits into the buffer. - * + * Prints an integer as a String. + * + * @param out + * The formatted string will be appended into this buffer. * @param number - * Number to be printed. Must be positive. + * The integer to be printed. + * @param nDigits + * The field will be printed by using at least this + * number of digits. For example, 5 will be printed as "0005" + * if nDigits==4. */ - private int print2Number( char[] out, int bufptr, int number ) { - out[bufptr++] = (char) ('0'+(number/10)); - out[bufptr++] = (char) ('0'+(number%10)); - return bufptr; + private void printNumber( StringBuilder out, int number, int nDigits ) { + String s = String.valueOf(number); + for (int i = s.length(); i < nDigits; i++) { + out.append('0'); + } + out.append(s); } /** - * Prints an int as four digits into the buffer. - * + * Prints an BigInteger as a String. + * + * @param out + * The formatted string will be appended into this buffer. * @param number - * Number to be printed. Must be positive. + * The integer to be printed. + * @param nDigits + * The field will be printed by using at least this + * number of digits. For example, 5 will be printed as "0005" + * if nDigits==4. */ - private int print4Number( char[] out, int bufptr, int number ) { - out[bufptr+3] = (char) ('0'+(number%10)); - number /= 10; - out[bufptr+2] = (char) ('0'+(number%10)); - number /= 10; - out[bufptr+1] = (char) ('0'+(number%10)); - number /= 10; - out[bufptr ] = (char) ('0'+(number%10)); - return bufptr+4; + private void printNumber( StringBuilder out, BigInteger number, int nDigits) { + String s = number.toString(); + for (int i=s.length(); i < nDigits; i++) { + out.append('0'); + } + out.append(s); } /** @@ -3085,6 +3108,26 @@ * with the creation of new XMLGregorianCalendars.

*/ public void reset() { - //PENDING : Implementation of reset method + eon = orig_eon; + year = orig_year; + month = orig_month; + day = orig_day; + hour = orig_hour; + minute = orig_minute; + second = orig_second; + fractionalSecond = orig_fracSeconds; + timezone = orig_timezone; } + + /** Deserialize Calendar. */ + private void readObject(ObjectInputStream ois) + throws ClassNotFoundException, IOException { + + // perform default deseralization + ois.defaultReadObject(); + + // initialize orig_* fields + save(); + + } // readObject(ObjectInputStream) }