# HG changeset patch # User lana # Date 1367865700 25200 # Node ID e3e2d366215bcc2cf1674b46c2012a380c6b3db8 # Parent 64d47cf7f372f3263e588f33dd045b78b1ee411c# Parent 4df3e7ceb396c0b07dbb22b6bafb1ab9d7bdf96f Merge diff -r 64d47cf7f372 -r e3e2d366215b jaxp/build.xml --- a/jaxp/build.xml Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/build.xml Mon May 06 11:41:40 2013 -0700 @@ -176,4 +176,42 @@ + + + + + + + +
Unofficial Javadoc generated from developer sources for preview purposes only]]>
+ + + + + + + + + + + + + + + + + + + +
+
+ + + + + diff -r 64d47cf7f372 -r e3e2d366215b jaxp/nbproject/project.xml --- a/jaxp/nbproject/project.xml Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/nbproject/project.xml Mon May 06 11:41:40 2013 -0700 @@ -15,6 +15,12 @@ . UTF-8 + + + java + src + UTF-8 + @@ -27,9 +33,16 @@ clean build + + javadoc-nb + + + + src + build.xml @@ -38,11 +51,16 @@ + - + + + src + + diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/datatype/DatatypeFactory.java --- a/jaxp/src/javax/xml/datatype/DatatypeFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/datatype/DatatypeFactory.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,8 @@ package javax.xml.datatype; +import java.math.BigDecimal; import java.math.BigInteger; -import java.math.BigDecimal; import java.util.GregorianCalendar; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -34,12 +34,12 @@ /** *

Factory that creates new javax.xml.datatype Objects that map XML to/from Java Objects.

* - *

{@link #newInstance()} is used to create a new DatatypeFactory. - * The following implementation resolution mechanisms are used in the following order:

+ *

A new instance of the DatatypeFactory is created through the {@link #newInstance()} method + * that uses the following implementation resolution mechanisms to determine an implementation:

*
    *
  1. * If the system property specified by {@link #DATATYPEFACTORY_PROPERTY}, "javax.xml.datatype.DatatypeFactory", - * exists, a class with the name of the property's value is instantiated. + * exists, a class with the name of the property value is instantiated. * Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}. *
  2. *
  3. @@ -48,8 +48,12 @@ * and processed as documented in the prior step. *
  4. *
  5. - * The services resolution mechanism is used, e.g. META-INF/services/java.xml.datatype.DatatypeFactory. - * Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}. + * Uses the service-provider loading facilities, defined by the {@link java.util.ServiceLoader} class, to attempt + * to locate and load an implementation of the service. + *
    + * In case of {@link java.util.ServiceConfigurationError service + * configuration error} a {@link javax.xml.datatype.DatatypeConfigurationException} + * will be thrown. *
  6. *
  7. * The final mechanism is to attempt to instantiate the Class specified by @@ -67,26 +71,33 @@ */ public abstract class DatatypeFactory { - /** - *

    Default property name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.

    - * - *

    Default value is javax.xml.datatype.DatatypeFactory.

    - */ - public static final String DATATYPEFACTORY_PROPERTY = "javax.xml.datatype.DatatypeFactory"; + /** + *

    Default property name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.

    + * + *

    Default value is javax.xml.datatype.DatatypeFactory.

    + */ + public static final String DATATYPEFACTORY_PROPERTY = + // We use a String constant here, rather than calling + // DatatypeFactory.class.getName() - in order to make javadoc + // generate a See Also: Constant Field Value link. + "javax.xml.datatype.DatatypeFactory"; - /** - *

    Default implementation class name as defined in - * JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.

    - * - *

    Implementers should specify the name of an appropriate class - * to be instantiated if no other implementation resolution mechanism - * succeeds.

    - * - *

    Users should not refer to this field; it is intended only to - * document a factory implementation detail. - *

    - */ - public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS = new String("com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl"); + /** + *

    Default implementation class name as defined in + * JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.

    + * + *

    Implementers should specify the name of an appropriate class + * to be instantiated if no other implementation resolution mechanism + * succeeds.

    + * + *

    Users should not refer to this field; it is intended only to + * document a factory implementation detail. + *

    + */ + public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS = + // We use new String() here to prevent javadoc from generating + // a See Also: Constant Field Value link. + new String("com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl"); /** * http://www.w3.org/TR/xpath-datamodel/#xdtschema defines two regexps @@ -101,40 +112,36 @@ private static final Pattern XDTSCHEMA_DTD = Pattern.compile("[^YM]*[DT].*"); - /** - *

    Protected constructor to prevent instaniation outside of package.

    - * - *

    Use {@link #newInstance()} to create a DatatypeFactory.

    - */ - protected DatatypeFactory() { - } + /** + *

    Protected constructor to prevent instaniation outside of package.

    + * + *

    Use {@link #newInstance()} to create a DatatypeFactory.

    + */ + protected DatatypeFactory() { + } - /** - *

    Obtain a new instance of a DatatypeFactory.

    - * + /** + *

    Obtain a new instance of a DatatypeFactory.

    + * *

    The implementation resolution mechanisms are defined in this * Class's documentation.

    - * - * @return New instance of a DatatypeFactory - * - * @throws DatatypeConfigurationException If the implementation is not - * available or cannot be instantiated. + * + * @return New instance of a DatatypeFactory + * + * @throws DatatypeConfigurationException If the implementation is not + * available or cannot be instantiated. * * @see #newInstance(String factoryClassName, ClassLoader classLoader) - */ - public static DatatypeFactory newInstance() - throws DatatypeConfigurationException { + */ + public static DatatypeFactory newInstance() + throws DatatypeConfigurationException { - try { - return (DatatypeFactory) FactoryFinder.find( - /* The default property name according to the JAXP spec */ - DATATYPEFACTORY_PROPERTY, - /* The fallback implementation class name */ - DATATYPEFACTORY_IMPLEMENTATION_CLASS); - } catch (FactoryFinder.ConfigurationError e) { - throw new DatatypeConfigurationException(e.getMessage(), e.getException()); - } - } + return FactoryFinder.find( + /* The default property name according to the JAXP spec */ + DatatypeFactory.class, + /* The fallback implementation class name */ + DATATYPEFACTORY_IMPLEMENTATION_CLASS); + } /** *

    Obtain a new instance of a DatatypeFactory from class name. @@ -172,57 +179,54 @@ */ public static DatatypeFactory newInstance(String factoryClassName, ClassLoader classLoader) throws DatatypeConfigurationException { - try { - return (DatatypeFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new DatatypeConfigurationException(e.getMessage(), e.getException()); - } - } + return FactoryFinder.newInstance(DatatypeFactory.class, + factoryClassName, classLoader, false); + } - /** - *

    Obtain a new instance of a Duration - * specifying the Duration as its string representation, "PnYnMnDTnHnMnS", - * as defined in XML Schema 1.0 section 3.2.6.1.

    - * - *

    XML Schema Part 2: Datatypes, 3.2.6 duration, defines duration as:

    - *
    - * duration represents a duration of time. - * The value space of duration is a six-dimensional space where the coordinates designate the - * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively. - * These components are ordered in their significance by their order of appearance i.e. as - * year, month, day, hour, minute, and second. - *
    - *

    All six values are set and availabe from the created {@link Duration}

    + /** + *

    Obtain a new instance of a Duration + * specifying the Duration as its string representation, "PnYnMnDTnHnMnS", + * as defined in XML Schema 1.0 section 3.2.6.1.

    + * + *

    XML Schema Part 2: Datatypes, 3.2.6 duration, defines duration as:

    + *
    + * duration represents a duration of time. + * The value space of duration is a six-dimensional space where the coordinates designate the + * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively. + * These components are ordered in their significance by their order of appearance i.e. as + * year, month, day, hour, minute, and second. + *
    + *

    All six values are set and available from the created {@link Duration}

    * *

    The XML Schema specification states that values can be of an arbitrary size. * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits * if implementation capacities are exceeded.

    - * - * @param lexicalRepresentation String representation of a Duration. - * - * @return New Duration created from parsing the lexicalRepresentation. - * - * @throws IllegalArgumentException If lexicalRepresentation is not a valid representation of a Duration. - * @throws UnsupportedOperationException If implementation cannot support requested values. - * @throws NullPointerException if lexicalRepresentation is null. - */ - public abstract Duration newDuration(final String lexicalRepresentation); + * + * @param lexicalRepresentation String representation of a Duration. + * + * @return New Duration created from parsing the lexicalRepresentation. + * + * @throws IllegalArgumentException If lexicalRepresentation is not a valid representation of a Duration. + * @throws UnsupportedOperationException If implementation cannot support requested values. + * @throws NullPointerException if lexicalRepresentation is null. + */ + public abstract Duration newDuration(final String lexicalRepresentation); - /** - *

    Obtain a new instance of a Duration - * specifying the Duration as milliseconds.

    - * - *

    XML Schema Part 2: Datatypes, 3.2.6 duration, defines duration as:

    - *
    - * duration represents a duration of time. - * The value space of duration is a six-dimensional space where the coordinates designate the - * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively. - * These components are ordered in their significance by their order of appearance i.e. as - * year, month, day, hour, minute, and second. - *
    + /** + *

    Obtain a new instance of a Duration + * specifying the Duration as milliseconds.

    + * + *

    XML Schema Part 2: Datatypes, 3.2.6 duration, defines duration as:

    + *
    + * duration represents a duration of time. + * The value space of duration is a six-dimensional space where the coordinates designate the + * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively. + * These components are ordered in their significance by their order of appearance i.e. as + * year, month, day, hour, minute, and second. + *
    *

    All six values are set by computing their values from the specified milliseconds - * and are availabe using the get methods of the created {@link Duration}. + * and are available using the get methods of the created {@link Duration}. * The values conform to and are defined by:

    *
      *
    • ISO 8601:2000(E) Section 5.5.3.2 Alternative format
    • @@ -231,25 +235,25 @@ * *
    • {@link XMLGregorianCalendar} Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation
    • *
    - * - *

    The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., - * {@link java.util.Calendar#YEAR} = 1970, - * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, - * {@link java.util.Calendar#DATE} = 1, etc. - * This is important as there are variations in the Gregorian Calendar, - * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} - * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced.

    - * - * @param durationInMilliSeconds Duration in milliseconds to create. - * - * @return New Duration representing durationInMilliSeconds. - */ - public abstract Duration newDuration(final long durationInMilliSeconds); + * + *

    The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., + * {@link java.util.Calendar#YEAR} = 1970, + * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, + * {@link java.util.Calendar#DATE} = 1, etc. + * This is important as there are variations in the Gregorian Calendar, + * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} + * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced.

    + * + * @param durationInMilliSeconds Duration in milliseconds to create. + * + * @return New Duration representing durationInMilliSeconds. + */ + public abstract Duration newDuration(final long durationInMilliSeconds); - /** - *

    Obtain a new instance of a Duration - * specifying the Duration as isPositive, years, months, days, hours, minutes, seconds.

    - * + /** + *

    Obtain a new instance of a Duration + * specifying the Duration as isPositive, years, months, days, hours, minutes, seconds.

    + * *

    The XML Schema specification states that values can be of an arbitrary size. * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits @@ -257,35 +261,35 @@ * *

    A null value indicates that field is not set.

    * - * @param isPositive Set to false to create a negative duration. When the length - * of the duration is zero, this parameter will be ignored. - * @param years of this Duration - * @param months of this Duration - * @param days of this Duration - * @param hours of this Duration - * @param minutes of this Duration - * @param seconds of this Duration - * - * @return New Duration created from the specified values. - * - * @throws IllegalArgumentException If the values are not a valid representation of a - * Duration: if all the fields (years, months, ...) are null or - * if any of the fields is negative. - * @throws UnsupportedOperationException If implementation cannot support requested values. - */ - public abstract Duration newDuration( - final boolean isPositive, - final BigInteger years, - final BigInteger months, - final BigInteger days, - final BigInteger hours, - final BigInteger minutes, - final BigDecimal seconds); + * @param isPositive Set to false to create a negative duration. When the length + * of the duration is zero, this parameter will be ignored. + * @param years of this Duration + * @param months of this Duration + * @param days of this Duration + * @param hours of this Duration + * @param minutes of this Duration + * @param seconds of this Duration + * + * @return New Duration created from the specified values. + * + * @throws IllegalArgumentException If the values are not a valid representation of a + * Duration: if all the fields (years, months, ...) are null or + * if any of the fields is negative. + * @throws UnsupportedOperationException If implementation cannot support requested values. + */ + public abstract Duration newDuration( + final boolean isPositive, + final BigInteger years, + final BigInteger months, + final BigInteger days, + final BigInteger hours, + final BigInteger minutes, + final BigDecimal seconds); - /** - *

    Obtain a new instance of a Duration - * specifying the Duration as isPositive, years, months, days, hours, minutes, seconds.

    - * + /** + *

    Obtain a new instance of a Duration + * specifying the Duration as isPositive, years, months, days, hours, minutes, seconds.

    + * *

    A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.

    * * @param isPositive Set to false to create a negative duration. When the length @@ -297,113 +301,113 @@ * @param minutes of this Duration * @param seconds of this Duration * - * @return New Duration created from the specified values. - * - * @throws IllegalArgumentException If the values are not a valid representation of a - * Duration: if any of the fields is negative. - * - * @see #newDuration( - * boolean isPositive, - * BigInteger years, - * BigInteger months, - * BigInteger days, - * BigInteger hours, - * BigInteger minutes, - * BigDecimal seconds) - */ - public Duration newDuration( - final boolean isPositive, - final int years, - final int months, - final int days, - final int hours, - final int minutes, - final int seconds) { + * @return New Duration created from the specified values. + * + * @throws IllegalArgumentException If the values are not a valid representation of a + * Duration: if any of the fields is negative. + * + * @see #newDuration( + * boolean isPositive, + * BigInteger years, + * BigInteger months, + * BigInteger days, + * BigInteger hours, + * BigInteger minutes, + * BigDecimal seconds) + */ + public Duration newDuration( + final boolean isPositive, + final int years, + final int months, + final int days, + final int hours, + final int minutes, + final int seconds) { - // years may not be set - BigInteger realYears = (years != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) years) : null; + // years may not be set + BigInteger realYears = (years != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) years) : null; - // months may not be set - BigInteger realMonths = (months != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) months) : null; + // months may not be set + BigInteger realMonths = (months != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) months) : null; - // days may not be set - BigInteger realDays = (days != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) days) : null; + // days may not be set + BigInteger realDays = (days != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) days) : null; - // hours may not be set - BigInteger realHours = (hours != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) hours) : null; + // hours may not be set + BigInteger realHours = (hours != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) hours) : null; - // minutes may not be set - BigInteger realMinutes = (minutes != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) minutes) : null; + // minutes may not be set + BigInteger realMinutes = (minutes != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) minutes) : null; - // seconds may not be set - BigDecimal realSeconds = (seconds != DatatypeConstants.FIELD_UNDEFINED) ? BigDecimal.valueOf((long) seconds) : null; + // seconds may not be set + BigDecimal realSeconds = (seconds != DatatypeConstants.FIELD_UNDEFINED) ? BigDecimal.valueOf((long) seconds) : null; - return newDuration( - isPositive, - realYears, - realMonths, - realDays, - realHours, - realMinutes, - realSeconds - ); - } + return newDuration( + isPositive, + realYears, + realMonths, + realDays, + realHours, + realMinutes, + realSeconds + ); + } - /** - *

    Create a Duration of type xdt:dayTimeDuration by parsing its String representation, - * "PnDTnHnMnS", - * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration.

    - * - *

    The datatype xdt:dayTimeDuration is a subtype of xs:duration - * whose lexical representation contains only day, hour, minute, and second components. - * This datatype resides in the namespace http://www.w3.org/2003/11/xpath-datatypes.

    - * - *

    All four values are set and availabe from the created {@link Duration}

    - * + /** + *

    Create a Duration of type xdt:dayTimeDuration by parsing its String representation, + * "PnDTnHnMnS", + * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration.

    + * + *

    The datatype xdt:dayTimeDuration is a subtype of xs:duration + * whose lexical representation contains only day, hour, minute, and second components. + * This datatype resides in the namespace http://www.w3.org/2003/11/xpath-datatypes.

    + * + *

    All four values are set and available from the created {@link Duration}

    + * *

    The XML Schema specification states that values can be of an arbitrary size. * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits * if implementation capacities are exceeded.

    * - * @param lexicalRepresentation Lexical representation of a duration. - * - * @return New Duration created using the specified lexicalRepresentation. - * - * @throws IllegalArgumentException If lexicalRepresentation is not a valid representation of a Duration expressed only in terms of days and time. - * @throws UnsupportedOperationException If implementation cannot support requested values. - * @throws NullPointerException If lexicalRepresentation is null. - */ - public Duration newDurationDayTime(final String lexicalRepresentation) { - // lexicalRepresentation must be non-null - if (lexicalRepresentation == null) { - throw new NullPointerException( - "Trying to create an xdt:dayTimeDuration with an invalid" - + " lexical representation of \"null\""); - } - - // test lexicalRepresentation against spec regex - Matcher matcher = XDTSCHEMA_DTD.matcher(lexicalRepresentation); - if (!matcher.matches()) { - throw new IllegalArgumentException( - "Trying to create an xdt:dayTimeDuration with an invalid" - + " lexical representation of \"" + lexicalRepresentation - + "\", data model requires years and months only."); - } - - return newDuration(lexicalRepresentation); + * @param lexicalRepresentation Lexical representation of a duration. + * + * @return New Duration created using the specified lexicalRepresentation. + * + * @throws IllegalArgumentException If lexicalRepresentation is not a valid representation of a Duration expressed only in terms of days and time. + * @throws UnsupportedOperationException If implementation cannot support requested values. + * @throws NullPointerException If lexicalRepresentation is null. + */ + public Duration newDurationDayTime(final String lexicalRepresentation) { + // lexicalRepresentation must be non-null + if (lexicalRepresentation == null) { + throw new NullPointerException( + "Trying to create an xdt:dayTimeDuration with an invalid" + + " lexical representation of \"null\""); } - /** - *

    Create a Duration of type xdt:dayTimeDuration using the specified milliseconds as defined in - * - * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration.

    - * - *

    The datatype xdt:dayTimeDuration is a subtype of xs:duration - * whose lexical representation contains only day, hour, minute, and second components. - * This datatype resides in the namespace http://www.w3.org/2003/11/xpath-datatypes.

    - * + // test lexicalRepresentation against spec regex + Matcher matcher = XDTSCHEMA_DTD.matcher(lexicalRepresentation); + if (!matcher.matches()) { + throw new IllegalArgumentException( + "Trying to create an xdt:dayTimeDuration with an invalid" + + " lexical representation of \"" + lexicalRepresentation + + "\", data model requires years and months only."); + } + + return newDuration(lexicalRepresentation); + } + + /** + *

    Create a Duration of type xdt:dayTimeDuration using the specified milliseconds as defined in + * + * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration.

    + * + *

    The datatype xdt:dayTimeDuration is a subtype of xs:duration + * whose lexical representation contains only day, hour, minute, and second components. + * This datatype resides in the namespace http://www.w3.org/2003/11/xpath-datatypes.

    + * *

    All four values are set by computing their values from the specified milliseconds - * and are availabe using the get methods of the created {@link Duration}. + * and are available using the get methods of the created {@link Duration}. * The values conform to and are defined by:

    *
      *
    • ISO 8601:2000(E) Section 5.5.3.2 Alternative format
    • @@ -412,39 +416,39 @@ * *
    • {@link XMLGregorianCalendar} Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation
    • *
    - * - *

    The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., - * {@link java.util.Calendar#YEAR} = 1970, - * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, - * {@link java.util.Calendar#DATE} = 1, etc. - * This is important as there are variations in the Gregorian Calendar, - * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} - * so the result of {@link Duration#getDays()} can be influenced.

    - * + * + *

    The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., + * {@link java.util.Calendar#YEAR} = 1970, + * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, + * {@link java.util.Calendar#DATE} = 1, etc. + * This is important as there are variations in the Gregorian Calendar, + * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} + * so the result of {@link Duration#getDays()} can be influenced.

    + * *

    Any remaining milliseconds after determining the day, hour, minute and second are discarded.

    * - * @param durationInMilliseconds Milliseconds of Duration to create. - * - * @return New Duration created with the specified durationInMilliseconds. - * - * @see - * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration - */ - public Duration newDurationDayTime(final long durationInMilliseconds) { + * @param durationInMilliseconds Milliseconds of Duration to create. + * + * @return New Duration created with the specified durationInMilliseconds. + * + * @see + * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration + */ + public Duration newDurationDayTime(final long durationInMilliseconds) { - return newDuration(durationInMilliseconds); - } + return newDuration(durationInMilliseconds); + } - /** - *

    Create a Duration of type xdt:dayTimeDuration using the specified - * day, hour, minute and second as defined in - * - * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration.

    - * - *

    The datatype xdt:dayTimeDuration is a subtype of xs:duration - * whose lexical representation contains only day, hour, minute, and second components. - * This datatype resides in the namespace http://www.w3.org/2003/11/xpath-datatypes.

    - * + /** + *

    Create a Duration of type xdt:dayTimeDuration using the specified + * day, hour, minute and second as defined in + * + * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration.

    + * + *

    The datatype xdt:dayTimeDuration is a subtype of xs:duration + * whose lexical representation contains only day, hour, minute, and second components. + * This datatype resides in the namespace http://www.w3.org/2003/11/xpath-datatypes.

    + * *

    The XML Schema specification states that values can be of an arbitrary size. * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits @@ -454,102 +458,102 @@ * * @param isPositive Set to false to create a negative duration. When the length * of the duration is zero, this parameter will be ignored. - * @param day Day of Duration. - * @param hour Hour of Duration. - * @param minute Minute of Duration. - * @param second Second of Duration. - * - * @return New Duration created with the specified day, hour, minute - * and second. - * - * @throws IllegalArgumentException If the values are not a valid representation of a - * Duration: if all the fields (day, hour, ...) are null or - * if any of the fields is negative. - * @throws UnsupportedOperationException If implementation cannot support requested values. - */ - public Duration newDurationDayTime( - final boolean isPositive, - final BigInteger day, - final BigInteger hour, - final BigInteger minute, - final BigInteger second) { + * @param day Day of Duration. + * @param hour Hour of Duration. + * @param minute Minute of Duration. + * @param second Second of Duration. + * + * @return New Duration created with the specified day, hour, minute + * and second. + * + * @throws IllegalArgumentException If the values are not a valid representation of a + * Duration: if all the fields (day, hour, ...) are null or + * if any of the fields is negative. + * @throws UnsupportedOperationException If implementation cannot support requested values. + */ + public Duration newDurationDayTime( + final boolean isPositive, + final BigInteger day, + final BigInteger hour, + final BigInteger minute, + final BigInteger second) { - return newDuration( - isPositive, - null, // years - null, // months - day, - hour, - minute, - (second != null)? new BigDecimal(second):null - ); - } + return newDuration( + isPositive, + null, // years + null, // months + day, + hour, + minute, + (second != null)? new BigDecimal(second):null + ); + } - /** - *

    Create a Duration of type xdt:dayTimeDuration using the specified - * day, hour, minute and second as defined in - * - * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration.

    - * - *

    The datatype xdt:dayTimeDuration is a subtype of xs:duration - * whose lexical representation contains only day, hour, minute, and second components. - * This datatype resides in the namespace http://www.w3.org/2003/11/xpath-datatypes.

    - * + /** + *

    Create a Duration of type xdt:dayTimeDuration using the specified + * day, hour, minute and second as defined in + * + * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration.

    + * + *

    The datatype xdt:dayTimeDuration is a subtype of xs:duration + * whose lexical representation contains only day, hour, minute, and second components. + * This datatype resides in the namespace http://www.w3.org/2003/11/xpath-datatypes.

    + * *

    A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.

    * * @param isPositive Set to false to create a negative duration. When the length * of the duration is zero, this parameter will be ignored. - * @param day Day of Duration. - * @param hour Hour of Duration. - * @param minute Minute of Duration. - * @param second Second of Duration. - * - * @return New Duration created with the specified day, hour, minute - * and second. - * - * @throws IllegalArgumentException If the values are not a valid representation of a - * Duration: if any of the fields (day, hour, ...) is negative. - */ - public Duration newDurationDayTime( - final boolean isPositive, - final int day, - final int hour, - final int minute, - final int second) { + * @param day Day of Duration. + * @param hour Hour of Duration. + * @param minute Minute of Duration. + * @param second Second of Duration. + * + * @return New Duration created with the specified day, hour, minute + * and second. + * + * @throws IllegalArgumentException If the values are not a valid representation of a + * Duration: if any of the fields (day, hour, ...) is negative. + */ + public Duration newDurationDayTime( + final boolean isPositive, + final int day, + final int hour, + final int minute, + final int second) { - return newDurationDayTime( - isPositive, - BigInteger.valueOf((long) day), - BigInteger.valueOf((long) hour), - BigInteger.valueOf((long) minute), - BigInteger.valueOf((long) second) - ); - } + return newDurationDayTime( + isPositive, + BigInteger.valueOf((long) day), + BigInteger.valueOf((long) hour), + BigInteger.valueOf((long) minute), + BigInteger.valueOf((long) second) + ); + } - /** - *

    Create a Duration of type xdt:yearMonthDuration by parsing its String representation, - * "PnYnM", - * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration.

    - * - *

    The datatype xdt:yearMonthDuration is a subtype of xs:duration - * whose lexical representation contains only year and month components. - * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.

    - * - *

    Both values are set and availabe from the created {@link Duration}

    - * + /** + *

    Create a Duration of type xdt:yearMonthDuration by parsing its String representation, + * "PnYnM", + * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration.

    + * + *

    The datatype xdt:yearMonthDuration is a subtype of xs:duration + * whose lexical representation contains only year and month components. + * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.

    + * + *

    Both values are set and available from the created {@link Duration}

    + * *

    The XML Schema specification states that values can be of an arbitrary size. * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits * if implementation capacities are exceeded.

    * - * @param lexicalRepresentation Lexical representation of a duration. - * - * @return New Duration created using the specified lexicalRepresentation. - * - * @throws IllegalArgumentException If lexicalRepresentation is not a valid representation of a Duration expressed only in terms of years and months. - * @throws UnsupportedOperationException If implementation cannot support requested values. - * @throws NullPointerException If lexicalRepresentation is null. - */ + * @param lexicalRepresentation Lexical representation of a duration. + * + * @return New Duration created using the specified lexicalRepresentation. + * + * @throws IllegalArgumentException If lexicalRepresentation is not a valid representation of a Duration expressed only in terms of years and months. + * @throws UnsupportedOperationException If implementation cannot support requested values. + * @throws NullPointerException If lexicalRepresentation is null. + */ public Duration newDurationYearMonth( final String lexicalRepresentation) { @@ -572,17 +576,17 @@ return newDuration(lexicalRepresentation); } - /** - *

    Create a Duration of type xdt:yearMonthDuration using the specified milliseconds as defined in - * - * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration.

    - * - *

    The datatype xdt:yearMonthDuration is a subtype of xs:duration - * whose lexical representation contains only year and month components. - * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.

    - * + /** + *

    Create a Duration of type xdt:yearMonthDuration using the specified milliseconds as defined in + * + * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration.

    + * + *

    The datatype xdt:yearMonthDuration is a subtype of xs:duration + * whose lexical representation contains only year and month components. + * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.

    + * *

    Both values are set by computing their values from the specified milliseconds - * and are availabe using the get methods of the created {@link Duration}. + * and are available using the get methods of the created {@link Duration}. * The values conform to and are defined by:

    *
      *
    • ISO 8601:2000(E) Section 5.5.3.2 Alternative format
    • @@ -592,20 +596,20 @@ *
    • {@link XMLGregorianCalendar} Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation
    • *
    * - *

    The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., - * {@link java.util.Calendar#YEAR} = 1970, - * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, - * {@link java.util.Calendar#DATE} = 1, etc. - * This is important as there are variations in the Gregorian Calendar, - * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} - * so the result of {@link Duration#getMonths()} can be influenced.

    - * + *

    The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., + * {@link java.util.Calendar#YEAR} = 1970, + * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, + * {@link java.util.Calendar#DATE} = 1, etc. + * This is important as there are variations in the Gregorian Calendar, + * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} + * so the result of {@link Duration#getMonths()} can be influenced.

    + * *

    Any remaining milliseconds after determining the year and month are discarded.

    - * - * @param durationInMilliseconds Milliseconds of Duration to create. - * - * @return New Duration created using the specified durationInMilliseconds. - */ + * + * @param durationInMilliseconds Milliseconds of Duration to create. + * + * @return New Duration created using the specified durationInMilliseconds. + */ public Duration newDurationYearMonth( final long durationInMilliseconds) { @@ -624,12 +628,12 @@ return newDurationYearMonth(isPositive, years, months); } - /** - *

    Create a Duration of type xdt:yearMonthDuration using the specified - * year and month as defined in - * - * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration.

    - * + /** + *

    Create a Duration of type xdt:yearMonthDuration using the specified + * year and month as defined in + * + * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration.

    + * *

    The XML Schema specification states that values can be of an arbitrary size. * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits @@ -639,74 +643,74 @@ * * @param isPositive Set to false to create a negative duration. When the length * of the duration is zero, this parameter will be ignored. - * @param year Year of Duration. - * @param month Month of Duration. - * - * @return New Duration created using the specified year and month. - * - * @throws IllegalArgumentException If the values are not a valid representation of a - * Duration: if all of the fields (year, month) are null or - * if any of the fields is negative. - * @throws UnsupportedOperationException If implementation cannot support requested values. - */ - public Duration newDurationYearMonth( - final boolean isPositive, - final BigInteger year, - final BigInteger month) { + * @param year Year of Duration. + * @param month Month of Duration. + * + * @return New Duration created using the specified year and month. + * + * @throws IllegalArgumentException If the values are not a valid representation of a + * Duration: if all of the fields (year, month) are null or + * if any of the fields is negative. + * @throws UnsupportedOperationException If implementation cannot support requested values. + */ + public Duration newDurationYearMonth( + final boolean isPositive, + final BigInteger year, + final BigInteger month) { - return newDuration( - isPositive, - year, - month, - null, // days - null, // hours - null, // minutes - null // seconds - ); - } + return newDuration( + isPositive, + year, + month, + null, // days + null, // hours + null, // minutes + null // seconds + ); + } - /** - *

    Create a Duration of type xdt:yearMonthDuration using the specified - * year and month as defined in - * - * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration.

    - * + /** + *

    Create a Duration of type xdt:yearMonthDuration using the specified + * year and month as defined in + * + * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration.

    + * *

    A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.

    * * @param isPositive Set to false to create a negative duration. When the length * of the duration is zero, this parameter will be ignored. - * @param year Year of Duration. - * @param month Month of Duration. - * - * @return New Duration created using the specified year and month. - * - * @throws IllegalArgumentException If the values are not a valid representation of a - * Duration: if any of the fields (year, month) is negative. - */ - public Duration newDurationYearMonth( - final boolean isPositive, - final int year, - final int month) { + * @param year Year of Duration. + * @param month Month of Duration. + * + * @return New Duration created using the specified year and month. + * + * @throws IllegalArgumentException If the values are not a valid representation of a + * Duration: if any of the fields (year, month) is negative. + */ + public Duration newDurationYearMonth( + final boolean isPositive, + final int year, + final int month) { - return newDurationYearMonth( - isPositive, - BigInteger.valueOf((long) year), - BigInteger.valueOf((long) month)); - } + return newDurationYearMonth( + isPositive, + BigInteger.valueOf((long) year), + BigInteger.valueOf((long) month)); + } - /** - *

    Create a new instance of an XMLGregorianCalendar.

    - * + /** + *

    Create a new instance of an XMLGregorianCalendar.

    + * *

    All date/time datatype fields set to {@link DatatypeConstants#FIELD_UNDEFINED} or null.

    * * @return New XMLGregorianCalendar with all date/time datatype fields set to * {@link DatatypeConstants#FIELD_UNDEFINED} or null. - */ - public abstract XMLGregorianCalendar newXMLGregorianCalendar(); + */ + public abstract XMLGregorianCalendar newXMLGregorianCalendar(); - /** - *

    Create a new XMLGregorianCalendar by parsing the String as a lexical representation.

    - * + /** + *

    Create a new XMLGregorianCalendar by parsing the String as a lexical representation.

    + * *

    Parsing the lexical string representation is defined in * XML Schema 1.0 Part 2, Section 3.2.[7-14].1, * Lexical Representation.

    @@ -721,344 +725,344 @@ *

    Except for the noted lexical/canonical representation mismatches * listed in * XML Schema 1.0 errata, Section 3.2.7.2.

    - * - * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes. - * - * @return XMLGregorianCalendar created from the lexicalRepresentation. - * - * @throws IllegalArgumentException If the lexicalRepresentation is not a valid XMLGregorianCalendar. - * @throws NullPointerException If lexicalRepresentation is null. - */ - public abstract XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation); + * + * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes. + * + * @return XMLGregorianCalendar created from the lexicalRepresentation. + * + * @throws IllegalArgumentException If the lexicalRepresentation is not a valid XMLGregorianCalendar. + * @throws NullPointerException If lexicalRepresentation is null. + */ + public abstract XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation); - /** - *

    Create an XMLGregorianCalendar from a {@link GregorianCalendar}.

    - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    - * Field by Field Conversion from - * {@link GregorianCalendar} to an {@link XMLGregorianCalendar} - *
    java.util.GregorianCalendar fieldjavax.xml.datatype.XMLGregorianCalendar field
    ERA == GregorianCalendar.BC ? -YEAR : YEAR{@link XMLGregorianCalendar#setYear(int year)}
    MONTH + 1{@link XMLGregorianCalendar#setMonth(int month)}
    DAY_OF_MONTH{@link XMLGregorianCalendar#setDay(int day)}
    HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}
    - * (ZONE_OFFSET + DST_OFFSET) / (60*1000)
    - * (in minutes) - *
    {@link XMLGregorianCalendar#setTimezone(int offset)}* - *
    - *

    *conversion loss of information. It is not possible to represent - * a java.util.GregorianCalendar daylight savings timezone id in the - * XML Schema 1.0 date/time datatype representation.

    - * - *

    To compute the return value's TimeZone field, - *

      - *
    • when this.getTimezone() != FIELD_UNDEFINED, - * create a java.util.TimeZone with a custom timezone id - * using the this.getTimezone().
    • - *
    • else use the GregorianCalendar default timezone value - * for the host is defined as specified by - * java.util.TimeZone.getDefault().
    • - * - * @param cal java.util.GregorianCalendar used to create XMLGregorianCalendar - * - * @return XMLGregorianCalendar created from java.util.GregorianCalendar - * - * @throws NullPointerException If cal is null. - */ - public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal); + /** + *

      Create an XMLGregorianCalendar from a {@link GregorianCalendar}.

      + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      + * Field by Field Conversion from + * {@link GregorianCalendar} to an {@link XMLGregorianCalendar} + *
      java.util.GregorianCalendar fieldjavax.xml.datatype.XMLGregorianCalendar field
      ERA == GregorianCalendar.BC ? -YEAR : YEAR{@link XMLGregorianCalendar#setYear(int year)}
      MONTH + 1{@link XMLGregorianCalendar#setMonth(int month)}
      DAY_OF_MONTH{@link XMLGregorianCalendar#setDay(int day)}
      HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}
      + * (ZONE_OFFSET + DST_OFFSET) / (60*1000)
      + * (in minutes) + *
      {@link XMLGregorianCalendar#setTimezone(int offset)}* + *
      + *

      *conversion loss of information. It is not possible to represent + * a java.util.GregorianCalendar daylight savings timezone id in the + * XML Schema 1.0 date/time datatype representation.

      + * + *

      To compute the return value's TimeZone field, + *

        + *
      • when this.getTimezone() != FIELD_UNDEFINED, + * create a java.util.TimeZone with a custom timezone id + * using the this.getTimezone().
      • + *
      • else use the GregorianCalendar default timezone value + * for the host is defined as specified by + * java.util.TimeZone.getDefault().
      • + * + * @param cal java.util.GregorianCalendar used to create XMLGregorianCalendar + * + * @return XMLGregorianCalendar created from java.util.GregorianCalendar + * + * @throws NullPointerException If cal is null. + */ + public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal); - /** - *

        Constructor allowing for complete value spaces allowed by - * W3C XML Schema 1.0 recommendation for xsd:dateTime and related - * builtin datatypes. Note that year parameter supports - * arbitrarily large numbers and fractionalSecond has infinite - * precision.

        - * + /** + *

        Constructor allowing for complete value spaces allowed by + * W3C XML Schema 1.0 recommendation for xsd:dateTime and related + * builtin datatypes. Note that year parameter supports + * arbitrarily large numbers and fractionalSecond has infinite + * precision.

        + * *

        A null value indicates that field is not set.

        * - * @param year of XMLGregorianCalendar to be created. - * @param month of XMLGregorianCalendar to be created. - * @param day of XMLGregorianCalendar to be created. - * @param hour of XMLGregorianCalendar to be created. - * @param minute of XMLGregorianCalendar to be created. - * @param second of XMLGregorianCalendar to be created. - * @param fractionalSecond of XMLGregorianCalendar to be created. - * @param timezone of XMLGregorianCalendar to be created. - * - * @return XMLGregorianCalendar created from specified values. - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalid XMLGregorianCalendar instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public abstract XMLGregorianCalendar newXMLGregorianCalendar( - final BigInteger year, - final int month, - final int day, - final int hour, - final int minute, - final int second, - final BigDecimal fractionalSecond, - final int timezone); + * @param year of XMLGregorianCalendar to be created. + * @param month of XMLGregorianCalendar to be created. + * @param day of XMLGregorianCalendar to be created. + * @param hour of XMLGregorianCalendar to be created. + * @param minute of XMLGregorianCalendar to be created. + * @param second of XMLGregorianCalendar to be created. + * @param fractionalSecond of XMLGregorianCalendar to be created. + * @param timezone of XMLGregorianCalendar to be created. + * + * @return XMLGregorianCalendar created from specified values. + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalid XMLGregorianCalendar instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public abstract XMLGregorianCalendar newXMLGregorianCalendar( + final BigInteger year, + final int month, + final int day, + final int hour, + final int minute, + final int second, + final BigDecimal fractionalSecond, + final int timezone); - /** - *

        Constructor of value spaces that a - * java.util.GregorianCalendar instance would need to convert to an - * XMLGregorianCalendar instance.

        - * - *

        XMLGregorianCalendar eon and - * fractionalSecond are set to null

        - * + /** + *

        Constructor of value spaces that a + * java.util.GregorianCalendar instance would need to convert to an + * XMLGregorianCalendar instance.

        + * + *

        XMLGregorianCalendar eon and + * fractionalSecond are set to null

        + * *

        A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.

        * - * @param year of XMLGregorianCalendar to be created. - * @param month of XMLGregorianCalendar to be created. - * @param day of XMLGregorianCalendar to be created. - * @param hour of XMLGregorianCalendar to be created. - * @param minute of XMLGregorianCalendar to be created. - * @param second of XMLGregorianCalendar to be created. - * @param millisecond of XMLGregorianCalendar to be created. - * @param timezone of XMLGregorianCalendar to be created. - * - * @return XMLGregorianCalendar created from specified values. - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalid XMLGregorianCalendar instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public XMLGregorianCalendar newXMLGregorianCalendar( - final int year, - final int month, - final int day, - final int hour, - final int minute, - final int second, - final int millisecond, - final int timezone) { + * @param year of XMLGregorianCalendar to be created. + * @param month of XMLGregorianCalendar to be created. + * @param day of XMLGregorianCalendar to be created. + * @param hour of XMLGregorianCalendar to be created. + * @param minute of XMLGregorianCalendar to be created. + * @param second of XMLGregorianCalendar to be created. + * @param millisecond of XMLGregorianCalendar to be created. + * @param timezone of XMLGregorianCalendar to be created. + * + * @return XMLGregorianCalendar created from specified values. + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalid XMLGregorianCalendar instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendar( + final int year, + final int month, + final int day, + final int hour, + final int minute, + final int second, + final int millisecond, + final int timezone) { - // year may be undefined - BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null; + // year may be undefined + BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null; - // millisecond may be undefined - // millisecond must be >= 0 millisecond <= 1000 - BigDecimal realMillisecond = null; // undefined value - if (millisecond != DatatypeConstants.FIELD_UNDEFINED) { - if (millisecond < 0 || millisecond > 1000) { - throw new IllegalArgumentException( - "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar(" - + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)" - + "with invalid millisecond: " + millisecond - ); - } + // millisecond may be undefined + // millisecond must be >= 0 millisecond <= 1000 + BigDecimal realMillisecond = null; // undefined value + if (millisecond != DatatypeConstants.FIELD_UNDEFINED) { + if (millisecond < 0 || millisecond > 1000) { + throw new IllegalArgumentException( + "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar(" + + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)" + + "with invalid millisecond: " + millisecond + ); + } - realMillisecond = BigDecimal.valueOf((long) millisecond).movePointLeft(3); - } + realMillisecond = BigDecimal.valueOf((long) millisecond).movePointLeft(3); + } - return newXMLGregorianCalendar( - realYear, - month, - day, - hour, - minute, - second, - realMillisecond, - timezone - ); - } + return newXMLGregorianCalendar( + realYear, + month, + day, + hour, + minute, + second, + realMillisecond, + timezone + ); + } - /** - *

        Create a Java representation of XML Schema builtin datatype date or g*.

        - * - *

        For example, an instance of gYear can be created invoking this factory - * with month and day parameters set to - * {@link DatatypeConstants#FIELD_UNDEFINED}.

        - * + /** + *

        Create a Java representation of XML Schema builtin datatype date or g*.

        + * + *

        For example, an instance of gYear can be created invoking this factory + * with month and day parameters set to + * {@link DatatypeConstants#FIELD_UNDEFINED}.

        + * *

        A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.

        * - * @param year of XMLGregorianCalendar to be created. - * @param month of XMLGregorianCalendar to be created. - * @param day of XMLGregorianCalendar to be created. - * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. - * - * @return XMLGregorianCalendar created from parameter values. - * - * @see DatatypeConstants#FIELD_UNDEFINED - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalid XMLGregorianCalendar instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public XMLGregorianCalendar newXMLGregorianCalendarDate( - final int year, - final int month, - final int day, - final int timezone) { + * @param year of XMLGregorianCalendar to be created. + * @param month of XMLGregorianCalendar to be created. + * @param day of XMLGregorianCalendar to be created. + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalid XMLGregorianCalendar instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendarDate( + final int year, + final int month, + final int day, + final int timezone) { - return newXMLGregorianCalendar( - year, - month, - day, - DatatypeConstants.FIELD_UNDEFINED, // hour - DatatypeConstants.FIELD_UNDEFINED, // minute - DatatypeConstants.FIELD_UNDEFINED, // second - DatatypeConstants.FIELD_UNDEFINED, // millisecond - timezone); - } + return newXMLGregorianCalendar( + year, + month, + day, + DatatypeConstants.FIELD_UNDEFINED, // hour + DatatypeConstants.FIELD_UNDEFINED, // minute + DatatypeConstants.FIELD_UNDEFINED, // second + DatatypeConstants.FIELD_UNDEFINED, // millisecond + timezone); + } - /** - *

        Create a Java instance of XML Schema builtin datatype time.

        - * + /** + *

        Create a Java instance of XML Schema builtin datatype time.

        + * *

        A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.

        * - * @param hours number of hours - * @param minutes number of minutes - * @param seconds number of seconds - * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. - * - * @return XMLGregorianCalendar created from parameter values. - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalid XMLGregorianCalendar instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - * - * @see DatatypeConstants#FIELD_UNDEFINED - */ - public XMLGregorianCalendar newXMLGregorianCalendarTime( - final int hours, - final int minutes, - final int seconds, - final int timezone) { + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalid XMLGregorianCalendar instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + * + * @see DatatypeConstants#FIELD_UNDEFINED + */ + public XMLGregorianCalendar newXMLGregorianCalendarTime( + final int hours, + final int minutes, + final int seconds, + final int timezone) { - return newXMLGregorianCalendar( - DatatypeConstants.FIELD_UNDEFINED, // Year - DatatypeConstants.FIELD_UNDEFINED, // Month - DatatypeConstants.FIELD_UNDEFINED, // Day - hours, - minutes, - seconds, - DatatypeConstants.FIELD_UNDEFINED, //Millisecond - timezone); - } + return newXMLGregorianCalendar( + DatatypeConstants.FIELD_UNDEFINED, // Year + DatatypeConstants.FIELD_UNDEFINED, // Month + DatatypeConstants.FIELD_UNDEFINED, // Day + hours, + minutes, + seconds, + DatatypeConstants.FIELD_UNDEFINED, //Millisecond + timezone); + } - /** - *

        Create a Java instance of XML Schema builtin datatype time.

        - * + /** + *

        Create a Java instance of XML Schema builtin datatype time.

        + * *

        A null value indicates that field is not set.

        *

        A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.

        * - * @param hours number of hours - * @param minutes number of minutes - * @param seconds number of seconds - * @param fractionalSecond value of null indicates that this optional field is not set. - * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. - * - * @return XMLGregorianCalendar created from parameter values. - * - * @see DatatypeConstants#FIELD_UNDEFINED - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalid XMLGregorianCalendar instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public XMLGregorianCalendar newXMLGregorianCalendarTime( - final int hours, - final int minutes, - final int seconds, - final BigDecimal fractionalSecond, - final int timezone) { + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param fractionalSecond value of null indicates that this optional field is not set. + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalid XMLGregorianCalendar instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendarTime( + final int hours, + final int minutes, + final int seconds, + final BigDecimal fractionalSecond, + final int timezone) { - return newXMLGregorianCalendar( - null, // year - DatatypeConstants.FIELD_UNDEFINED, // month - DatatypeConstants.FIELD_UNDEFINED, // day - hours, - minutes, - seconds, - fractionalSecond, - timezone); - } + return newXMLGregorianCalendar( + null, // year + DatatypeConstants.FIELD_UNDEFINED, // month + DatatypeConstants.FIELD_UNDEFINED, // day + hours, + minutes, + seconds, + fractionalSecond, + timezone); + } - /** - *

        Create a Java instance of XML Schema builtin datatype time.

        - * + /** + *

        Create a Java instance of XML Schema builtin datatype time.

        + * *

        A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.

        * - * @param hours number of hours - * @param minutes number of minutes - * @param seconds number of seconds - * @param milliseconds number of milliseconds - * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. - * - * @return XMLGregorianCalendar created from parameter values. - * - * @see DatatypeConstants#FIELD_UNDEFINED - * - * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field - * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} - * or if the composite values constitute an invalid XMLGregorianCalendar instance - * as determined by {@link XMLGregorianCalendar#isValid()}. - */ - public XMLGregorianCalendar newXMLGregorianCalendarTime( - final int hours, - final int minutes, - final int seconds, - final int milliseconds, - final int timezone) { + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + * @param milliseconds number of milliseconds + * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. + * + * @return XMLGregorianCalendar created from parameter values. + * + * @see DatatypeConstants#FIELD_UNDEFINED + * + * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field + * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} + * or if the composite values constitute an invalid XMLGregorianCalendar instance + * as determined by {@link XMLGregorianCalendar#isValid()}. + */ + public XMLGregorianCalendar newXMLGregorianCalendarTime( + final int hours, + final int minutes, + final int seconds, + final int milliseconds, + final int timezone) { - // millisecond may be undefined - // millisecond must be >= 0 millisecond <= 1000 - BigDecimal realMilliseconds = null; // undefined value - if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) { - if (milliseconds < 0 || milliseconds > 1000) { - throw new IllegalArgumentException( - "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime(" - + "int hours, int minutes, int seconds, int milliseconds, int timezone)" - + "with invalid milliseconds: " + milliseconds - ); - } + // millisecond may be undefined + // millisecond must be >= 0 millisecond <= 1000 + BigDecimal realMilliseconds = null; // undefined value + if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) { + if (milliseconds < 0 || milliseconds > 1000) { + throw new IllegalArgumentException( + "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime(" + + "int hours, int minutes, int seconds, int milliseconds, int timezone)" + + "with invalid milliseconds: " + milliseconds + ); + } - realMilliseconds = BigDecimal.valueOf((long) milliseconds).movePointLeft(3); - } + realMilliseconds = BigDecimal.valueOf((long) milliseconds).movePointLeft(3); + } - return newXMLGregorianCalendarTime( - hours, - minutes, - seconds, - realMilliseconds, - timezone - ); - } + return newXMLGregorianCalendarTime( + hours, + minutes, + seconds, + realMilliseconds, + timezone + ); + } } diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/datatype/FactoryFinder.java --- a/jaxp/src/javax/xml/datatype/FactoryFinder.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/datatype/FactoryFinder.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,14 +26,12 @@ package javax.xml.datatype; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; - +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URL; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** *

        Implements pluggable Datatypes.

        @@ -54,19 +52,19 @@ /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + private final static Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties * have been cached. */ - static volatile boolean firstTime = true; + private static volatile boolean firstTime = true; /** * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + private final static SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -99,31 +97,31 @@ * * Use bootstrap classLoader if cl = null and useBSClsLoader is true */ - static private Class getProviderClass(String className, ClassLoader cl, + static private Class getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { if (cl == null) { if (useBSClsLoader) { - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { throw e1; @@ -135,6 +133,9 @@ * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -144,16 +145,19 @@ * @param doFallback True if the current ClassLoader should be tried as * a fallback if the class is not found using cl */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError + static T newInstance(Class type, String className, ClassLoader cl, boolean doFallback) + throws DatatypeConfigurationException { - return newInstance(className, cl, doFallback, false); + return newInstance(type, className, cl, doFallback, false); } /** * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -166,9 +170,12 @@ * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) - throws ConfigurationError + static T newInstance(Class type, String className, ClassLoader cl, + boolean doFallback, boolean useBSClsLoader) + throws DatatypeConfigurationException { + assert type != null; + // make sure we have access to restricted packages if (System.getSecurityManager() != null) { if (className != null && className.startsWith(DEFAULT_PACKAGE)) { @@ -178,20 +185,23 @@ } try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + if (!type.isAssignableFrom(providerClass)) { + throw new ClassCastException(className + " cannot be cast to " + type.getName()); + } Object instance = providerClass.newInstance(); if (debug) { // Extra check to avoid computing cl strings dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); } - return instance; + return type.cast(instance); } catch (ClassNotFoundException x) { - throw new ConfigurationError( + throw new DatatypeConfigurationException( "Provider " + className + " not found", x); } catch (Exception x) { - throw new ConfigurationError( + throw new DatatypeConfigurationException( "Provider " + className + " could not be instantiated: " + x, x); } @@ -202,16 +212,17 @@ * entry point. * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws DatatypeConfigurationException { + final String factoryId = type.getName(); dPrint("find factoryId =" + factoryId); // Use the system property first @@ -219,7 +230,7 @@ String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true); + return newInstance(type, systemProp, null, true); } } catch (SecurityException se) { @@ -228,7 +239,6 @@ // try to read from $java.home/lib/jaxp.properties try { - String factoryClassName = null; if (firstTime) { synchronized (cacheProps) { if (firstTime) { @@ -243,11 +253,11 @@ } } } - factoryClassName = cacheProps.getProperty(factoryId); + final String factoryClassName = cacheProps.getProperty(factoryId); if (factoryClassName != null) { dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); - return newInstance(factoryClassName, null, true); + return newInstance(type, factoryClassName, null, true); } } catch (Exception ex) { @@ -255,112 +265,46 @@ } // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); + final T provider = findServiceProvider(type); if (provider != null) { return provider; } if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); + throw new DatatypeConfigurationException( + "Provider for " + factoryId + " cannot be found"); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, null, true); + return newInstance(type, fallbackClassName, null, true); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader API + * + * @param type Base class / Service interface of the factory to find. * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError + private static T findServiceProvider(final Class type) + throws DatatypeConfigurationException { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; + return AccessController.doPrivileged(new PrivilegedAction() { + public T run() { + final ServiceLoader serviceLoader = ServiceLoader.load(type); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } + }); + } catch(ServiceConfigurationError e) { + final DatatypeConfigurationException error = + new DatatypeConfigurationException( + "Provider for " + type + " cannot be found", e); + throw error; } } diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java --- a/jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/parsers/DocumentBuilderFactory.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,9 +40,6 @@ public abstract class DocumentBuilderFactory { - /** The default property name according to the JAXP spec */ - private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.DocumentBuilderFactory"; - private boolean validating = false; private boolean namespaceAware = false; private boolean whitespace = false; @@ -50,8 +47,6 @@ private boolean ignoreComments = false; private boolean coalescing = false; - private boolean canonicalState = false; - /** *

        Protected constructor to prevent instantiation. * Use {@link #newInstance()}.

        @@ -85,14 +80,12 @@ * of any property in jaxp.properties after it has been read for the first time. * *
      • - * Use the Services API (as detailed in the JAR specification), if - * available, to determine the classname. The Services API will look - * for a classname in the file - * META-INF/services/javax.xml.parsers.DocumentBuilderFactory - * in jars available to the runtime. + * Uses the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. *
      • *
      • - * Platform default DocumentBuilderFactory instance. + * Otherwise, the system-default implementation is returned. *
      • *
      * @@ -113,21 +106,16 @@ * * @return New instance of a DocumentBuilderFactory * - * @throws FactoryConfigurationError if the implementation is not - * available or cannot be instantiated. + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static DocumentBuilderFactory newInstance() { - try { - return (DocumentBuilderFactory) FactoryFinder.find( + return FactoryFinder.find( /* The default property name according to the JAXP spec */ - "javax.xml.parsers.DocumentBuilderFactory", + DocumentBuilderFactory.class, // "javax.xml.parsers.DocumentBuilderFactory" /* The fallback implementation class name */ "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } - } /** @@ -165,13 +153,9 @@ * @since 1.6 */ public static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader){ - try { //do not fallback if given classloader can't find the class, throw exception - return (DocumentBuilderFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + return FactoryFinder.newInstance(DocumentBuilderFactory.class, + factoryClassName, classLoader, false); } /** @@ -391,75 +375,64 @@ public abstract Object getAttribute(String name) throws IllegalArgumentException; - /** - *

      Set a feature for this DocumentBuilderFactory and DocumentBuilders created by this factory.

      - * - *

      - * Feature names are fully qualified {@link java.net.URI}s. - * Implementations may define their own features. - * A {@link ParserConfigurationException} is thrown if this DocumentBuilderFactory or the - * DocumentBuilders it creates cannot support the feature. - * It is possible for a DocumentBuilderFactory to expose a feature value but be unable to change its state. - *

      - * - *

      - * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. - * When the feature is:

      - *
        - *
      • - * true: the implementation will limit XML processing to conform to implementation limits. - * Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources. - * If XML processing is limited for security reasons, it will be reported via a call to the registered - * {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}. - * See {@link DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}. - *
      • - *
      • - * false: the implementation will processing XML according to the XML specifications without - * regard to possible implementation limits. - *
      • - *
      - * - * @param name Feature name. - * @param value Is feature state true or false. - * - * @throws ParserConfigurationException if this DocumentBuilderFactory or the DocumentBuilders - * it creates cannot support this feature. + /** + *

      Set a feature for this DocumentBuilderFactory and DocumentBuilders created by this factory.

      + * + *

      + * Feature names are fully qualified {@link java.net.URI}s. + * Implementations may define their own features. + * A {@link ParserConfigurationException} is thrown if this DocumentBuilderFactory or the + * DocumentBuilders it creates cannot support the feature. + * It is possible for a DocumentBuilderFactory to expose a feature value but be unable to change its state. + *

      + * + *

      + * All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. + * When the feature is:

      + *
        + *
      • + * true: the implementation will limit XML processing to conform to implementation limits. + * Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources. + * If XML processing is limited for security reasons, it will be reported via a call to the registered + * {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}. + * See {@link DocumentBuilder#setErrorHandler(org.xml.sax.ErrorHandler errorHandler)}. + *
      • + *
      • + * false: the implementation will processing XML according to the XML specifications without + * regard to possible implementation limits. + *
      • + *
      + * + * @param name Feature name. + * @param value Is feature state true or false. + * + * @throws ParserConfigurationException if this DocumentBuilderFactory or the DocumentBuilders + * it creates cannot support this feature. * @throws NullPointerException If the name parameter is null. - */ - public abstract void setFeature(String name, boolean value) - throws ParserConfigurationException; + */ + public abstract void setFeature(String name, boolean value) + throws ParserConfigurationException; - /** - *

      Get the state of the named feature.

      - * - *

      - * Feature names are fully qualified {@link java.net.URI}s. - * Implementations may define their own features. - * An {@link ParserConfigurationException} is thrown if this DocumentBuilderFactory or the - * DocumentBuilders it creates cannot support the feature. - * It is possible for an DocumentBuilderFactory to expose a feature value but be unable to change its state. - *

      - * - * @param name Feature name. - * - * @return State of the named feature. - * - * @throws ParserConfigurationException if this DocumentBuilderFactory - * or the DocumentBuilders it creates cannot support this feature. - */ - public abstract boolean getFeature(String name) - throws ParserConfigurationException; - - - /**

      Get current state of canonicalization.

      + /** + *

      Get the state of the named feature.

      * - * @return current state canonicalization control + *

      + * Feature names are fully qualified {@link java.net.URI}s. + * Implementations may define their own features. + * An {@link ParserConfigurationException} is thrown if this DocumentBuilderFactory or the + * DocumentBuilders it creates cannot support the feature. + * It is possible for an DocumentBuilderFactory to expose a feature value but be unable to change its state. + *

      + * + * @param name Feature name. + * + * @return State of the named feature. + * + * @throws ParserConfigurationException if this DocumentBuilderFactory + * or the DocumentBuilders it creates cannot support this feature. */ - /* - public boolean getCanonicalization() { - return canonicalState; - } - */ + public abstract boolean getFeature(String name) + throws ParserConfigurationException; /** @@ -488,17 +461,6 @@ } - /*

      Set canonicalization control to true or - * false.

      - * - * @param state of canonicalization - */ - /* - public void setCanonicalization(boolean state) { - canonicalState = state; - } - */ - /** *

      Set the {@link Schema} to be used by parsers created * from this factory. diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/parsers/FactoryFinder.java --- a/jaxp/src/javax/xml/parsers/FactoryFinder.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/parsers/FactoryFinder.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,16 @@ package javax.xml.parsers; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** - *

      Implements pluggable Datatypes.

      + *

      Implements pluggable Parsers.

      * *

      This class is duplicated for each JAXP subpackage so keep it in * sync. It is package private for secure class loading.

      @@ -51,7 +52,7 @@ /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + private static final Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties @@ -63,7 +64,7 @@ * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + private static final SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -96,31 +97,31 @@ * * Use bootstrap classLoader if cl = null and useBSClsLoader is true */ - static private Class getProviderClass(String className, ClassLoader cl, + static private Class getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { if (cl == null) { if (useBSClsLoader) { - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { throw e1; @@ -132,6 +133,9 @@ * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -141,16 +145,20 @@ * @param doFallback True if the current ClassLoader should be tried as * a fallback if the class is not found using cl */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError + static T newInstance(Class type, String className, ClassLoader cl, + boolean doFallback) + throws FactoryConfigurationError { - return newInstance(className, cl, doFallback, false); + return newInstance(type, className, cl, doFallback, false); } /** * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -163,9 +171,11 @@ * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) - throws ConfigurationError + static T newInstance(Class type, String className, ClassLoader cl, + boolean doFallback, boolean useBSClsLoader) + throws FactoryConfigurationError { + assert type != null; // make sure we have access to restricted packages if (System.getSecurityManager() != null) { if (className != null && className.startsWith(DEFAULT_PACKAGE)) { @@ -175,22 +185,24 @@ } try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + if (!type.isAssignableFrom(providerClass)) { + throw new ClassCastException(className + " cannot be cast to " + type.getName()); + } Object instance = providerClass.newInstance(); if (debug) { // Extra check to avoid computing cl strings dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); } - return instance; + return type.cast(instance); } catch (ClassNotFoundException x) { - throw new ConfigurationError( - "Provider " + className + " not found", x); + throw new FactoryConfigurationError(x, + "Provider " + className + " not found"); } catch (Exception x) { - throw new ConfigurationError( - "Provider " + className + " could not be instantiated: " + x, - x); + throw new FactoryConfigurationError(x, + "Provider " + className + " could not be instantiated: " + x); } } @@ -199,16 +211,17 @@ * entry point. * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws FactoryConfigurationError { + final String factoryId = type.getName(); dPrint("find factoryId =" + factoryId); // Use the system property first @@ -216,7 +229,7 @@ String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true); + return newInstance(type, systemProp, null, true); } } catch (SecurityException se) { @@ -225,7 +238,6 @@ // try to read from $java.home/lib/jaxp.properties try { - String factoryClassName = null; if (firstTime) { synchronized (cacheProps) { if (firstTime) { @@ -240,11 +252,11 @@ } } } - factoryClassName = cacheProps.getProperty(factoryId); + final String factoryClassName = cacheProps.getProperty(factoryId); if (factoryClassName != null) { dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); - return newInstance(factoryClassName, null, true); + return newInstance(type, factoryClassName, null, true); } } catch (Exception ex) { @@ -252,112 +264,52 @@ } // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); + T provider = findServiceProvider(type); if (provider != null) { return provider; } if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); + throw new FactoryConfigurationError( + "Provider for " + factoryId + " cannot be found"); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, null, true); + return newInstance(type, fallbackClassName, null, true); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader API + * + * @param type Base class / Service interface of the factory to find. * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError - { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; + private static T findServiceProvider(final Class type) { try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; + return AccessController.doPrivileged(new PrivilegedAction() { + public T run() { + final ServiceLoader serviceLoader = ServiceLoader.load(type); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } + }); + } catch(ServiceConfigurationError e) { + // It is not possible to wrap an error directly in + // FactoryConfigurationError - so we need to wrap the + // ServiceConfigurationError in a RuntimeException. + // The alternative would be to modify the logic in + // FactoryConfigurationError to allow setting a + // Throwable as the cause, but that could cause + // compatibility issues down the road. + final RuntimeException x = new RuntimeException( + "Provider for " + type + " cannot be created", e); + final FactoryConfigurationError error = + new FactoryConfigurationError(x, x.getMessage()); + throw error; } } diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/parsers/SAXParserFactory.java --- a/jaxp/src/javax/xml/parsers/SAXParserFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/parsers/SAXParserFactory.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package javax.xml.parsers; import javax.xml.validation.Schema; - import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; @@ -42,8 +41,6 @@ * */ public abstract class SAXParserFactory { - /** The default property name according to the JAXP spec */ - private static final String DEFAULT_PROPERTY_NAME = "javax.xml.parsers.SAXParserFactory"; /** *

      Should Parsers be validating?

      @@ -87,14 +84,12 @@ * of any property in jaxp.properties after it has been read for the first time. * *
    • - * Use the Services API (as detailed in the JAR specification), if - * available, to determine the classname. The Services API will look - * for a classname in the file - * META-INF/services/javax.xml.parsers.SAXParserFactory - * in jars available to the runtime. + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. *
    • *
    • - * Platform default SAXParserFactory instance. + * Otherwise the system-default implementation is returned. *
    • *
    * @@ -109,7 +104,7 @@ * this method to print a lot of debug messages * to System.err about what it is doing and where it is looking at.

    * - *

    If you have problems loading {@link DocumentBuilder}s, try:

    + *

    If you have problems loading {@link SAXParser}s, try:

    *
          * java -Djaxp.debug=1 YourProgram ....
          * 
    @@ -117,21 +112,17 @@ * * @return A new instance of a SAXParserFactory. * - * @throws FactoryConfigurationError if the implementation is - * not available or cannot be instantiated. + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static SAXParserFactory newInstance() { - try { - return (SAXParserFactory) FactoryFinder.find( + return FactoryFinder.find( /* The default property name according to the JAXP spec */ - "javax.xml.parsers.SAXParserFactory", + SAXParserFactory.class, /* The fallback implementation class name */ "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } } /** @@ -169,13 +160,9 @@ * @since 1.6 */ public static SAXParserFactory newInstance(String factoryClassName, ClassLoader classLoader){ - try { //do not fallback if given classloader can't find the class, throw exception - return (SAXParserFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + return FactoryFinder.newInstance(SAXParserFactory.class, + factoryClassName, classLoader, false); } /** @@ -266,22 +253,22 @@ * A list of the core features and properties can be found at * http://www.saxproject.org/

    * - *

    All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. - * When the feature is

    - *
      - *
    • - * true: the implementation will limit XML processing to conform to implementation limits. - * Examples include enity expansion limits and XML Schema constructs that would consume large amounts of resources. - * If XML processing is limited for security reasons, it will be reported via a call to the registered - * {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}. - * See {@link SAXParser} parse methods for handler specification. - *
    • - *
    • - * When the feature is false, the implementation will processing XML according to the XML specifications without - * regard to possible implementation limits. - *
    • - *
    - * + *

    All implementations are required to support the {@link javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING} feature. + * When the feature is

    + *
      + *
    • + * true: the implementation will limit XML processing to conform to implementation limits. + * Examples include entity expansion limits and XML Schema constructs that would consume large amounts of resources. + * If XML processing is limited for security reasons, it will be reported via a call to the registered + * {@link org.xml.sax.ErrorHandler#fatalError(SAXParseException exception)}. + * See {@link SAXParser} parse methods for handler specification. + *
    • + *
    • + * When the feature is false, the implementation will processing XML according to the XML specifications without + * regard to possible implementation limits. + *
    • + *
    + * * @param name The name of the feature to be set. * @param value The value of the feature to be set. * @@ -320,17 +307,6 @@ SAXNotSupportedException; - - /*

    Get current state of canonicalization.

    - * - * @return current state canonicalization control - */ - /* - public boolean getCanonicalization() { - return canonicalState; - } - */ - /** * Gets the {@link Schema} object specified through * the {@link #setSchema(Schema schema)} method. @@ -357,17 +333,6 @@ ); } - /**

    Set canonicalization control to true or - * false.

    - * - * @param state of canonicalization - */ - /* - public void setCanonicalization(boolean state) { - canonicalState = state; - } - */ - /** *

    Set the {@link Schema} to be used by parsers created * from this factory.

    @@ -400,7 +365,7 @@ * Such configuration will cause a {@link SAXException} * exception when those properties are set on a {@link SAXParser}.

    * - *

    Note for implmentors

    + *

    Note for implementors

    *

    * A parser must be able to work with any {@link Schema} * implementation. However, parsers and schemas are allowed diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/stream/FactoryFinder.java --- a/jaxp/src/javax/xml/stream/FactoryFinder.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/stream/FactoryFinder.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,15 +25,16 @@ package javax.xml.stream; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** - *

    Implements pluggable Datatypes.

    + *

    Implements pluggable streams.

    * *

    This class is duplicated for each JAXP subpackage so keep it in * sync. It is package private for secure class loading.

    @@ -52,19 +53,19 @@ /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + final private static Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties * have been cached. */ - static volatile boolean firstTime = true; + private static volatile boolean firstTime = true; /** * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + final private static SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -103,25 +104,25 @@ try { if (cl == null) { if (useBSClsLoader) { - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { throw e1; @@ -133,6 +134,9 @@ * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -142,16 +146,19 @@ * @param doFallback True if the current ClassLoader should be tried as * a fallback if the class is not found using cl */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError + static T newInstance(Class type, String className, ClassLoader cl, boolean doFallback) + throws FactoryConfigurationError { - return newInstance(className, cl, doFallback, false); + return newInstance(type, className, cl, doFallback, false); } /** * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * + * @param type Base class / Service interface of the factory to + * instantiate. + * * @param className Name of the concrete class corresponding to the * service provider * @@ -164,9 +171,12 @@ * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) - throws ConfigurationError + static T newInstance(Class type, String className, ClassLoader cl, + boolean doFallback, boolean useBSClsLoader) + throws FactoryConfigurationError { + assert type != null; + // make sure we have access to restricted packages if (System.getSecurityManager() != null) { if (className != null && className.startsWith(DEFAULT_PACKAGE)) { @@ -176,20 +186,23 @@ } try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + if (!type.isAssignableFrom(providerClass)) { + throw new ClassCastException(className + " cannot be cast to " + type.getName()); + } Object instance = providerClass.newInstance(); if (debug) { // Extra check to avoid computing cl strings dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); } - return instance; + return type.cast(instance); } catch (ClassNotFoundException x) { - throw new ConfigurationError( + throw new FactoryConfigurationError( "Provider " + className + " not found", x); } catch (Exception x) { - throw new ConfigurationError( + throw new FactoryConfigurationError( "Provider " + className + " could not be instantiated: " + x, x); } @@ -200,17 +213,18 @@ * * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. + * * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws FactoryConfigurationError { - return find(factoryId, null, fallbackClassName); + return find(type, type.getName(), null, fallbackClassName); } /** @@ -218,6 +232,9 @@ * entry point. * @return Class object of factory, never null * + * @param type Base class / Service interface of the + * factory to find. + * * @param factoryId Name of the factory to find, same as * a property name * @@ -229,8 +246,8 @@ * * Package private so this code can be shared. */ - static Object find(String factoryId, ClassLoader cl, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String factoryId, ClassLoader cl, String fallbackClassName) + throws FactoryConfigurationError { dPrint("find factoryId =" + factoryId); @@ -239,7 +256,9 @@ String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true); + // There's a bug here - because 'cl' is ignored. + // This will be handled separately. + return newInstance(type, systemProp, null, true); } } catch (SecurityException se) { @@ -250,7 +269,6 @@ // $java.home/lib/jaxp.properties if former not present String configFile = null; try { - String factoryClassName = null; if (firstTime) { synchronized (cacheProps) { if (firstTime) { @@ -269,130 +287,80 @@ if (ss.doesFileExist(f)) { dPrint("Read properties file "+f); cacheProps.load(ss.getFileInputStream(f)); + } + } } } } - } - } - factoryClassName = cacheProps.getProperty(factoryId); + final String factoryClassName = cacheProps.getProperty(factoryId); if (factoryClassName != null) { dPrint("found in " + configFile + " value=" + factoryClassName); - return newInstance(factoryClassName, null, true); + // There's a bug here - because 'cl' is ignored. + // This will be handled separately. + return newInstance(type, factoryClassName, null, true); } } catch (Exception ex) { if (debug) ex.printStackTrace(); } - // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); - if (provider != null) { - return provider; + if (type.getName().equals(factoryId)) { + // Try Jar Service Provider Mechanism + final T provider = findServiceProvider(type); + if (provider != null) { + return provider; + } + } else { + // We're in the case where a 'custom' factoryId was provided, + // and in every case where that happens, we expect that + // fallbackClassName will be null. + assert fallbackClassName == null; } if (fallbackClassName == null) { - throw new ConfigurationError( + throw new FactoryConfigurationError( "Provider for " + factoryId + " cannot be found", null); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, cl, true); + return newInstance(type, fallbackClassName, cl, true); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader API + * + * @param type Base class / Service interface of the factory to find. * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError - { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; + private static T findServiceProvider(final Class type) { try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; - } - } + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public T run() { + final ServiceLoader serviceLoader = ServiceLoader.load(type); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } + }); + } catch(ServiceConfigurationError e) { + // It is not possible to wrap an error directly in + // FactoryConfigurationError - so we need to wrap the + // ServiceConfigurationError in a RuntimeException. + // The alternative would be to modify the logic in + // FactoryConfigurationError to allow setting a + // Throwable as the cause, but that could cause + // compatibility issues down the road. + final RuntimeException x = new RuntimeException( + "Provider for " + type + " cannot be created", e); + final FactoryConfigurationError error = + new FactoryConfigurationError(x, x.getMessage()); + throw error; + } + } } diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/stream/XMLEventFactory.java --- a/jaxp/src/javax/xml/stream/XMLEventFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/stream/XMLEventFactory.java Mon May 06 11:41:40 2013 -0700 @@ -23,14 +23,14 @@ */ /* - * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved. + * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved. */ package javax.xml.stream; -import javax.xml.stream.events.*; +import java.util.Iterator; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; -import java.util.Iterator; +import javax.xml.stream.events.*; /** * This interface defines a utility class for creating instances of * XMLEvents @@ -54,48 +54,59 @@ /** - * Create a new instance of the factory + * Creates a new instance of the factory in exactly the same manner as the + * {@link #newFactory()} method. * @throws FactoryConfigurationError if an instance of this factory cannot be loaded */ public static XMLEventFactory newInstance() throws FactoryConfigurationError { - return (XMLEventFactory) FactoryFinder.find( - JAXPFACTORYID, - DEFAULIMPL); + return FactoryFinder.find(XMLEventFactory.class, DEFAULIMPL); } /** * Create a new instance of the factory. + *

    * This static method creates a new factory instance. * This method uses the following ordered lookup procedure to determine * the XMLEventFactory implementation class to load: + *

    + *
      + *
    • * Use the javax.xml.stream.XMLEventFactory system property. + *
    • + *
    • * Use the properties file "lib/stax.properties" in the JRE directory. * This configuration file is in standard java.util.Properties format * and contains the fully qualified name of the implementation class * with the key being the system property defined above. - * Use the Services API (as detailed in the JAR specification), if available, - * to determine the classname. The Services API will look for a classname - * in the file META-INF/services/javax.xml.stream.XMLEventFactory in jars - * available to the runtime. - * Platform default XMLEventFactory instance. - * + *
    • + *
    • + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
    • + *
    • + * Otherwise, the system-default implementation is returned. + *
    • + *
    + *

    * Once an application has obtained a reference to a XMLEventFactory it * can use the factory to configure and obtain stream instances. - * + *

    + *

    * Note that this is a new method that replaces the deprecated newInstance() method. * No changes in behavior are defined by this replacement method relative to * the deprecated method. - * - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + *

    + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLEventFactory newFactory() throws FactoryConfigurationError { - return (XMLEventFactory) FactoryFinder.find( - JAXPFACTORYID, - DEFAULIMPL); + return FactoryFinder.find(XMLEventFactory.class, DEFAULIMPL); } /** @@ -116,40 +127,59 @@ public static XMLEventFactory newInstance(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLEventFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLEventFactory.class, factoryId, classLoader, null); } /** * Create a new instance of the factory. * If the classLoader argument is null, then the ContextClassLoader is used. + *

    + * This method uses the following ordered lookup procedure to determine + * the XMLEventFactory implementation class to load: + *

    + *
      + *
    • + * Use the value of the system property identified by {@code factoryId}. + *
    • + *
    • + * Use the properties file "lib/stax.properties" in the JRE directory. + * This configuration file is in standard java.util.Properties format + * and contains the fully qualified name of the implementation class + * with the key being the given {@code factoryId}. + *
    • + *
    • + * If {@code factoryId} is "javax.xml.stream.XMLEventFactory", + * use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
    • + *
    • + * Otherwise, throws a {@link FactoryConfigurationError}. + *
    • + *
    * + *

    * Note that this is a new method that replaces the deprecated - * newInstance(String factoryId, ClassLoader classLoader) method. + * {@link #newInstance(java.lang.String, java.lang.ClassLoader) + * newInstance(String factoryId, ClassLoader classLoader)} method. * No changes in behavior are defined by this replacement method relative * to the deprecated method. + *

    * * @param factoryId Name of the factory to find, same as * a property name * @param classLoader classLoader to use * @return the factory implementation - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLEventFactory newFactory(String factoryId, - ClassLoader classLoader) + ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLEventFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLEventFactory.class, factoryId, classLoader, null); } /** diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/stream/XMLInputFactory.java --- a/jaxp/src/javax/xml/stream/XMLInputFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/stream/XMLInputFactory.java Mon May 06 11:41:40 2013 -0700 @@ -23,13 +23,13 @@ */ /* - * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved. + * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved. */ package javax.xml.stream; +import javax.xml.stream.util.XMLEventAllocator; import javax.xml.transform.Source; -import javax.xml.stream.util.XMLEventAllocator; /** * Defines an abstract implementation of a factory for getting streams. @@ -144,48 +144,59 @@ protected XMLInputFactory(){} /** - * Create a new instance of the factory. + * Creates a new instance of the factory in exactly the same manner as the + * {@link #newFactory()} method. * @throws FactoryConfigurationError if an instance of this factory cannot be loaded */ public static XMLInputFactory newInstance() throws FactoryConfigurationError { - return (XMLInputFactory) FactoryFinder.find( - "javax.xml.stream.XMLInputFactory", - DEFAULIMPL); + return FactoryFinder.find(XMLInputFactory.class, DEFAULIMPL); } /** * Create a new instance of the factory. + *

    * This static method creates a new factory instance. * This method uses the following ordered lookup procedure to determine * the XMLInputFactory implementation class to load: + *

    + *
      + *
    • * Use the javax.xml.stream.XMLInputFactory system property. + *
    • + *
    • * Use the properties file "lib/stax.properties" in the JRE directory. * This configuration file is in standard java.util.Properties format * and contains the fully qualified name of the implementation class * with the key being the system property defined above. - * Use the Services API (as detailed in the JAR specification), if available, - * to determine the classname. The Services API will look for a classname - * in the file META-INF/services/javax.xml.stream.XMLInputFactory in jars - * available to the runtime. - * Platform default XMLInputFactory instance. - * + *
    • + *
    • + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
    • + *
    • + * Otherwise, the system-default implementation is returned. + *
    • + *
    + *

    * Once an application has obtained a reference to a XMLInputFactory it * can use the factory to configure and obtain stream instances. - * + *

    + *

    * Note that this is a new method that replaces the deprecated newInstance() method. * No changes in behavior are defined by this replacement method relative to * the deprecated method. - * - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + *

    + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLInputFactory newFactory() throws FactoryConfigurationError { - return (XMLInputFactory) FactoryFinder.find( - "javax.xml.stream.XMLInputFactory", - DEFAULIMPL); + return FactoryFinder.find(XMLInputFactory.class, DEFAULIMPL); } /** @@ -206,40 +217,60 @@ public static XMLInputFactory newInstance(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null); } /** * Create a new instance of the factory. * If the classLoader argument is null, then the ContextClassLoader is used. + *

    + * This method uses the following ordered lookup procedure to determine + * the XMLInputFactory implementation class to load: + *

    + *
      + *
    • + * Use the value of the system property identified by {@code factoryId}. + *
    • + *
    • + * Use the properties file "lib/stax.properties" in the JRE directory. + * This configuration file is in standard java.util.Properties format + * and contains the fully qualified name of the implementation class + * with the key being the given {@code factoryId}. + *
    • + *
    • + * If {@code factoryId} is "javax.xml.stream.XMLInputFactory", + * use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
    • + *
    • + * Otherwise, throws a {@link FactoryConfigurationError}. + *
    • + *
    * + *

    * Note that this is a new method that replaces the deprecated - * newInstance(String factoryId, ClassLoader classLoader) method. + * {@link #newInstance(java.lang.String, java.lang.ClassLoader) + * newInstance(String factoryId, ClassLoader classLoader)} method. * No changes in behavior are defined by this replacement method relative * to the deprecated method. + *

    * * @param factoryId Name of the factory to find, same as * a property name * @param classLoader classLoader to use * @return the factory implementation + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. * @throws FactoryConfigurationError if an instance of this factory cannot be loaded */ public static XMLInputFactory newFactory(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null); } /** diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/stream/XMLOutputFactory.java --- a/jaxp/src/javax/xml/stream/XMLOutputFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/stream/XMLOutputFactory.java Mon May 06 11:41:40 2013 -0700 @@ -23,7 +23,7 @@ */ /* - * Copyright (c) 2009 by Oracle Corporation. All Rights Reserved. + * Copyright (c) 2009, 2013, by Oracle Corporation. All Rights Reserved. */ package javax.xml.stream; @@ -120,46 +120,58 @@ protected XMLOutputFactory(){} /** - * Create a new instance of the factory. + * Creates a new instance of the factory in exactly the same manner as the + * {@link #newFactory()} method. * @throws FactoryConfigurationError if an instance of this factory cannot be loaded */ public static XMLOutputFactory newInstance() throws FactoryConfigurationError { - return (XMLOutputFactory) FactoryFinder.find("javax.xml.stream.XMLOutputFactory", - DEFAULIMPL); + return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL); } /** * Create a new instance of the factory. + *

    * This static method creates a new factory instance. This method uses the * following ordered lookup procedure to determine the XMLOutputFactory * implementation class to load: + *

    + *
      + *
    • * Use the javax.xml.stream.XMLOutputFactory system property. + *
    • + *
    • * Use the properties file "lib/stax.properties" in the JRE directory. * This configuration file is in standard java.util.Properties format * and contains the fully qualified name of the implementation class * with the key being the system property defined above. - * Use the Services API (as detailed in the JAR specification), if available, - * to determine the classname. The Services API will look for a classname - * in the file META-INF/services/javax.xml.stream.XMLOutputFactory in jars - * available to the runtime. - * Platform default XMLOutputFactory instance. - * + *
    • + *
    • + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
    • + *
    • + * Otherwise, the system-default implementation is returned. + *
    • + *

      * Once an application has obtained a reference to a XMLOutputFactory it * can use the factory to configure and obtain stream instances. - * + *

      + *

      * Note that this is a new method that replaces the deprecated newInstance() method. * No changes in behavior are defined by this replacement method relative to the * deprecated method. - * - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + *

      + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLOutputFactory newFactory() throws FactoryConfigurationError { - return (XMLOutputFactory) FactoryFinder.find("javax.xml.stream.XMLOutputFactory", - DEFAULIMPL); + return FactoryFinder.find(XMLOutputFactory.class, DEFAULIMPL); } /** @@ -179,42 +191,59 @@ public static XMLInputFactory newInstance(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLInputFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLInputFactory.class, factoryId, classLoader, null); } /** * Create a new instance of the factory. * If the classLoader argument is null, then the ContextClassLoader is used. - * - * Note that this is a new method that replaces the deprecated - * newInstance(String factoryId, ClassLoader classLoader) method. + *

      + * This method uses the following ordered lookup procedure to determine + * the XMLOutputFactory implementation class to load: + *

      + *
        + *
      • + * Use the value of the system property identified by {@code factoryId}. + *
      • + *
      • + * Use the properties file "lib/stax.properties" in the JRE directory. + * This configuration file is in standard java.util.Properties format + * and contains the fully qualified name of the implementation class + * with the key being the given {@code factoryId}. + *
      • + *
      • + * If {@code factoryId} is "javax.xml.stream.XMLOutputFactory", + * use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
      • + *
      • + * Otherwise, throws a {@link FactoryConfigurationError}. + *
      • + *
      * - * No changes in behavior are defined by this replacement method relative - * to the deprecated method. - * + *

      + * Note that this is a new method that replaces the deprecated + * {@link #newInstance(java.lang.String, java.lang.ClassLoader) + * newInstance(String factoryId, ClassLoader classLoader)} method. + * No changes in behavior are defined by this replacement method relative + * to the deprecated method. + *

      * * @param factoryId Name of the factory to find, same as * a property name * @param classLoader classLoader to use * @return the factory implementation - * @throws FactoryConfigurationError if an instance of this factory cannot be loaded + * @throws FactoryConfigurationError in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static XMLOutputFactory newFactory(String factoryId, ClassLoader classLoader) throws FactoryConfigurationError { - try { - //do not fallback if given classloader can't find the class, throw exception - return (XMLOutputFactory) FactoryFinder.find(factoryId, classLoader, null); - } catch (FactoryFinder.ConfigurationError e) { - throw new FactoryConfigurationError(e.getException(), - e.getMessage()); - } + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.find(XMLOutputFactory.class, factoryId, classLoader, null); } /** diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/transform/FactoryFinder.java --- a/jaxp/src/javax/xml/transform/FactoryFinder.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/transform/FactoryFinder.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,15 @@ package javax.xml.transform; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Iterator; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** *

      Implements pluggable Datatypes.

      @@ -53,7 +55,7 @@ /** * Cache for properties in java.home/lib/jaxp.properties */ - static Properties cacheProps = new Properties(); + private final static Properties cacheProps = new Properties(); /** * Flag indicating if properties from java.home/lib/jaxp.properties @@ -65,7 +67,7 @@ * Security support class use to check access control before * getting certain system resources. */ - static SecuritySupport ss = new SecuritySupport(); + private final static SecuritySupport ss = new SecuritySupport(); // Define system property "jaxp.debug" to get output static { @@ -98,31 +100,31 @@ * * Use bootstrap classLoader if cl = null and useBSClsLoader is true */ - static private Class getProviderClass(String className, ClassLoader cl, + static private Class getProviderClass(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader) throws ClassNotFoundException { try { if (cl == null) { if (useBSClsLoader) { - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { cl = ss.getContextClassLoader(); if (cl == null) { throw new ClassNotFoundException(); } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } } else { - return cl.loadClass(className); + return Class.forName(className, false, cl); } } catch (ClassNotFoundException e1) { if (doFallback) { // Use current class loader - should always be bootstrap CL - return Class.forName(className, true, FactoryFinder.class.getClassLoader()); + return Class.forName(className, false, FactoryFinder.class.getClassLoader()); } else { throw e1; @@ -134,24 +136,8 @@ * Create an instance of a class. Delegates to method * getProviderClass() in order to load the class. * - * @param className Name of the concrete class corresponding to the - * service provider - * - * @param cl ClassLoader used to load the factory class. If null - * current Thread's context classLoader is used to load the factory class. - * - * @param doFallback True if the current ClassLoader should be tried as - * a fallback if the class is not found using cl - */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback) - throws ConfigurationError - { - return newInstance(className, cl, doFallback, false, false); - } - - /** - * Create an instance of a class. Delegates to method - * getProviderClass() in order to load the class. + * @param type Base class / Service interface of the factory to + * instantiate. * * @param className Name of the concrete class corresponding to the * service provider @@ -162,14 +148,15 @@ * @param doFallback True if the current ClassLoader should be tried as * a fallback if the class is not found using cl * - * @param useBSClsLoader True if cl=null actually meant bootstrap classLoader. This parameter - * is needed since DocumentBuilderFactory/SAXParserFactory defined null as context classLoader. - * * @param useServicesMechanism True use services mechanism */ - static Object newInstance(String className, ClassLoader cl, boolean doFallback, boolean useBSClsLoader, boolean useServicesMechanism) - throws ConfigurationError + static T newInstance(Class type, String className, ClassLoader cl, + boolean doFallback, boolean useServicesMechanism) + throws TransformerFactoryConfigurationError { + assert type != null; + + boolean useBSClsLoader = false; // make sure we have access to restricted packages if (System.getSecurityManager() != null) { if (className != null && className.startsWith(DEFAULT_PACKAGE)) { @@ -179,10 +166,13 @@ } try { - Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + Class providerClass = getProviderClass(className, cl, doFallback, useBSClsLoader); + if (!type.isAssignableFrom(providerClass)) { + throw new ClassCastException(className + " cannot be cast to " + type.getName()); + } Object instance = null; if (!useServicesMechanism) { - instance = newInstanceNoServiceLoader(providerClass); + instance = newInstanceNoServiceLoader(type, providerClass); } if (instance == null) { instance = providerClass.newInstance(); @@ -191,63 +181,87 @@ dPrint("created new instance of " + providerClass + " using ClassLoader: " + cl); } - return instance; + return type.cast(instance); } catch (ClassNotFoundException x) { - throw new ConfigurationError( - "Provider " + className + " not found", x); + throw new TransformerFactoryConfigurationError(x, + "Provider " + className + " not found"); } catch (Exception x) { - throw new ConfigurationError( - "Provider " + className + " could not be instantiated: " + x, - x); + throw new TransformerFactoryConfigurationError(x, + "Provider " + className + " could not be instantiated: " + x); } } + /** * Try to construct using newTransformerFactoryNoServiceLoader * method if available. */ - private static Object newInstanceNoServiceLoader( - Class providerClass - ) { + private static T newInstanceNoServiceLoader(Class type, Class providerClass) { // Retain maximum compatibility if no security manager. if (System.getSecurityManager() == null) { return null; } try { - Method creationMethod = - providerClass.getDeclaredMethod( - "newTransformerFactoryNoServiceLoader" - ); - return creationMethod.invoke(null, (Object[])null); - } catch (NoSuchMethodException exc) { + final Method creationMethod = + providerClass.getDeclaredMethod( + "newTransformerFactoryNoServiceLoader" + ); + final int modifiers = creationMethod.getModifiers(); + + // Do not call the method if it's not public static. + if (!Modifier.isPublic(modifiers) || !Modifier.isStatic(modifiers)) { return null; - } catch (Exception exc) { - return null; + } + + // Only call the method if it's declared to return an instance of + // TransformerFactory + final Class returnType = creationMethod.getReturnType(); + if (type.isAssignableFrom(returnType)) { + final Object result = creationMethod.invoke(null, (Object[])null); + return type.cast(result); + } else { + // This should not happen, as + // TransformerFactoryImpl.newTransformerFactoryNoServiceLoader is + // declared to return TransformerFactory. + throw new ClassCastException(returnType + " cannot be cast to " + type); + } + } catch (ClassCastException e) { + throw new TransformerFactoryConfigurationError(e, e.getMessage()); + } catch (NoSuchMethodException exc) { + return null; + } catch (Exception exc) { + return null; } } + /** * Finds the implementation Class object in the specified order. Main * entry point. * @return Class object of factory, never null * - * @param factoryId Name of the factory to find, same as - * a property name + * @param type Base class / Service interface of the + * factory to find. + * * @param fallbackClassName Implementation class name, if nothing else * is found. Use null to mean no fallback. * * Package private so this code can be shared. */ - static Object find(String factoryId, String fallbackClassName) - throws ConfigurationError + static T find(Class type, String fallbackClassName) + throws TransformerFactoryConfigurationError { + assert type != null; + + final String factoryId = type.getName(); + dPrint("find factoryId =" + factoryId); // Use the system property first try { String systemProp = ss.getSystemProperty(factoryId); if (systemProp != null) { dPrint("found system property, value=" + systemProp); - return newInstance(systemProp, null, true, false, true); + return newInstance(type, systemProp, null, true, true); } } catch (SecurityException se) { @@ -256,7 +270,6 @@ // try to read from $java.home/lib/jaxp.properties try { - String factoryClassName = null; if (firstTime) { synchronized (cacheProps) { if (firstTime) { @@ -271,11 +284,11 @@ } } } - factoryClassName = cacheProps.getProperty(factoryId); + final String factoryClassName = cacheProps.getProperty(factoryId); if (factoryClassName != null) { dPrint("found in $java.home/jaxp.properties, value=" + factoryClassName); - return newInstance(factoryClassName, null, true, false, true); + return newInstance(type, factoryClassName, null, true, true); } } catch (Exception ex) { @@ -283,113 +296,54 @@ } // Try Jar Service Provider Mechanism - Object provider = findJarServiceProvider(factoryId); + T provider = findServiceProvider(type); if (provider != null) { return provider; } if (fallbackClassName == null) { - throw new ConfigurationError( - "Provider for " + factoryId + " cannot be found", null); + throw new TransformerFactoryConfigurationError(null, + "Provider for " + factoryId + " cannot be found"); } dPrint("loaded from fallback value: " + fallbackClassName); - return newInstance(fallbackClassName, null, true, false, true); + return newInstance(type, fallbackClassName, null, true, true); } /* - * Try to find provider using Jar Service Provider Mechanism + * Try to find provider using the ServiceLoader. + * + * @param type Base class / Service interface of the factory to find. * * @return instance of provider class if found or null */ - private static Object findJarServiceProvider(String factoryId) - throws ConfigurationError + private static T findServiceProvider(final Class type) + throws TransformerFactoryConfigurationError { - String serviceId = "META-INF/services/" + factoryId; - InputStream is = null; - - // First try the Context ClassLoader - ClassLoader cl = ss.getContextClassLoader(); - boolean useBSClsLoader = false; - if (cl != null) { - is = ss.getResourceAsStream(cl, serviceId); - - // If no provider found then try the current ClassLoader - if (is == null) { - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - } else { - // No Context ClassLoader, try the current ClassLoader - cl = FactoryFinder.class.getClassLoader(); - is = ss.getResourceAsStream(cl, serviceId); - useBSClsLoader = true; - } - - if (is == null) { - // No provider found - return null; - } - - if (debug) { // Extra check to avoid computing cl strings - dPrint("found jar resource=" + serviceId + " using ClassLoader: " + cl); - } - - BufferedReader rd; - try { - rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } - catch (java.io.UnsupportedEncodingException e) { - rd = new BufferedReader(new InputStreamReader(is)); - } - - String factoryClassName = null; - try { - // XXX Does not handle all possible input as specified by the - // Jar Service Provider specification - factoryClassName = rd.readLine(); - rd.close(); - } catch (IOException x) { - // No provider found - return null; - } - - if (factoryClassName != null && !"".equals(factoryClassName)) { - dPrint("found in resource, value=" + factoryClassName); - - // Note: here we do not want to fall back to the current - // ClassLoader because we want to avoid the case where the - // resource file was found using one ClassLoader and the - // provider class was instantiated using a different one. - return newInstance(factoryClassName, cl, false, useBSClsLoader, true); - } - - // No provider found - return null; - } - - static class ConfigurationError extends Error { - private Exception exception; - - /** - * Construct a new instance with the specified detail string and - * exception. - */ - ConfigurationError(String msg, Exception x) { - super(msg); - this.exception = x; - } - - Exception getException() { - return exception; - } - /** - * use the exception chaining mechanism of JDK1.4 - */ - @Override - public Throwable getCause() { - return exception; + try { + return AccessController.doPrivileged(new PrivilegedAction() { + public T run() { + final ServiceLoader serviceLoader = ServiceLoader.load(type); + final Iterator iterator = serviceLoader.iterator(); + if (iterator.hasNext()) { + return iterator.next(); + } else { + return null; + } + } + }); + } catch(ServiceConfigurationError e) { + // It is not possible to wrap an error directly in + // FactoryConfigurationError - so we need to wrap the + // ServiceConfigurationError in a RuntimeException. + // The alternative would be to modify the logic in + // FactoryConfigurationError to allow setting a + // Throwable as the cause, but that could cause + // compatibility issues down the road. + final RuntimeException x = new RuntimeException( + "Provider for " + type + " cannot be created", e); + final TransformerFactoryConfigurationError error = + new TransformerFactoryConfigurationError(x, x.getMessage()); + throw error; } } - } diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/transform/TransformerFactory.java --- a/jaxp/src/javax/xml/transform/TransformerFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/transform/TransformerFactory.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,8 +52,8 @@ /** *

      Obtain a new instance of a TransformerFactory. - * This static method creates a new factory instance - * This method uses the following ordered lookup procedure to determine + * This static method creates a new factory instance.

      + *

      This method uses the following ordered lookup procedure to determine * the TransformerFactory implementation class to * load:

      *
        @@ -67,7 +67,7 @@ * format and contains the fully qualified name of the * implementation class with the key being the system property defined * above. - * + *
        * The jaxp.properties file is read only once by the JAXP implementation * and it's values are then cached for future use. If the file does not exist * when the first attempt is made to read from it, no further attempts are @@ -75,14 +75,12 @@ * of any property in jaxp.properties after it has been read for the first time. * *
      • - * Use the Services API (as detailed in the JAR specification), if - * available, to determine the classname. The Services API will look - * for a classname in the file - * META-INF/services/javax.xml.transform.TransformerFactory - * in jars available to the runtime. + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. *
      • *
      • - * Platform default TransformerFactory instance. + * Otherwise, the system-default implementation is returned. *
      • *
      * @@ -92,22 +90,18 @@ * * @return new TransformerFactory instance, never null. * - * @throws TransformerFactoryConfigurationError Thrown if the implementation - * is not available or cannot be instantiated. + * @throws TransformerFactoryConfigurationError Thrown in case of {@linkplain + * java.util.ServiceConfigurationError service configuration error} or if + * the implementation is not available or cannot be instantiated. */ public static TransformerFactory newInstance() throws TransformerFactoryConfigurationError { - try { - return (TransformerFactory) FactoryFinder.find( + + return FactoryFinder.find( /* The default property name according to the JAXP spec */ - "javax.xml.transform.TransformerFactory", + TransformerFactory.class, /* The fallback implementation class name, XSLTC */ "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); - } catch (FactoryFinder.ConfigurationError e) { - throw new TransformerFactoryConfigurationError( - e.getException(), - e.getMessage()); - } } /** @@ -147,14 +141,10 @@ */ public static TransformerFactory newInstance(String factoryClassName, ClassLoader classLoader) throws TransformerFactoryConfigurationError{ - try { - //do not fallback if given classloader can't find the class, throw exception - return (TransformerFactory) FactoryFinder.newInstance(factoryClassName, classLoader, false); - } catch (FactoryFinder.ConfigurationError e) { - throw new TransformerFactoryConfigurationError( - e.getException(), - e.getMessage()); - } + + //do not fallback if given classloader can't find the class, throw exception + return FactoryFinder.newInstance(TransformerFactory.class, + factoryClassName, classLoader, false, false); } /** *

      Process the Source into a Transformer diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/validation/SchemaFactory.java --- a/jaxp/src/javax/xml/validation/SchemaFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/validation/SchemaFactory.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,15 +27,14 @@ import java.io.File; import java.net.URL; - import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; - import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; /** * Factory that creates {@link Schema} objects. Entry-point to @@ -79,7 +78,7 @@ * and has a significant effect on the parsing process, it is impossible * to define the DTD validation as a process independent from parsing. * For this reason, this specification does not define the semantics for - * the XML DTD. This doesn't prohibit implentors from implementing it + * the XML DTD. This doesn't prohibit implementors from implementing it * in a way they see fit, but users are warned that any DTD * validation implemented on this interface necessarily deviate from * the XML DTD semantics as defined in the XML 1.0. @@ -147,14 +146,17 @@ * is looked for. If present, the value is processed just like above. * *

    • - *

      The class loader is asked for service provider provider-configuration files matching - * javax.xml.validation.SchemaFactory in the resource directory META-INF/services. - * See the JAR File Specification for file format and parsing rules. - * Each potential service provider is required to implement the method:

      - *
      -     *        {@link #isSchemaLanguageSupported(String schemaLanguage)}
      -     *     
      - * The first service provider found in class loader order that supports the specified schema language is returned. + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service.
      + * Each potential service provider is required to implement the method + * {@link #isSchemaLanguageSupported(String schemaLanguage)}. + *
      + * The first service provider found that supports the specified schema + * language is returned. + *
      + * In case of {@link java.util.ServiceConfigurationError} a + * {@link SchemaFactoryConfigurationError} will be thrown. *
    • *
    • * Platform default SchemaFactory is located @@ -186,10 +188,12 @@ * If no implementation of the schema language is available. * @throws NullPointerException * If the schemaLanguage parameter is null. + * @throws SchemaFactoryConfigurationError + * If a configuration error is encountered. * * @see #newInstance(String schemaLanguage, String factoryClassName, ClassLoader classLoader) */ - public static final SchemaFactory newInstance(String schemaLanguage) { + public static SchemaFactory newInstance(String schemaLanguage) { ClassLoader cl; cl = ss.getContextClassLoader(); @@ -275,19 +279,19 @@ } - /** - *

      Is specified schema supported by this SchemaFactory?

      - * - * @param schemaLanguage Specifies the schema language which the returned SchemaFactory will understand. + /** + *

      Is specified schema supported by this SchemaFactory?

      + * + * @param schemaLanguage Specifies the schema language which the returned SchemaFactory will understand. * schemaLanguage must specify a valid schema language. - * - * @return true if SchemaFactory supports schemaLanguage, else false. - * - * @throws NullPointerException If schemaLanguage is null. - * @throws IllegalArgumentException If schemaLanguage.length() == 0 - * or schemaLanguage does not specify a valid schema language. - */ - public abstract boolean isSchemaLanguageSupported(String schemaLanguage); + * + * @return true if SchemaFactory supports schemaLanguage, else false. + * + * @throws NullPointerException If schemaLanguage is null. + * @throws IllegalArgumentException If schemaLanguage.length() == 0 + * or schemaLanguage does not specify a valid schema language. + */ + public abstract boolean isSchemaLanguageSupported(String schemaLanguage); /** * Look up the value of a feature flag. diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/validation/SchemaFactoryConfigurationError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/javax/xml/validation/SchemaFactoryConfigurationError.java Mon May 06 11:41:40 2013 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.xml.validation; + +/** + * Thrown when a problem with configuration with the Schema Factories + * exists. This error will typically be thrown when the class of a + * schema factory specified in the system properties cannot be found + * or instantiated. + * @since 1.8 + */ +public final class SchemaFactoryConfigurationError extends Error { + + static final long serialVersionUID = 3531438703147750126L; + + /** + * Create a new SchemaFactoryConfigurationError with no + * detail message. + */ + public SchemaFactoryConfigurationError() { + } + + + /** + * Create a new SchemaFactoryConfigurationError with + * the String specified as an error message. + * + * @param message The error message for the exception. + */ + public SchemaFactoryConfigurationError(String message) { + super(message); + } + + /** + * Create a new SchemaFactoryConfigurationError with the + * given Throwable base cause. + * + * @param cause The exception or error to be encapsulated in a + * SchemaFactoryConfigurationError. + */ + public SchemaFactoryConfigurationError(Throwable cause) { + super(cause); + } + + /** + * Create a new SchemaFactoryConfigurationError with the + * given Throwable base cause and detail message. + * + * @param cause The exception or error to be encapsulated in a + * SchemaFactoryConfigurationError. + * @param message The detail message. + */ + public SchemaFactoryConfigurationError(String message, Throwable cause) { + super(message, cause); + } + +} diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/validation/SchemaFactoryFinder.java --- a/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/validation/SchemaFactoryFinder.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,19 +25,16 @@ package javax.xml.validation; -import java.io.BufferedReader; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.NoSuchElementException; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** * Implementation of {@link SchemaFactory#newInstance(String)}. @@ -53,17 +50,17 @@ /** *

      Take care of restrictions imposed by java security model

      */ - private static SecuritySupport ss = new SecuritySupport(); + private static final SecuritySupport ss = new SecuritySupport(); private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xerces.internal"; /** *

      Cache properties for performance.

      */ - private static Properties cacheProps = new Properties(); + private static final Properties cacheProps = new Properties(); - /** - *

      First time requires initialization overhead.

      - */ - private static volatile boolean firstTime = true; + /** + *

      First time requires initialization overhead.

      + */ + private static volatile boolean firstTime = true; static { // Use try/catch block to support applets @@ -115,7 +112,7 @@ return; } } catch( Throwable unused ) { - ; // getContextClassLoader() undefined in JDK1.1 + // getContextClassLoader() undefined in JDK1.1 } if( classLoader==ClassLoader.getSystemClassLoader() ) { @@ -138,9 +135,13 @@ * * @throws NullPointerException * If the schemaLanguage parameter is null. + * @throws SchemaFactoryConfigurationError + * If a configuration error is encountered. */ public SchemaFactory newFactory(String schemaLanguage) { - if(schemaLanguage==null) throw new NullPointerException(); + if(schemaLanguage==null) { + throw new NullPointerException(); + } SchemaFactory f = _newFactory(schemaLanguage); if (f != null) { debugPrintln("factory '" + f.getClass().getName() + "' was found for " + schemaLanguage); @@ -183,7 +184,6 @@ String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties"; - String factoryClassName = null ; // try to read from $java.home/lib/jaxp.properties try { @@ -199,7 +199,7 @@ } } } - factoryClassName = cacheProps.getProperty(propertyName); + final String factoryClassName = cacheProps.getProperty(propertyName); debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); if (factoryClassName != null) { @@ -214,21 +214,15 @@ } } - // try META-INF/services files - Iterator sitr = createServiceFileIterator(); - while(sitr.hasNext()) { - URL resource = (URL)sitr.next(); - debugPrintln("looking into " + resource); - try { - sf = loadFromService(schemaLanguage,resource.toExternalForm(), - ss.getURLInputStream(resource)); - if(sf!=null) return sf; - } catch(IOException e) { - if( debug ) { - debugPrintln("failed to read "+resource); - e.printStackTrace(); - } - } + // Try with ServiceLoader + final SchemaFactory factoryImpl = findServiceProvider(schemaLanguage); + + // The following assertion should always be true. + // Uncomment it, recompile, and run with -ea in case of doubts: + // assert factoryImpl == null || factoryImpl.isSchemaLanguageSupported(schemaLanguage); + + if (factoryImpl != null) { + return factoryImpl; } // platform default @@ -246,8 +240,8 @@ * @param className Name of class to create. * @return Created class or null. */ - private Class createClass(String className) { - Class clazz; + private Class createClass(String className) { + Class clazz; // make sure we have access to restricted packages boolean internal = false; if (System.getSecurityManager() != null) { @@ -256,25 +250,27 @@ } } - try { - if (classLoader != null && !internal) { - clazz = classLoader.loadClass(className); - } else { - clazz = Class.forName(className); - } - } catch (Throwable t) { - if(debug) t.printStackTrace(); - return null; + try { + if (classLoader != null && !internal) { + clazz = Class.forName(className, false, classLoader); + } else { + clazz = Class.forName(className); } + } catch (Throwable t) { + if(debug) { + t.printStackTrace(); + } + return null; + } - return clazz; + return clazz; } /** *

      Creates an instance of the specified and returns it.

      * * @param className - * fully qualified class name to be instanciated. + * fully qualified class name to be instantiated. * * @return null * if it fails. Error messages will be printed by this method. @@ -289,7 +285,7 @@ debugPrintln("createInstance(" + className + ")"); // get Class from className - Class clazz = createClass(className); + Class clazz = createClass(className); if (clazz == null) { debugPrintln("failed to getClass(" + className + ")"); return null; @@ -298,9 +294,13 @@ // instantiate Class as a SchemaFactory try { - if (!useServicesMechanism) { - schemaFactory = (SchemaFactory) newInstanceNoServiceLoader(clazz); - } + if (!SchemaFactory.class.isAssignableFrom(clazz)) { + throw new ClassCastException(clazz.getName() + + " cannot be cast to " + SchemaFactory.class); + } + if (!useServicesMechanism) { + schemaFactory = newInstanceNoServiceLoader(clazz); + } if (schemaFactory == null) { schemaFactory = (SchemaFactory) clazz.newInstance(); } @@ -326,11 +326,12 @@ return schemaFactory; } + /** - * Try to construct using newTransformerFactoryNoServiceLoader + * Try to construct using newXMLSchemaFactoryNoServiceLoader * method if available. */ - private static Object newInstanceNoServiceLoader( + private static SchemaFactory newInstanceNoServiceLoader( Class providerClass ) { // Retain maximum compatibility if no security manager. @@ -338,196 +339,87 @@ return null; } try { - Method creationMethod = + final Method creationMethod = providerClass.getDeclaredMethod( "newXMLSchemaFactoryNoServiceLoader" ); - return creationMethod.invoke(null, (Object[])null); - } catch (NoSuchMethodException exc) { - return null; - } catch (Exception exc) { - return null; - } - } + final int modifiers = creationMethod.getModifiers(); - /** Iterator that lazily computes one value and returns it. */ - private static abstract class SingleIterator implements Iterator { - private boolean seen = false; - - public final void remove() { throw new UnsupportedOperationException(); } - public final boolean hasNext() { return !seen; } - public final Object next() { - if(seen) throw new NoSuchElementException(); - seen = true; - return value(); - } + // Do not call the method if it's not public static. + if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) { + return null; + } - protected abstract Object value(); - } - - /** - * Looks up a value in a property file - * while producing all sorts of debug messages. - * - * @return null - * if there was an error. - */ - private SchemaFactory loadFromProperty( String keyName, String resourceName, InputStream in ) - throws IOException { - debugPrintln("Reading "+resourceName ); - - Properties props=new Properties(); - props.load(in); - in.close(); - String factoryClassName = props.getProperty(keyName); - if(factoryClassName != null){ - debugPrintln("found "+keyName+" = " + factoryClassName); - return createInstance(factoryClassName); - } else { - debugPrintln(keyName+" is not in the property file"); + // Only calls "newXMLSchemaFactoryNoServiceLoader" if it's + // declared to return an instance of SchemaFactory. + final Class returnType = creationMethod.getReturnType(); + if (SERVICE_CLASS.isAssignableFrom(returnType)) { + return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null)); + } else { + // Should not happen since + // XMLSchemaFactory.newXMLSchemaFactoryNoServiceLoader is + // declared to return XMLSchemaFactory. + throw new ClassCastException(returnType + + " cannot be cast to " + SERVICE_CLASS); + } + } catch(ClassCastException e) { + throw new SchemaFactoryConfigurationError(e.getMessage(), e); + } catch (NoSuchMethodException exc) { + return null; + } catch (Exception exc) { return null; } } - /** - *

      Look up a value in a property file.

      - * - *

      Set debug to true to trace property evaluation.

      - * - * @param schemaLanguage Schema Language to support. - * @param inputName Name of InputStream. - * @param in InputStream of properties. - * - * @return SchemaFactory as determined by keyName value or null if there was an error. - * - * @throws IOException If IO error reading from in. - */ - private SchemaFactory loadFromService( - String schemaLanguage, - String inputName, - InputStream in) - throws IOException { - - SchemaFactory schemaFactory = null; - final Class[] stringClassArray = {"".getClass()}; - final Object[] schemaLanguageObjectArray = {schemaLanguage}; - final String isSchemaLanguageSupportedMethod = "isSchemaLanguageSupported"; - - debugPrintln("Reading " + inputName); - - // read from InputStream until a match is found - BufferedReader configFile = new BufferedReader(new InputStreamReader(in)); - String line = null; - while ((line = configFile.readLine()) != null) { - // '#' is comment char - int comment = line.indexOf("#"); - switch (comment) { - case -1: break; // no comment - case 0: line = ""; break; // entire line is a comment - default: line = line.substring(0, comment); break; // trim comment - } - - // trim whitespace - line = line.trim(); - - // any content left on line? - if (line.length() == 0) { - continue; - } - - // line content is now the name of the class - Class clazz = createClass(line); - if (clazz == null) { - continue; - } - - // create an instance of the Class - try { - schemaFactory = (SchemaFactory) clazz.newInstance(); - } catch (ClassCastException classCastExcpetion) { - schemaFactory = null; - continue; - } catch (InstantiationException instantiationException) { - schemaFactory = null; - continue; - } catch (IllegalAccessException illegalAccessException) { - schemaFactory = null; - continue; - } - - // does this Class support desired Schema? - try { - Method isSchemaLanguageSupported = clazz.getMethod(isSchemaLanguageSupportedMethod, stringClassArray); - Boolean supported = (Boolean) isSchemaLanguageSupported.invoke(schemaFactory, schemaLanguageObjectArray); - if (supported.booleanValue()) { - break; - } - } catch (NoSuchMethodException noSuchMethodException) { - - } catch (IllegalAccessException illegalAccessException) { - - } catch (InvocationTargetException invocationTargetException) { - - } - schemaFactory = null; + // Call isSchemaLanguageSupported with initial context. + private boolean isSchemaLanguageSupportedBy(final SchemaFactory factory, + final String schemaLanguage, + AccessControlContext acc) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return factory.isSchemaLanguageSupported(schemaLanguage); } - - // clean up - configFile.close(); - - // return new instance of SchemaFactory or null - return schemaFactory; + }, acc); } /** - * Returns an {@link Iterator} that enumerates all - * the META-INF/services files that we care. + * Finds a service provider subclass of SchemaFactory that supports the + * given schema language using the ServiceLoader. + * + * @param schemaLanguage The schema language for which we seek a factory. + * @return A SchemaFactory supporting the specified schema language, or null + * if none is found. + * @throws SchemaFactoryConfigurationError if a configuration error is found. */ - private Iterator createServiceFileIterator() { - if (classLoader == null) { - return new SingleIterator() { - protected Object value() { - ClassLoader classLoader = SchemaFactoryFinder.class.getClassLoader(); - //return (ClassLoader.getSystemResource( SERVICE_ID )); - return ss.getResourceAsURL(classLoader, SERVICE_ID); - } - }; - } else { - try { - //final Enumeration e = classLoader.getResources(SERVICE_ID); - final Enumeration e = ss.getResources(classLoader, SERVICE_ID); - if(!e.hasMoreElements()) { - debugPrintln("no "+SERVICE_ID+" file was found"); + private SchemaFactory findServiceProvider(final String schemaLanguage) { + assert schemaLanguage != null; + // store current context. + final AccessControlContext acc = AccessController.getContext(); + try { + return AccessController.doPrivileged(new PrivilegedAction() { + public SchemaFactory run() { + final ServiceLoader loader = + ServiceLoader.load(SERVICE_CLASS); + for (SchemaFactory factory : loader) { + // restore initial context to call + // factory.isSchemaLanguageSupported + if (isSchemaLanguageSupportedBy(factory, schemaLanguage, acc)) { + return factory; + } + } + return null; // no factory found. } - - // wrap it into an Iterator. - return new Iterator() { - public void remove() { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() { - return e.hasMoreElements(); - } - - public Object next() { - return e.nextElement(); - } - }; - } catch (IOException e) { - debugPrintln("failed to enumerate resources "+SERVICE_ID); - if(debug) e.printStackTrace(); - return new ArrayList().iterator(); // empty iterator - } + }); + } catch (ServiceConfigurationError error) { + throw new SchemaFactoryConfigurationError( + "Provider for " + SERVICE_CLASS + " cannot be created", error); } } - private static final Class SERVICE_CLASS = SchemaFactory.class; - private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName(); + private static final Class SERVICE_CLASS = SchemaFactory.class; - - private static String which( Class clazz ) { + private static String which( Class clazz ) { return which( clazz.getName(), clazz.getClassLoader() ); } diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/xpath/XPathFactory.java --- a/jaxp/src/javax/xml/xpath/XPathFactory.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/xpath/XPathFactory.java Mon May 06 11:41:40 2013 -0700 @@ -90,7 +90,7 @@ * @throws RuntimeException When there is a failure in creating an * XPathFactory for the default object model. */ - public static final XPathFactory newInstance() { + public static XPathFactory newInstance() { try { return newInstance(DEFAULT_OBJECT_MODEL_URI); @@ -121,14 +121,17 @@ * If present, the value is processed just like above. *
    • *
    • - * The class loader is asked for service provider provider-configuration files matching javax.xml.xpath.XPathFactory - * in the resource directory META-INF/services. - * See the JAR File Specification for file format and parsing rules. - * Each potential service provider is required to implement the method: - *
      -    *       {@link #isObjectModelSupported(String objectModel)}
      -    *     
      - * The first service provider found in class loader order that supports the specified object model is returned. + * Use the service-provider loading facilities, defined by the + * {@link java.util.ServiceLoader} class, to attempt to locate and load an + * implementation of the service. + *
      + * Each potential service provider is required to implement the method + * {@link #isObjectModelSupported(String objectModel)}. + * The first service provider found that supports the specified object + * model is returned. + *
      + * In case of {@link java.util.ServiceConfigurationError} an + * {@link XPathFactoryConfigurationException} will be thrown. *
    • *
    • * Platform default XPathFactory is located in a platform specific way. @@ -152,43 +155,41 @@ * * @return Instance of an XPathFactory. * - * @throws XPathFactoryConfigurationException If the specified object model is unavailable. + * @throws XPathFactoryConfigurationException If the specified object model + * is unavailable, or if there is a configuration error. * @throws NullPointerException If uri is null. - * @throws IllegalArgumentException If uri is null + * @throws IllegalArgumentException If uri is null * or uri.length() == 0. */ - public static final XPathFactory newInstance(final String uri) + public static XPathFactory newInstance(final String uri) throws XPathFactoryConfigurationException { if (uri == null) { - throw new NullPointerException( - "XPathFactory#newInstance(String uri) cannot be called with uri == null" - ); + throw new NullPointerException( + "XPathFactory#newInstance(String uri) cannot be called with uri == null"); } - if (uri.length() == 0) { - throw new IllegalArgumentException( - "XPathFactory#newInstance(String uri) cannot be called with uri == \"\"" - ); - } + if (uri.length() == 0) { + throw new IllegalArgumentException( + "XPathFactory#newInstance(String uri) cannot be called with uri == \"\""); + } - ClassLoader classLoader = ss.getContextClassLoader(); + ClassLoader classLoader = ss.getContextClassLoader(); if (classLoader == null) { //use the current class loader classLoader = XPathFactory.class.getClassLoader(); } - XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri); + XPathFactory xpathFactory = new XPathFactoryFinder(classLoader).newFactory(uri); - if (xpathFactory == null) { - throw new XPathFactoryConfigurationException( - "No XPathFactory implementation found for the object model: " - + uri - ); - } + if (xpathFactory == null) { + throw new XPathFactoryConfigurationException( + "No XPathFactory implementation found for the object model: " + + uri); + } - return xpathFactory; + return xpathFactory; } /** @@ -242,16 +243,14 @@ ClassLoader cl = classLoader; if (uri == null) { - throw new NullPointerException( - "XPathFactory#newInstance(String uri) cannot be called with uri == null" - ); + throw new NullPointerException( + "XPathFactory#newInstance(String uri) cannot be called with uri == null"); } - if (uri.length() == 0) { - throw new IllegalArgumentException( - "XPathFactory#newInstance(String uri) cannot be called with uri == \"\"" - ); - } + if (uri.length() == 0) { + throw new IllegalArgumentException( + "XPathFactory#newInstance(String uri) cannot be called with uri == \"\""); + } if (cl == null) { cl = ss.getContextClassLoader(); @@ -260,31 +259,32 @@ XPathFactory f = new XPathFactoryFinder(cl).createInstance(factoryClassName); if (f == null) { - throw new XPathFactoryConfigurationException( - "No XPathFactory implementation found for the object model: " - + uri - ); + throw new XPathFactoryConfigurationException( + "No XPathFactory implementation found for the object model: " + + uri); } //if this factory supports the given schemalanguage return this factory else thrown exception - if(f.isObjectModelSupported(uri)){ + if (f.isObjectModelSupported(uri)) { return f; - }else{ - throw new XPathFactoryConfigurationException("Factory " + factoryClassName + " doesn't support given " + uri + " object model"); + } else { + throw new XPathFactoryConfigurationException("Factory " + + factoryClassName + " doesn't support given " + uri + + " object model"); } } - /** - *

      Is specified object model supported by this XPathFactory?

      - * - * @param objectModel Specifies the object model which the returned XPathFactory will understand. - * - * @return true if XPathFactory supports objectModel, else false. - * - * @throws NullPointerException If objectModel is null. - * @throws IllegalArgumentException If objectModel.length() == 0. - */ - public abstract boolean isObjectModelSupported(String objectModel); + /** + *

      Is specified object model supported by this XPathFactory?

      + * + * @param objectModel Specifies the object model which the returned XPathFactory will understand. + * + * @return true if XPathFactory supports objectModel, else false. + * + * @throws NullPointerException If objectModel is null. + * @throws IllegalArgumentException If objectModel.length() == 0. + */ + public abstract boolean isObjectModelSupported(String objectModel); /** *

      Set a feature for this XPathFactory and @@ -314,8 +314,8 @@ * it creates cannot support this feature. * @throws NullPointerException if name is null. */ - public abstract void setFeature(String name, boolean value) - throws XPathFactoryConfigurationException; + public abstract void setFeature(String name, boolean value) + throws XPathFactoryConfigurationException; /** *

      Get the state of the named feature.

      @@ -339,8 +339,8 @@ * it creates cannot support this feature. * @throws NullPointerException if name is null. */ - public abstract boolean getFeature(String name) - throws XPathFactoryConfigurationException; + public abstract boolean getFeature(String name) + throws XPathFactoryConfigurationException; /** *

      Establish a default variable resolver.

      @@ -359,19 +359,19 @@ public abstract void setXPathVariableResolver(XPathVariableResolver resolver); /** - *

      Establish a default function resolver.

      - * - *

      Any XPath objects constructed from this factory will - * use the specified resolver by default.

      - * - *

      A NullPointerException is thrown if - * resolver is null.

      - * - * @param resolver XPath function resolver. - * - * @throws NullPointerException If resolver is - * null. - */ + *

      Establish a default function resolver.

      + * + *

      Any XPath objects constructed from this factory will + * use the specified resolver by default.

      + * + *

      A NullPointerException is thrown if + * resolver is null.

      + * + * @param resolver XPath function resolver. + * + * @throws NullPointerException If resolver is + * null. + */ public abstract void setXPathFunctionResolver(XPathFunctionResolver resolver); /** diff -r 64d47cf7f372 -r e3e2d366215b jaxp/src/javax/xml/xpath/XPathFactoryFinder.java --- a/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java Thu May 02 13:35:16 2013 -0700 +++ b/jaxp/src/javax/xml/xpath/XPathFactoryFinder.java Mon May 06 11:41:40 2013 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,16 @@ package javax.xml.xpath; -import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.NoSuchElementException; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Properties; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** * Implementation of {@link XPathFactory#newInstance(String)}. @@ -50,7 +46,7 @@ class XPathFactoryFinder { private static final String DEFAULT_PACKAGE = "com.sun.org.apache.xpath.internal"; - private static SecuritySupport ss = new SecuritySupport() ; + private static final SecuritySupport ss = new SecuritySupport() ; /** debug support code. */ private static boolean debug = false; static { @@ -65,12 +61,12 @@ /** *

      Cache properties for performance.

      */ - private static Properties cacheProps = new Properties(); + private static final Properties cacheProps = new Properties(); - /** - *

      First time requires initialization overhead.

      - */ - private volatile static boolean firstTime = true; + /** + *

      First time requires initialization overhead.

      + */ + private volatile static boolean firstTime = true; /** *

      Conditional debug printing.

      @@ -93,9 +89,8 @@ * to find XPathFactory.

      * * @param loader - * to be used to load resource, {@link XPathFactory}, and - * {@link SchemaFactoryLoader} implementations during - * the resolution process. + * to be used to load resource and {@link XPathFactory} + * implementations during the resolution process. * If this parameter is null, the default system class loader * will be used. */ @@ -113,7 +108,7 @@ return; } } catch( Throwable unused ) { - ; // getContextClassLoader() undefined in JDK1.1 + // getContextClassLoader() undefined in JDK1.1 } if( classLoader==ClassLoader.getSystemClassLoader() ) { @@ -126,7 +121,7 @@ /** *

      Creates a new {@link XPathFactory} object for the specified - * schema language.

      + * object model.

      * * @param uri * Identifies the underlying object model. @@ -136,8 +131,10 @@ * @throws NullPointerException * If the parameter is null. */ - public XPathFactory newFactory(String uri) { - if(uri==null) throw new NullPointerException(); + public XPathFactory newFactory(String uri) throws XPathFactoryConfigurationException { + if (uri == null) { + throw new NullPointerException(); + } XPathFactory f = _newFactory(uri); if (f != null) { debugPrintln("factory '" + f.getClass().getName() + "' was found for " + uri); @@ -154,8 +151,8 @@ * * @return {@link XPathFactory} for the given object model. */ - private XPathFactory _newFactory(String uri) { - XPathFactory xpathFactory; + private XPathFactory _newFactory(String uri) throws XPathFactoryConfigurationException { + XPathFactory xpathFactory = null; String propertyName = SERVICE_CLASS.getName() + ":" + uri; @@ -166,7 +163,9 @@ if(r!=null) { debugPrintln("The value is '"+r+"'"); xpathFactory = createInstance(r, true); - if(xpathFactory != null) return xpathFactory; + if (xpathFactory != null) { + return xpathFactory; + } } else debugPrintln("The property is undefined."); } catch( Throwable t ) { @@ -180,8 +179,6 @@ String configFile = javah + File.separator + "lib" + File.separator + "jaxp.properties"; - String factoryClassName = null ; - // try to read from $java.home/lib/jaxp.properties try { if(firstTime){ @@ -196,7 +193,7 @@ } } } - factoryClassName = cacheProps.getProperty(propertyName); + final String factoryClassName = cacheProps.getProperty(propertyName); debugPrintln("found " + factoryClassName + " in $java.home/jaxp.properties"); if (factoryClassName != null) { @@ -211,23 +208,16 @@ } } - // try META-INF/services files - Iterator sitr = createServiceFileIterator(); - while(sitr.hasNext()) { - URL resource = (URL)sitr.next(); - debugPrintln("looking into " + resource); - try { - xpathFactory = loadFromService(uri, resource.toExternalForm(), - ss.getURLInputStream(resource)); - if (xpathFactory != null) { - return xpathFactory; - } - } catch(IOException e) { - if( debug ) { - debugPrintln("failed to read "+resource); - e.printStackTrace(); - } - } + // Try with ServiceLoader + assert xpathFactory == null; + xpathFactory = findServiceProvider(uri); + + // The following assertion should always be true. + // Uncomment it, recompile, and run with -ea in case of doubts: + // assert xpathFactory == null || xpathFactory.isObjectModelSupported(uri); + + if (xpathFactory != null) { + return xpathFactory; } // platform default @@ -245,8 +235,8 @@ * @param className Name of class to create. * @return Created class or null. */ - private Class createClass(String className) { - Class clazz; + private Class createClass(String className) { + Class clazz; // make sure we have access to restricted packages boolean internal = false; if (System.getSecurityManager() != null) { @@ -258,47 +248,54 @@ // use approprite ClassLoader try { if (classLoader != null && !internal) { - clazz = classLoader.loadClass(className); + clazz = Class.forName(className, false, classLoader); } else { clazz = Class.forName(className); } } catch (Throwable t) { - if(debug) t.printStackTrace(); - return null; + if(debug) { + t.printStackTrace(); + } + return null; } - return clazz; + return clazz; } /** *

      Creates an instance of the specified and returns it.

      * * @param className - * fully qualified class name to be instanciated. + * fully qualified class name to be instantiated. * * @return null * if it fails. Error messages will be printed by this method. */ - XPathFactory createInstance( String className ) { + XPathFactory createInstance( String className ) + throws XPathFactoryConfigurationException + { return createInstance( className, false ); } - XPathFactory createInstance( String className, boolean useServicesMechanism ) { + + XPathFactory createInstance( String className, boolean useServicesMechanism ) + throws XPathFactoryConfigurationException + { XPathFactory xPathFactory = null; debugPrintln("createInstance(" + className + ")"); // get Class from className - Class clazz = createClass(className); + Class clazz = createClass(className); if (clazz == null) { - debugPrintln("failed to getClass(" + className + ")"); - return null; + debugPrintln("failed to getClass(" + className + ")"); + return null; } debugPrintln("loaded " + className + " from " + which(clazz)); // instantiate Class as a XPathFactory try { if (!useServicesMechanism) { - xPathFactory = (XPathFactory) newInstanceNoServiceLoader(clazz); + xPathFactory = newInstanceNoServiceLoader(clazz); } if (xPathFactory == null) { xPathFactory = (XPathFactory) clazz.newInstance(); @@ -329,203 +326,94 @@ * Try to construct using newXPathFactoryNoServiceLoader * method if available. */ - private static Object newInstanceNoServiceLoader( + private static XPathFactory newInstanceNoServiceLoader( Class providerClass - ) { + ) throws XPathFactoryConfigurationException { // Retain maximum compatibility if no security manager. if (System.getSecurityManager() == null) { return null; } try { Method creationMethod = - providerClass.getDeclaredMethod( - "newXPathFactoryNoServiceLoader" - ); - return creationMethod.invoke(null, (Object[])null); - } catch (NoSuchMethodException exc) { - return null; - } catch (Exception exc) { - return null; - } - } - - /** - *

      Look up a value in a property file.

      - * - *

      Set debug to true to trace property evaluation.

      - * - * @param objectModel URI of object model to support. - * @param inputName Name of InputStream. - * @param in InputStream of properties. - * - * @return XPathFactory as determined by keyName value or null if there was an error. - * - * @throws IOException If IO error reading from in. - */ - private XPathFactory loadFromService( - String objectModel, - String inputName, - InputStream in) - throws IOException { - - XPathFactory xPathFactory = null; - final Class[] stringClassArray = {"".getClass()}; - final Object[] objectModelObjectArray = {objectModel}; - final String isObjectModelSupportedMethod = "isObjectModelSupported"; - - debugPrintln("Reading " + inputName); + providerClass.getDeclaredMethod( + "newXPathFactoryNoServiceLoader" + ); + final int modifiers = creationMethod.getModifiers(); - // read from InputStream until a match is found - BufferedReader configFile = new BufferedReader(new InputStreamReader(in)); - String line = null; - while ((line = configFile.readLine()) != null) { - // '#' is comment char - int comment = line.indexOf("#"); - switch (comment) { - case -1: break; // no comment - case 0: line = ""; break; // entire line is a comment - default: line = line.substring(0, comment); break; // trim comment - } - - // trim whitespace - line = line.trim(); - - // any content left on line? - if (line.length() == 0) { - continue; - } - - // line content is now the name of the class - Class clazz = createClass(line); - if (clazz == null) { - continue; - } - - // create an instance of the Class - try { - xPathFactory = (XPathFactory) clazz.newInstance(); - } catch (ClassCastException classCastExcpetion) { - xPathFactory = null; - continue; - } catch (InstantiationException instantiationException) { - xPathFactory = null; - continue; - } catch (IllegalAccessException illegalAccessException) { - xPathFactory = null; - continue; - } - - // does this Class support desired object model? - try { - Method isObjectModelSupported = clazz.getMethod(isObjectModelSupportedMethod, stringClassArray); - Boolean supported = (Boolean) isObjectModelSupported.invoke(xPathFactory, objectModelObjectArray); - if (supported.booleanValue()) { - break; - } - - } catch (NoSuchMethodException noSuchMethodException) { - - } catch (IllegalAccessException illegalAccessException) { - - } catch (InvocationTargetException invocationTargetException) { - - } - xPathFactory = null; + // Do not call "newXPathFactoryNoServiceLoader" if it's + // not public static. + if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) { + return null; } - // clean up - configFile.close(); - - // return new instance of XPathFactory or null - return xPathFactory; - } - - /** Iterator that lazily computes one value and returns it. */ - private static abstract class SingleIterator implements Iterator { - private boolean seen = false; - - public final void remove() { throw new UnsupportedOperationException(); } - public final boolean hasNext() { return !seen; } - public final Object next() { - if(seen) throw new NoSuchElementException(); - seen = true; - return value(); - } - - protected abstract Object value(); - } - - /** - * Looks up a value in a property file - * while producing all sorts of debug messages. - * - * @return null - * if there was an error. - */ - private XPathFactory loadFromProperty( String keyName, String resourceName, InputStream in ) - throws IOException { - debugPrintln("Reading "+resourceName ); - - Properties props = new Properties(); - props.load(in); - in.close(); - String factoryClassName = props.getProperty(keyName); - if(factoryClassName != null){ - debugPrintln("found "+keyName+" = " + factoryClassName); - return createInstance(factoryClassName, true); - } else { - debugPrintln(keyName+" is not in the property file"); + // Only calls "newXPathFactoryNoServiceLoader" if it's + // declared to return an instance of XPathFactory. + final Class returnType = creationMethod.getReturnType(); + if (SERVICE_CLASS.isAssignableFrom(returnType)) { + return SERVICE_CLASS.cast(creationMethod.invoke(null, (Object[])null)); + } else { + // Should not happen since + // XPathFactoryImpl.newXPathFactoryNoServiceLoader is + // declared to return XPathFactory. + throw new ClassCastException(returnType + + " cannot be cast to " + SERVICE_CLASS); + } + } catch (ClassCastException e) { + throw new XPathFactoryConfigurationException(e); + } catch (NoSuchMethodException exc) { + return null; + } catch (Exception exc) { return null; } } + // Call isObjectModelSupportedBy with initial context. + private boolean isObjectModelSupportedBy(final XPathFactory factory, + final String objectModel, + AccessControlContext acc) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return factory.isObjectModelSupported(objectModel); + } + }, acc); + } + /** - * Returns an {@link Iterator} that enumerates all - * the META-INF/services files that we care. + * Finds a service provider subclass of XPathFactory that supports the + * given object model using the ServiceLoader. + * + * @param objectModel URI of object model to support. + * @return An XPathFactory supporting the specified object model, or null + * if none is found. + * @throws XPathFactoryConfigurationException if a configuration error is found. */ - private Iterator createServiceFileIterator() { - if (classLoader == null) { - return new SingleIterator() { - protected Object value() { - ClassLoader classLoader = XPathFactoryFinder.class.getClassLoader(); - return ss.getResourceAsURL(classLoader, SERVICE_ID); - //return (ClassLoader.getSystemResource( SERVICE_ID )); - } - }; - } else { - try { - //final Enumeration e = classLoader.getResources(SERVICE_ID); - final Enumeration e = ss.getResources(classLoader, SERVICE_ID); - if(!e.hasMoreElements()) { - debugPrintln("no "+SERVICE_ID+" file was found"); + private XPathFactory findServiceProvider(final String objectModel) + throws XPathFactoryConfigurationException { + + assert objectModel != null; + // store current context. + final AccessControlContext acc = AccessController.getContext(); + try { + return AccessController.doPrivileged(new PrivilegedAction() { + public XPathFactory run() { + final ServiceLoader loader = + ServiceLoader.load(SERVICE_CLASS); + for (XPathFactory factory : loader) { + // restore initial context to call + // factory.isObjectModelSupportedBy + if (isObjectModelSupportedBy(factory, objectModel, acc)) { + return factory; + } + } + return null; // no factory found. } - - // wrap it into an Iterator. - return new Iterator() { - public void remove() { - throw new UnsupportedOperationException(); - } - - public boolean hasNext() { - return e.hasMoreElements(); - } - - public Object next() { - return e.nextElement(); - } - }; - } catch (IOException e) { - debugPrintln("failed to enumerate resources "+SERVICE_ID); - if(debug) e.printStackTrace(); - return new ArrayList().iterator(); // empty iterator - } + }); + } catch (ServiceConfigurationError error) { + throw new XPathFactoryConfigurationException(error); } } - private static final Class SERVICE_CLASS = XPathFactory.class; - private static final String SERVICE_ID = "META-INF/services/" + SERVICE_CLASS.getName(); - - + private static final Class SERVICE_CLASS = XPathFactory.class; private static String which( Class clazz ) { return which( clazz.getName(), clazz.getClassLoader() );