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