1 /*
   2  * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.xml.datatype;
  27 
  28 import java.math.BigDecimal;
  29 import java.math.BigInteger;
  30 import java.util.GregorianCalendar;
  31 import java.util.regex.Matcher;
  32 import java.util.regex.Pattern;
  33 import com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl;
  34 
  35 /**
  36  * Factory that creates new {@code javax.xml.datatype} {@code Object}s that map XML to/from Java {@code Object}s.
  37  * <p>
  38  * A new instance of the {@code DatatypeFactory} is created through the {@link #newInstance()} method
  39  * that uses the following implementation resolution mechanisms to determine an implementation:
  40  * <ol>
  41  *    <li>
  42  *      If the system property specified by {@link #DATATYPEFACTORY_PROPERTY}, "{@code javax.xml.datatype.DatatypeFactory}",
  43  *      exists, a class with the name of the property value is instantiated.
  44  *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
  45  *    </li>
  46  *    <li>
  47  *      <p>
  48  *      Use the configuration file "jaxp.properties". The file is in standard
  49  *      {@link java.util.Properties} format and typically located in the
  50  *      {@code conf} directory of the Java installation. It contains the fully qualified
  51  *      name of the implementation class with the key being the system property
  52  *      defined above.
  53  *      <p>
  54  *      The jaxp.properties file is read only once by the JAXP implementation
  55  *      and its values are then cached for future use.  If the file does not exist
  56  *      when the first attempt is made to read from it, no further attempts are
  57  *      made to check for its existence.  It is not possible to change the value
  58  *      of any property in jaxp.properties after it has been read for the first time.
  59  *    </li>
  60  *    <li>
  61  *     <p>
  62  *     Use the service-provider loading facility, defined by the {@link java.util.ServiceLoader} class, to attempt
  63  *     to locate and load an implementation of the service using the {@linkplain
  64  *     java.util.ServiceLoader#load(java.lang.Class) default loading mechanism}:
  65  *     the service-provider loading facility will use the {@linkplain
  66  *     java.lang.Thread#getContextClassLoader() current thread's context class loader}
  67  *     to attempt to load the service. If the context class
  68  *     loader is null, the {@linkplain
  69  *     ClassLoader#getSystemClassLoader() system class loader} will be used.
  70  *     <p>
  71  *     In case of {@link java.util.ServiceConfigurationError service
  72  *     configuration error}, a {@link javax.xml.datatype.DatatypeConfigurationException}
  73  *     will be thrown.
  74  *    </li>
  75  *    <li>
  76  *      <p>
  77  *      The final mechanism is to attempt to instantiate the {@code Class} specified by
  78  *      {@link #DATATYPEFACTORY_IMPLEMENTATION_CLASS}.
  79  *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
  80  *    </li>
  81  * </ol>
  82  *
  83  * @author <a href="mailto:Joseph.Fialli@Sun.COM">Joseph Fialli</a>
  84  * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
  85  * @author <a href="mailto:Neeraj.Bajaj@sun.com">Neeraj Bajaj</a>
  86  *
  87  * @since 1.5
  88  */
  89 public abstract class DatatypeFactory {
  90 
  91     /**
  92      * Default property name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.
  93      *
  94      * <p>Default value is {@code javax.xml.datatype.DatatypeFactory}.
  95      */
  96     public static final String DATATYPEFACTORY_PROPERTY =
  97             // We use a String constant here, rather than calling
  98             // DatatypeFactory.class.getName() - in order to make javadoc
  99             // generate a See Also: Constant Field Value link.
 100             "javax.xml.datatype.DatatypeFactory";
 101 
 102     /**
 103      * Default implementation class name as defined in
 104      * <em>JSR 206: Java(TM) API for XML Processing (JAXP) 1.3</em>.
 105      *
 106      * <p>Implementers should specify the name of an appropriate class
 107      * to be instantiated if no other implementation resolution mechanism
 108      * succeeds.
 109      *
 110      * <p>Users should not refer to this field; it is intended only to
 111      * document a factory implementation detail.
 112      */
 113     public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS =
 114         // We use new String() here to prevent javadoc from generating
 115         // a See Also: Constant Field Value link.
 116         new String("com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl");
 117 
 118     /**
 119      * http://www.w3.org/TR/xpath-datamodel/#xdtschema defines two regexps
 120      * to constrain the value space of dayTimeDuration ([^YM]*[DT].*)
 121      * and yearMonthDuration ([^DT]*). Note that these expressions rely on
 122      * the fact that the value must be an xs:Duration, they simply exclude
 123      * some Durations.
 124      */
 125     private static final Pattern XDTSCHEMA_YMD =
 126         Pattern.compile("[^DT]*");
 127 
 128     private static final Pattern XDTSCHEMA_DTD =
 129         Pattern.compile("[^YM]*[DT].*");
 130 
 131     /**
 132      * Protected constructor to prevent instantiation outside of package.
 133      *
 134      * <p>Use {@link #newInstance()} to create a {@code DatatypeFactory}.
 135      */
 136     protected DatatypeFactory() {
 137     }
 138 
 139     /**
 140      * Creates a new instance of the {@code DatatypeFactory} {@linkplain
 141      * #DATATYPEFACTORY_IMPLEMENTATION_CLASS builtin system-default
 142      * implementation}.
 143      *
 144      * @return A new instance of the {@code DatatypeFactory} builtin
 145      *         system-default implementation.
 146      *
 147      * @since 9
 148      */
 149     public static DatatypeFactory newDefaultInstance() {
 150         return new DatatypeFactoryImpl();
 151     }
 152 
 153     /**
 154      * Obtain a new instance of a {@code DatatypeFactory}.
 155      *
 156      * <p>The implementation resolution mechanisms are <a href="#DatatypeFactory.newInstance">defined</a> in this
 157      * {@code Class}'s documentation.
 158      *
 159      * @return New instance of a {@code DatatypeFactory}
 160      *
 161      * @throws DatatypeConfigurationException If the implementation is not
 162      *   available or cannot be instantiated.
 163      *
 164      * @see #newInstance(String factoryClassName, ClassLoader classLoader)
 165      */
 166     public static DatatypeFactory newInstance()
 167             throws DatatypeConfigurationException {
 168 
 169             return FactoryFinder.find(
 170                     /* The default property name according to the JAXP spec */
 171                     DatatypeFactory.class,
 172                     /* The fallback implementation class name */
 173                     DATATYPEFACTORY_IMPLEMENTATION_CLASS);
 174     }
 175 
 176     /**
 177      * Obtain a new instance of a {@code DatatypeFactory} from class name.
 178      * This function is useful when there are multiple providers in the classpath.
 179      * It gives more control to the application as it can specify which provider
 180      * should be loaded.
 181      *
 182      * <p>Once an application has obtained a reference to a {@code DatatypeFactory}
 183      * it can use the factory to configure and obtain datatype instances.
 184      *
 185      *
 186      * <h2>Tip for Trouble-shooting</h2>
 187      * <p>Setting the {@code jaxp.debug} system property will cause
 188      * this method to print a lot of debug messages
 189      * to {@code System.err} about what it is doing and where it is looking at.
 190      *
 191      * <p> If you have problems try:
 192      * <pre>
 193      * java -Djaxp.debug=1 YourProgram ....
 194      * </pre>
 195      *
 196      * @param factoryClassName fully qualified factory class name that provides implementation of {@code javax.xml.datatype.DatatypeFactory}.
 197      *
 198      * @param classLoader {@code ClassLoader} used to load the factory class. If {@code null}
 199      *                     current {@code Thread}'s context classLoader is used to load the factory class.
 200      *
 201      * @return New instance of a {@code DatatypeFactory}
 202      *
 203      * @throws DatatypeConfigurationException if {@code factoryClassName} is {@code null}, or
 204      *                                   the factory class cannot be loaded, instantiated.
 205      *
 206      * @see #newInstance()
 207      *
 208      * @since 1.6
 209      */
 210     public static DatatypeFactory newInstance(String factoryClassName, ClassLoader classLoader)
 211         throws DatatypeConfigurationException {
 212         return FactoryFinder.newInstance(DatatypeFactory.class,
 213                     factoryClassName, classLoader, false);
 214      }
 215 
 216     /**
 217      * Obtain a new instance of a {@code Duration}
 218      * specifying the {@code Duration} as its string representation, "PnYnMnDTnHnMnS",
 219      * as defined in XML Schema 1.0 section 3.2.6.1.
 220      *
 221      * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines {@code duration} as:
 222      * <blockquote>
 223      * duration represents a duration of time.
 224      * The value space of duration is a six-dimensional space where the coordinates designate the
 225      * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
 226      * These components are ordered in their significance by their order of appearance i.e. as
 227      * year, month, day, hour, minute, and second.
 228      * </blockquote>
 229      * <p>All six values are set and available from the created {@link Duration}
 230      *
 231      * <p>The XML Schema specification states that values can be of an arbitrary size.
 232      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
 233      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
 234      * if implementation capacities are exceeded.
 235      *
 236      * @param lexicalRepresentation {@code String} representation of a {@code Duration}.
 237      *
 238      * @return New {@code Duration} created from parsing the {@code lexicalRepresentation}.
 239      *
 240      * @throws IllegalArgumentException If {@code lexicalRepresentation} is not a valid representation of a {@code Duration}.
 241      * @throws UnsupportedOperationException If implementation cannot support requested values.
 242      * @throws NullPointerException if {@code lexicalRepresentation} is {@code null}.
 243      */
 244     public abstract Duration newDuration(final String lexicalRepresentation);
 245 
 246     /**
 247      * Obtain a new instance of a {@code Duration}
 248      * specifying the {@code Duration} as milliseconds.
 249      *
 250      * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines {@code duration} as:
 251      * <blockquote>
 252      * duration represents a duration of time.
 253      * The value space of duration is a six-dimensional space where the coordinates designate the
 254      * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
 255      * These components are ordered in their significance by their order of appearance i.e. as
 256      * year, month, day, hour, minute, and second.
 257      * </blockquote>
 258      * <p>All six values are set by computing their values from the specified milliseconds
 259      * and are available using the {@code get} methods of  the created {@link Duration}.
 260      * The values conform to and are defined by:
 261      * <ul>
 262      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
 263      *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
 264      *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
 265      *   </li>
 266      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
 267      * </ul>
 268      *
 269      * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
 270      * {@link java.util.Calendar#YEAR} = 1970,
 271      * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
 272      * {@link java.util.Calendar#DATE} = 1, etc.
 273      * This is important as there are variations in the Gregorian Calendar,
 274      * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
 275      * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced.
 276      *
 277      * @param durationInMilliSeconds Duration in milliseconds to create.
 278      *
 279      * @return New {@code Duration} representing {@code durationInMilliSeconds}.
 280      */
 281     public abstract Duration newDuration(final long durationInMilliSeconds);
 282 
 283     /**
 284      * Obtain a new instance of a {@code Duration}
 285      * specifying the {@code Duration} as isPositive, years, months, days, hours, minutes, seconds.
 286      *
 287      * <p>The XML Schema specification states that values can be of an arbitrary size.
 288      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
 289      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
 290      * if implementation capacities are exceeded.
 291      *
 292      * <p>A {@code null} value indicates that field is not set.
 293      *
 294      * @param isPositive Set to {@code false} to create a negative duration. When the length
 295      *   of the duration is zero, this parameter will be ignored.
 296      * @param years of this {@code Duration}
 297      * @param months of this {@code Duration}
 298      * @param days of this {@code Duration}
 299      * @param hours of this {@code Duration}
 300      * @param minutes of this {@code Duration}
 301      * @param seconds of this {@code Duration}
 302      *
 303      * @return New {@code Duration} created from the specified values.
 304      *
 305      * @throws IllegalArgumentException If the values are not a valid representation of a
 306      * {@code Duration}: if all the fields (years, months, ...) are null or
 307      * if any of the fields is negative.
 308      * @throws UnsupportedOperationException If implementation cannot support requested values.
 309      */
 310     public abstract Duration newDuration(
 311             final boolean isPositive,
 312             final BigInteger years,
 313             final BigInteger months,
 314             final BigInteger days,
 315             final BigInteger hours,
 316             final BigInteger minutes,
 317             final BigDecimal seconds);
 318 
 319     /**
 320      * Obtain a new instance of a {@code Duration}
 321      * specifying the {@code Duration} as isPositive, years, months, days, hours, minutes, seconds.
 322      *
 323      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
 324      *
 325      * @param isPositive Set to {@code false} to create a negative duration. When the length
 326      *   of the duration is zero, this parameter will be ignored.
 327      * @param years of this {@code Duration}
 328      * @param months of this {@code Duration}
 329      * @param days of this {@code Duration}
 330      * @param hours of this {@code Duration}
 331      * @param minutes of this {@code Duration}
 332      * @param seconds of this {@code Duration}
 333      *
 334      * @return New {@code Duration} created from the specified values.
 335      *
 336      * @throws IllegalArgumentException If the values are not a valid representation of a
 337      * {@code Duration}: if any of the fields is negative.
 338      *
 339      * @see #newDuration(
 340      *   boolean isPositive,
 341      *   BigInteger years,
 342      *   BigInteger months,
 343      *   BigInteger days,
 344      *   BigInteger hours,
 345      *   BigInteger minutes,
 346      *   BigDecimal seconds)
 347      */
 348     public Duration newDuration(
 349             final boolean isPositive,
 350             final int years,
 351             final int months,
 352             final int days,
 353             final int hours,
 354             final int minutes,
 355             final int seconds) {
 356 
 357             // years may not be set
 358             BigInteger realYears = (years != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) years) : null;
 359 
 360             // months may not be set
 361             BigInteger realMonths = (months != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) months) : null;
 362 
 363             // days may not be set
 364             BigInteger realDays = (days != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) days) : null;
 365 
 366             // hours may not be set
 367             BigInteger realHours = (hours != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) hours) : null;
 368 
 369             // minutes may not be set
 370             BigInteger realMinutes = (minutes != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) minutes) : null;
 371 
 372             // seconds may not be set
 373             BigDecimal realSeconds = (seconds != DatatypeConstants.FIELD_UNDEFINED) ? BigDecimal.valueOf((long) seconds) : null;
 374 
 375                     return newDuration(
 376                             isPositive,
 377                             realYears,
 378                             realMonths,
 379                             realDays,
 380                             realHours,
 381                             realMinutes,
 382                             realSeconds
 383                     );
 384             }
 385 
 386     /**
 387      * Create a {@code Duration} of type {@code xdt:dayTimeDuration}
 388      * by parsing its {@code String} representation,
 389      * "<em>PnDTnHnMnS</em>", <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
 390      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.
 391      *
 392      * <p>The datatype {@code xdt:dayTimeDuration} is a subtype of {@code xs:duration}
 393      * whose lexical representation contains only day, hour, minute, and second components.
 394      * This datatype resides in the namespace {@code http://www.w3.org/2003/11/xpath-datatypes}.
 395      *
 396      * <p>All four values are set and available from the created {@link Duration}
 397      *
 398      * <p>The XML Schema specification states that values can be of an arbitrary size.
 399      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
 400      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
 401      * if implementation capacities are exceeded.
 402      *
 403      * @param lexicalRepresentation Lexical representation of a duration.
 404      *
 405      * @return New {@code Duration} created using the specified {@code lexicalRepresentation}.
 406      *
 407      * @throws IllegalArgumentException If {@code lexicalRepresentation} is
 408      *         not a valid representation of a {@code Duration} expressed only in terms of days and time.
 409      * @throws UnsupportedOperationException If implementation cannot support requested values.
 410      * @throws NullPointerException If {@code lexicalRepresentation} is {@code null}.
 411      */
 412     public Duration newDurationDayTime(final String lexicalRepresentation) {
 413         // lexicalRepresentation must be non-null
 414         if (lexicalRepresentation == null) {
 415             throw new NullPointerException(
 416                 "Trying to create an xdt:dayTimeDuration with an invalid"
 417                 + " lexical representation of \"null\"");
 418         }
 419 
 420         // test lexicalRepresentation against spec regex
 421         Matcher matcher = XDTSCHEMA_DTD.matcher(lexicalRepresentation);
 422         if (!matcher.matches()) {
 423             throw new IllegalArgumentException(
 424                 "Trying to create an xdt:dayTimeDuration with an invalid"
 425                 + " lexical representation of \"" + lexicalRepresentation
 426                 + "\", data model requires years and months only.");
 427         }
 428 
 429         return newDuration(lexicalRepresentation);
 430     }
 431 
 432     /**
 433      * Create a {@code Duration} of type {@code xdt:dayTimeDuration}
 434      * using the specified milliseconds as defined in
 435      * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
 436      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.
 437      *
 438      * <p>The datatype {@code xdt:dayTimeDuration} is a subtype of {@code xs:duration}
 439      * whose lexical representation contains only day, hour, minute, and second components.
 440      * This datatype resides in the namespace {@code http://www.w3.org/2003/11/xpath-datatypes}.
 441      *
 442      * <p>All four values are set by computing their values from the specified milliseconds
 443      * and are available using the {@code get} methods of  the created {@link Duration}.
 444      * The values conform to and are defined by:
 445      * <ul>
 446      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
 447      *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
 448      *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
 449      *   </li>
 450      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
 451      * </ul>
 452      *
 453      * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
 454      * {@link java.util.Calendar#YEAR} = 1970,
 455      * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
 456      * {@link java.util.Calendar#DATE} = 1, etc.
 457      * This is important as there are variations in the Gregorian Calendar,
 458      * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
 459      * so the result of {@link Duration#getDays()} can be influenced.
 460      *
 461      * <p>Any remaining milliseconds after determining the day, hour, minute and second are discarded.
 462      *
 463      * @param durationInMilliseconds Milliseconds of {@code Duration} to create.
 464      *
 465      * @return New {@code Duration} created with the specified {@code durationInMilliseconds}.
 466      *
 467      * @see <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
 468      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>
 469      */
 470     public Duration newDurationDayTime(final long durationInMilliseconds) {
 471 
 472             return newDuration(durationInMilliseconds);
 473     }
 474 
 475     /**
 476      * Create a {@code Duration} of type {@code xdt:dayTimeDuration} using the specified
 477      * {@code day}, {@code hour}, {@code minute} and {@code second} as defined in
 478      * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
 479      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.
 480      *
 481      * <p>The datatype {@code xdt:dayTimeDuration} is a subtype of {@code xs:duration}
 482      * whose lexical representation contains only day, hour, minute, and second components.
 483      * This datatype resides in the namespace {@code http://www.w3.org/2003/11/xpath-datatypes}.
 484      *
 485      * <p>The XML Schema specification states that values can be of an arbitrary size.
 486      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
 487      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
 488      * if implementation capacities are exceeded.
 489      *
 490      * <p>A {@code null} value indicates that field is not set.
 491      *
 492      * @param isPositive Set to {@code false} to create a negative duration. When the length
 493      *   of the duration is zero, this parameter will be ignored.
 494      * @param day Day of {@code Duration}.
 495      * @param hour Hour of {@code Duration}.
 496      * @param minute Minute of {@code Duration}.
 497      * @param second Second of {@code Duration}.
 498      *
 499      * @return New {@code Duration} created with the specified {@code day}, {@code hour}, {@code minute}
 500      * and {@code second}.
 501      *
 502      * @throws IllegalArgumentException If the values are not a valid representation of a
 503      * {@code Duration}: if all the fields (day, hour, ...) are null or
 504      * if any of the fields is negative.
 505      * @throws UnsupportedOperationException If implementation cannot support requested values.
 506      */
 507     public Duration newDurationDayTime(
 508             final boolean isPositive,
 509             final BigInteger day,
 510             final BigInteger hour,
 511             final BigInteger minute,
 512             final BigInteger second) {
 513 
 514             return newDuration(
 515                     isPositive,
 516                     null,  // years
 517                     null, // months
 518                     day,
 519                     hour,
 520                     minute,
 521                     (second != null)? new BigDecimal(second):null
 522             );
 523     }
 524 
 525     /**
 526      * Create a {@code Duration} of type {@code xdt:dayTimeDuration} using the specified
 527      * {@code day}, {@code hour}, {@code minute} and {@code second} as defined in
 528      * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration">
 529      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.
 530      *
 531      * <p>The datatype {@code xdt:dayTimeDuration} is a subtype of {@code xs:duration}
 532      * whose lexical representation contains only day, hour, minute, and second components.
 533      * This datatype resides in the namespace {@code http://www.w3.org/2003/11/xpath-datatypes}.
 534      *
 535      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
 536      *
 537      * @param isPositive Set to {@code false} to create a negative duration. When the length
 538      *   of the duration is zero, this parameter will be ignored.
 539      * @param day Day of {@code Duration}.
 540      * @param hour Hour of {@code Duration}.
 541      * @param minute Minute of {@code Duration}.
 542      * @param second Second of {@code Duration}.
 543      *
 544      * @return New {@code Duration} created with the specified {@code day}, {@code hour}, {@code minute}
 545      * and {@code second}.
 546      *
 547      * @throws IllegalArgumentException If the values are not a valid representation of a
 548      * {@code Duration}: if any of the fields (day, hour, ...) is negative.
 549      */
 550     public Duration newDurationDayTime(
 551             final boolean isPositive,
 552             final int day,
 553             final int hour,
 554             final int minute,
 555             final int second) {
 556 
 557                     return newDurationDayTime(
 558                             isPositive,
 559                             BigInteger.valueOf((long) day),
 560                             BigInteger.valueOf((long) hour),
 561                             BigInteger.valueOf((long) minute),
 562                             BigInteger.valueOf((long) second)
 563                             );
 564             }
 565 
 566     /**
 567      * Create a {@code Duration} of type {@code xdt:yearMonthDuration}
 568      * by parsing its {@code String} representation,
 569      * "<em>PnYnM</em>", <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
 570      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.
 571      *
 572      * <p>The datatype {@code xdt:yearMonthDuration} is a subtype of {@code xs:duration}
 573      * whose lexical representation contains only year and month components.
 574      * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.
 575      *
 576      * <p>Both values are set and available from the created {@link Duration}
 577      *
 578      * <p>The XML Schema specification states that values can be of an arbitrary size.
 579      * Implementations may chose not to or be incapable of supporting
 580      * arbitrarily large and/or small values. An {@link UnsupportedOperationException}
 581      * will be thrown with a message indicating implementation limits
 582      * if implementation capacities are exceeded.
 583      *
 584      * @param lexicalRepresentation Lexical representation of a duration.
 585      *
 586      * @return New {@code Duration} created using the specified {@code lexicalRepresentation}.
 587      *
 588      * @throws IllegalArgumentException If {@code lexicalRepresentation} is not a valid representation of a {@code Duration} expressed only in terms of years and months.
 589      * @throws UnsupportedOperationException If implementation cannot support requested values.
 590      * @throws NullPointerException If {@code lexicalRepresentation} is {@code null}.
 591      */
 592     public Duration newDurationYearMonth(
 593             final String lexicalRepresentation) {
 594 
 595         // lexicalRepresentation must be non-null
 596         if (lexicalRepresentation == null) {
 597             throw new NullPointerException(
 598                     "Trying to create an xdt:yearMonthDuration with an invalid"
 599                     + " lexical representation of \"null\"");
 600         }
 601 
 602         // test lexicalRepresentation against spec regex
 603         Matcher matcher = XDTSCHEMA_YMD.matcher(lexicalRepresentation);
 604         if (!matcher.matches()) {
 605             throw new IllegalArgumentException(
 606                     "Trying to create an xdt:yearMonthDuration with an invalid"
 607                     + " lexical representation of \"" + lexicalRepresentation
 608                     + "\", data model requires days and times only.");
 609         }
 610 
 611         return newDuration(lexicalRepresentation);
 612     }
 613 
 614     /**
 615      * Create a {@code Duration} of type {@code xdt:yearMonthDuration}
 616      * using the specified milliseconds as defined in
 617      * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
 618      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.
 619      *
 620      * <p>The datatype {@code xdt:yearMonthDuration} is a subtype of {@code xs:duration}
 621      * whose lexical representation contains only year and month components.
 622      * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.
 623      *
 624      * <p>Both values are set by computing their values from the specified milliseconds
 625      * and are available using the {@code get} methods of  the created {@link Duration}.
 626      * The values conform to and are defined by:
 627      * <ul>
 628      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
 629      *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
 630      *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
 631      *   </li>
 632      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
 633      * </ul>
 634      *
 635      * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
 636      * {@link java.util.Calendar#YEAR} = 1970,
 637      * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
 638      * {@link java.util.Calendar#DATE} = 1, etc.
 639      * This is important as there are variations in the Gregorian Calendar,
 640      * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
 641      * so the result of {@link Duration#getMonths()} can be influenced.
 642      *
 643      * <p>Any remaining milliseconds after determining the year and month are discarded.
 644      *
 645      * @param durationInMilliseconds Milliseconds of {@code Duration} to create.
 646      *
 647      * @return New {@code Duration} created using the specified {@code durationInMilliseconds}.
 648      */
 649     public Duration newDurationYearMonth(
 650             final long durationInMilliseconds) {
 651 
 652         // create a Duration that only has sign, year & month
 653         // Duration is immutable, so need to create a new Duration
 654         // implementations may override this method in a more efficient way
 655         Duration fullDuration = newDuration(durationInMilliseconds);
 656         boolean isPositive = (fullDuration.getSign() == -1) ? false : true;
 657         BigInteger years =
 658             (BigInteger) fullDuration.getField(DatatypeConstants.YEARS);
 659         if (years == null) { years = BigInteger.ZERO; }
 660         BigInteger months =
 661             (BigInteger) fullDuration.getField(DatatypeConstants.MONTHS);
 662         if (months == null) { months = BigInteger.ZERO; }
 663 
 664         return newDurationYearMonth(isPositive, years, months);
 665     }
 666 
 667     /**
 668      * Create a {@code Duration} of type {@code xdt:yearMonthDuration} using the specified
 669      * {@code year} and {@code month} as defined in
 670      * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
 671      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.
 672      *
 673      * <p>The XML Schema specification states that values can be of an arbitrary size.
 674      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
 675      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
 676      * if implementation capacities are exceeded.
 677      *
 678      * <p>A {@code null} value indicates that field is not set.
 679      *
 680      * @param isPositive Set to {@code false} to create a negative duration. When the length
 681      *   of the duration is zero, this parameter will be ignored.
 682      * @param year Year of {@code Duration}.
 683      * @param month Month of {@code Duration}.
 684      *
 685      * @return New {@code Duration} created using the specified {@code year} and {@code month}.
 686      *
 687      * @throws IllegalArgumentException If the values are not a valid representation of a
 688      * {@code Duration}: if all of the fields (year, month) are null or
 689      * if any of the fields is negative.
 690      * @throws UnsupportedOperationException If implementation cannot support requested values.
 691      */
 692     public Duration newDurationYearMonth(
 693             final boolean isPositive,
 694             final BigInteger year,
 695             final BigInteger month) {
 696 
 697             return newDuration(
 698                     isPositive,
 699                     year,
 700                     month,
 701                     null, // days
 702                     null, // hours
 703                     null, // minutes
 704                     null  // seconds
 705             );
 706     }
 707 
 708     /**
 709      * Create a {@code Duration} of type {@code xdt:yearMonthDuration} using the specified
 710      * {@code year} and {@code month} as defined in
 711      * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
 712      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.
 713      *
 714      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
 715      *
 716      * @param isPositive Set to {@code false} to create a negative duration. When the length
 717      *   of the duration is zero, this parameter will be ignored.
 718      * @param year Year of {@code Duration}.
 719      * @param month Month of {@code Duration}.
 720      *
 721      * @return New {@code Duration} created using the specified {@code year} and {@code month}.
 722      *
 723      * @throws IllegalArgumentException If the values are not a valid representation of a
 724      * {@code Duration}: if any of the fields (year, month) is negative.
 725      */
 726     public Duration newDurationYearMonth(
 727             final boolean isPositive,
 728             final int year,
 729             final int month) {
 730 
 731             return newDurationYearMonth(
 732                     isPositive,
 733                     BigInteger.valueOf((long) year),
 734                     BigInteger.valueOf((long) month));
 735             }
 736 
 737     /**
 738      * Create a new instance of an {@code XMLGregorianCalendar}.
 739      *
 740      * <p>All date/time datatype fields set to {@link DatatypeConstants#FIELD_UNDEFINED} or null.
 741      *
 742      * @return New {@code XMLGregorianCalendar} with all date/time datatype fields set to
 743      *   {@link DatatypeConstants#FIELD_UNDEFINED} or null.
 744      */
 745     public abstract XMLGregorianCalendar newXMLGregorianCalendar();
 746 
 747     /**
 748      * Create a new XMLGregorianCalendar by parsing the String as a lexical representation.
 749      *
 750      * <p>Parsing the lexical string representation is defined in
 751      * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
 752      * <em>Lexical Representation</em>.</a>
 753      *
 754      * <p>The string representation may not have any leading and trailing whitespaces.
 755      *
 756      * <p>The parsing is done field by field so that
 757      * the following holds for any lexically correct String x:
 758      * <pre>
 759      * newXMLGregorianCalendar(x).toXMLFormat().equals(x)
 760      * </pre>
 761      * <p>Except for the noted lexical/canonical representation mismatches
 762      * listed in <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-45">
 763      * XML Schema 1.0 errata, Section 3.2.7.2</a>.
 764      *
 765      * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes.
 766      *
 767      * @return {@code XMLGregorianCalendar} created from the {@code lexicalRepresentation}.
 768      *
 769      * @throws IllegalArgumentException If the {@code lexicalRepresentation} is not a valid {@code XMLGregorianCalendar}.
 770      * @throws NullPointerException If {@code lexicalRepresentation} is {@code null}.
 771      */
 772     public abstract XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation);
 773 
 774     /**
 775      * Create an {@code XMLGregorianCalendar} from a {@link GregorianCalendar}.
 776      *
 777      * <table border="2" rules="all" cellpadding="2">
 778      *   <thead>
 779      *     <tr>
 780      *       <th align="center" colspan="2">
 781      *          Field by Field Conversion from
 782      *          {@link GregorianCalendar} to an {@link XMLGregorianCalendar}
 783      *       </th>
 784      *     </tr>
 785      *     <tr>
 786      *        <th>{@code java.util.GregorianCalendar} field</th>
 787      *        <th>{@code javax.xml.datatype.XMLGregorianCalendar} field</th>
 788      *     </tr>
 789      *   </thead>
 790      *   <tbody>
 791      *     <tr>
 792      *       <td>{@code ERA == GregorianCalendar.BC ? -YEAR : YEAR}</td>
 793      *       <td>{@link XMLGregorianCalendar#setYear(int year)}</td>
 794      *     </tr>
 795      *     <tr>
 796      *       <td>{@code MONTH + 1}</td>
 797      *       <td>{@link XMLGregorianCalendar#setMonth(int month)}</td>
 798      *     </tr>
 799      *     <tr>
 800      *       <td>{@code DAY_OF_MONTH}</td>
 801      *       <td>{@link XMLGregorianCalendar#setDay(int day)}</td>
 802      *     </tr>
 803      *     <tr>
 804      *       <td>{@code HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND}</td>
 805      *       <td>{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}</td>
 806      *     </tr>
 807      *     <tr>
 808      *       <td>
 809      *         {@code (ZONE_OFFSET + DST_OFFSET) / (60*1000)}<br>
 810      *         <em>(in minutes)</em>
 811      *       </td>
 812      *       <td>{@link XMLGregorianCalendar#setTimezone(int offset)}<sup><em>*</em></sup>
 813      *       </td>
 814      *     </tr>
 815      *   </tbody>
 816      * </table>
 817      * <p><em>*</em>conversion loss of information. It is not possible to represent
 818      * a {@code java.util.GregorianCalendar} daylight savings timezone id in the
 819      * XML Schema 1.0 date/time datatype representation.
 820      *
 821      * <p>To compute the return value's {@code TimeZone} field,
 822      * <ul>
 823      * <li>when {@code this.getTimezone() != FIELD_UNDEFINED},
 824      * create a {@code java.util.TimeZone} with a custom timezone id
 825      * using the {@code this.getTimezone()}.</li>
 826      * <li>else use the {@code GregorianCalendar} default timezone value
 827      * for the host is defined as specified by
 828      * {@code java.util.TimeZone.getDefault()}.</li>
 829      * </ul>
 830      *
 831      * @param cal {@code java.util.GregorianCalendar} used to create {@code XMLGregorianCalendar}
 832      *
 833      * @return {@code XMLGregorianCalendar} created from {@code java.util.GregorianCalendar}
 834      *
 835      * @throws NullPointerException If {@code cal} is {@code null}.
 836      */
 837     public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal);
 838 
 839     /**
 840      * Constructor allowing for complete value spaces allowed by
 841      * W3C XML Schema 1.0 recommendation for xsd:dateTime and related
 842      * builtin datatypes. Note that {@code year} parameter supports
 843      * arbitrarily large numbers and fractionalSecond has infinite
 844      * precision.
 845      *
 846      * <p>A {@code null} value indicates that field is not set.
 847      *
 848      * @param year of {@code XMLGregorianCalendar} to be created.
 849      * @param month of {@code XMLGregorianCalendar} to be created.
 850      * @param day of {@code XMLGregorianCalendar} to be created.
 851      * @param hour of {@code XMLGregorianCalendar} to be created.
 852      * @param minute of {@code XMLGregorianCalendar} to be created.
 853      * @param second of {@code XMLGregorianCalendar} to be created.
 854      * @param fractionalSecond of {@code XMLGregorianCalendar} to be created.
 855      * @param timezone of {@code XMLGregorianCalendar} to be created.
 856      *
 857      * @return {@code XMLGregorianCalendar} created from specified values.
 858      *
 859      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
 860      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
 861      *   or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance
 862      *   as determined by {@link XMLGregorianCalendar#isValid()}.
 863      */
 864     public abstract XMLGregorianCalendar newXMLGregorianCalendar(
 865             final BigInteger year,
 866             final int month,
 867             final int day,
 868             final int hour,
 869             final int minute,
 870             final int second,
 871             final BigDecimal fractionalSecond,
 872             final int timezone);
 873 
 874     /**
 875      * Constructor of value spaces that a
 876      * {@code java.util.GregorianCalendar} instance would need to convert to an
 877      * {@code XMLGregorianCalendar} instance.
 878      *
 879      * <p>{@code XMLGregorianCalendar eon} and
 880      * {@code fractionalSecond} are set to {@code null}
 881      *
 882      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
 883      *
 884      * @param year of {@code XMLGregorianCalendar} to be created.
 885      * @param month of {@code XMLGregorianCalendar} to be created.
 886      * @param day of {@code XMLGregorianCalendar} to be created.
 887      * @param hour of {@code XMLGregorianCalendar} to be created.
 888      * @param minute of {@code XMLGregorianCalendar} to be created.
 889      * @param second of {@code XMLGregorianCalendar} to be created.
 890      * @param millisecond of {@code XMLGregorianCalendar} to be created.
 891      * @param timezone of {@code XMLGregorianCalendar} to be created.
 892      *
 893      * @return {@code XMLGregorianCalendar} created from specified values.
 894      *
 895      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
 896      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
 897      *   or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance
 898      *   as determined by {@link XMLGregorianCalendar#isValid()}.
 899      */
 900     public XMLGregorianCalendar newXMLGregorianCalendar(
 901             final int year,
 902             final int month,
 903             final int day,
 904             final int hour,
 905             final int minute,
 906             final int second,
 907             final int millisecond,
 908             final int timezone) {
 909 
 910             // year may be undefined
 911             BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null;
 912 
 913             // millisecond may be undefined
 914             // millisecond must be >= 0 millisecond <= 1000
 915             BigDecimal realMillisecond = null; // undefined value
 916             if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
 917                     if (millisecond < 0 || millisecond > 1000) {
 918                             throw new IllegalArgumentException(
 919                                                     "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar("
 920                                                     + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)"
 921                                                     + "with invalid millisecond: " + millisecond
 922                                                     );
 923                     }
 924 
 925                     realMillisecond = BigDecimal.valueOf((long) millisecond).movePointLeft(3);
 926             }
 927 
 928             return newXMLGregorianCalendar(
 929                     realYear,
 930                     month,
 931                     day,
 932                     hour,
 933                     minute,
 934                     second,
 935                     realMillisecond,
 936                     timezone
 937             );
 938     }
 939 
 940     /**
 941      * Create a Java representation of XML Schema builtin datatype {@code date} or {@code g*}.
 942      *
 943      * <p>For example, an instance of {@code gYear} can be created invoking this factory
 944      * with {@code month} and {@code day} parameters set to
 945      * {@link DatatypeConstants#FIELD_UNDEFINED}.
 946      *
 947      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
 948      *
 949      * @param year of {@code XMLGregorianCalendar} to be created.
 950      * @param month of {@code XMLGregorianCalendar} to be created.
 951      * @param day of {@code XMLGregorianCalendar} to be created.
 952      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 953      *
 954      * @return {@code XMLGregorianCalendar} created from parameter values.
 955      *
 956      * @see DatatypeConstants#FIELD_UNDEFINED
 957      *
 958      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
 959      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
 960      *   or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance
 961      *   as determined by {@link XMLGregorianCalendar#isValid()}.
 962      */
 963     public XMLGregorianCalendar newXMLGregorianCalendarDate(
 964             final int year,
 965             final int month,
 966             final int day,
 967             final int timezone) {
 968 
 969             return newXMLGregorianCalendar(
 970                     year,
 971                     month,
 972                     day,
 973                     DatatypeConstants.FIELD_UNDEFINED, // hour
 974                     DatatypeConstants.FIELD_UNDEFINED, // minute
 975                     DatatypeConstants.FIELD_UNDEFINED, // second
 976                     DatatypeConstants.FIELD_UNDEFINED, // millisecond
 977                     timezone);
 978             }
 979 
 980     /**
 981      * Create a Java instance of XML Schema builtin datatype {@code time}.
 982      *
 983      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
 984      *
 985      * @param hours number of hours
 986      * @param minutes number of minutes
 987      * @param seconds number of seconds
 988      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 989      *
 990      * @return {@code XMLGregorianCalendar} created from parameter values.
 991      *
 992      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
 993      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
 994      *   or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance
 995      *   as determined by {@link XMLGregorianCalendar#isValid()}.
 996      *
 997      * @see DatatypeConstants#FIELD_UNDEFINED
 998      */
 999     public XMLGregorianCalendar newXMLGregorianCalendarTime(
1000             final int hours,
1001             final int minutes,
1002             final int seconds,
1003             final int timezone) {
1004 
1005             return newXMLGregorianCalendar(
1006                     DatatypeConstants.FIELD_UNDEFINED, // Year
1007                     DatatypeConstants.FIELD_UNDEFINED, // Month
1008                     DatatypeConstants.FIELD_UNDEFINED, // Day
1009                     hours,
1010                     minutes,
1011                     seconds,
1012                     DatatypeConstants.FIELD_UNDEFINED, //Millisecond
1013                     timezone);
1014     }
1015 
1016     /**
1017      * Create a Java instance of XML Schema builtin datatype time.
1018      *
1019      * <p>A {@code null} value indicates that field is not set.
1020      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
1021      *
1022      * @param hours number of hours
1023      * @param minutes number of minutes
1024      * @param seconds number of seconds
1025      * @param fractionalSecond value of {@code null} indicates that this optional field is not set.
1026      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
1027      *
1028      * @return {@code XMLGregorianCalendar} created from parameter values.
1029      *
1030      * @see DatatypeConstants#FIELD_UNDEFINED
1031      *
1032      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
1033      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
1034      *   or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance
1035      *   as determined by {@link XMLGregorianCalendar#isValid()}.
1036      */
1037     public XMLGregorianCalendar newXMLGregorianCalendarTime(
1038             final int hours,
1039             final int minutes,
1040             final int seconds,
1041             final BigDecimal fractionalSecond,
1042             final int timezone) {
1043 
1044             return newXMLGregorianCalendar(
1045                     null, // year
1046                     DatatypeConstants.FIELD_UNDEFINED, // month
1047                     DatatypeConstants.FIELD_UNDEFINED, // day
1048                     hours,
1049                     minutes,
1050                     seconds,
1051                     fractionalSecond,
1052                     timezone);
1053             }
1054 
1055     /**
1056      * Create a Java instance of XML Schema builtin datatype time.
1057      *
1058      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.
1059      *
1060      * @param hours number of hours
1061      * @param minutes number of minutes
1062      * @param seconds number of seconds
1063      * @param milliseconds number of milliseconds
1064      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
1065      *
1066      * @return {@code XMLGregorianCalendar} created from parameter values.
1067      *
1068      * @see DatatypeConstants#FIELD_UNDEFINED
1069      *
1070      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
1071      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
1072      *   or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance
1073      *   as determined by {@link XMLGregorianCalendar#isValid()}.
1074      */
1075     public XMLGregorianCalendar newXMLGregorianCalendarTime(
1076             final int hours,
1077             final int minutes,
1078             final int seconds,
1079             final int milliseconds,
1080             final int timezone) {
1081 
1082             // millisecond may be undefined
1083             // millisecond must be >= 0 millisecond <= 1000
1084             BigDecimal realMilliseconds = null; // undefined value
1085             if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) {
1086                     if (milliseconds < 0 || milliseconds > 1000) {
1087                             throw new IllegalArgumentException(
1088                                                     "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime("
1089                                                     + "int hours, int minutes, int seconds, int milliseconds, int timezone)"
1090                                                     + "with invalid milliseconds: " + milliseconds
1091                                                     );
1092                     }
1093 
1094                     realMilliseconds = BigDecimal.valueOf((long) milliseconds).movePointLeft(3);
1095             }
1096 
1097             return newXMLGregorianCalendarTime(
1098                     hours,
1099                     minutes,
1100                     seconds,
1101                     realMilliseconds,
1102                     timezone
1103             );
1104     }
1105 }