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