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