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