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