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