--- old/jaxp/src/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java Tue Feb 18 09:40:13 2014 +++ new/jaxp/src/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java Tue Feb 18 09:40:13 2014 @@ -3,14 +3,15 @@ * DO NOT REMOVE OR ALTER! */ /* - * Copyright 2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -39,20 +40,20 @@ /** *

Immutable representation of a time span as defined in * the W3C XML Schema 1.0 specification.

- * + * *

A Duration object represents a period of Gregorian time, * which consists of six fields (years, months, days, hours, * minutes, and seconds) plus a sign (+/-) field.

- * + * *

The first five fields have non-negative (>=0) integers or null * (which represents that the field is not set), * and the seconds field has a non-negative decimal or null. - * A negative sign indicates a negative duration.

- * + * A negative sign indicates a negative duration.

+ * *

This class provides a number of methods that make it easy * to use for the duration datatype of XML Schema 1.0 with * the errata.

- * + * *

Order relationship

*

Duration objects only have partial order, where two values A and B * maybe either:

@@ -65,12 +66,12 @@ *

For example, 30 days cannot be meaningfully compared to one month. * The {@link #compare(Duration)} method implements this * relationship.

- * + * *

See the {@link #isLongerThan(Duration)} method for details about * the order relationship among {@link Duration} objects.

- * - * - * + * + * + * *

Operations over Duration

*

This class provides a set of basic arithmetic operations, such * as addition, subtraction and multiplication. @@ -78,16 +79,16 @@ * fail for some combinations of operations. For example, you cannot * subtract 15 days from 1 month. See the javadoc of those methods * for detailed conditions where this could happen.

- * + * *

Also, division of a duration by a number is not provided because * the {@link Duration} class can only deal with finite precision - * decimal numbers. For example, one cannot represent 1 sec divided by 3.

- * + * decimal numbers. For example, one cannot represent 1 sec divided by 3.

+ * *

However, you could substitute a division by 3 with multiplying * by numbers such as 0.3 or 0.333.

* * - * + * *

Range of allowed values

*

* Because some operations of {@link Duration} rely on {@link Calendar} @@ -94,8 +95,8 @@ * even though {@link Duration} can hold very large or very small values, * some of the methods may not work correctly on such {@link Duration}s. * The impacted methods document their dependency on {@link Calendar}. - * - * + * + * * @author Kohsuke Kawaguchi * @author Joseph Fialli * @version $Revision: 1.8 $, $Date: 2010/05/19 23:20:06 $ @@ -103,27 +104,23 @@ * @see XMLGregorianCalendar#add(Duration) */ class DurationImpl - extends Duration - implements Serializable { + extends Duration + implements Serializable { + /** - *

Number of Fields.

- */ - private static final int FIELD_NUM = 6; - - /** *

Internal array of value Fields.

*/ - private static final DatatypeConstants.Field[] FIELDS = new DatatypeConstants.Field[]{ - DatatypeConstants.YEARS, - DatatypeConstants.MONTHS, - DatatypeConstants.DAYS, - DatatypeConstants.HOURS, - DatatypeConstants.MINUTES, - DatatypeConstants.SECONDS - }; + private static final DatatypeConstants.Field[] FIELDS = new DatatypeConstants.Field[]{ + DatatypeConstants.YEARS, + DatatypeConstants.MONTHS, + DatatypeConstants.DAYS, + DatatypeConstants.HOURS, + DatatypeConstants.MINUTES, + DatatypeConstants.SECONDS + }; - /** + /** *

Internal array of value Field ids.

*/ private static final int[] FIELD_IDS = { @@ -141,9 +138,9 @@ private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); /** - *

BigDecimal value of 0.

- */ - private static final BigDecimal ZERO = BigDecimal.valueOf((long) 0); + *

BigDecimal value of 0.

+ */ + private static final BigDecimal ZERO = BigDecimal.valueOf(0); /** *

Indicates the sign. -1, 0 or 1 if the duration is negative, @@ -186,48 +183,48 @@ */ protected BigDecimal seconds; - /** - * Returns the sign of this duration in -1,0, or 1. - * - * @return - * -1 if this duration is negative, 0 if the duration is zero, - * and 1 if the duration is postive. - */ - public int getSign() { + /** + * Returns the sign of this duration in -1,0, or 1. + * + * @return + * -1 if this duration is negative, 0 if the duration is zero, + * and 1 if the duration is postive. + */ + public int getSign() { - return signum; - } + return signum; + } - /** - * TODO: Javadoc - * @param isPositive Sign. - * - * @return 1 if positive, else -1. - */ + /** + * TODO: Javadoc + * @param isPositive Sign. + * + * @return 1 if positive, else -1. + */ protected int calcSignum(boolean isPositive) { if ((years == null || years.signum() == 0) - && (months == null || months.signum() == 0) - && (days == null || days.signum() == 0) - && (hours == null || hours.signum() == 0) - && (minutes == null || minutes.signum() == 0) - && (seconds == null || seconds.signum() == 0)) { + && (months == null || months.signum() == 0) + && (days == null || days.signum() == 0) + && (hours == null || hours.signum() == 0) + && (minutes == null || minutes.signum() == 0) + && (seconds == null || seconds.signum() == 0)) { return 0; - } + } - if (isPositive) { - return 1; - } else { - return -1; - } - + if (isPositive) { + return 1; + } + else { + return -1; + } } - + /** *

Constructs a new Duration object by specifying each field individually.

- * + * *

All the parameters are optional as long as at least one field is present. * If specified, parameters have to be zero or positive.

- * + * * @param isPositive Set to false to create a negative duration. When the length * of the duration is zero, this parameter will be ignored. * @param years of this Duration @@ -236,7 +233,7 @@ * @param hours of this Duration * @param minutes of this Duration * @param seconds of this Duration - * + * * @throws IllegalArgumentException * If years, months, days, hours, minutes and * seconds parameters are all null. Or if any @@ -250,7 +247,7 @@ BigInteger hours, BigInteger minutes, BigDecimal seconds) { - + this.years = years; this.months = months; this.days = days; @@ -279,48 +276,48 @@ testNonNegative(minutes, DatatypeConstants.MINUTES); testNonNegative(seconds, DatatypeConstants.SECONDS); } - + /** *

Makes sure that the given number is non-negative. If it is not, * throw {@link IllegalArgumentException}.

- * + * * @param n Number to test. * @param f Field to test. */ protected static void testNonNegative(BigInteger n, DatatypeConstants.Field f) { if (n != null && n.signum() < 0) { - throw new IllegalArgumentException( + throw new IllegalArgumentException( DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object[]{f.toString()}) ); } } - + /** *

Makes sure that the given number is non-negative. If it is not, * throw {@link IllegalArgumentException}.

- * + * * @param n Number to test. * @param f Field to test. */ protected static void testNonNegative(BigDecimal n, DatatypeConstants.Field f) { if (n != null && n.signum() < 0) { - + throw new IllegalArgumentException( - DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object[]{f.toString()}) + DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object[]{f.toString()}) ); } } - + /** *

Constructs a new Duration object by specifying each field * individually.

- * + * *

This method is functionally equivalent to * invoking another constructor by wrapping * all non-zero parameters into {@link BigInteger} and {@link BigDecimal}. * Zero value of int parameter is equivalent of null value of - * the corresponding field.

- * + * the corresponding field.

+ * * @see #DurationImpl(boolean, BigInteger, BigInteger, BigInteger, BigInteger, * BigInteger, BigDecimal) */ @@ -342,28 +339,28 @@ seconds != DatatypeConstants.FIELD_UNDEFINED ? new BigDecimal(String.valueOf(seconds)) : null); } - /** - * TODO: Javadoc - * - * @param i int to convert to BigInteger. - * - * @return BigInteger representation of int. - */ + /** + * TODO: Javadoc + * + * @param i int to convert to BigInteger. + * + * @return BigInteger representation of int. + */ protected static BigInteger wrap(final int i) { - // field may not be set - if (i == DatatypeConstants.FIELD_UNDEFINED) { - return null; - } - - // int -> BigInteger - return new BigInteger(String.valueOf(i)); + // field may not be set + if (i == DatatypeConstants.FIELD_UNDEFINED) { + return null; + } + + // int -> BigInteger + return BigInteger.valueOf(i); } - + /** *

Constructs a new Duration object by specifying the duration * in milliseconds.

- * + * * @param durationInMilliSeconds * The length of the duration in milliseconds. */ @@ -373,7 +370,8 @@ if (l > 0) { signum = 1; - } else if (l < 0) { + } + else if (l < 0) { signum = -1; if (l == 0x8000000000000000L) { // negating 0x8000000000000000L causes an overflow @@ -380,7 +378,8 @@ l++; } l *= -1; - } else { + } + else { signum = 0; } @@ -418,27 +417,27 @@ + gregorianCalendar.get(Calendar.MILLISECOND); this.seconds = BigDecimal.valueOf(int2long, 3); } - + /** * Constructs a new Duration object by * parsing its string representation * "PnYnMnDTnHnMnS" as defined in XML Schema 1.0 section 3.2.6.1. - * + * *

* The string representation may not have any leading * and trailing whitespaces. - * + * *

* For example, this method parses strings like * "P1D" (1 day), "-PT100S" (-100 sec.), "P1DT12H" (1 days and 12 hours). - * + * *

- * The parsing is done field by field so that + * The parsing is done field by field so that * the following holds for any lexically correct string x: *

      * new Duration(x).toString().equals(x)
      * 
- * + * * Returns a non-null valid duration object that holds the value * indicated by the lexicalRepresentation parameter. * @@ -454,6 +453,10 @@ throws IllegalArgumentException { // only if I could use the JDK1.4 regular expression .... + if (lexicalRepresentation == null) { + throw new NullPointerException(); + } + final String s = lexicalRepresentation; boolean positive; int[] idx = new int[1]; @@ -460,15 +463,12 @@ int length = s.length(); boolean timeRequired = false; - if (lexicalRepresentation == null) { - throw new NullPointerException(); - } - idx[0] = 0; if (length != idx[0] && s.charAt(idx[0]) == '-') { idx[0]++; positive = false; - } else { + } + else { positive = true; } @@ -484,8 +484,8 @@ String[] dateParts = new String[3]; int[] datePartsIndex = new int[3]; while (length != idx[0] - && isDigit(s.charAt(idx[0])) - && dateLen < 3) { + && isDigit(s.charAt(idx[0])) + && dateLen < 3) { datePartsIndex[dateLen] = idx[0]; dateParts[dateLen++] = parsePiece(s, idx); } @@ -493,7 +493,8 @@ if (length != idx[0]) { if (s.charAt(idx[0]++) == 'T') { timeRequired = true; - } else { + } + else { throw new IllegalArgumentException(s); // ,idx[0]-1); } } @@ -502,8 +503,8 @@ String[] timeParts = new String[3]; int[] timePartsIndex = new int[3]; while (length != idx[0] - && isDigitOrPeriod(s.charAt(idx[0])) - && timeLen < 3) { + && isDigitOrPeriod(s.charAt(idx[0])) + && timeLen < 3) { timePartsIndex[timeLen] = idx[0]; timeParts[timeLen++] = parsePiece(s, idx); } @@ -533,38 +534,38 @@ seconds = parseBigDecimal(s, timeParts[2], timePartsIndex[2]); signum = calcSignum(positive); } - - + + /** * TODO: Javadoc - * + * * @param ch char to test. - * + * * @return true if ch is a digit, else false. */ private static boolean isDigit(char ch) { return '0' <= ch && ch <= '9'; } - + /** * TODO: Javadoc - * + * * @param ch to test. - * + * * @return true if ch is a digit or a period, else false. */ private static boolean isDigitOrPeriod(char ch) { return isDigit(ch) || ch == '.'; } - + /** * TODO: Javadoc - * + * * @param whole String to parse. * @param idx TODO: ??? - * + * * @return Result of parsing. - * + * * @throws IllegalArgumentException If whole cannot be parsed. */ private static String parsePiece(String whole, int[] idx) @@ -582,16 +583,16 @@ return whole.substring(start, idx[0]); } - + /** * TODO: Javadoc. - * + * * @param whole TODO: ??? * @param parts TODO: ??? * @param partsIndex TODO: ??? * @param len TODO: ??? * @param tokens TODO: ??? - * + * * @throws IllegalArgumentException TODO: ??? */ private static void organizeParts( @@ -604,6 +605,9 @@ int idx = tokens.length(); for (int i = len - 1; i >= 0; i--) { + if (parts[i] == null) { + throw new IllegalArgumentException(whole); + } int nidx = tokens.lastIndexOf( parts[i].charAt(parts[i].length() - 1), @@ -624,16 +628,16 @@ parts[idx] = null; } } - + /** * TODO: Javadoc - * + * * @param whole TODO: ???. * @param part TODO: ???. * @param index TODO: ???. - * + * * @return TODO: ???. - * + * * @throws IllegalArgumentException TODO: ???. */ private static BigInteger parseBigInteger( @@ -651,16 +655,16 @@ // throw new ParseException( whole, index ); // } } - + /** * TODO: Javadoc. - * + * * @param whole TODO: ???. * @param part TODO: ???. * @param index TODO: ???. - * + * * @return TODO: ???. - * + * * @throws IllegalArgumentException TODO: ???. */ private static BigDecimal parseBigDecimal( @@ -679,7 +683,7 @@ // throw new ParseException( whole, index ); // } } - + /** *

Four constants defined for the comparison of durations.

*/ @@ -689,213 +693,212 @@ XMLGregorianCalendarImpl.parse("1903-03-01T00:00:00Z"), XMLGregorianCalendarImpl.parse("1903-07-01T00:00:00Z") }; - - /** - *

Partial order relation comparison with this Duration instance.

- * - *

Comparison result must be in accordance with - * W3C XML Schema 1.0 Part 2, Section 3.2.7.6.2, - * Order relation on duration.

- * - *

Return:

- * - * - * @param duration to compare - * - * @return the relationship between this Durationand duration parameter as - * {@link DatatypeConstants#LESSER}, {@link DatatypeConstants#EQUAL}, {@link DatatypeConstants#GREATER} - * or {@link DatatypeConstants#INDETERMINATE}. - * - * @throws UnsupportedOperationException If the underlying implementation - * cannot reasonably process the request, e.g. W3C XML Schema allows for - * arbitrarily large/small/precise values, the request may be beyond the - * implementations capability. - * @throws NullPointerException if duration is null. - * - * @see #isShorterThan(Duration) - * @see #isLongerThan(Duration) - */ + + /** + *

Partial order relation comparison with this Duration instance.

+ * + *

Comparison result must be in accordance with + * W3C XML Schema 1.0 Part 2, Section 3.2.7.6.2, + * Order relation on duration.

+ * + *

Return:

+ * + * + * @param duration to compare + * + * @return the relationship between this Durationand duration parameter as + * {@link DatatypeConstants#LESSER}, {@link DatatypeConstants#EQUAL}, {@link DatatypeConstants#GREATER} + * or {@link DatatypeConstants#INDETERMINATE}. + * + * @throws UnsupportedOperationException If the underlying implementation + * cannot reasonably process the request, e.g. W3C XML Schema allows for + * arbitrarily large/small/precise values, the request may be beyond the + * implementations capability. + * @throws NullPointerException if duration is null. + * + * @see #isShorterThan(Duration) + * @see #isLongerThan(Duration) + */ public int compare(Duration rhs) { + + BigInteger maxintAsBigInteger = BigInteger.valueOf(Integer.MAX_VALUE); - BigInteger maxintAsBigInteger = BigInteger.valueOf((long) Integer.MAX_VALUE); - BigInteger minintAsBigInteger = BigInteger.valueOf((long) Integer.MIN_VALUE); - - // check for fields that are too large in this Duration - if (years != null && years.compareTo(maxintAsBigInteger) == 1) { + // check for fields that are too large in this Duration + if (years != null && years.compareTo(maxintAsBigInteger) == 1) { throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.YEARS.toString(), years.toString()}) - //this.getClass().getName() + "#compare(Duration duration)" - //+ " years too large to be supported by this implementation " - //+ years.toString() - ); - } - if (months != null && months.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + //this.getClass().getName() + "#compare(Duration duration)" + //+ " years too large to be supported by this implementation " + //+ years.toString() + ); + } + if (months != null && months.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MONTHS.toString(), months.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " months too large to be supported by this implementation " - //+ months.toString() - ); - } - if (days != null && days.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " months too large to be supported by this implementation " + //+ months.toString() + ); + } + if (days != null && days.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.DAYS.toString(), days.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " days too large to be supported by this implementation " - //+ days.toString() - ); - } - if (hours != null && hours.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " days too large to be supported by this implementation " + //+ days.toString() + ); + } + if (hours != null && hours.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.HOURS.toString(), hours.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " hours too large to be supported by this implementation " - //+ hours.toString() - ); - } - if (minutes != null && minutes.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " hours too large to be supported by this implementation " + //+ hours.toString() + ); + } + if (minutes != null && minutes.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MINUTES.toString(), minutes.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " minutes too large to be supported by this implementation " - //+ minutes.toString() - ); - } - if (seconds != null && seconds.toBigInteger().compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", - new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), seconds.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " seconds too large to be supported by this implementation " - //+ seconds.toString() - ); - } - - // check for fields that are too large in rhs Duration - BigInteger rhsYears = (BigInteger) rhs.getField(DatatypeConstants.YEARS); - if (rhsYears != null && rhsYears.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " minutes too large to be supported by this implementation " + //+ minutes.toString() + ); + } + if (seconds != null && seconds.toBigInteger().compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", + new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), toString(seconds)}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " seconds too large to be supported by this implementation " + //+ seconds.toString() + ); + } + + // check for fields that are too large in rhs Duration + BigInteger rhsYears = (BigInteger) rhs.getField(DatatypeConstants.YEARS); + if (rhsYears != null && rhsYears.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.YEARS.toString(), rhsYears.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " years too large to be supported by this implementation " - //+ rhsYears.toString() - ); - } - BigInteger rhsMonths = (BigInteger) rhs.getField(DatatypeConstants.MONTHS); - if (rhsMonths != null && rhsMonths.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " years too large to be supported by this implementation " + //+ rhsYears.toString() + ); + } + BigInteger rhsMonths = (BigInteger) rhs.getField(DatatypeConstants.MONTHS); + if (rhsMonths != null && rhsMonths.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MONTHS.toString(), rhsMonths.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " months too large to be supported by this implementation " - //+ rhsMonths.toString() - ); - } - BigInteger rhsDays = (BigInteger) rhs.getField(DatatypeConstants.DAYS); - if (rhsDays != null && rhsDays.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " months too large to be supported by this implementation " + //+ rhsMonths.toString() + ); + } + BigInteger rhsDays = (BigInteger) rhs.getField(DatatypeConstants.DAYS); + if (rhsDays != null && rhsDays.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.DAYS.toString(), rhsDays.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " days too large to be supported by this implementation " - //+ rhsDays.toString() - ); - } - BigInteger rhsHours = (BigInteger) rhs.getField(DatatypeConstants.HOURS); - if (rhsHours != null && rhsHours.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " days too large to be supported by this implementation " + //+ rhsDays.toString() + ); + } + BigInteger rhsHours = (BigInteger) rhs.getField(DatatypeConstants.HOURS); + if (rhsHours != null && rhsHours.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.HOURS.toString(), rhsHours.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " hours too large to be supported by this implementation " - //+ rhsHours.toString() - ); - } - BigInteger rhsMinutes = (BigInteger) rhs.getField(DatatypeConstants.MINUTES); - if (rhsMinutes != null && rhsMinutes.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " hours too large to be supported by this implementation " + //+ rhsHours.toString() + ); + } + BigInteger rhsMinutes = (BigInteger) rhs.getField(DatatypeConstants.MINUTES); + if (rhsMinutes != null && rhsMinutes.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MINUTES.toString(), rhsMinutes.toString()}) - - //this.getClass().getName() + "#compare(Duration duration)" - //+ " minutes too large to be supported by this implementation " - //+ rhsMinutes.toString() - ); - } - BigDecimal rhsSecondsAsBigDecimal = (BigDecimal) rhs.getField(DatatypeConstants.SECONDS); - BigInteger rhsSeconds = null; + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " minutes too large to be supported by this implementation " + //+ rhsMinutes.toString() + ); + } + BigDecimal rhsSecondsAsBigDecimal = (BigDecimal) rhs.getField(DatatypeConstants.SECONDS); + BigInteger rhsSeconds = null; if ( rhsSecondsAsBigDecimal != null ) { rhsSeconds = rhsSecondsAsBigDecimal.toBigInteger(); } - if (rhsSeconds != null && rhsSeconds.compareTo(maxintAsBigInteger) == 1) { - throw new UnsupportedOperationException( - DatatypeMessageFormatter.formatMessage(null, "TooLarge", + if (rhsSeconds != null && rhsSeconds.compareTo(maxintAsBigInteger) == 1) { + throw new UnsupportedOperationException( + DatatypeMessageFormatter.formatMessage(null, "TooLarge", new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), rhsSeconds.toString()}) + + //this.getClass().getName() + "#compare(Duration duration)" + //+ " seconds too large to be supported by this implementation " + //+ rhsSeconds.toString() + ); + } - //this.getClass().getName() + "#compare(Duration duration)" - //+ " seconds too large to be supported by this implementation " - //+ rhsSeconds.toString() - ); - } + // turn this Duration into a GregorianCalendar + GregorianCalendar lhsCalendar = new GregorianCalendar( + 1970, + 1, + 1, + 0, + 0, + 0); + lhsCalendar.add(GregorianCalendar.YEAR, getYears() * getSign()); + lhsCalendar.add(GregorianCalendar.MONTH, getMonths() * getSign()); + lhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, getDays() * getSign()); + lhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, getHours() * getSign()); + lhsCalendar.add(GregorianCalendar.MINUTE, getMinutes() * getSign()); + lhsCalendar.add(GregorianCalendar.SECOND, getSeconds() * getSign()); + + // turn compare Duration into a GregorianCalendar + GregorianCalendar rhsCalendar = new GregorianCalendar( + 1970, + 1, + 1, + 0, + 0, + 0); + rhsCalendar.add(GregorianCalendar.YEAR, rhs.getYears() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.MONTH, rhs.getMonths() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, rhs.getDays() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, rhs.getHours() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.MINUTE, rhs.getMinutes() * rhs.getSign()); + rhsCalendar.add(GregorianCalendar.SECOND, rhs.getSeconds() * rhs.getSign()); + + + if (lhsCalendar.equals(rhsCalendar)) { + return DatatypeConstants.EQUAL; + } - // turn this Duration into a GregorianCalendar - GregorianCalendar lhsCalendar = new GregorianCalendar( - 1970, - 1, - 1, - 0, - 0, - 0); - lhsCalendar.add(GregorianCalendar.YEAR, getYears() * getSign()); - lhsCalendar.add(GregorianCalendar.MONTH, getMonths() * getSign()); - lhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, getDays() * getSign()); - lhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, getHours() * getSign()); - lhsCalendar.add(GregorianCalendar.MINUTE, getMinutes() * getSign()); - lhsCalendar.add(GregorianCalendar.SECOND, getSeconds() * getSign()); - - // turn compare Duration into a GregorianCalendar - GregorianCalendar rhsCalendar = new GregorianCalendar( - 1970, - 1, - 1, - 0, - 0, - 0); - rhsCalendar.add(GregorianCalendar.YEAR, rhs.getYears() * rhs.getSign()); - rhsCalendar.add(GregorianCalendar.MONTH, rhs.getMonths() * rhs.getSign()); - rhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, rhs.getDays() * rhs.getSign()); - rhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, rhs.getHours() * rhs.getSign()); - rhsCalendar.add(GregorianCalendar.MINUTE, rhs.getMinutes() * rhs.getSign()); - rhsCalendar.add(GregorianCalendar.SECOND, rhs.getSeconds() * rhs.getSign()); - - - if (lhsCalendar.equals(rhsCalendar)) { - return DatatypeConstants.EQUAL; - } - - return compareDates(this, rhs); + return compareDates(this, rhs); } - + /** * Compares 2 given durations. (refer to W3C Schema Datatypes "3.2.6 duration") * @@ -909,13 +912,13 @@ * return GREATER_THAN if date1 is greater than OR equal to date2 */ private int compareDates(Duration duration1, Duration duration2) { - - int resultA = DatatypeConstants.INDETERMINATE; + + int resultA = DatatypeConstants.INDETERMINATE; int resultB = DatatypeConstants.INDETERMINATE; - + XMLGregorianCalendar tempA = (XMLGregorianCalendar)TEST_POINTS[0].clone(); XMLGregorianCalendar tempB = (XMLGregorianCalendar)TEST_POINTS[0].clone(); - + //long comparison algorithm is required tempA.add(duration1); tempB.add(duration2); @@ -926,7 +929,7 @@ tempA = (XMLGregorianCalendar)TEST_POINTS[1].clone(); tempB = (XMLGregorianCalendar)TEST_POINTS[1].clone(); - + tempA.add(duration1); tempB.add(duration2); resultB = tempA.compare(tempB); @@ -937,7 +940,7 @@ tempA = (XMLGregorianCalendar)TEST_POINTS[2].clone(); tempB = (XMLGregorianCalendar)TEST_POINTS[2].clone(); - + tempA.add(duration1); tempB.add(duration2); resultB = tempA.compare(tempB); @@ -948,7 +951,7 @@ tempA = (XMLGregorianCalendar)TEST_POINTS[3].clone(); tempB = (XMLGregorianCalendar)TEST_POINTS[3].clone(); - + tempA.add(duration1); tempB.add(duration2); resultB = tempA.compare(tempB); @@ -957,9 +960,9 @@ return resultA; } - private int compareResults(int resultA, int resultB){ + private int compareResults(int resultA, int resultB) { - if ( resultB == DatatypeConstants.INDETERMINATE ) { + if ( resultB == DatatypeConstants.INDETERMINATE ) { return DatatypeConstants.INDETERMINATE; } else if ( resultA!=resultB) { @@ -967,11 +970,11 @@ } return resultA; } - + /** * Returns a hash code consistent with the definition of the equals method. - * - * @see Object#hashCode() + * + * @see Object#hashCode() */ public int hashCode() { // component wise hash is not correct because 1day = 24hours @@ -979,23 +982,23 @@ this.addTo(cal); return (int) getCalendarTimeInMillis(cal); } - + /** * Returns a string representation of this duration object. - * + * *

* The result is formatter according to the XML Schema 1.0 * spec and can be always parsed back later into the * equivalent duration object by * the {@link #DurationImpl(String)} constructor. - * + * *

* Formally, the following holds for any {@link Duration} - * object x. + * object x. *

      * new Duration(x.toString()).equals(x)
      * 
- * + * * @return * Always return a non-null valid String object. */ @@ -1005,42 +1008,42 @@ buf.append('-'); } buf.append('P'); - + if (years != null) { - buf.append(years + "Y"); + buf.append(years).append('Y'); } if (months != null) { - buf.append(months + "M"); + buf.append(months).append('M'); } if (days != null) { - buf.append(days + "D"); + buf.append(days).append('D'); } if (hours != null || minutes != null || seconds != null) { buf.append('T'); if (hours != null) { - buf.append(hours + "H"); + buf.append(hours).append('H'); } if (minutes != null) { - buf.append(minutes + "M"); + buf.append(minutes).append('M'); } if (seconds != null) { - buf.append(toString(seconds) + "S"); + buf.append(toString(seconds)).append('S'); } } - + return buf.toString(); } /** *

Turns {@link BigDecimal} to a string representation.

- * + * *

Due to a behavior change in the {@link BigDecimal#toString()} * method in JDK1.5, this had to be implemented here.

- * + * * @param bd BigDecimal to format as a String - * - * @return String representation of BigDecimal + * + * @return String representation of BigDecimal */ private String toString(BigDecimal bd) { String intString = bd.unscaledValue().toString(); @@ -1055,10 +1058,12 @@ int insertionPoint = intString.length() - scale; if (insertionPoint == 0) { /* Point goes right before intVal */ return "0." + intString; - } else if (insertionPoint > 0) { /* Point goes inside intVal */ + } + else if (insertionPoint > 0) { /* Point goes inside intVal */ buf = new StringBuffer(intString); buf.insert(insertionPoint, '.'); - } else { /* We must insert zeros between point and intVal */ + } + else { /* We must insert zeros between point and intVal */ buf = new StringBuffer(3 - insertionPoint + intString.length()); buf.append("0."); for (int i = 0; i < -insertionPoint; i++) { @@ -1071,70 +1076,70 @@ /** * Checks if a field is set. - * + * * A field of a duration object may or may not be present. * This method can be used to test if a field is present. - * + * * @param field * one of the six Field constants (YEARS,MONTHS,DAYS,HOURS, * MINUTES, or SECONDS.) * @return * true if the field is present. false if not. - * + * * @throws NullPointerException * If the field parameter is null. */ public boolean isSet(DatatypeConstants.Field field) { - - if (field == null) { + + if (field == null) { String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field)" ; - throw new NullPointerException( + throw new NullPointerException( //"cannot be called with field == null" - DatatypeMessageFormatter.formatMessage(null, "FieldCannotBeNull", new Object[]{methodName}) - ); - } + DatatypeMessageFormatter.formatMessage(null, "FieldCannotBeNull", new Object[]{methodName}) + ); + } + + if (field == DatatypeConstants.YEARS) { + return years != null; + } - if (field == DatatypeConstants.YEARS) { - return years != null; - } + if (field == DatatypeConstants.MONTHS) { + return months != null; + } - if (field == DatatypeConstants.MONTHS) { - return months != null; - } + if (field == DatatypeConstants.DAYS) { + return days != null; + } - if (field == DatatypeConstants.DAYS) { - return days != null; - } + if (field == DatatypeConstants.HOURS) { + return hours != null; + } - if (field == DatatypeConstants.HOURS) { - return hours != null; - } - - if (field == DatatypeConstants.MINUTES) { - return minutes != null; - } - - if (field == DatatypeConstants.SECONDS) { - return seconds != null; - } + if (field == DatatypeConstants.MINUTES) { + return minutes != null; + } + + if (field == DatatypeConstants.SECONDS) { + return seconds != null; + } String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field)"; - + throw new IllegalArgumentException( - DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object[]{methodName, field.toString()}) - ); - + DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object[]{methodName, field.toString()}) + ); + } - + /** - * Gets the value of a field. - * + * Gets the value of a field. + * * Fields of a duration object may contain arbitrary large value. * Therefore this method is designed to return a {@link Number} object. - * + * * In case of YEARS, MONTHS, DAYS, HOURS, and MINUTES, the returned * number will be a non-negative integer. In case of seconds, * the returned number may be a non-negative decimal value. - * + * * @param field * one of the six Field constants (YEARS,MONTHS,DAYS,HOURS, * MINUTES, or SECONDS.) @@ -1144,73 +1149,73 @@ * represents its value. If it is not present, return null. * For YEARS, MONTHS, DAYS, HOURS, and MINUTES, this method * returns a {@link BigInteger} object. For SECONDS, this - * method returns a {@link BigDecimal}. - * + * method returns a {@link BigDecimal}. + * * @throws NullPointerException * If the field parameter is null. */ public Number getField(DatatypeConstants.Field field) { - if (field == null) { + if (field == null) { String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field) " ; - - throw new NullPointerException( + + throw new NullPointerException( DatatypeMessageFormatter.formatMessage(null,"FieldCannotBeNull", new Object[]{methodName}) ); - } + } + + if (field == DatatypeConstants.YEARS) { + return years; + } - if (field == DatatypeConstants.YEARS) { - return years; - } + if (field == DatatypeConstants.MONTHS) { + return months; + } - if (field == DatatypeConstants.MONTHS) { - return months; - } + if (field == DatatypeConstants.DAYS) { + return days; + } - if (field == DatatypeConstants.DAYS) { - return days; - } + if (field == DatatypeConstants.HOURS) { + return hours; + } - if (field == DatatypeConstants.HOURS) { - return hours; - } - - if (field == DatatypeConstants.MINUTES) { - return minutes; - } - - if (field == DatatypeConstants.SECONDS) { - return seconds; - } - /** - throw new IllegalArgumentException( - "javax.xml.datatype.Duration" - + "#(getSet(DatatypeConstants.Field field) called with an unknown field: " - + field.toString() - ); + if (field == DatatypeConstants.MINUTES) { + return minutes; + } + + if (field == DatatypeConstants.SECONDS) { + return seconds; + } + /** + throw new IllegalArgumentException( + "javax.xml.datatype.Duration" + + "#(getSet(DatatypeConstants.Field field) called with an unknown field: " + + field.toString() + ); */ String methodName = "javax.xml.datatype.Duration" + "#(getSet(DatatypeConstants.Field field)"; - + throw new IllegalArgumentException( - DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object[]{methodName, field.toString()}) - ); - + DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object[]{methodName, field.toString()}) + ); + } - + /** * Obtains the value of the YEARS field as an integer value, * or 0 if not present. - * + * *

- * This method is a convenience method around the + * This method is a convenience method around the * {@link #getField(DatatypeConstants.Field)} method. - * + * *

* Note that since this method returns int, this * method will return an incorrect value for {@link Duration}s * with the year field that goes beyond the range of int. * Use getField(YEARS) to avoid possible loss of precision.

- * + * * @return * If the YEARS field is present, return * its value as an integer by using the {@link Number#intValue()} @@ -1219,68 +1224,68 @@ public int getYears() { return getInt(DatatypeConstants.YEARS); } - + /** * Obtains the value of the MONTHS field as an integer value, * or 0 if not present. - * + * * This method works just like {@link #getYears()} except * that this method works on the MONTHS field. - * + * * @return Months of this Duration. */ public int getMonths() { return getInt(DatatypeConstants.MONTHS); } - + /** * Obtains the value of the DAYS field as an integer value, * or 0 if not present. - * + * * This method works just like {@link #getYears()} except * that this method works on the DAYS field. - * + * * @return Days of this Duration. */ public int getDays() { return getInt(DatatypeConstants.DAYS); } - + /** * Obtains the value of the HOURS field as an integer value, * or 0 if not present. - * + * * This method works just like {@link #getYears()} except * that this method works on the HOURS field. - * + * * @return Hours of this Duration. - * + * */ public int getHours() { return getInt(DatatypeConstants.HOURS); } - + /** * Obtains the value of the MINUTES field as an integer value, * or 0 if not present. - * + * * This method works just like {@link #getYears()} except * that this method works on the MINUTES field. - * + * * @return Minutes of this Duration. - * + * */ public int getMinutes() { return getInt(DatatypeConstants.MINUTES); } - + /** * Obtains the value of the SECONDS field as an integer value, * or 0 if not present. - * + * * This method works just like {@link #getYears()} except * that this method works on the SECONDS field. - * + * * @return seconds in the integer value. The fraction of seconds * will be discarded (for example, if the actual value is 2.5, * this method returns 2) @@ -1288,14 +1293,14 @@ public int getSeconds() { return getInt(DatatypeConstants.SECONDS); } - + /** *

Return the requested field value as an int.

- * + * *

If field is not set, i.e. == null, 0 is returned.

- * + * * @param field To get value for. - * + * * @return int value of field or 0 if field is not set. */ private int getInt(DatatypeConstants.Field field) { @@ -1302,74 +1307,74 @@ Number n = getField(field); if (n == null) { return 0; - } else { + } + else { return n.intValue(); } } - + /** *

Returns the length of the duration in milli-seconds.

- * + * *

If the seconds field carries more digits than milli-second order, - * those will be simply discarded (or in other words, rounded to zero.) + * those will be simply discarded (or in other words, rounded to zero.) * For example, for any Calendar value x,

*
      * new Duration("PT10.00099S").getTimeInMills(x) == 10000.
      * new Duration("-PT10.00099S").getTimeInMills(x) == -10000.
      * 
- * + * *

* Note that this method uses the {@link #addTo(Calendar)} method, * which may work incorectly with {@link Duration} objects with * very large values in its fields. See the {@link #addTo(Calendar)} * method for details. - * + * * @param startInstant * The length of a month/year varies. The startInstant is * used to disambiguate this variance. Specifically, this method * returns the difference between startInstant and * startInstant+duration - * + * * @return milliseconds between startInstant and * startInstant plus this Duration * - * @throws NullPointerException if startInstant parameter + * @throws NullPointerException if startInstant parameter * is null. - * + * */ public long getTimeInMillis(final Calendar startInstant) { Calendar cal = (Calendar) startInstant.clone(); addTo(cal); - return getCalendarTimeInMillis(cal) - - getCalendarTimeInMillis(startInstant); + return getCalendarTimeInMillis(cal) - getCalendarTimeInMillis(startInstant); } - + /** *

Returns the length of the duration in milli-seconds.

- * + * *

If the seconds field carries more digits than milli-second order, * those will be simply discarded (or in other words, rounded to zero.) - * For example, for any Date value x,

+ * For example, for any Date value x,

*
      * new Duration("PT10.00099S").getTimeInMills(x) == 10000.
      * new Duration("-PT10.00099S").getTimeInMills(x) == -10000.
      * 
- * + * *

* Note that this method uses the {@link #addTo(Date)} method, * which may work incorectly with {@link Duration} objects with * very large values in its fields. See the {@link #addTo(Date)} * method for details. - * + * * @param startInstant * The length of a month/year varies. The startInstant is * used to disambiguate this variance. Specifically, this method * returns the difference between startInstant and * startInstant+duration. - * + * * @throws NullPointerException * If the startInstant parameter is null. - * + * * @return milliseconds between startInstant and * startInstant plus this Duration * @@ -1381,15 +1386,15 @@ this.addTo(cal); return getCalendarTimeInMillis(cal) - startInstant.getTime(); } - + // /** // * Returns an equivalent but "normalized" duration value. -// * +// * // * Intuitively, the normalization moves YEARS into // * MONTHS (by x12) and moves DAYS, HOURS, and MINUTES fields // * into SECONDS (by x86400, x3600, and x60 respectively.) -// * -// * +// * +// * // * Formally, this method satisfies the following conditions: // *

    // *
  • x.normalize().equals(x) @@ -1398,33 +1403,33 @@ // *
  • !x.normalize().isSet(Duration.HOURS) // *
  • !x.normalize().isSet(Duration.MINUTES) // *
-// * +// * // * @return -// * always return a non-null valid value. +// * always return a non-null valid value. // */ // public Duration normalize() { // return null; // } - + /** *

Converts the years and months fields into the days field * by using a specific time instant as the reference point.

- * + * *

For example, duration of one month normalizes to 31 days * given the start time instance "July 8th 2003, 17:40:32".

- * + * *

Formally, the computation is done as follows:

*
    *
  1. The given Calendar object is cloned. *
  2. The years, months and days fields will be added to * the {@link Calendar} object - * by using the {@link Calendar#add(int,int)} method. + * by using the {@link Calendar#add(int,int)} method. *
  3. The difference between two Calendars are computed in terms of days. *
  4. The computed days, along with the hours, minutes and seconds * fields of this duration object is used to construct a new * Duration object. *
- * + * *

Note that since the Calendar class uses int to * hold the value of year and month, this method may produce * an unexpected result if this duration object holds @@ -1431,9 +1436,9 @@ * a very large value in the years or months fields.

* * @param startTimeInstant Calendar reference point. - * + * * @return Duration of years and months of this Duration as days. - * + * * @throws NullPointerException If the startTimeInstant parameter is null. */ public Duration normalizeWith(Calendar startTimeInstant) { @@ -1440,7 +1445,7 @@ Calendar c = (Calendar) startTimeInstant.clone(); - // using int may cause overflow, but + // using int may cause overflow, but // Calendar internally treats value as int anyways. c.add(Calendar.YEAR, getYears() * signum); c.add(Calendar.MONTH, getMonths() * signum); @@ -1451,39 +1456,39 @@ int days = (int) (diff / (1000L * 60L * 60L * 24L)); return new DurationImpl( - days >= 0, - null, - null, - wrap(Math.abs(days)), - (BigInteger) getField(DatatypeConstants.HOURS), - (BigInteger) getField(DatatypeConstants.MINUTES), - (BigDecimal) getField(DatatypeConstants.SECONDS)); + days >= 0, + null, + null, + wrap(Math.abs(days)), + (BigInteger) getField(DatatypeConstants.HOURS), + (BigInteger) getField(DatatypeConstants.MINUTES), + (BigDecimal) getField(DatatypeConstants.SECONDS)); } - + /** *

Computes a new duration whose value is factor times * longer than the value of this duration.

- * + * *

This method is provided for the convenience. * It is functionally equivalent to the following code:

*
      * multiply(new BigDecimal(String.valueOf(factor)))
      * 
- * + * * @param factor Factor times longer of new Duration to create. - * + * * @return New Duration that is factortimes longer than this Duration. - * + * * @see #multiply(BigDecimal) */ public Duration multiply(int factor) { return multiply(BigDecimal.valueOf(factor)); } - + /** * Computes a new duration whose value is factor times * longer than the value of this duration. - * + * *

* For example, *

@@ -1491,12 +1496,12 @@
      * "PT1M" (1 min) * "0.3" = "PT18S" (18 seconds)
      * "P1M" (1 month) * "1.5" = IllegalStateException
      * 
- * + * *

* Since the {@link Duration} class is immutable, this method * doesn't change the value of this object. It simply computes * a new Duration object and returns it. - * + * *

* The operation will be performed field by field with the precision * of {@link BigDecimal}. Since all the fields except seconds are @@ -1507,23 +1512,23 @@ * which will be carried down to "PT12H" (12 hours). * When fractions of month cannot be meaningfully carried down * to days, or year to months, this will cause an - * {@link IllegalStateException} to be thrown. + * {@link IllegalStateException} to be thrown. * For example if you multiple one month by 0.5.

- * + * *

* To avoid {@link IllegalStateException}, use * the {@link #normalizeWith(Calendar)} method to remove the years * and months fields. - * + * * @param factor to multiply by - * + * * @return * returns a non-null valid {@link Duration} object * - * @throws IllegalStateException if operation produces fraction in + * @throws IllegalStateException if operation produces fraction in * the months field. * - * @throws NullPointerException if the factor parameter is + * @throws NullPointerException if the factor parameter is * null. * */ @@ -1531,15 +1536,15 @@ BigDecimal carry = ZERO; int factorSign = factor.signum(); factor = factor.abs(); - + BigDecimal[] buf = new BigDecimal[6]; - + for (int i = 0; i < 5; i++) { BigDecimal bd = getFieldAsBigDecimal(FIELDS[i]); bd = bd.multiply(factor).add(carry); - + buf[i] = bd.setScale(0, BigDecimal.ROUND_DOWN); - + bd = bd.subtract(buf[i]); if (i == 1) { if (bd.signum() != 0) { @@ -1547,17 +1552,19 @@ } else { carry = ZERO; } - } else { + } + else { carry = bd.multiply(FACTORS[i]); } } - + if (seconds != null) { buf[5] = seconds.multiply(factor).add(carry); - } else { + } + else { buf[5] = carry; } - + return new DurationImpl( this.signum * factorSign >= 0, toBigInteger(buf[0], null == years), @@ -1567,14 +1574,14 @@ toBigInteger(buf[4], null == minutes), (buf[5].signum() == 0 && seconds == null) ? null : buf[5]); } - + /** *

Gets the value of the field as a {@link BigDecimal}.

- * + * *

If the field is unset, return 0.

- * + * * @param f Field to get value for. - * + * * @return non-null valid {@link BigDecimal}. */ private BigDecimal getFieldAsBigDecimal(DatatypeConstants.Field f) { @@ -1581,25 +1588,28 @@ if (f == DatatypeConstants.SECONDS) { if (seconds != null) { return seconds; - } else { + } + else { return ZERO; } - } else { + } + else { BigInteger bi = (BigInteger) getField(f); if (bi == null) { return ZERO; - } else { + } + else { return new BigDecimal(bi); } } } - + /** *

BigInteger value of BigDecimal value.

- * + * * @param value Value to convert. * @param canBeNull Can returned value be null? - * + * * @return BigInteger value of BigDecimal, possibly null. */ private static BigInteger toBigInteger( @@ -1607,26 +1617,27 @@ boolean canBeNull) { if (canBeNull && value.signum() == 0) { return null; - } else { + } + else { return value.unscaledValue(); } } - + /** * 1 unit of FIELDS[i] is equivalent to FACTORS[i] unit of * FIELDS[i+1]. */ - private static final BigDecimal[] FACTORS = new BigDecimal[]{ + private static final BigDecimal[] FACTORS = new BigDecimal[] { BigDecimal.valueOf(12), null/*undefined*/, BigDecimal.valueOf(24), BigDecimal.valueOf(60), BigDecimal.valueOf(60) - }; - + }; + /** *

Computes a new duration whose value is this+rhs.

- * + * *

For example,

*
      * "1 day" + "-3 days" = "-2 days"
@@ -1635,11 +1646,11 @@
      * "15 hours" + "-3 days" = "-(2 days,9 hours)"
      * "1 year" + "-1 day" = IllegalStateException
      * 
- * + * *

Since there's no way to meaningfully subtract 1 day from 1 month, * there are cases where the operation fails in - * {@link IllegalStateException}.

- * + * {@link IllegalStateException}.

+ * *

* Formally, the computation is defined as follows.

*

@@ -1647,23 +1658,23 @@ * are both positive without losing generality (i.e., * (-X)+Y=Y-X, X+(-Y)=X-Y, * (-X)+(-Y)=-(X+Y)) - * + * *

- * Addition of two positive {@link Duration}s are simply defined as + * Addition of two positive {@link Duration}s are simply defined as * field by field addition where missing fields are treated as 0. *

* A field of the resulting {@link Duration} will be unset if and - * only if respective fields of two input {@link Duration}s are unset. + * only if respective fields of two input {@link Duration}s are unset. *

* Note that lhs.add(rhs) will be always successful if * lhs.signum()*rhs.signum()!=-1 or both of them are * normalized.

- * + * * @param rhs Duration to add to this Duration - * + * * @return * non-null valid Duration object. - * + * * @throws NullPointerException * If the rhs parameter is null. * @throws IllegalStateException @@ -1670,31 +1681,31 @@ * If two durations cannot be meaningfully added. For * example, adding negative one day to one month causes * this exception. - * - * + * + * * @see #subtract(Duration) */ public Duration add(final Duration rhs) { Duration lhs = this; BigDecimal[] buf = new BigDecimal[6]; - + buf[0] = sanitize((BigInteger) lhs.getField(DatatypeConstants.YEARS), - lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.YEARS), rhs.getSign())); + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.YEARS), rhs.getSign())); buf[1] = sanitize((BigInteger) lhs.getField(DatatypeConstants.MONTHS), - lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.MONTHS), rhs.getSign())); + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.MONTHS), rhs.getSign())); buf[2] = sanitize((BigInteger) lhs.getField(DatatypeConstants.DAYS), - lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.DAYS), rhs.getSign())); + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.DAYS), rhs.getSign())); buf[3] = sanitize((BigInteger) lhs.getField(DatatypeConstants.HOURS), - lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.HOURS), rhs.getSign())); + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.HOURS), rhs.getSign())); buf[4] = sanitize((BigInteger) lhs.getField(DatatypeConstants.MINUTES), - lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.MINUTES), rhs.getSign())); + lhs.getSign()).add(sanitize((BigInteger) rhs.getField(DatatypeConstants.MINUTES), rhs.getSign())); buf[5] = sanitize((BigDecimal) lhs.getField(DatatypeConstants.SECONDS), - lhs.getSign()).add(sanitize((BigDecimal) rhs.getField(DatatypeConstants.SECONDS), rhs.getSign())); - + lhs.getSign()).add(sanitize((BigDecimal) rhs.getField(DatatypeConstants.SECONDS), rhs.getSign())); + // align sign alignSigns(buf, 0, 2); // Y,M alignSigns(buf, 2, 6); // D,h,m,s - + // make sure that the sign bit is consistent across all 6 fields. int s = 0; for (int i = 0; i < 6; i++) { @@ -1705,28 +1716,28 @@ s = buf[i].signum(); } } - + return new DurationImpl( s >= 0, toBigInteger(sanitize(buf[0], s), - lhs.getField(DatatypeConstants.YEARS) == null && rhs.getField(DatatypeConstants.YEARS) == null), + lhs.getField(DatatypeConstants.YEARS) == null && rhs.getField(DatatypeConstants.YEARS) == null), toBigInteger(sanitize(buf[1], s), - lhs.getField(DatatypeConstants.MONTHS) == null && rhs.getField(DatatypeConstants.MONTHS) == null), + lhs.getField(DatatypeConstants.MONTHS) == null && rhs.getField(DatatypeConstants.MONTHS) == null), toBigInteger(sanitize(buf[2], s), - lhs.getField(DatatypeConstants.DAYS) == null && rhs.getField(DatatypeConstants.DAYS) == null), + lhs.getField(DatatypeConstants.DAYS) == null && rhs.getField(DatatypeConstants.DAYS) == null), toBigInteger(sanitize(buf[3], s), - lhs.getField(DatatypeConstants.HOURS) == null && rhs.getField(DatatypeConstants.HOURS) == null), + lhs.getField(DatatypeConstants.HOURS) == null && rhs.getField(DatatypeConstants.HOURS) == null), toBigInteger(sanitize(buf[4], s), - lhs.getField(DatatypeConstants.MINUTES) == null && rhs.getField(DatatypeConstants.MINUTES) == null), + lhs.getField(DatatypeConstants.MINUTES) == null && rhs.getField(DatatypeConstants.MINUTES) == null), (buf[5].signum() == 0 && lhs.getField(DatatypeConstants.SECONDS) == null && rhs.getField(DatatypeConstants.SECONDS) == null) ? null : sanitize(buf[5], s)); } - + private static void alignSigns(BigDecimal[] buf, int start, int end) { // align sign boolean touched; - + do { // repeat until all the sign bits become consistent touched = false; int s = 0; // sign of the left fields @@ -1755,7 +1766,7 @@ } } while (touched); } - + /** * Compute value*signum where value==null is treated as * value==0. @@ -1773,13 +1784,13 @@ } return new BigDecimal(value.negate()); } - + /** *

Compute value*signum where value==null is treated as value==0

. - * + * * @param value Value to sanitize. * @param signum 0 to sanitize to 0, > 0 to sanitize to value, < 0 to sanitize to negative value. - * + * * @return non-null {@link BigDecimal}. */ static BigDecimal sanitize(BigDecimal value, int signum) { @@ -1791,10 +1802,10 @@ } return value.negate(); } - + /** *

Computes a new duration whose value is this-rhs.

- * + * *

For example:

*
      * "1 day" - "-3 days" = "4 days"
@@ -1803,57 +1814,57 @@
      * "15 hours" - "-3 days" = "3 days and 15 hours"
      * "1 year" - "-1 day" = "1 year and 1 day"
      * 
- * + * *

Since there's no way to meaningfully subtract 1 day from 1 month, - * there are cases where the operation fails in {@link IllegalStateException}.

- * + * there are cases where the operation fails in {@link IllegalStateException}.

+ * *

Formally the computation is defined as follows. * First, we can assume that two {@link Duration}s are both positive * without losing generality. (i.e., * (-X)-Y=-(X+Y), X-(-Y)=X+Y, * (-X)-(-Y)=-(X-Y))

- * + * *

Then two durations are subtracted field by field. * If the sign of any non-zero field F is different from * the sign of the most significant field, * 1 (if F is negative) or -1 (otherwise) * will be borrowed from the next bigger unit of F.

- * + * *

This process is repeated until all the non-zero fields have - * the same sign.

- * + * the same sign.

+ * *

If a borrow occurs in the days field (in other words, if * the computation needs to borrow 1 or -1 month to compensate * days), then the computation fails by throwing an * {@link IllegalStateException}.

- * + * * @param rhs Duration to substract from this Duration. - * + * * @return New Duration created from subtracting rhs from this Duration. - * + * * @throws IllegalStateException * If two durations cannot be meaningfully subtracted. For * example, subtracting one day from one month causes * this exception. - * + * * @throws NullPointerException * If the rhs parameter is null. - * + * * @see #add(Duration) */ public Duration subtract(final Duration rhs) { return add(rhs.negate()); } - + /** * Returns a new {@link Duration} object whose * value is -this. - * + * *

* Since the {@link Duration} class is immutable, this method * doesn't change the value of this object. It simply computes * a new Duration object and returns it. - * + * * @return * always return a non-null valid {@link Duration} object. */ @@ -1867,10 +1878,10 @@ minutes, seconds); } - + /** * Returns the sign of this duration in -1,0, or 1. - * + * * @return * -1 if this duration is negative, 0 if the duration is zero, * and 1 if the duration is postive. @@ -1878,11 +1889,11 @@ public int signum() { return signum; } - - + + /** * Adds this duration to a {@link Calendar} object. - * + * *

* Calls {@link java.util.Calendar#add(int,int)} in the * order of YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, and MILLISECONDS @@ -1889,22 +1900,22 @@ * if those fields are present. Because the {@link Calendar} class * uses int to hold values, there are cases where this method * won't work correctly (for example if values of fields - * exceed the range of int.) + * exceed the range of int.) *

- * + * *

* Also, since this duration class is a Gregorian duration, this * method will not work correctly if the given {@link Calendar} - * object is based on some other calendar systems. + * object is based on some other calendar systems. *

- * + * *

* Any fractional parts of this {@link Duration} object * beyond milliseconds will be simply ignored. For example, if * this duration is "P1.23456S", then 1 is added to SECONDS, - * 234 is added to MILLISECONDS, and the rest will be unused. + * 234 is added to MILLISECONDS, and the rest will be unused. *

- * + * *

* Note that because {@link Calendar#add(int, int)} is using * int, {@link Duration} with values beyond the @@ -1913,7 +1924,7 @@ * {@link XMLGregorianCalendar#add(Duration)} provides the same * basic operation as this method while avoiding * the overflow/underflow issues. - * + * * @param calendar * A calendar object whose value will be modified. * @throws NullPointerException @@ -1934,23 +1945,23 @@ calendar.add(Calendar.MILLISECOND, millisec * signum); } } - + /** * Adds this duration to a {@link Date} object. - * + * *

* The given date is first converted into * a {@link java.util.GregorianCalendar}, then the duration * is added exactly like the {@link #addTo(Calendar)} method. - * + * *

* The updated time instant is then converted back into a * {@link Date} object and used to update the given {@link Date} object. - * + * *

* This somewhat redundant computation is necessary to unambiguously * determine the duration of months and years. - * + * * @param date * A date object whose value will be modified. * @throws NullPointerException @@ -1962,19 +1973,29 @@ this.addTo(cal); date.setTime(getCalendarTimeInMillis(cal)); } - + /** + * Returns time value in milliseconds + * @param cal A calendar object + * @return time value + * + * Diff from Xerces; Use JDK 1.5 feature. + */ + private static long getCalendarTimeInMillis(Calendar cal) { + return cal.getTimeInMillis(); + } + + /** *

Stream Unique Identifier.

- * - *

TODO: Serialization should use the XML string representation as - * the serialization format to ensure future compatibility.

+ * + *

Serialization uses the lexical form returned by toString().

*/ private static final long serialVersionUID = 1L; - + /** * Writes {@link Duration} as a lexical representation * for maximum future compatibility. - * + * * @return * An object that encapsulates the string * returned by this.toString(). @@ -1996,25 +2017,10 @@ } private Object readResolve() throws ObjectStreamException { - // try { return new DurationImpl(lexical); - // } catch( ParseException e ) { - // throw new StreamCorruptedException("unable to parse "+lexical+" as duration"); - // } } private static final long serialVersionUID = 1L; } - /** - * Calls the {@link Calendar#getTimeInMillis} method. - * Prior to JDK1.4, this method was protected and therefore - * cannot be invoked directly. - * - * In future, this should be replaced by - * cal.getTimeInMillis() - */ - private static long getCalendarTimeInMillis(Calendar cal) { - return cal.getTime().getTime(); - } } --- 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) } --- /dev/null Tue Feb 18 09:40:17 2014 +++ new/jdk/test/javax/xml/jaxp/datatype/8033980/CalendarDuration1097Test.java Tue Feb 18 09:40:15 2014 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8033980 + * @summary verify that offset in minutes in getTimeZone is converted correctly + * Note that JDK did not have this bug. + * @run main CalendarDuration1097Test + */ + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + + +/** + * + * @author Joe Wang huizhe.wang@oracle.com + */ +public class CalendarDuration1097Test { + + /** + * main method. + * + * @param args Standard args. + */ + public static void main(String[] args) { + try { + String dateTimeString = "0001-01-01T00:00:00.0000000-05:00"; + DatatypeFactory dtf = DatatypeFactory.newInstance(); + XMLGregorianCalendar cal = dtf.newXMLGregorianCalendar( dateTimeString ); + System.out.println( "Expected: 0001-01-01T00:00:00.0000000-05:00"); + System.out.println( "Actual:" + cal.toString() ); + System.out.println( "toXMLFormat:" + cal.toXMLFormat() ); + String test = cal.toString(); + if (test.indexOf("E-7") > -1) { + throw new RuntimeException("Expected: 0001-01-01T00:00:00.0000000-05:00"); + } + } catch (DatatypeConfigurationException ex) { + throw new RuntimeException(ex.getMessage()); + } + } + +} --- /dev/null Tue Feb 18 09:40:18 2014 +++ new/jdk/test/javax/xml/jaxp/datatype/8033980/CalendarDuration1243Test.java Tue Feb 18 09:40:17 2014 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8033980 + * @summary verify that offset in minutes in getTimeZone is converted correctly + * @run main CalendarDuration1243Test + */ + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; + + +/** + * + * @author Joe Wang huizhe.wang@oracle.com + */ +public class CalendarDuration1243Test { + + /** + * main method. + * + * @param args Standard args. + */ + public static void main(String[] args) { + try { + String dateTimeString = "2006-11-22T00:00:00.0+01:02"; + DatatypeFactory dtf = DatatypeFactory.newInstance(); + XMLGregorianCalendar cal = dtf.newXMLGregorianCalendar( dateTimeString ); + System.out.println( "XMLGregCal:" + cal.toString() ); + System.out.println( "GregCal:" + cal.toGregorianCalendar() ); + String toGCal = cal.toGregorianCalendar().toString(); + if (toGCal.indexOf("GMT+12:00") > -1) { + throw new RuntimeException("Expected GMT+01:02"); + } + } catch (DatatypeConfigurationException ex) { + throw new RuntimeException(ex.getMessage()); + } + } + +} --- /dev/null Tue Feb 18 09:40:19 2014 +++ new/jdk/test/javax/xml/jaxp/datatype/8033980/CalendarDuration1416Test.java Tue Feb 18 09:40:18 2014 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8033980 + * @summary test that invalid durations are caught + * @run main CalendarDuration1416Test + */ + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; + + +/** + * + * @author Joe Wang huizhe.wang@oracle.com + */ +public class CalendarDuration1416Test { + + /** + * main method. + * + * @param args Standard args. + */ + public static void main(String[] args) { + test1416("PT1D1H"); + test1416("PT1D1H30M"); + test1416("PT1D1H30S"); + } + + static void test1416(String d) { + try + { + DatatypeFactory dtf = DatatypeFactory.newInstance(); + dtf.newDuration(d); + throw new Error("no bug for " + d); + } catch (DatatypeConfigurationException ex) { + fail(ex.getMessage()); + } + catch (NullPointerException e) { + fail("NPE bug ! " + d); + + } + catch(IllegalArgumentException e) + { + System.out.println("OK, BUG FIXED for " + d); + } + + } + + static void fail(String errMessage) { + throw new RuntimeException(errMessage); + } +} Binary files /tmp/dYIaWQP and new/jdk/test/javax/xml/jaxp/datatype/8033980/JDK6_Duration.ser differ Binary files /tmp/d5YaGVP and new/jdk/test/javax/xml/jaxp/datatype/8033980/JDK6_XMLGregorianCalendar.ser differ Binary files /tmp/dlfaq0P and new/jdk/test/javax/xml/jaxp/datatype/8033980/JDK7_Duration.ser differ Binary files /tmp/dNzaa5P and new/jdk/test/javax/xml/jaxp/datatype/8033980/JDK7_XMLGregorianCalendar.ser differ Binary files /tmp/dXZaW9P and new/jdk/test/javax/xml/jaxp/datatype/8033980/JDK8_Duration.ser differ Binary files /tmp/dtzaGcQ and new/jdk/test/javax/xml/jaxp/datatype/8033980/JDK8_XMLGregorianCalendar.ser differ Binary files /tmp/d_UaqhQ and new/jdk/test/javax/xml/jaxp/datatype/8033980/JDK9_Duration.ser differ Binary files /tmp/dj_aGmQ and new/jdk/test/javax/xml/jaxp/datatype/8033980/JDK9_XMLGregorianCalendar.ser differ --- /dev/null Tue Feb 18 09:40:31 2014 +++ new/jdk/test/javax/xml/jaxp/datatype/8033980/SerializationTest.java Tue Feb 18 09:40:30 2014 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8033980 + * @summary verify serialization compatibility for XMLGregorianCalendar and Duration + * @run main SerializationTest read + */ + +import java.io.*; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; + +/** + * use "read" to test compatibility + * SerializationTest read + * + * use "write" to create test files + * SerializationTest write javaVersion + * where javaVersion is 6, 7, 8, or 9 + * + * @author huizhe.wang@oracle.com + */ +public class SerializationTest { + + final String FILENAME_CAL = "_XMLGregorianCalendar.ser"; + final String FILENAME_DURATION = "_Duration.ser"; + String filePath; + + { + filePath = System.getProperty("test.src"); + if (filePath == null) { + //current directory + filePath = System.getProperty("user.dir"); + } + filePath += File.separator; + } + final String EXPECTED_CAL = "0001-01-01T00:00:00.0000000-05:00"; + final String EXPECTED_DURATION = "P1Y1M1DT1H1M1S"; + static String[] JDK = {"JDK6", "JDK7", "JDK8", "JDK9"}; + + public static void main(String[] args) { + SerializationTest test = new SerializationTest(); + + if (args[0].equalsIgnoreCase("read")) { + test.testReadCal(); + test.testReadDuration(); + test.report(); + } else { + int ver = Integer.valueOf(args[1]).intValue(); + test.createTestFile(JDK[ver - 6]); + } + + } + + public void testReadCal() { + try { + for (String javaVersion : JDK) { + XMLGregorianCalendar d1 = (XMLGregorianCalendar) fromFile( + javaVersion + FILENAME_CAL); + if (!d1.toString().equalsIgnoreCase(EXPECTED_CAL)) { + fail("Java version: " + javaVersion + + "\nExpected: " + EXPECTED_CAL + + "\nActual: " + d1.toString()); + } else { + success("testReadCal: read " + javaVersion + " serialized file, passed."); + } + } + } catch (ClassNotFoundException ex) { + fail("testReadCal: " + ex.getMessage()); + } catch (IOException ex) { + fail("testReadCal: " + ex.getMessage()); + } + } + + public void testReadDuration() { + try { + for (String javaVersion : JDK) { + Duration d1 = (Duration) fromFile( + javaVersion + FILENAME_DURATION); + if (!d1.toString().equalsIgnoreCase(EXPECTED_DURATION)) { + fail("Java version: " + javaVersion + + "\nExpected: " + EXPECTED_DURATION + + "\nActual: " + d1.toString()); + } else { + success("testReadDuration: read " + javaVersion + " serialized file, passed."); + } + } + } catch (ClassNotFoundException ex) { + fail("testReadDuration: " + ex.getMessage()); + } catch (IOException ex) { + fail("testReadDuration: " + ex.getMessage()); + } + } + + /** + * Create test files + * + * @param javaVersion JDK version + */ + public void createTestFile(String javaVersion) { + try { + DatatypeFactory dtf = DatatypeFactory.newInstance(); + XMLGregorianCalendar c = dtf.newXMLGregorianCalendar(EXPECTED_CAL); + Duration d = dtf.newDuration(EXPECTED_DURATION); + toFile((Serializable) c, filePath + javaVersion + FILENAME_CAL); + toFile((Serializable) d, filePath + javaVersion + FILENAME_DURATION); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + /** + * Read the object from a file. + */ + private static Object fromFile(String filePath) throws IOException, + ClassNotFoundException { + InputStream streamIn = SerializationTest.class.getResourceAsStream( + filePath); + ObjectInputStream objectinputstream = new ObjectInputStream(streamIn); + Object o = objectinputstream.readObject(); + return o; + } + + /** + * Write the object to a file. + */ + private static void toFile(Serializable o, String filePath) throws IOException { +System.out.println("filePath=" + filePath); + FileOutputStream fout = new FileOutputStream(filePath, true); + ObjectOutputStream oos = new ObjectOutputStream(fout); + oos.writeObject(o); + oos.close(); + } + + static String errMessage; + int passed = 0, failed = 0; + + void fail(String errMsg) { + if (errMessage == null) { + errMessage = errMsg; + } else { + errMessage = errMessage + "\n" + errMsg; + } + failed++; + } + + void success(String msg) { + passed++; + System.out.println(msg); + } + + public void report() { + + System.out.println("\nNumber of tests passed: " + passed); + System.out.println("Number of tests failed: " + failed + "\n"); + + if (errMessage != null) { + throw new RuntimeException(errMessage); + } + } +}