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