org.xmlresolver.ResolverFeature Maven / Gradle / Ivy
Show all versions of xmlresolver Show documentation
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);
}