JDK-8316997 : Catalog API Enhancement: add a factory method
  • Type: CSR
  • Component: xml
  • Sub-Component: jaxp
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 22
  • Submitted: 2023-09-26
  • Updated: 2023-10-27
  • Resolved: 2023-10-27
Related Reports
CSR :  
Description
Summary
-------

Define an Enum action type for the CatalogResolver to determine the behavior when it is unable to resolve a reference. Add a new factory method for creating a CatalogResolver with a Catalog and the action type.

Problem
-------

The CatalogResolver implements XML resolver interfaces with a Catalog, representing an XML catalog along with its attributes defined in CatalogFeatures. This resolver delegates the resolution process to the underlying Catalog. When it is unable to resolve a reference, it behaves according to the setting of the Catalog's RESOLVE property that instructs the resolver to either skip the reference, continue processing, or report an error. 

The problem is that the value of the RESOLVE property can be specified outside of the Catalog and changed after the catalog has been created. Relying on the Catalog therefore may cause the resolver to miss changes to the property. Since both the Catalog and CatalogResolver are immutable, it is also not possible to update the objects to reflect any changes.

Solution
--------

This solution proposes a method to obtain a CatalogResolver from a Catalog and an action type, that is: `CatalogManager::catalogResolver(Catalog catalog, CatalogResolver.NotFoundAction action)`. The CatalogResolver created with the method then uses the action type to determine the action it shall take when unable to resolve a reference, rather than relying on the underlying Catalog's RESOLVE property.

The action type is defined as an enum with three values that are mapped to those of the {@link CatalogFeatures.Feature#RESOLVE RESOLVE} property. The actions are exactly as defined in {@link CatalogFeatures}, that is:
  -- CONTINUE: instructs the resolver to continue processing
  -- IGNORE: instructs the resolver to skip the reference
  -- STRICT: instructs the resolver to throw a CatalogException

Note that the new two-arg method is not related to the one-arg method, `CatalogManager::catalogResolver(Catalog catalog)`, in that it creates a CatalogResolver that has the action type explicitly specified, unlike the later that delegates to the underlying Catalog.

Specification
-------------

Package `javax.xml.catalog`

Class 'CatalogResolver'

    /**
     * Defines the actions that a CatalogResolver may take when it is unable to 
     * resolve an external reference. The actions are mapped to the string values
     * of the {@link CatalogFeatures.Feature#RESOLVE RESOLVE} property.
     * 
     * @since 22
     */
    public static enum NotFoundAction {
        /**
         * Indicates that the processing should continue as defined by the
         * {@link CatalogFeatures.Feature#RESOLVE RESOLVE} property.
         */
        CONTINUE {
            @Override
            public String toString() { return "continue"; }
        },
        /**
         * Indicates that the reference is skipped as defined by the
         * {@link CatalogFeatures.Feature#RESOLVE RESOLVE} property.
         */
        IGNORE {
            @Override
            public String toString() { return "ignore"; }
        },
        /**
         * Indicates that the resolver should throw a CatalogException as defined
         * by the {@link CatalogFeatures.Feature#RESOLVE RESOLVE} property.
         */
        STRICT {
            @Override
            public String toString() { return "strict"; }
        },
    }


Class `CatalogManager`

    /**
     * Creates a {@code CatalogResolver} that resolves external references with the given
     * {@code catalog} and {@link CatalogResolver.NotFoundAction action} type
     * that determines the behavior when unable to resolve a reference.
     * <p>
     * The {@link CatalogResolver.NotFoundAction action} types are mapped to the values
     * of the {@link CatalogFeatures.Feature#RESOLVE RESOLVE} property.
     *
     * @param catalog the catalog instance
     * @param action the action to be taken when unable to resolve a reference
     * 
     * @return a {@code CatalogResolver} with the {@code catalog} and {@code action} type
     * 
     * @since 22
     */
    public static CatalogResolver catalogResolver(Catalog catalog, CatalogResolver.NotFoundAction action)


With the addition of the two-arg method, add a apiNote to explain the relationship with the existing one-arg method.

    /**
     * Creates an instance of a {@code CatalogResolver} using the specified catalog.
     *
    +  * @apiNote The {@code CatalogResolver} created by this method delegates to
    +  * the underlying {@code catalog}'s RESOLVE property. The {@code CatalogResolver}
    +  * created by {@link #catalogResolver(Catalog, CatalogResolver.NotFoundAction) 
    +  * catalogResover(Catalog, CatalogResolver.NotFoundAction)} is based on the
    +  * specified action type when it is unable to resolve a reference.
     * 
     * @param catalog the catalog instance
     * @return an instance of a {@code CatalogResolver}
     */
    public static CatalogResolver catalogResolver(Catalog catalog)

Comments
Moving to Approved.
27-10-2023

Back to draft to address Alan's concern about the String type for the 2nd argument. The new proposal changes the String type to an Enum so that the proposed method changes from: public static CatalogResolver catalogResolver(Catalog catalog, String resolve) to: public static CatalogResolver catalogResolver(Catalog catalog, CatalogResolver.NotFoundAction action) The specification changes include: -- added definition:CatalogResolver.NotFoundAction -- changed the 2nd argument of the factory method from String to Enum. -- changed javadocs accordingly. Note that there's no longer IAE for unsupported input values, no additional throws statement needed for NPE to that specified in the package.
24-10-2023

Thanks [~joehw]; re-Approved updated request.
05-10-2023

Thanks Joe! During the PR review, it's noted that although we have a package-level NPE defined, it needs to be clear about null handling for the “catalog” parameter, given it is allowed for the “resolve” parameter. Change made: added the following statement to the "catalogResolver(Catalog catalog, String resolve)" method: @throws NullPointerException if {@code catalog} is null
05-10-2023

Moving to Approved.
05-10-2023

Thanks Joe. Added a apiNote for the one-arg method. Accordingly, adjusted the javadoc for the two-arg method to allow null.
04-10-2023

Moving to Provisional, not Approved. [~joehw], should the various catalogResolver method in this class contain some statements about their relation to each other? I don't know if it would appropriate in this case, but other class in the JDK contain a statement like "Call this one-arg method is equivalent to calling this two-arg method with the second argument set to FOO", etc.
03-10-2023

For reference, the following is the current method that takes a Catalog object to create a CatalogResolver: public static CatalogResolver catalogResolver(Catalog catalog) Link: https://docs.oracle.com/en/java/javase/21/docs/api/java.xml/javax/xml/catalog/CatalogManager.html#catalogResolver(javax.xml.catalog.Catalog)
26-09-2023