All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xmlresolver.ResolverFeature Maven / Gradle / Ivy

There is a newer version: 6.0.11
Show newest version
package org.xmlresolver;

import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xmlresolver.logging.ResolverLogger;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.util.*;
import java.util.function.Supplier;

/**
 * An individual resolver feature. The complete set of known features is instantiated as a
 * collection of static final fields.
 *
 * @param  The type of the feature.
 */

public class ResolverFeature {
    private String name = null;
    private T defaultValue = null;

    private static final Map> index = new TreeMap>();

    protected ResolverFeature(String name, T defaultValue) {
        this.name = name;
        this.defaultValue = defaultValue;
        index.put(name, this);
    }

    /**
     * Get the name of the feature.
     *
     * @return The feature name.
     */
    public String getName() {
        return name;
    }

    /**
     * Get the default value of the feature.
     *
     * @return The feature default value.
     */
    public T getDefaultValue() {
        return defaultValue;
    }

    /**
     * Find a known static feature by name.
     *
     * @param name The feature name.
     * @return The instance of that feature.
     */
    public static ResolverFeature byName(String name) {
        return index.get(name);
    }

    /**
     * Iterates over the known feature names.
     *
     * @return An iterator over the feature names.
     */
    public static Iterator getNames() {
        return index.keySet().iterator();
    }

    /**
     * Sets the list of catalog files.
     */
    public static final ResolverFeature> CATALOG_FILES = new ResolverFeature<>(
            "http://xmlresolver.org/feature/catalog-files", Collections.unmodifiableList(new ArrayList<>()));

    /**
     * Sets the list of additional catalog files.
     */
    public static final ResolverFeature> CATALOG_ADDITIONS = new ResolverFeature<>(
            "http://xmlresolver.org/feature/catalog-additions", Collections.unmodifiableList(new ArrayList<>()));

    /**
     * Determines whether public IDs are preferred.
     */
    public static final ResolverFeature PREFER_PUBLIC = new ResolverFeature<>(
            "http://xmlresolver.org/feature/prefer-public", true);

    /**
     * Determines whether property file values are preferred over
     * system property values.
     *
     * 

In earlier versions of this API, this was effectively always true. * The default is now false which allows system property values to override property file values. * Set this to true in your property file to preserve the old behavior.

*/ public static final ResolverFeature PREFER_PROPERTY_FILE = new ResolverFeature<>( "http://xmlresolver.org/feature/prefer-property-file", false); /** * Determines whether the catalog PI in a document * may change the list of catalog files to be consulted. * *

It defaults to true, but there's a small performance cost. Each parse needs * it's own copy of the configuration if you enable this feature (otherwise, the PI in one document * might have an effect on other documents). If you know you aren't using the PI, it might be sensible * to make this false.

*/ public static final ResolverFeature ALLOW_CATALOG_PI = new ResolverFeature<>( "http://xmlresolver.org/feature/allow-catalog-pi", true); /** * Should the resolver always return a resource, even when it didn't find it in the catalog? * *

It defaults to true, but this is in violation of the entity resolver contract. * The resolver should return null if it fails to find the resource. But some parsers don't follow * redirects and therefore cannot http-to-https redirected URIs. And the source returned by the * resolver contains additional, useful information.

*

It's worth noting that the .NET contract for the resolver *is* that it always returns * something, so there's that.

*/ public static final ResolverFeature ALWAYS_RESOLVE = new ResolverFeature<>( "http://xmlresolver.org/feature/always-resolve", true); /** * Provides access to the {@link CatalogManager} that * the resolver is using. */ public static final ResolverFeature CATALOG_MANAGER = new ResolverFeature<>( "http://xmlresolver.org/feature/catalog-manager", (CatalogManager) null); /** * Determines whether uri catalog entries * can be used to resolve external identifiers. * *

This only applies if resolution fails through * system and public entries.

*/ public static final ResolverFeature URI_FOR_SYSTEM = new ResolverFeature<>( "http://xmlresolver.org/feature/uri-for-system", true); /** * Determines whether http: and https: URIs compare the same. * *

Historically, most web servers used http:, now most use https:. * There are existing catalogs that can't practically be updated that use http: for * system identifiers and URIs. But authors copying and pasting are likely to get https: * URIs. If this option is true, then http: and https: are considred * the same for the purpose of comparison in the catalog.

* *

This option has no effect on the URIs returned; it only influences catalog URI comparisons.

*/ public static final ResolverFeature MERGE_HTTPS = new ResolverFeature<>( "http://xmlresolver.org/feature/merge-https", true); /** * Determines whether a classpath: or jar: URI is returned by the resolver. * *

When the resolver finds a resource, for example a schema or a stylesheet, it returns * the location of the resolved resource as the base URI for the resource. This enables * the following common scenario:

* *
    *
  • Download a distribution and store it locally.
  • *
  • Create a catalog that maps from the entry point(s) into the local * distribution: http://example.com/acme-schema/start/here -> /opt/acme-schema-1.0/here
  • *
  • Profit.
  • *
* *

A document requests http://example.com/acme-schema/start/here, the resolver * returns /opt/achme-schema-1.0/here. When the schema attempts to import a library, * the URI for that library is resolved against the base URI on the filesystem, a new path is * constructed, and it all just works.

* *

Adding support for classpath and jar: URIs to XML Resolver 3.0 has enabled another * very attractive scenario:

* *
    *
  • Put the distribution in a jar file with an included catalog.
  • *
  • Arrange for the project to depend on that jar file, so it'll be on the classpath.
  • *
  • Add classpath:/org/example/acme-schema/catalog.xml to your catalog list.
  • *
  • More profit!
  • *
* *

Trouble is, the resolved URI will be something like this:

* *

jar:file:///where/the/jar/is/acme-schema-1.0.jar!/org/example/acme-schema/here

* *

And the trouble with that is, Java doesn't think the classpath: and jar: * URI schemes are hierarchical and won't resolve the URI for the imported library correctly. It will * work just fine for any document that doesn't include parts with relative URIs. The DocBook schema, * for example, is distributed as a single RELAX NG file, so it works. But the xslTNG stylesheets would * not.

* *

If MASK_JAR_URIS is true, the resolver will return the local resource from the jar * file, but will leave the URI unchanged. As long as the catalog has a mapping for all of the resources, * and not just the entry point(s), this will do exactly the right thing.

* *

Often, this can be achieved with, for example, a rewrite rule:

* *
<rewriteURI uriStartString="http://example.com/acme-start/"
     *             rewritePrefix="acme-start/">
     * 
* *

Assuming the catalog is in a location where that rewrite prefix works, the entry point * will be remapped and the local resource returned. The resource it imports will be resolved against * the http: URI, but that will also be remapped, and everyone wins.

* *

You don't need to use a rewrite rule, you can use any combination of catalog rules you like * as long as each of the requested URIs will be mapped.

*/ public static final ResolverFeature MASK_JAR_URIS = new ResolverFeature<>( "http://xmlresolver.org/feature/mask-jar-uris", true); /** * Identifies the catalog loader class. * *

The default catalog loader class is usually fine. The validating class can be used * to enforce schema validity checks on loaded catalogs.

*/ public static final ResolverFeature CATALOG_LOADER_CLASS = new ResolverFeature<>( "http://xmlresolver.org/feature/catalog-loader-class", "org.xmlresolver.loaders.XmlLoader"); /** * Controls whether or not namespace documents will be parsed for RDDL annotations. * *

If this feature is enabled, then if an attempt to get a namespace returns an HTML document, * and if a nature and purpose has been specified in the request, the HTML document will be parsed * for RDDL annotations. If a matching entry is found, the annotated URI will be used.

* *

In the {@link org.w3c.dom.ls.LSResourceResolver}, if the type of the request is the XML * Schema or RELAX NG namespace, the purpose is assumed to be validation.

*/ public static final ResolverFeature PARSE_RDDL = new ResolverFeature<>( "http://xmlresolver.org/feature/rddl", true); /** * Determines whether or not catalogs on the classpath should be loaded automatically. * *

If this feature is enabled, then the resolver will attempt to find and load all * of the catalogs named org/xmlresolver/catalog.xml on the classpath. * These will be added to the of the catalogs loaded from properties.

*/ public static final ResolverFeature CLASSPATH_CATALOGS = new ResolverFeature<>( "http://xmlresolver.org/feature/classpath-catalogs", true); /** * Identify the ClassLoader to use for accessing resources on the classpath. * *

A {@link ClassLoader} is used to access the class path and load resources * from the class path. By default the resolver configuration uses the class * loader obtained from the class:

* *
getClass().getClassLoader()
* *

If you're using the resolver in an environment where an alternate class * loader is required, you can specify it with this feature.

*/ public static final ResolverFeature CLASSLOADER = new ResolverFeature<>( "http://xmlresolver.org/feature/classloader", null); /** * Adds support for placing ZIP files on the catalog path. * *

If enabled, then you can put ZIP files on the catalog path. The resolver * will look for catalog.xml and org/xmlresolver/catalog.xml, * using whichever it finds first. If it doesn't find either, the file is ignored.

*/ public static final ResolverFeature ARCHIVED_CATALOGS = new ResolverFeature<>( "http://xmlresolver.org/feature/archived-catalogs", true); /** * Allows the resolver to throw exceptions for invalid URIs. * *

If enabled, when the resolver attempts to process a URI, if the processing * raises an exception, that exception will be thrown rather than suppressed. For * checked exceptions, such as URISyntaxException, what's thrown will * be a IllegalArgumentException wrapping the underlying exception.

*/ public static final ResolverFeature THROW_URI_EXCEPTIONS = new ResolverFeature<>( "http://xmlresolver.org/feature/throw-uri-exceptions", false); /** * Identifies the resolver logger class. * *

Any class that implements {@link org.xmlresolver.logging.ResolverLogger} can be used. * XML Resolver ships with two implementations:

* *
    *
  • The {@link org.xmlresolver.logging.DefaultLogger org.xmlresolver.logging.DefaultLogger} class writes log messages * to System.err.
  • *
  • The {@link org.xmlresolver.logging.SystemLogger org.xmlresolver.logging.SystemLogger} class uses * a logging backend. (You must configure a concrete backend for the logging facade on your * classpath.)
  • *
* */ public static final ResolverFeature RESOLVER_LOGGER_CLASS = new ResolverFeature<>( "http://xmlresolver.org/feature/resolver-logger-class", "org.xmlresolver.logging.DefaultLogger"); /** * Identifies the resolver logger. * *

This feature can get and set an instance of the logger. The logger is usually * configured with the RESOLVER_LOGGER_CLASS feature. If the logger * has been configured via RESOLVER_LOGGER_CLASS, an attempt to get the RESOLVER_LOGGER * will instantiate the class (if it hasn't already been instantiated).

*/ public static final ResolverFeature RESOLVER_LOGGER = new ResolverFeature<>( "http://xmlresolver.org/feature/resolver-logger", null); /** * Specify the logging level for the default logger. * *

This feature only applies to the {@link org.xmlresolver.logging.DefaultLogger} (or other classes * that use it). In particular, it has no effect if the {@link org.xmlresolver.logging.SystemLogger} is used. * How that is configured depends on the concrete backend selected at runtime.

*/ public static final ResolverFeature DEFAULT_LOGGER_LOG_LEVEL = new ResolverFeature<>( "http://xmlresolver.org/feature/default-logger-log-level", "warn"); /** * Specify the protocols allowed for entity lookup. * *

This feature restricts the protocols that are allowed during entity resolution. If an * attempt is made to resolve an entity and the system identifier for that entity uses a protocol * not listed in this feature, the request is rejected. See JAXP 185.

*

The keyword "all" allows all protocols. An empty list allows none.

*/ public static final ResolverFeature ACCESS_EXTERNAL_ENTITY = new ResolverFeature<>( "http://xmlresolver.org/feature/access-external-entity", "all"); /** * Specify the protocols allowed for URI lookup. * *

This feature restricts the protocols that are allowed during URI resolution. If an * attempt is made to resolve a document and the URI for that document uses a protocol * not listed in this feature, the request is rejected. See JAXP 185.

*

The keyword "all" allows all protocols. An empty list allows none.

*/ public static final ResolverFeature ACCESS_EXTERNAL_DOCUMENT = new ResolverFeature<>( "http://xmlresolver.org/feature/access-external-document", "all"); /** * Identify the SAXParserFactory class. * *

If unconfigured, parsers are created with {@link #XMLREADER_SUPPLIER}.

* *

This feature and the {@link #XMLREADER_SUPPLIER} are different mechanisms for * configuring the same underlying feature: how does the resolver get an XML parser if it needs one? (For * example, it needs one to parse the cache, but the {@link org.xmlresolver.tools.ResolvingXMLFilter ResolvingXMLFilter} and * {@link org.xmlresolver.tools.ResolvingXMLReader ResolvingXMLReader} also use this mechanism.)

* *

The SAXPARSERFACTORY_CLASS is initially null and the * XMLREADER_SUPPLIER is used. The purpose of the SAXPARSERFACTORY_CLASS * is to allow the factory to be configured with a property since the {@link #XMLREADER_SUPPLIER} cannot.

* *

If a SAXPARSERFACTORY_CLASS is specified, it will be used in favor of the default * XMLREADER_SUPPLIER. If an XMLREADER_SUPPLIER is explicitly set after the * configuration is initialized, it will set this feature to null and take precedence.

*/ public static final ResolverFeature SAXPARSERFACTORY_CLASS = new ResolverFeature<>( "http://xmlresolver.org/feature/saxparserfactory-class", null); /** * Configure the default XML reader. * *

The default supplier is obtained with SAXParserFactory.newInstance() and * the global mechanisms that it uses.

* *

This feature and the {@link #SAXPARSERFACTORY_CLASS} are different mechanisms for * configuring the same underlying feature: how does the resolver get an XML parser if it needs one? (For * example, it needs one to parse the cache, but the {@link org.xmlresolver.tools.ResolvingXMLFilter ResolvingXMLFilter} and * {@link org.xmlresolver.tools.ResolvingXMLReader ResolvingXMLReader} also use this mechanism.)

* *

The {@link #SAXPARSERFACTORY_CLASS} is initially null and the * XMLREADER_SUPPLIER is used. The purpose of the SAXPARSERFACTORY_CLASS * is to allow the factory to be configured with a property since the XMLREADER_SUPPLIER cannot.

* *

If a SAXPARSERFACTORY_CLASS is specified, it will be used in favor of the default * XMLREADER_SUPPLIER. If an XMLREADER_SUPPLIER is explicitly set after the * configuration is initialized, it will set this feature to null and take precedence.

*/ public static final ResolverFeature> XMLREADER_SUPPLIER = new ResolverFeature<>( "http://xmlresolver.org/feature/xmlreader-supplier", () -> { try { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); factory.setValidating(false); factory.setXIncludeAware(false); SAXParser parser = factory.newSAXParser(); return parser.getXMLReader(); } catch (ParserConfigurationException| SAXException ex) { return null; } }); /** * Fix backslashes in system identifiers on Windows? *

System identifiers are URIs and URIs may not contain un-escaped backslashes. However, Windows * uses the backslash as the path separator and it's not uncommon for filenames to appear in system * identifiers. If this flag is set, the resolver will replace backslashes with forward slashes in * system identifiers.

*/ public static final ResolverFeature FIX_WINDOWS_SYSTEM_IDENTIFIERS = new ResolverFeature<>( "http://xmlresolver.org/feature/fix-windows-system-identifiers", false); }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy