# HG changeset patch # User joehw # Date 1446180801 25200 # Node ID 9f0eef87e8c18581dd4a6856c52fb7c7524f222b # Parent d131f4b8433a79408f935eff9bf92a0664229b60 8081248: Implement JEP 268: XML Catalog API Reviewed-by: lancea, dfuchs diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/AltCatalog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/AltCatalog.java Thu Oct 29 21:53:21 2015 -0700 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 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.catalog; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +/** + * Represents an alternative catalog entry. + * + * @since 9 + */ +class AltCatalog extends BaseEntry { + URI catalogURI; + + AltCatalog(CatalogEntryType type, String base) { + super(type, base); + } + + /** + * Set the catalog attribute. If the value of the catalog attribute is relative, it + * must be made absolute with respect to the base URI currently in effect. + * + * @param catalog The catalog attribute value. + * @throws CatalogException if converting to catalog URI failed + */ + void setCatalog(String catalog) { + URL url = verifyURI("catalog", baseURI, catalog); + try { + catalogURI = url.toURI(); + } catch (URISyntaxException ex) { + CatalogMessages.reportRunTimeError(CatalogMessages.ERR_OTHER, ex); + } + + } + + /** + * Returns the catalog attribute as an URI String. + * @return The value of the catalog attribute + */ + String getCatalogId() { + return catalogURI.toASCIIString(); + } + + /** + * Returns the catalog attribute as an URI. + * @return The value of the catalog attribute + */ + URI getCatalogURI() { + return catalogURI; + } + + /** + * Matches the specified id with the entry. Returns the match if it + * is successful and the length of the start String is longer than the + * longest of any previous match. + * + * @param id The id to be matched. + * @param currentMatch The length of start String of previous match if any. + * @return The replacement URI if the match is successful, null if not. + */ + public URI matchURI(String id, int currentMatch) { + return null; + } +} diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/BaseEntry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/BaseEntry.java Thu Oct 29 21:53:21 2015 -0700 @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2015, 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.catalog; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Objects; +import jdk.xml.internal.SecuritySupport; + +/** + * Represents a general Catalog entry. + * + * @since 9 + */ +abstract class BaseEntry { + final String SLASH = "/"; + + CatalogEntryType type; + + //The id attribute + String id; + + //The attribute to be matched, e.g. systemId + String matchId; + + //The baseURI attribute + URL baseURI; + + //Indicates whether the base attribute is specified + boolean baseSpecified = false; + + /** + * CatalogEntryType represents catalog entry types. + */ + static enum CatalogEntryType { + + CATALOG("catalogfile"), + CATALOGENTRY("catalog"), + GROUP("group"), + PUBLIC("public"), + SYSTEM("system"), + REWRITESYSTEM("rewriteSystem"), + SYSTEMSUFFIX("systemSuffix"), + DELEGATEPUBLIC("delegatePublic"), + DELEGATESYSTEM("delegateSystem"), + URI("uri"), + REWRITEURI("rewriteURI"), + URISUFFIX("uriSuffix"), + DELEGATEURI("delegateURI"), + NEXTCATALOG("nextCatalog"); + + final String literal; + + CatalogEntryType(String literal) { + this.literal = literal; + } + + public boolean isType(String type) { + return literal.equals(type); + } + + static public CatalogEntryType getType(String entryType) { + for (CatalogEntryType type : CatalogEntryType.values()) { + if (type.isType(entryType)) { + return type; + } + } + return null; + } + } + + /** + * Constructs a CatalogEntry + * + * @param type The type of the entry + */ + public BaseEntry(CatalogEntryType type) { + this.type = Objects.requireNonNull(type); + } + + /** + * Constructs a CatalogEntry + * + * @param type The type of the entry + * @param base The base URI + */ + public BaseEntry(CatalogEntryType type, String base) { + this.type = Objects.requireNonNull(type); + setBaseURI(base); + } + + /** + * Returns the type of the entry + * + * @return The type of the entry + */ + public CatalogEntryType getType() { + return type; + } + + /** + * Sets the entry type + * + * @param type The entry type + */ + public void setType(CatalogEntryType type) { + this.type = type; + } + + /** + * Returns the id of the entry + * + * @return The id of the entry + */ + public String getId() { + return id; + } + + /** + * Set the entry Id + * + * @param id The Id attribute + */ + public void setId(String id) { + this.id = id; + } + + /** + * Sets the base URI for the entry + * + * @param base The base URI + */ + public final void setBaseURI(String base) { + baseURI = verifyURI("base", null, base); + } + + /** + * Gets the base URI for the entry + * + * @return The base URI as a string. + */ + public URL getBaseURI() { + return baseURI; + } + + /** + * Gets the attribute used for matching + * + * @return The value of the field + */ + public String getMatchId() { + return matchId; + } + + /** + * Sets the matchId field + * @param matchId The value of the Id + */ + public void setMatchId(String matchId) { + this.matchId = matchId; + } + + /** + * Matches the specified string with the identifier attribute of the entry. + * + * @param match The identifier attribute to be matched + * @return The replacement URI if a matching entry is found, null if not. + */ + public String match(String match) { + return null; + } + + /** + * Try to match the specified id with the entry. Return the match if it + * is successful and the length of the start String is longer than the + * longest of any previous match. + * + * @param id The id to be matched. + * @param currentMatch The length of start String of previous match if any. + * @return The replacement URI if the match is successful, null if not. + */ + public String match(String id, int currentMatch) { + return null; + } + + /** + * Verifies the specified URI. + * + * @param arg The name of the argument + * @param uri The URI to be verified + * @return The URI created from the specified uri + * @throws IllegalArgumentException if the specified uri is null, + * or an URL can not be created based on the specified base and uri + */ + URL verifyURI(String arg, URL base, String uri) { + if (uri == null) { + CatalogMessages.reportIAE(new Object[]{uri, arg}, null); + } + + URL url = null; + uri = Normalizer.normalizeURI(uri); + + try { + if (base != null) { + url = new URL(base, uri); + } else { + url = new URL(uri); + } + } catch (MalformedURLException e) { + CatalogMessages.reportIAE(new Object[]{uri, arg}, e); + } + return url; + } + + /** + * Replace backslashes with forward slashes. (URLs always use forward + * slashes.) + * + * @param sysid The input system identifier. + * @return The same system identifier with backslashes turned into forward + * slashes. + */ + protected String fixSlashes(String sysid) { + return sysid.replace('\\', '/'); + } + + /** + * Construct an absolute URI from a relative one, using the current base + * URI. + * + * @param sysid The (possibly relative) system identifier + * @return The system identifier made absolute with respect to the current + * {@link #base}. + */ + protected String makeAbsolute(String sysid) { + URL local = null; + + sysid = fixSlashes(sysid); + /** + * try { local = new URL(base, sysid); } catch (MalformedURLException e) + * { catalogManager.debug.message(1, "Malformed URL on system + * identifier", sysid); } + */ + if (local != null) { + return local.toString(); + } else { + return sysid; + } + } +} diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/Catalog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Catalog.java Thu Oct 29 21:53:21 2015 -0700 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, 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.catalog; + +import java.util.stream.Stream; + +/** + * The Catalog class represents an entity Catalog as defined by + * + * XML Catalogs, OASIS Standard V1.1, 7 October 2005. + *
+ * A catalog is an XML file that contains a root {@code catalog} entry with a list + * of catalog entries. The entries can also be grouped with a {@code group} entry. + * The catalog and group entries may specify {@code prefer} and {@code xml:base} + * attributes that set preference of public or system type of entries and base URI + * to resolve relative URIs. + * + *
+ * A catalog can be used in two situations: + *
+ * For case 1, the standard defines 6 External Identifier Entries:
+ * {@code public, system, rewriteSystem, systemSuffix, delegatePublic, and
+ * delegateSystem}.
+ *
+ * While for case 2, it defines 4 URI Entries:
+ * {@code uri, rewriteURI, uriSuffix and delegateURI}.
+ *
+ * In addition to the above entry types, a catalog may define nextCatalog + * entries to add additional catalog entry files. + *
+ * + * @since 9 + */ +public interface Catalog { + + /** + * Attempts to find a matching entry in the catalog by systemId. + * + *
+ * The method searches through the system-type entries, including {@code system, + * rewriteSystem, systemSuffix, delegateSystem}, and {@code group} entries in the + * current catalog in order to find a match. + *
+ * Resolution follows the steps listed below:
+ *
+ * Refer to the description about + * Feature PREFER in the table Catalog Features in class + * {@link CatalogFeatures}. Public entries are only considered if the + * {@code prefer} is {@code public} and {@code system} entries are not found. + *
+ * Resolution follows the steps listed below:
+ *
+ * The method searches through the uri-type entries, including {@code uri, + * rewriteURI, uriSuffix, delegateURI} and {@code group} entries in the current + * catalog in order to find a match. + * + *
+ * Resolution follows the steps listed below:
+ *
+ * The order of Catalogs in the returned stream is the same as the order
+ * in which the corresponding {@code nextCatalog} entries appear in the
+ * current catalog. The alternative catalogs from the input file list are
+ * appended to the end of the stream in the order they are entered.
+ *
+ * @return a sequential Stream of Catalogs
+ */
+ public Stream
+ *
+ * Catalog Features
Feature | + *Description | + *Property Name | + *System Property [1] | + *jaxp.properties [1] | + *Value [2] | + *Action | + *|
---|---|---|---|---|---|---|---|
Type | + *Value | + *||||||
FILES | + *A semicolon-delimited list of catalog files. Relative file paths are + * considered relative to ${user.dir}. + * | + *javax.xml.catalog.files | + *javax.xml.catalog.files | + *javax.xml.catalog.files | + *String | + *File paths | + *+ * Reads the first catalog as the current catalog; Loads others if no match + * is found in the current catalog including delegate catalogs if any. + * | + *
PREFER | + *Indicates the preference between the public and system + * identifiers. The default value is public [3]. | + *javax.xml.catalog.prefer | + *N/A | + *N/A | + *String | + *{@code system} | + *Searches system entries for a match; Searches public entries when + * external identifier specifies only a public identifier | + *
{@code public} | + *Searches system entries for a match; Searches public entries when + * there is no matching system entry. | + *||||||
DEFER | + *Indicates that the alternative catalogs including those + * specified in delegate entries or nextCatalog are not read until they are + * needed. The default value is true. | + *javax.xml.catalog.defer [4] | + *javax.xml.catalog.defer | + *javax.xml.catalog.defer | + *String | + *{@code true} | + *Loads alternative catalogs as needed. + * | + *
{@code false} | + *Loads all catalogs[5]. | + *||||||
RESOLVE | + *Determines the action if there is no matching entry found after + * all of the specified catalogs are exhausted. The default is strict. | + *javax.xml.catalog.resolve [4] | + *javax.xml.catalog.resolve | + *javax.xml.catalog.resolve | + *String | + *{@code strict} | + *Throws CatalogException if there is no match. + * | + *
{@code continue} | + *Allows the XML parser to continue as if there is no match. + * | + *||||||
{@code ignore} | + *Tells the XML parser to skip the external references if there no match. + * | + *
+ * [1] There is no System property for the features that marked as "N/A". + * + *
+ * [2] The value shall be exactly as listed in this table, case-sensitive. + * Any unspecified value will result in {@link IllegalArgumentException}. + *
+ * [3] The Catalog specification defined complex rules on + * + * the prefer attribute. Although the prefer can be public or system, the + * specification actually made system the preferred option, that is, no matter + * the option, a system entry is always used if found. Public entries are only + * considered if the prefer is public and system entries are not found. It is + * therefore recommended that the prefer attribute be set as public + * (which is the default). + *
+ * [4] Although non-standard attributes in the OASIS Catalog specification, + * {@code defer} and {@code resolve} are recognized by the Java Catalog API the + * same as the {@code prefer} as being an attribute in the catalog entry of the + * main catalog. Note that only the attributes specified for the catalog entry + * of the main Catalog file will be used. + *
+ * [5] If the intention is to share an entire catalog store, it may be desirable to + * set the property {@code javax.xml.catalog.defer} to false to allow the entire + * catalog to be pre-loaded. + *
+ *
+ * Properties that are specified as attributes in the catalog file for the
+ * catalog and group entries shall take preference over any of the other settings.
+ * For example, if a {@code prefer} attribute is set in the catalog file as in
+ * {@code
+ * Properties set through the Catalog API override those that may have been set
+ * by system properties and/or in {@code jaxp.properties}. In case of multiple
+ * interfaces, the latest in a procedure shall take preference. For
+ * {@link Feature#FILES}, this means that the path(s) specified through the methods
+ * of the {@link CatalogManager} will override any that may have been entered
+ * through the {@link Builder}.
+ *
+ *
+ * System properties when set shall override those in {@code jaxp.properties}.
+ *
+ * The {@code jaxp.properties} file is typically in the conf directory of the Java
+ * installation. The file is read only once by the JAXP implementation and
+ * its 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
+ * made to check for its existence. It is not possible to change the value
+ * of any properties in {@code jaxp.properties} after it has been read.
+ *
+ * A CatalogFeatures instance can be created through its builder as illustrated
+ * in the following sample code:
+ *
+ * If more than one catalog files are specified through the path argument or
+ * {@code javax.xml.catalog.files} property, the first entry is considered
+ * the main catalog, while others are treated as alternative catalogs after
+ * those referenced by the {@code nextCatalog} elements in the main catalog.
+ *
+ * @param features the catalog features
+ * @param path path(s) to one or more catalogs.
+ *
+ * @return a catalog instance
+ * @throws CatalogException If no catalog can be found whether through the
+ * specified path or the System property {@code javax.xml.catalog.files}, or
+ * an error occurs while parsing the catalog
+ */
+ public static Catalog catalog(CatalogFeatures features, String... path) {
+ return new CatalogImpl(features, path);
+ }
+
+ /**
+ * Creates an instance of a CatalogResolver using the specified catalog.
+ *
+ * @param catalog the catalog instance
+ * @return an instance of a CatalogResolver
+ */
+ public static CatalogResolver catalogResolver(Catalog catalog) {
+ if (catalog == null) CatalogMessages.reportNPEOnNull("catalog", null);
+ return new CatalogResolverImpl(catalog);
+ }
+
+ /**
+ * Creates an instance of a CatalogUriResolver using the specified catalog.
+ *
+ * @param catalog the catalog instance
+ * @return an instance of a CatalogResolver
+ */
+ public static CatalogUriResolver catalogUriResolver(Catalog catalog) {
+ if (catalog == null) CatalogMessages.reportNPEOnNull("catalog", null);
+ return new CatalogUriResolverImpl(catalog);
+ }
+
+ /**
+ * Creates an instance of a CatalogResolver using the specified feature settings
+ * and path to a catalog file. If the features is null, the default features will
+ * be used. If the path is empty, System property {@code javax.xml.catalog.files}
+ * will be read to locate the initial list of catalog files.
+ *
+ * If more than one catalog files are specified through the path argument or
+ * {@code javax.xml.catalog.files} property, the first entry is considered
+ * the main catalog, while others are treated as alternative catalogs after
+ * those referenced by the {@code nextCatalog} elements in the main catalog.
+ *
+ * @param features the catalog features
+ * @param path the path(s) to one or more catalogs
+ *
+ * @return an instance of a CatalogResolver
+ * @throws CatalogException If no catalog can be found whether through the
+ * specified path or the System property {@code javax.xml.catalog.files}, or
+ * an error occurs while parsing the catalog
+ */
+ public static CatalogResolver catalogResolver(CatalogFeatures features, String... path) {
+ Catalog catalog = catalog(features, path);
+ return new CatalogResolverImpl(catalog);
+ }
+
+ /**
+ * Creates an instance of a CatalogUriResolver using the specified feature settings
+ * and path to a catalog file. If the features is null, the default features will
+ * be used. If the path is empty, System property {@code javax.xml.catalog.files}
+ * will be read to locate the initial list of catalog files.
+ *
+ * If more than one catalog files are specified through the path argument or
+ * {@code javax.xml.catalog.files} property, the first entry is considered
+ * the main catalog, while others are treated as alternative catalogs after
+ * those referenced by the {@code nextCatalog} elements in the main catalog.
+ *
+ * @param features the catalog features
+ * @param path the path(s) to one or more catalogs
+ *
+ * @return an instance of a CatalogResolver
+ * @throws CatalogException If no catalog can be found whether through the
+ * specified path or the System property {@code javax.xml.catalog.files}, or
+ * an error occurs while parsing the catalog
+ */
+ public static CatalogUriResolver catalogUriResolver(CatalogFeatures features, String... path) {
+ Catalog catalog = catalog(features, path);
+ return new CatalogUriResolverImpl(catalog);
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import jdk.xml.internal.SecuritySupport;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Catalog Error messages
+ *
+ * @since 9
+ */
+final class CatalogMessages {
+
+ public static final String ERR_INVALID_CATALOG = "InvalidCatalog";
+ public static final String ERR_INVALID_ENTRY_TYPE = "InvalidEntryType";
+ public static final String ERR_INVALID_ARGUMENT = "InvalidArgument";
+ public static final String ERR_NULL_ARGUMENT = "NullArgument";
+ public static final String ERR_CIRCULAR_REFERENCE = "CircularReference";
+ public static final String ERR_INVALID_PATH = "InvalidPath";
+ public static final String ERR_PARSER_CONF = "ParserConf";
+ public static final String ERR_PARSING_FAILED = "ParsingFailed";
+ public static final String ERR_NO_CATALOG = "NoCatalogFound";
+ public static final String ERR_NO_MATCH = "NoMatchFound";
+ public static final String ERR_NO_URI_MATCH = "NoMatchURIFound";
+ public static final String ERR_CREATING_URI = "FailedCreatingURI";
+ public static final String ERR_OTHER = "OtherError";
+
+ static final String bundleName = CatalogMessages.class.getPackage().getName() + ".CatalogMessages";
+ static ResourceBundle resourceBundle;
+
+ /**
+ * Reports an error.
+ * @param key the message key
+ */
+ static void reportError(String key) {
+ reportError(key, null);
+ }
+
+ /**
+ * Reports an error.
+ * @param key the message key
+ * @param arguments the message replacement text arguments. The order of the
+ * arguments must match that of the placeholders in the actual message.
+ */
+ static void reportError(String key, Object[] arguments) {
+ throw new CatalogException(formatMessage(key, arguments));
+ }
+
+ /**
+ * Reports a CatalogException.
+ * @param key the message key
+ * @param arguments the message replacement text arguments. The order of the
+ * arguments must match that of the placeholders in the actual message.
+ */
+ static void reportRunTimeError(String key, Object[] arguments) {
+ throw new CatalogException(formatMessage(key, arguments));
+ }
+
+ /**
+ * Reports a CatalogException.
+ * @param key the message key
+ * @param cause the cause if any
+ */
+ static void reportRunTimeError(String key, Throwable cause) {
+ throw new CatalogException(formatMessage(key, null), cause);
+ }
+
+ /**
+ * Reports a CatalogException.
+ * @param key the message key
+ * @param arguments the message replacement text arguments. The order of the
+ * arguments must match that of the placeholders in the actual message.
+ * @param cause the cause if any
+ */
+ static void reportRunTimeError(String key, Object[] arguments, Throwable cause) {
+ throw new CatalogException(formatMessage(key, arguments), cause);
+ }
+
+ /**
+ * Reports IllegalArgumentException if the argument is null.
+ *
+ * @param name the name of the argument
+ * @param value the value of the argument
+ */
+ static void reportIAEOnNull(String name, String value) {
+ if (value == null) {
+ throw new IllegalArgumentException(
+ formatMessage(ERR_INVALID_ARGUMENT, new Object[]{null, name}));
+ }
+ }
+
+ /**
+ * Reports NullPointerException if the argument is null.
+ *
+ * @param name the name of the argument
+ * @param value the value of the argument
+ */
+ static void reportNPEOnNull(String name, String value) {
+ if (value == null) {
+ throw new NullPointerException(
+ formatMessage(ERR_NULL_ARGUMENT, new Object[]{name}));
+ }
+ }
+
+ /**
+ * Reports IllegalArgumentException
+ * @param arguments the arguments for formating the error message
+ * @param cause the cause if any
+ */
+ static void reportIAE(Object[] arguments, Throwable cause) {
+ throw new IllegalArgumentException(
+ formatMessage(ERR_INVALID_ARGUMENT, arguments), cause);
+ }
+
+ /**
+ * Format a message with the specified arguments using the default locale
+ * information.
+ *
+ * @param key the message key
+ * @param arguments the message replacement text arguments. The order of the
+ * arguments must match that of the placeholders in the actual message.
+ *
+ * @return the formatted message
+ *
+ * @throws MissingResourceException If the message with the specified key
+ * cannot be found
+ */
+ static String formatMessage(String key, Object[] arguments) {
+ return formatMessage(key, arguments, Locale.getDefault());
+ }
+
+ /**
+ * Format a message with the specified arguments using the given locale
+ * information.
+ *
+ * @param key the message key
+ * @param arguments the message replacement text arguments. The order of the
+ * arguments must match that of the placeholders in the actual message.
+ * @param locale the locale of the message
+ *
+ * @return the formatted message
+ *
+ * @throws MissingResourceException If the message with the specified key
+ * cannot be found
+ */
+ static String formatMessage(String key, Object[] arguments, Locale locale) {
+ return SecuritySupport.getErrorMessage(locale, bundleName, key, arguments);
+ }
+
+ /**
+ * Returns sanitized URI.
+ * @param uri an URI to be sanitized
+ */
+ static String sanitize(String uri) {
+ if (uri == null) {
+ return null;
+ }
+ String temp;
+ int p;
+ p = uri.lastIndexOf("/");
+ if (p > 0 && p < uri.length()) {
+ return uri.substring(p + 1);
+ }
+ return uri;
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.properties
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.properties Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,43 @@
+# Copyright (c) 2015, 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.
+
+# Messages for message reporting
+BadMessageKey = The error message corresponding to the message key can not be found.
+FormatFailed = An internal error occurred while formatting the following message:\n
+
+#invalid catalog file
+InvalidCatalog = The document element of a catalog must be catalog.
+InvalidEntryType = The entry type ''{0}'' is not valid.
+CircularReference = Circular reference is not allowed: ''{0}''.
+
+#errors
+InvalidArgument = The specified argument ''{0}'' (case sensitive) for ''{1}'' is not valid.
+NullArgument = The argument ''{0}'' can not be null.
+InvalidPath = The path ''{0}'' is invalid.
+ParserConf = Unexpected error while configuring a SAX parser.
+ParsingFailed = Failed to parse the catalog file.
+NoCatalogFound = No Catalog is specified.
+NoMatchFound = No match found for publicId ''{0}'' and systemId ''{1}''.
+NoMatchURIFound = No match found for href ''{0}'' and base ''{1}''.
+FailedCreatingURI = Can not construct URI using href ''{0}'' and base ''{1}''.
+OtherError = Unexpected error.
\ No newline at end of file
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.io.StringReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import javax.xml.catalog.BaseEntry.CatalogEntryType;
+import javax.xml.parsers.SAXParser;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXSource;
+import org.xml.sax.Attributes;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * CatalogReader handles SAX events while parsing through a catalog file to
+ * create a catalog object.
+ *
+ * @since 9
+ */
+class CatalogReader extends DefaultHandler implements EntityResolver, URIResolver {
+ /** URI of the W3C XML Schema for OASIS XML Catalog files. */
+ public static final String xmlCatalogXSD = "http://www.oasis-open.org/committees/entity/release/1.0/catalog.xsd";
+
+ /** Public identifier for OASIS XML Catalog files. */
+ public static final String xmlCatalogPubId = "-//OASIS//DTD XML Catalogs V1.0//EN";
+
+ /**
+ * The namespace name defined by the OASIS Standard
+ */
+ public static final String NAMESPACE_OASIS = "urn:oasis:names:tc:entity:xmlns:xml:catalog";
+
+ //Indicate whether the root element has been found
+ boolean seenRoot;
+
+ //Indicate that the parser is in a group entry
+ boolean inGroup;
+
+ //The Catalog instance
+ CatalogImpl catalog;
+
+ //The parser for reading the catalog
+ SAXParser parser;
+
+ //The current catalog entry
+ CatalogEntry catalogEntry;
+
+ //The current group
+ GroupEntry group;
+
+ //The current entry
+ BaseEntry entry;
+
+ //remove this variable once 8136778 is committed
+ boolean ignoreTheCatalog = false;
+
+ /**
+ * Constructs an instance with a Catalog object and parser.
+ *
+ * @param catalog The Catalog object that represents a catalog
+ */
+ @SuppressWarnings("unchecked")
+ public CatalogReader(Catalog catalog, SAXParser parser) {
+ this.catalog = (CatalogImpl) catalog;
+ this.parser = parser;
+ }
+
+ /**
+ * Returns when the specified path is valid.
+ * @param path a path
+ * @return true if the path is valid, false otherwise
+ */
+ boolean isValidPath(String path) {
+ boolean valid = true;
+ try {
+ Path p = Paths.get(new URI(path));
+ if (!p.toFile().exists()) {
+ valid = false;
+ }
+ } catch (URISyntaxException ex) {
+ valid = false;
+ }
+
+ return valid;
+ }
+
+ @Override
+ public void startElement(String namespaceURI,
+ String localName,
+ String qName,
+ Attributes atts)
+ throws SAXException {
+
+ //ignore the catalog if it's not compliant. See section 8, item 3 of the spec.
+ if (ignoreTheCatalog) return;
+ if (!NAMESPACE_OASIS.equals(namespaceURI)) {
+//wait till 8136778 is committed
+// parser.stop();
+ ignoreTheCatalog = true;
+ return;
+ }
+
+
+ CatalogEntryType type = CatalogEntryType.getType(localName);
+ if (type == null) {
+ CatalogMessages.reportError(CatalogMessages.ERR_INVALID_ENTRY_TYPE,
+ new Object[]{localName});
+ }
+ if (type != CatalogEntryType.CATALOGENTRY) {
+ if (!seenRoot) {
+ CatalogMessages.reportError(CatalogMessages.ERR_INVALID_CATALOG);
+ }
+ }
+
+ String base = atts.getValue("xml:base");
+ if (base == null) {
+ if (inGroup) {
+ base = group.getBaseURI().toString();
+ } else {
+ if (type == CatalogEntryType.CATALOGENTRY) {
+ base = catalog.getBaseURI().toString();
+ } else {
+ base = catalogEntry.getBaseURI().toString();
+ }
+ }
+ } else {
+ base = Normalizer.normalizeURI(base);
+ }
+
+ //parse the catalog and group entries
+ if (type == CatalogEntryType.CATALOGENTRY
+ || type == CatalogEntryType.GROUP) {
+ String prefer = atts.getValue("prefer");
+ if (prefer == null) {
+ if (type == CatalogEntryType.CATALOGENTRY) {
+ //use the general setting
+ prefer = catalog.isPreferPublic() ?
+ CatalogFeatures.PREFER_PUBLIC : CatalogFeatures.PREFER_SYSTEM;
+ } else {
+ //Group inherit from the catalog entry
+ prefer = catalogEntry.isPreferPublic() ?
+ CatalogFeatures.PREFER_PUBLIC : CatalogFeatures.PREFER_SYSTEM;
+ }
+ }
+
+ if (type == CatalogEntryType.CATALOGENTRY) {
+ seenRoot = true;
+ if (catalog.isTop()) {
+ String defer = atts.getValue("defer");
+ String resolve = atts.getValue("resolve");
+ if (defer == null) {
+ defer = catalog.isDeferred() ?
+ CatalogFeatures.DEFER_TRUE : CatalogFeatures.DEFER_FALSE;
+ }
+ if (resolve == null) {
+ resolve = catalog.getResolve().literal;
+ }
+ catalog.setResolve(resolve);
+ catalogEntry = new CatalogEntry(base, prefer, defer, resolve);
+ } else {
+ catalogEntry = new CatalogEntry(base, prefer);
+ }
+ return;
+ } else {
+ inGroup = true;
+ group = new GroupEntry(catalog, base, prefer);
+ catalog.addEntry(group);
+ return;
+ }
+ }
+
+ //parse entries other than the catalog and group entries
+ switch (type) {
+ case PUBLIC:
+ entry = new PublicEntry(base, atts.getValue("publicId"), atts.getValue("uri"));
+ break;
+ case SYSTEM:
+ entry = new SystemEntry(base, atts.getValue("systemId"), atts.getValue("uri"));
+ break;
+ case REWRITESYSTEM:
+ entry = new RewriteSystem(base, atts.getValue("systemIdStartString"), atts.getValue("rewritePrefix"));
+ break;
+ case SYSTEMSUFFIX:
+ entry = new SystemSuffix(base, atts.getValue("systemIdSuffix"), atts.getValue("uri"));
+ break;
+ case DELEGATEPUBLIC:
+ entry = new DelegatePublic(base, atts.getValue("publicIdStartString"), atts.getValue("catalog"));
+ break;
+ case DELEGATESYSTEM:
+ entry = new DelegateSystem(base, atts.getValue("systemIdStartString"), atts.getValue("catalog"));
+ break;
+ case URI:
+ entry = new UriEntry(base, atts.getValue("name"), atts.getValue("uri"));
+ break;
+ case REWRITEURI:
+ entry = new RewriteUri(base, atts.getValue("uriStartString"), atts.getValue("rewritePrefix"));
+ break;
+ case URISUFFIX:
+ entry = new UriSuffix(base, atts.getValue("uriSuffix"), atts.getValue("uri"));
+ break;
+ case DELEGATEURI:
+ entry = new DelegateUri(base, atts.getValue("uriStartString"), atts.getValue("catalog"));
+ break;
+ case NEXTCATALOG:
+ entry = new NextCatalog(base, atts.getValue("catalog"));
+ break;
+ }
+
+ if (type == CatalogEntryType.NEXTCATALOG) {
+ catalog.addNextCatalog((NextCatalog) entry);
+ } else if (inGroup) {
+ group.addEntry(entry);
+ } else {
+ catalog.addEntry(entry);
+ }
+
+ }
+
+ /**
+ * Handles endElement event
+ */
+ @Override
+ public void endElement(String namespaceURI, String localName, String qName)
+ throws SAXException {
+ if (ignoreTheCatalog) return;
+
+ CatalogEntryType type = CatalogEntryType.getType(localName);
+ if (type == CatalogEntryType.GROUP) {
+ inGroup = false;
+ } else if (type == CatalogEntryType.CATALOGENTRY) {
+ /*
+ Done reading the catalog file.
+ Load delegate and alternative catalogs if defer is false.
+ */
+ if (!catalog.isDeferred()) {
+ catalog.loadDelegateCatalogs();
+ catalog.loadNextCatalogs();
+ }
+ }
+ }
+
+
+ /**
+ * Skips external DTD since resolving external DTD is not required
+ * by the specification.
+ */
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId) {
+ return new InputSource(new StringReader(""));
+ }
+
+ /**
+ * Skips external references since resolution is not required
+ * by the specification.
+ */
+ @Override
+ public Source resolve(String href, String base)
+ throws TransformerException {
+ return new SAXSource(new InputSource(new StringReader("")));
+ }
+
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolver.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolver.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+/**
+ * A SAX EntityResolver that uses catalogs to resolve references.
+ *
+ * @since 9
+ */
+public interface CatalogResolver extends EntityResolver {
+
+ /**
+ * The method searches through the catalog entries in the main and
+ * alternative catalogs to attempt to find a match with the specified publicId
+ * or systemId.
+ *
+ * For resolving external entities, system entries will be matched before
+ * the public entries.
+ *
+ * The {@code prefer} attribute: if the {@code prefer} is public,
+ * and there is no match found through the system entries, public entries
+ * will be considered. If it is not specified, the {@code prefer} is public
+ * by default (Note that by the OASIS standard, system entries will always
+ * be considered first when the external system identifier is specified.
+ * Prefer public means that public entries will be matched when both system
+ * and public identifiers are specified. In general therefore, prefer
+ * public is recommended.)
+ *
+ * @param publicId the public identifier of the external entity being
+ * referenced, or null if none was supplied
+ *
+ * @param systemId the system identifier of the external entity being
+ * referenced. A system identifier is required on all external entities. XML
+ * requires a system identifier on all external entities, so this value is
+ * always specified.
+ *
+ * @return a {@link org.xml.sax.InputSource} object if a mapping is found. If no mapping is
+ * found, returns a {@link org.xml.sax.InputSource} object containing an empty
+ * {@link java.io.Reader} if the {@code javax.xml.catalog.resolve} property
+ * is set to {@code ignore}; returns null if the
+ * {@code javax.xml.catalog.resolve} property is set to {@code continue}.
+ *
+ * @throws CatalogException if no mapping is found and
+ * {@code javax.xml.catalog.resolve} is specified as strict
+ */
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId);
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.io.StringReader;
+import java.util.Iterator;
+import org.xml.sax.InputSource;
+
+/**
+ * A SAX EntityResolver/JAXP URIResolver that uses catalogs.
+ *
+ *
+ * This class implements both a SAX EntityResolver and a JAXP URIResolver.
+ *
+ *
+ * @since 9
+ */
+final class CatalogResolverImpl implements CatalogResolver {
+ Catalog catalog;
+
+ /**
+ * Construct an instance of the CatalogResolver from a Catalog.
+ *
+ * @param catalog A Catalog.
+ */
+ public CatalogResolverImpl(Catalog catalog) {
+ this.catalog = catalog;
+ }
+
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId) {
+ //Normalize publicId and systemId
+ systemId = Normalizer.normalizeURI(systemId);
+ publicId = Normalizer.normalizePublicId(Normalizer.decodeURN(publicId));
+
+ //check whether systemId is an urn
+ if (systemId != null && systemId.startsWith("urn:publicid:")) {
+ systemId = Normalizer.decodeURN(systemId);
+ if (publicId != null && !publicId.equals(systemId)) {
+ systemId = null;
+ } else {
+ publicId = systemId;
+ systemId = null;
+ }
+ }
+
+ CatalogImpl c = (CatalogImpl)catalog;
+ String resolvedSystemId = resolve(c, publicId, systemId);
+
+ if (resolvedSystemId != null) {
+ return new InputSource(resolvedSystemId);
+ }
+
+ GroupEntry.ResolveType resolveType = ((CatalogImpl) catalog).getResolve();
+ switch (resolveType) {
+ case IGNORE:
+ return new InputSource(new StringReader(""));
+ case STRICT:
+ CatalogMessages.reportError(CatalogMessages.ERR_NO_MATCH,
+ new Object[]{publicId, systemId});
+ }
+
+ //no action, allow the parser to continue
+ return null;
+ }
+
+ /**
+ * Resolves the publicId or systemId to one specified in the catalog.
+ * @param catalog the catalog
+ * @param publicId the publicId
+ * @param systemId the systemId
+ * @return the resolved systemId if a match is found, null otherwise
+ */
+ String resolve(CatalogImpl catalog, String publicId, String systemId) {
+ String resolvedSystemId = null;
+
+ //search the current catalog
+ catalog.reset();
+ if (systemId != null) {
+ resolvedSystemId = catalog.matchSystem(systemId);
+ }
+ if (resolvedSystemId == null) {
+ resolvedSystemId = catalog.matchPublic(publicId);
+ }
+
+ //mark the catalog as having been searched before trying alternatives
+ catalog.markAsSearched();
+
+ //search alternative catalogs
+ if (resolvedSystemId == null) {
+ Iterator
+ * This class implements both a SAX EntityResolver and a JAXP URIResolver.
+ *
+ *
+ * @since 9
+ */
+final class CatalogUriResolverImpl implements CatalogUriResolver {
+
+ Catalog catalog;
+ CatalogResolverImpl entityResolver;
+
+ /**
+ * Construct an instance of the CatalogResolver from a Catalog.
+ *
+ * @param catalog A Catalog.
+ */
+ public CatalogUriResolverImpl(Catalog catalog) {
+ this.catalog = catalog;
+ }
+
+ @Override
+ public Source resolve(String href, String base) {
+ if (href == null) return null;
+
+ CatalogImpl c = (CatalogImpl)catalog;
+ String uri = Normalizer.normalizeURI(href);
+ String result;
+
+ //remove fragment if any.
+ int hashPos = uri.indexOf("#");
+ if (hashPos >= 0) {
+ uri = uri.substring(0, hashPos);
+ }
+
+ //search the current catalog
+ result = resolve(c, uri);
+ if (result == null) {
+ GroupEntry.ResolveType resolveType = c.getResolve();
+ switch (resolveType) {
+ case IGNORE:
+ return new SAXSource(new InputSource(new StringReader("")));
+ case STRICT:
+ CatalogMessages.reportError(CatalogMessages.ERR_NO_URI_MATCH,
+ new Object[]{href, base});
+ }
+ try {
+ URL url = null;
+
+ if (base == null) {
+ url = new URL(uri);
+ result = url.toString();
+ } else {
+ URL baseURL = new URL(base);
+ url = (href.length() == 0 ? baseURL : new URL(baseURL, uri));
+ result = url.toString();
+ }
+ } catch (java.net.MalformedURLException mue) {
+ CatalogMessages.reportError(CatalogMessages.ERR_CREATING_URI,
+ new Object[]{href, base});
+ }
+ }
+
+ SAXSource source = new SAXSource();
+ source.setInputSource(new InputSource(result));
+ setEntityResolver(source);
+ return source;
+ }
+
+ /**
+ * Resolves the publicId or systemId to one specified in the catalog.
+ * @param catalog the catalog
+ * @param href an href attribute, which may be relative or absolute
+ * @return the resolved systemId if a match is found, null otherwise
+ */
+ String resolve(CatalogImpl catalog, String href) {
+ String result = null;
+
+ //search the current catalog
+ catalog.reset();
+ if (href != null) {
+ result = catalog.matchURI(href);
+ }
+
+ //mark the catalog as having been searched before trying alternatives
+ catalog.markAsSearched();
+
+ //search alternative catalogs
+ if (result == null) {
+ Iterator
+ * This is called from the URIResolver to set an EntityResolver on the SAX
+ * parser to be used for new XML documents that are encountered as a result
+ * of the document() function, xsl:import, or xsl:include. This is done
+ * because the XSLT processor calls out to the SAXParserFactory itself to
+ * create a new SAXParser to parse the new document. The new parser does not
+ * automatically inherit the EntityResolver of the original (although
+ * arguably it should). Quote from JAXP specification on Class
+ * SAXTransformerFactory:
+ *
+ * {@code If an application wants to set the ErrorHandler or EntityResolver
+ * for an XMLReader used during a transformation, it should use a URIResolver
+ * to return the SAXSource which provides (with getXMLReader) a reference to
+ * the XMLReader}
+ *
+ */
+ private void setEntityResolver(SAXSource source) {
+ XMLReader reader = source.getXMLReader();
+ if (reader == null) {
+ SAXParserFactory spFactory = new SAXParserFactoryImpl();
+ spFactory.setNamespaceAware(true);
+ try {
+ reader = spFactory.newSAXParser().getXMLReader();
+ } catch (ParserConfigurationException | SAXException ex) {
+ CatalogMessages.reportRunTimeError(CatalogMessages.ERR_PARSER_CONF, ex);
+ }
+ }
+ if (entityResolver != null) {
+ entityResolver = new CatalogResolverImpl(catalog);
+ }
+ reader.setEntityResolver(entityResolver);
+ source.setXMLReader(reader);
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegatePublic.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegatePublic.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URI;
+
+/**
+ * Represents a delegatePublic entry.
+ *
+ * @since 9
+ */
+final class DelegatePublic extends AltCatalog {
+ String publicIdStartString;
+
+ /**
+ * Construct a delegatePublic entry.
+ * @param startString The publicIdStartString attribute.
+ * @param catalog The catalog attribute.
+ */
+ public DelegatePublic(String base, String startString, String catalog) {
+ super(CatalogEntryType.DELEGATEPUBLIC, base);
+ setPublicIdStartString(startString);
+ setCatalog(catalog);
+ }
+
+ /**
+ * Set the publicIdStartString attribute.
+ * @param startString The publicIdStartString attribute value.
+ */
+ public void setPublicIdStartString (String startString) {
+ CatalogMessages.reportNPEOnNull("publicIdStartString", startString);
+ this.publicIdStartString = Normalizer.normalizePublicId(startString);
+ setMatchId(publicIdStartString);
+ }
+
+ /**
+ * Get the publicIdStartString attribute.
+ * @return The publicIdStartString
+ */
+ public String getPublicIdStartString () {
+ return publicIdStartString;
+ }
+
+ /**
+ * Try to match the specified publicId with the entry.
+ *
+ * @param publicId The publicId to be matched.
+ * @return The URI of the catalog.
+ */
+ @Override
+ public String match(String publicId) {
+ return match(publicId, 0);
+ }
+
+ /**
+ * Try to match the specified publicId with the entry. Return the match if it
+ * is successful and the length of the publicIdStartString is longer than the
+ * longest of any previous match.
+ *
+ * @param publicId The publicId to be matched.
+ * @param currentMatch The length of publicIdStartString of previous match if any.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public URI matchURI(String publicId, int currentMatch) {
+ if (publicIdStartString.length() <= publicId.length() &&
+ publicIdStartString.equals(publicId.substring(0, publicIdStartString.length()))) {
+ if (currentMatch < publicIdStartString.length()) {
+ return catalogURI;
+ }
+ }
+ return null;
+ }
+
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegateSystem.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegateSystem.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URI;
+
+/**
+ * Represents a delegateSystem entry.
+ *
+ * @since 9
+ */
+final class DelegateSystem extends AltCatalog {
+ String systemIdStartString;
+
+ /**
+ * Construct a delegateSystem entry.
+ * @param systemIdStartString The systemIdStartString attribute.
+ * @param catalog The catalog attribute.
+ */
+ public DelegateSystem(String base, String systemIdStartString, String catalog) {
+ super(CatalogEntryType.DELEGATESYSTEM, base);
+ setSystemIdStartString(systemIdStartString);
+ setCatalog(catalog);
+ }
+
+ /**
+ * Set the systemIdStartString attribute.
+ * @param systemIdStartString The systemIdStartString attribute value.
+ */
+ public void setSystemIdStartString (String systemIdStartString) {
+ CatalogMessages.reportNPEOnNull("systemIdStartString", systemIdStartString);
+ this.systemIdStartString = Normalizer.normalizeURI(systemIdStartString);
+ setMatchId(this.systemIdStartString);
+ }
+
+ /**
+ * Get the systemIdStartString attribute.
+ * @return The systemIdStartString
+ */
+ public String getSystemIdStartString () {
+ return systemIdStartString;
+ }
+
+ /**
+ * Try to match the specified systemId with the entry.
+ *
+ * @param systemId The systemId to be matched.
+ * @return The URI of the catalog.
+ */
+ @Override
+ public String match(String systemId) {
+ return match(systemId, 0);
+ }
+
+ /**
+ * Matches the specified publicId with the entry. Return the match if it
+ * is successful and the length of the systemIdStartString is longer than the
+ * longest of any previous match.
+ *
+ * @param systemId The systemId to be matched.
+ * @param currentMatch The length of systemIdStartString of previous match if any.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public URI matchURI(String systemId, int currentMatch) {
+ if (systemIdStartString.length() <= systemId.length() &&
+ systemIdStartString.equals(systemId.substring(0, systemIdStartString.length()))) {
+ if (currentMatch < systemIdStartString.length()) {
+ return catalogURI;
+ }
+ }
+ return null;
+ }
+
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegateUri.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegateUri.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URI;
+
+/**
+ * Represents a delegateURI entry.
+ *
+ * @since 9
+ */
+final class DelegateUri extends AltCatalog {
+ String uriStartString;
+
+ /**
+ * Construct a delegateURI entry.
+ * @param uriStartString The uriStartString attribute.
+ * @param catalog The catalog attribute.
+ */
+ public DelegateUri(String base, String uriStartString, String catalog) {
+ super(CatalogEntryType.DELEGATEURI, base);
+ setURIStartString (uriStartString);
+ setCatalog(catalog);
+ }
+
+ /**
+ * Set the uriStartString attribute.
+ *
+ * @param uriStartString The uriStartString attribute value.
+ */
+ public void setURIStartString (String uriStartString) {
+ CatalogMessages.reportNPEOnNull("uriStartString", uriStartString);
+ this.uriStartString = Normalizer.normalizeURI(uriStartString);
+ setMatchId(this.uriStartString);
+ }
+
+ /**
+ * Get the uriStartString attribute.
+ * @return The uriStartString
+ */
+ public String getURIStartString () {
+ return uriStartString;
+ }
+
+ /**
+ * Try to match the specified systemId with the entry.
+ *
+ * @param systemId The systemId to be matched.
+ * @return The URI of the catalog.
+ */
+ @Override
+ public String match(String systemId) {
+ return match(systemId, 0);
+ }
+
+ /**
+ * Matches the specified systemId with the entry. Return the match if it
+ * is successful and the length of the uriStartString is longer than the
+ * longest of any previous match.
+ *
+ * @param systemId The systemId to be matched.
+ * @param currentMatch The length of uriStartString of previous match if any.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public URI matchURI(String systemId, int currentMatch) {
+ if (uriStartString.length() <= systemId.length() &&
+ uriStartString.equals(systemId.substring(0, uriStartString.length()))) {
+ if (currentMatch < uriStartString.length()) {
+ return catalogURI;
+ }
+ }
+ return null;
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a group entry.
+ *
+ * @since 9
+ */
+class GroupEntry extends BaseEntry {
+ static final int ATTRIBUTE_PREFER = 0;
+ static final int ATTRIBUTE_DEFFER = 1;
+ static final int ATTRIBUTE_RESOLUTION = 2;
+
+ //Unmodifiable features when the Catalog is created
+ CatalogFeatures features;
+
+ //Value of the prefer attribute
+ boolean isPreferPublic = true;
+
+ //The catalog instance this group belongs to
+ CatalogImpl catalog;
+
+ //A list of all entries in a catalog or group
+ List
+ * The method searches through the system-type entries, including system,
+ * rewriteSystem, systemSuffix, delegateSystem, and group entries in the
+ * current catalog in order to find a match.
+ *
+ *
+ * @param systemId The system identifier of the external entity being
+ * referenced.
+ *
+ * @return An URI string if a mapping is found, or null otherwise.
+ */
+ public String matchSystem(String systemId) {
+ String match = null;
+ for (BaseEntry entry : entries) {
+ switch (entry.type) {
+ case SYSTEM:
+ match = ((SystemEntry) entry).match(systemId);
+ //if there's a matching system entry, use it
+ if (match != null) {
+ isInstantMatch = true;
+ return match;
+ }
+ break;
+ case REWRITESYSTEM:
+ match = ((RewriteSystem) entry).match(systemId, longestRewriteMatch);
+ if (match != null) {
+ rewriteMatch = match;
+ longestRewriteMatch = ((RewriteSystem) entry).getSystemIdStartString().length();
+ }
+ break;
+ case SYSTEMSUFFIX:
+ match = ((SystemSuffix) entry).match(systemId, longestSuffixMatch);
+ if (match != null) {
+ suffixMatch = match;
+ longestSuffixMatch = ((SystemSuffix) entry).getSystemIdSuffix().length();
+ }
+ break;
+ case GROUP:
+ GroupEntry grpEntry = (GroupEntry) entry;
+ match = grpEntry.matchSystem(systemId);
+ if (grpEntry.isInstantMatch) {
+ //use it if there is a match of the system type
+ return match;
+ } else if (grpEntry.longestRewriteMatch > longestRewriteMatch) {
+ rewriteMatch = match;
+ } else if (grpEntry.longestSuffixMatch > longestSuffixMatch) {
+ suffixMatch = match;
+ }
+ break;
+ }
+ }
+
+ if (longestRewriteMatch > 0) {
+ return rewriteMatch;
+ } else if (longestSuffixMatch > 0) {
+ return suffixMatch;
+ }
+
+ //if no single match is found, try delegates
+ return matchDelegate(CatalogEntryType.DELEGATESYSTEM, systemId);
+ }
+
+ /**
+ * Attempt to find a matching entry in the catalog by publicId.
+ *
+ *
+ * The method searches through the public-type entries, including public,
+ * delegatePublic, and group entries in the current catalog in order to find
+ * a match.
+ *
+ *
+ * @param publicId The public identifier of the external entity being
+ * referenced.
+ *
+ * @return An URI string if a mapping is found, or null otherwise.
+ */
+ public String matchPublic(String publicId) {
+ //as the specification required
+ if (!isPreferPublic) {
+ return null;
+ }
+
+ //match public entries
+ String match = null;
+ for (BaseEntry entry : entries) {
+ switch (entry.type) {
+ case PUBLIC:
+ match = ((PublicEntry) entry).match(publicId);
+ break;
+ case GROUP:
+ match = ((GroupEntry) entry).matchPublic(publicId);
+ break;
+ }
+ if (match != null) {
+ return match;
+ }
+ }
+
+ //if no single match is found, try delegates
+ return matchDelegate(CatalogEntryType.DELEGATEPUBLIC, publicId);
+ }
+
+ /**
+ * Attempt to find a matching entry in the catalog by the uri element.
+ *
+ *
+ * The method searches through the uri-type entries, including uri,
+ * rewriteURI, uriSuffix, delegateURI and group entries in the current
+ * catalog in order to find a match.
+ *
+ *
+ * @param uri The URI reference of a resource.
+ *
+ * @return An URI string if a mapping is found, or null otherwise.
+ */
+ public String matchURI(String uri) {
+ String match = null;
+ for (BaseEntry entry : entries) {
+ switch (entry.type) {
+ case URI:
+ match = ((UriEntry) entry).match(uri);
+ if (match != null) {
+ isInstantMatch = true;
+ return match;
+ }
+ break;
+ case REWRITEURI:
+ match = ((RewriteUri) entry).match(uri, longestRewriteMatch);
+ if (match != null) {
+ rewriteMatch = match;
+ longestRewriteMatch = ((RewriteUri) entry).getURIStartString().length();
+ }
+ break;
+ case URISUFFIX:
+ match = ((UriSuffix) entry).match(uri, longestSuffixMatch);
+ if (match != null) {
+ suffixMatch = match;
+ longestSuffixMatch = ((UriSuffix) entry).getURISuffix().length();
+ }
+ break;
+ case GROUP:
+ GroupEntry grpEntry = (GroupEntry) entry;
+ match = grpEntry.matchURI(uri);
+ if (grpEntry.isInstantMatch) {
+ //use it if there is a match of the uri type
+ return match;
+ } else if (grpEntry.longestRewriteMatch > longestRewriteMatch) {
+ rewriteMatch = match;
+ } else if (grpEntry.longestSuffixMatch > longestSuffixMatch) {
+ suffixMatch = match;
+ }
+ break;
+ }
+ }
+
+ if (longestRewriteMatch > 0) {
+ return rewriteMatch;
+ } else if (longestSuffixMatch > 0) {
+ return suffixMatch;
+ }
+
+ //if no single match is found, try delegates
+ return matchDelegate(CatalogEntryType.DELEGATEURI, uri);
+ }
+
+ /**
+ * Matches delegatePublic or delegateSystem against the specified id
+ *
+ * @param isSystem The flag to indicate whether the delegate is system or
+ * public
+ * @param id The system or public id to be matched
+ * @return The URI string if a mapping is found, or null otherwise.
+ */
+ private String matchDelegate(CatalogEntryType type, String id) {
+ String match = null;
+ int longestMatch = 0;
+ URI catalogId = null;
+ URI temp;
+
+ //Check delegate types in the current catalog
+ for (BaseEntry entry : entries) {
+ if (entry.type == type) {
+ if (type == CatalogEntryType.DELEGATESYSTEM) {
+ temp = ((DelegateSystem)entry).matchURI(id, longestMatch);
+ } else if (type == CatalogEntryType.DELEGATEPUBLIC) {
+ temp = ((DelegatePublic)entry).matchURI(id, longestMatch);
+ } else {
+ temp = ((DelegateUri)entry).matchURI(id, longestMatch);
+ }
+ if (temp != null) {
+ longestMatch = entry.getMatchId().length();
+ catalogId = temp;
+ }
+ }
+ }
+
+ //Check delegate Catalogs
+ if (catalogId != null) {
+ Catalog delegateCatalog = loadCatalog(catalogId);
+
+ if (delegateCatalog != null) {
+ if (type == CatalogEntryType.DELEGATESYSTEM) {
+ match = delegateCatalog.matchSystem(id);
+ } else if (type == CatalogEntryType.DELEGATEPUBLIC) {
+ match = delegateCatalog.matchPublic(id);
+ } else {
+ match = delegateCatalog.matchURI(id);
+ }
+ }
+ }
+
+ return match;
+ }
+
+ /**
+ * Loads all delegate catalogs.
+ */
+ void loadDelegateCatalogs() {
+ entries.stream()
+ .filter((entry) -> (entry.type == CatalogEntryType.DELEGATESYSTEM ||
+ entry.type == CatalogEntryType.DELEGATEPUBLIC ||
+ entry.type == CatalogEntryType.DELEGATEURI))
+ .map((entry) -> (AltCatalog)entry)
+ .forEach((altCatalog) -> {
+ loadCatalog(altCatalog.getCatalogURI());
+ });
+ }
+
+ /**
+ * Loads a delegate catalog by the catalogId specified.
+ * @param catalogId the catalog Id
+ */
+ Catalog loadCatalog(URI catalogURI) {
+ Catalog delegateCatalog = null;
+ if (catalogURI != null) {
+ String catalogId = catalogURI.toASCIIString();
+ delegateCatalog = getLoadedCatalog(catalogId);
+ if (delegateCatalog == null) {
+ if (verifyCatalogFile(catalogURI)) {
+ delegateCatalog = new CatalogImpl(catalog, features, catalogId);
+ delegateCatalogs.put(catalogId, delegateCatalog);
+ }
+ }
+ }
+
+ return delegateCatalog;
+ }
+
+ /**
+ * Returns a previously loaded Catalog object if found.
+ *
+ * @param catalogId The systemId of a catalog
+ * @return a Catalog object previously loaded, or null if none in the saved
+ * list
+ */
+ Catalog getLoadedCatalog(String catalogId) {
+ Catalog c = null;
+
+ //checl delegate Catalogs
+ c = delegateCatalogs.get(catalogId);
+ if (c == null) {
+ //check other loaded Catalogs
+ c = loadedCatalogs.get(catalogId);
+ }
+
+ return c;
+ }
+
+
+ /**
+ * Verifies that the catalog file represented by the catalogId exists. If it
+ * doesn't, returns false to ignore it as specified in the Catalog
+ * specification, section 8. Resource Failures.
+ *
+ * Verifies that the catalog represented by the catalogId has not been
+ * searched or is not circularly referenced.
+ *
+ * @param catalogId The URI to a catalog
+ * @throws CatalogException if circular reference is found.
+ * @return true if the catalogId passed verification, false otherwise
+ */
+ final boolean verifyCatalogFile(URI catalogURI) {
+ if (catalogURI == null) {
+ return false;
+ }
+
+ //Ignore it if it doesn't exist
+ if (!Files.exists(Paths.get(catalogURI))) {
+ return false;
+ }
+
+ String catalogId = catalogURI.toASCIIString();
+ if (catalogsSearched.contains(catalogId)) {
+ CatalogMessages.reportRunTimeError(CatalogMessages.ERR_CIRCULAR_REFERENCE,
+ new Object[]{CatalogMessages.sanitize(catalogId)});
+ }
+
+ return true;
+ }
+
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/NextCatalog.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/NextCatalog.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+/**
+ * Represents a nextCatalog entry.
+ *
+ * @since 9
+ */
+final class NextCatalog extends AltCatalog {
+
+ /**
+ * Construct a nextCatalog entry.
+ * @param catalog The catalog attribute.
+ */
+ public NextCatalog(String base, String catalog) {
+ super(CatalogEntryType.NEXTCATALOG, base);
+ setCatalog(catalog);
+ }
+
+ @Override
+ public String match(String match) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/Normalizer.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Normalizer.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+/**
+ * The Normalizer is responsible for normalizing Public and System Identifiers
+ * as specified in section 6.2, 6.3 and 6.4 of the specification
+ * *
+ * XML Catalogs, OASIS Standard V1.1, 7 October 2005.
+ *
+ * @since 9
+ */
+class Normalizer {
+
+ /**
+ * Normalize a public identifier in accordance with section 6.2 of the
+ * Catalog specification.
+ *
+ *
+ * All strings of white space in public identifiers must be normalized to
+ * single space characters (#x20), and leading and trailing white space must
+ * be removed.
+ *
+ * @param publicId The unnormalized public identifier
+ *
+ * @return The normalized identifier
+ */
+ static String normalizePublicId(String publicId) {
+ if (publicId == null) return null;
+
+ StringBuilder sb = new StringBuilder(publicId.length());
+ char last = 'a';
+ for (char c : publicId.toCharArray()) {
+ //skip beginning and duplicate space
+ if ((c == ' ') && (sb.length() == 0 || last == ' ')) {
+ continue;
+ }
+
+ //replace whitespace with space
+ if (c == '\t' || c == '\r' || c == '\n') {
+ if (last != ' ') {
+ sb.append(' ');
+ last = ' ';
+ }
+ } else {
+ sb.append(c);
+ last = c;
+ }
+ }
+ //remove the last space
+ if (last == ' ') {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Encode a public identifier as a "publicid" URN.
+ *
+ * @param publicId The unnormalized public identifier
+ *
+ * @return The normalized identifier
+ * @throws CatalogException if encoding failed
+ */
+ static String encodeURN(String publicId) {
+ String urn = normalizePublicId(publicId);
+
+ try {
+ urn = URLEncoder.encode(urn, "UTF-8");
+ urn = urn.replace("::", ";");
+ urn = urn.replace("//", ":");
+ } catch (UnsupportedEncodingException ex) {
+ CatalogMessages.reportRunTimeError(CatalogMessages.ERR_OTHER, ex);
+ }
+ return "urn:publicid:" + urn;
+ }
+
+ /**
+ * Decode a "publicid" URN into a public identifier.
+ *
+ * @param urn The urn:publicid: URN
+ *
+ * @return The normalized identifier
+ * @throws CatalogException if decoding failed
+ */
+ static String decodeURN(String urn) {
+ String publicId;
+
+ if (urn != null && urn.startsWith("urn:publicid:")) {
+ publicId = urn.substring(13);
+ } else {
+ return urn;
+ }
+ try {
+ publicId = publicId.replace(":", "//");
+ publicId = publicId.replace(";", "::");
+ publicId = URLDecoder.decode(publicId, "UTF-8");
+ } catch (UnsupportedEncodingException ex) {
+ CatalogMessages.reportRunTimeError(CatalogMessages.ERR_OTHER, ex);
+ }
+
+ return publicId;
+ }
+
+ /**
+ * Perform character normalization on a URI reference.
+ *
+ * @param uriref The URI reference
+ * @return The normalized URI reference
+ */
+ static String normalizeURI(String uriref) {
+ if (uriref == null) {
+ return null;
+ }
+
+ byte[] bytes;
+ uriref = uriref.trim();
+ try {
+ bytes = uriref.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException uee) {
+ // this can't happen
+ return uriref;
+ }
+
+ StringBuilder newRef = new StringBuilder(bytes.length);
+ for (int count = 0; count < bytes.length; count++) {
+ int ch = bytes[count] & 0xFF;
+
+ if ((ch <= 0x20) // ctrl
+ || (ch > 0x7F) // high ascii
+ || (ch == 0x22) // "
+ || (ch == 0x3C) // <
+ || (ch == 0x3E) // >
+ || (ch == 0x5C) // \
+ || (ch == 0x5E) // ^
+ || (ch == 0x60) // `
+ || (ch == 0x7B) // {
+ || (ch == 0x7C) // |
+ || (ch == 0x7D) // }
+ || (ch == 0x7F)) {
+ newRef.append("%").append(String.format("%02X", ch));
+ } else {
+ newRef.append((char) bytes[count]);
+ }
+ }
+
+ return newRef.toString().trim();
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/PublicEntry.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/PublicEntry.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URL;
+
+/**
+ * Represents a public entry.
+ *
+ * @since 9
+ */
+final class PublicEntry extends BaseEntry {
+ String publicId;
+ URL uri;
+
+ /**
+ * Construct a public entry.
+ * @param publicId The publicId attribute.
+ * @param uri The uri attribute.
+ */
+ public PublicEntry(String base, String publicId, String uri) {
+ super(CatalogEntryType.PUBLIC, base);
+ setPublicId(publicId);
+ setURI(uri);
+ }
+
+ /**
+ * Set the publicId attribute.
+ * @param publicId The publicId attribute value.
+ */
+ public void setPublicId(String publicId) {
+ CatalogMessages.reportNPEOnNull("publicId", publicId);
+ this.publicId = Normalizer.normalizePublicId(publicId);
+ }
+
+ /**
+ * Set the uri attribute. If the value of the uri attribute is relative, it
+ * must be made absolute with respect to the base URI currently in effect.
+ * The URI reference should not include a fragment identifier.
+ * @param uri The uri attribute value.
+ */
+ public void setURI(String uri) {
+ this.uri = verifyURI("uri", baseURI, uri);
+ }
+
+ /**
+ * Get the publicId attribute.
+ * @return The publicId
+ */
+ public String getPublicId() {
+ return publicId;
+ }
+ /**
+ * Get the uri attribute.
+ * @return The uri attribute value.
+ */
+ public URL getURI() {
+ return uri;
+ }
+
+ @Override
+ public String match(String publicId) {
+ if (this.publicId.equals(publicId)) {
+ return uri.toString();
+ }
+ return null;
+ }
+
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URL;
+
+/**
+ * Represents a rewriteSystem entry.
+ *
+ * @since 9
+ */
+final class RewriteSystem extends BaseEntry {
+ String systemIdStartString;
+ URL rewritePrefix;
+
+ /**
+ * Construct a rewriteSystem entry.
+ *
+ * @param systemIdStartString The systemIdStartString attribute.
+ * @param rewritePrefix The rewritePrefix attribute.
+ */
+ public RewriteSystem(String base, String systemIdStartString, String rewritePrefix) {
+ super(CatalogEntryType.REWRITESYSTEM, base);
+ setSystemIdStartString (systemIdStartString);
+ setRewritePrefix(rewritePrefix);
+ }
+
+ /**
+ * Set the systemIdStartString attribute.
+ * @param systemIdStartString The systemIdStartString attribute value.
+ */
+ public void setSystemIdStartString (String systemIdStartString) {
+ CatalogMessages.reportNPEOnNull("systemIdStartString", systemIdStartString);
+ this.systemIdStartString = Normalizer.normalizeURI(systemIdStartString);
+ }
+
+ /**
+ * Set the rewritePrefix attribute. If the value of the rewritePrefix attribute
+ * is relative, it must be made absolute with respect to the base URI currently in effect.
+ * @param rewritePrefix The rewritePrefix attribute value.
+ */
+ public void setRewritePrefix(String rewritePrefix) {
+ this.rewritePrefix = verifyURI("setRewritePrefix", baseURI, rewritePrefix);
+ }
+
+ /**
+ * Get the systemIdStartString attribute.
+ * @return The systemIdStartString
+ */
+ public String getSystemIdStartString () {
+ return systemIdStartString;
+ }
+ /**
+ * Get the rewritePrefix attribute.
+ * @return The rewritePrefix attribute value.
+ */
+ public URL getRewritePrefix() {
+ return rewritePrefix;
+ }
+
+
+ /**
+ * Try to match the specified systemId with the entry. Return the match if it
+ * is successful and the length of the systemIdStartString is longer than the
+ * longest of any previous match.
+ *
+ * @param systemId The systemId to be matched.
+ * @param currentMatch The length of systemIdStartString of previous match if any.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ public String match(String systemId, int currentMatch) {
+ if (systemIdStartString.length() <= systemId.length() &&
+ systemIdStartString.equals(systemId.substring(0, systemIdStartString.length()))) {
+ if (currentMatch < systemIdStartString.length()) {
+ String prefix = rewritePrefix.toExternalForm();
+ if (!prefix.endsWith(SLASH) && !systemId.startsWith(SLASH)) {
+ return prefix + SLASH + systemId.substring(systemIdStartString.length());
+ } else {
+ return prefix + systemId.substring(systemIdStartString.length());
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Try to match the specified systemId with the entry.
+ *
+ * @param systemId The systemId to be matched.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public String match(String systemId) {
+ return match(systemId, 0);
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URL;
+
+/**
+ * Represents a rewriteURI entry.
+ *
+ * @since 9
+ */
+final class RewriteUri extends BaseEntry {
+ String uriStartString;
+ URL rewritePrefix;
+
+ /**
+ * Construct a rewriteURI entry.
+ * @param uriStartString The uriStartString attribute.
+ * @param rewritePrefix The rewritePrefix attribute.
+ */
+ public RewriteUri(String base, String uriStartString, String rewritePrefix) {
+ super(CatalogEntryType.REWRITEURI, base);
+ setURIStartString (uriStartString);
+ setRewritePrefix(rewritePrefix);
+ }
+
+ /**
+ * Set the uriStartString attribute.
+ * @param uriStartString The uriStartString attribute value.
+ */
+ public void setURIStartString (String uriStartString) {
+ CatalogMessages.reportNPEOnNull("uriStartString", uriStartString);
+ this.uriStartString = Normalizer.normalizeURI(uriStartString);
+ }
+
+ /**
+ * Set the rewritePrefix attribute. If the value of the rewritePrefix attribute
+ * is relative, it must be made absolute with respect to the base URI currently in effect.
+ *
+ * @param rewritePrefix The rewritePrefix attribute value.
+ */
+ public void setRewritePrefix(String rewritePrefix) {
+ this.rewritePrefix = verifyURI("setRewritePrefix", baseURI, rewritePrefix);
+ }
+
+ /**
+ * Get the uriStartString attribute.
+ * @return The uriStartString
+ */
+ public String getURIStartString () {
+ return uriStartString;
+ }
+ /**
+ * Get the rewritePrefix attribute.
+ * @return The rewritePrefix attribute value.
+ */
+ public URL getRewritePrefix() {
+ return rewritePrefix;
+ }
+
+ /**
+ * Try to match the specified systemId with the entry. Return the match if it
+ * is successful and the length of the systemIdStartString is longer than the
+ * longest of any previous match.
+ *
+ * @param systemId The systemId to be matched.
+ * @param currentMatch The length of uriStartString of previous match if any.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public String match(String systemId, int currentMatch) {
+ if (uriStartString.length() <= systemId.length() &&
+ uriStartString.equals(systemId.substring(0, uriStartString.length()))) {
+ if (currentMatch < uriStartString.length()) {
+ String prefix = rewritePrefix.toExternalForm();
+ if (!prefix.endsWith(SLASH) && !systemId.startsWith(SLASH)) {
+ return prefix + SLASH + systemId.substring(uriStartString.length());
+ } else {
+ return prefix + systemId.substring(uriStartString.length());
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String match(String systemId) {
+ return match(systemId, 0);
+ }
+
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/SystemEntry.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/SystemEntry.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URL;
+
+/**
+ * Represents a system entry.
+ *
+ * @since 9
+ */
+final class SystemEntry extends BaseEntry {
+ String systemId;
+ URL uri;
+
+ /**
+ * Construct a system entry.
+ *
+ * @param systemId The systemId attribute.
+ * @param uri The uri attribute.
+ */
+ public SystemEntry(String base, String systemId, String uri) {
+ super(CatalogEntryType.SYSTEM, base);
+ setSystemId(systemId);
+ setURI(uri);
+ }
+
+ /**
+ * Set the systemId attribute.
+ * @param systemId The systemId attribute value.
+ */
+ public void setSystemId(String systemId) {
+ CatalogMessages.reportNPEOnNull("systemId", systemId);
+ this.systemId = Normalizer.normalizeURI(systemId);
+ }
+
+ /**
+ * Set the uri attribute. If the value of the uri attribute is relative, it
+ * must be made absolute with respect to the base URI currently in effect.
+ * The URI reference should not include a fragment identifier.
+ * @param uri The uri attribute value.
+ */
+ public void setURI(String uri) {
+ this.uri = verifyURI("setURI", baseURI, uri);
+ }
+
+ /**
+ * Get the systemId attribute.
+ * @return The systemId
+ */
+ public String getSystemId() {
+ return systemId;
+ }
+ /**
+ * Get the uri attribute.
+ * @return The uri attribute value.
+ */
+ public URL getURI() {
+ return uri;
+ }
+
+ /**
+ * Try to match the specified string with the entry
+ *
+ * @param systemId The systemId to be matched
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public String match(String systemId) {
+ if (this.systemId.equals(systemId)) {
+ return uri.toString();
+ }
+ return null;
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/SystemSuffix.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/SystemSuffix.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URL;
+
+/**
+ * Represents a systemSuffix entry.
+ *
+ * @since 9
+ */
+final class SystemSuffix extends BaseEntry {
+ String systemIdSuffix;
+ URL uri;
+
+ /**
+ * Construct a systemSuffix entry.
+ * @param systemIdSuffix The systemIdSuffix attribute.
+ * @param uri The uri attribute.
+ */
+ public SystemSuffix(String base, String systemIdSuffix, String uri) {
+ super(CatalogEntryType.SYSTEMSUFFIX, base);
+ setSystemIdSuffix(systemIdSuffix);
+ setURI(uri);
+ }
+
+ /**
+ * Set the systemIdSuffix attribute.
+ * @param systemIdSuffix The systemIdSuffix attribute value.
+ */
+ public void setSystemIdSuffix(String systemIdSuffix) {
+ CatalogMessages.reportNPEOnNull("systemIdSuffix", systemIdSuffix);
+ this.systemIdSuffix = Normalizer.normalizeURI(systemIdSuffix);
+ }
+
+ /**
+ * Set the uri attribute. If the value of the uri attribute is relative, it
+ * must be made absolute with respect to the base URI currently in effect.
+ * The URI reference should not include a fragment identifier.
+ * @param uri The uri attribute value.
+ */
+ public void setURI(String uri) {
+ this.uri = verifyURI("setURI", baseURI, uri);
+ }
+
+ /**
+ * Get the systemIdSuffix attribute.
+ * @return The systemIdSuffix
+ */
+ public String getSystemIdSuffix () {
+ return systemIdSuffix;
+ }
+ /**
+ * Get the uri attribute.
+ * @return The uri attribute value.
+ */
+ public URL getURI() {
+ return uri;
+ }
+
+ /**
+ * Try to match the specified systemId with the entry. Return the match if it
+ * is successful and the length of the systemIdSuffix is longer than the longest
+ * of any previous match.
+ *
+ * @param systemId The systemId to be matched.
+ * @param currentMatch The length of systemIdSuffix of previous match if any.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public String match(String systemId, int currentMatch) {
+ if (systemId.endsWith(systemIdSuffix)) {
+ if (currentMatch < systemIdSuffix.length()) {
+ return uri.toString();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Try to match the specified systemId with the entry.
+ *
+ * @param systemId The systemId to be matched.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public String match(String systemId) {
+ return match(systemId, 0);
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/UriEntry.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/UriEntry.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URL;
+
+/**
+ * Represents an uriEntry entry.
+ *
+ * @since 9
+ */
+final class UriEntry extends BaseEntry {
+ String name;
+ URL uri;
+
+ /**
+ * Construct a group entry.
+ * @param name The name attribute.
+ * @param uri The uri attribute.
+ */
+ public UriEntry(String base, String name, String uri) {
+ super(CatalogEntryType.URI, base);
+ setName(name);
+ setURI(uri);
+ }
+
+ /**
+ * Set the name attribute.
+ * @param name The name attribute value.
+ */
+ public void setName(String name) {
+ CatalogMessages.reportNPEOnNull("name", name);
+ this.name = Normalizer.normalizeURI(name);
+ }
+
+ /**
+ * Set the uri attribute. If the value of the uri attribute is relative, it
+ * must be made absolute with respect to the base URI currently in effect.
+ *
+ * @param uri The uri attribute value.
+ */
+ public void setURI(String uri) {
+ this.uri = verifyURI("setURI", baseURI, uri);
+ }
+
+ /**
+ * Get the name attribute.
+ * @return The name
+ */
+ public String getName() {
+ return name;
+ }
+ /**
+ * Get the uri attribute.
+ * @return The uri attribute value.
+ */
+ public URL getURI() {
+ return uri;
+ }
+
+ @Override
+ public String match(String name) {
+ if (this.name.equals(name)) {
+ return uri.toString();
+ }
+ return null;
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/UriSuffix.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/UriSuffix.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import java.net.URL;
+
+/**
+ * Represents a uriSuffix entry.
+ *
+ * @since 9
+ */
+final class UriSuffix extends BaseEntry {
+ String uriSuffix;
+ URL uri;
+
+ /**
+ * Construct a group entry.
+ * @param uriSuffix The uriSuffix attribute.
+ * @param uri The uri attribute.
+ */
+ public UriSuffix(String base, String uriSuffix, String uri) {
+ super(CatalogEntryType.URISUFFIX, base);
+ setURISuffix (uriSuffix);
+ setURI(uri);
+ }
+
+ /**
+ * Set the uriSuffix attribute.
+ * @param uriSuffix The uriSuffix attribute value.
+ */
+ public void setURISuffix(String uriSuffix) {
+ CatalogMessages.reportNPEOnNull("uriSuffix", uriSuffix);
+ this.uriSuffix = Normalizer.normalizeURI(uriSuffix);
+ }
+
+ /**
+ * Set the uri attribute. If the value of the uri attribute is relative, it
+ * must be made absolute with respect to the base URI currently in effect.
+ * The URI reference should not include a fragment identifier.
+ * @param uri The uri attribute value.
+ */
+ public void setURI(String uri) {
+ this.uri = verifyURI("setURI", baseURI, uri);
+ }
+
+ /**
+ * Get the uriSuffix attribute.
+ * @return The uriSuffix
+ */
+ public String getURISuffix () {
+ return uriSuffix;
+ }
+ /**
+ * Get the uri attribute.
+ * @return The uri attribute value.
+ */
+ public String getURI() {
+ return uri.toString();
+ }
+
+ /**
+ * Try to match the specified systemId with the entry. Return the match if it
+ * is successful and the length of the uriSuffix is longer than the longest
+ * of any previous match.
+ *
+ * @param systemId The systemId to be matched.
+ * @param currentMatch The length of uriSuffix of previous match if any.
+ * @return The replacement URI if the match is successful, null if not.
+ */
+ @Override
+ public String match(String systemId, int currentMatch) {
+ if (systemId.endsWith(uriSuffix)) {
+ if (currentMatch < uriSuffix.length()) {
+ return uri.toString();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String match(String systemId) {
+ return match(systemId, 0);
+ }
+
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import jdk.xml.internal.SecuritySupport;
+
+/**
+ *
+ * @since 9
+ */
+class Util {
+ /**
+ * Find catalog file paths by reading the system property, and then
+ * jaxp.properties if the system property is not specified.
+ *
+ * @param sysPropertyName the name of system property
+ * @return the catalog file paths, or null if not found.
+ */
+ static public String[] getCatalogFiles(String sysPropertyName) {
+ String value = SecuritySupport.getJAXPSystemProperty(sysPropertyName);
+ if (value != null && !value.equals("")) {
+ return value.split(";");
+ }
+ return null;
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/package.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/package.html Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,44 @@
+
+
+
+ Unless otherwise noted, passing a null argument to
+ a constructor or method in any class or interface in this package will
+ cause a NullPointerException to be thrown.
+ {@code
+ CatalogFeatures f = CatalogFeatures.builder()
+ .with(Feature.FILES, "catalog.xml")
+ .with(Feature.PREFER, "public")
+ .with(Feature.DEFER, "true")
+ .with(Feature.RESOLVE, "ignore")
+ .build();
+ * }
+ *
+ * @since 9
+ */
+public class CatalogFeatures {
+
+ /**
+ * The constant name of the javax.xml.catalog.files property. See the property table for more details.
+ */
+ static final String CATALOG_FILES = "javax.xml.catalog.files";
+
+ /**
+ * The javax.xml.catalog.prefer property. See the property table for more details.
+ */
+ static final String CATALOG_PREFER = "javax.xml.catalog.prefer";
+
+ /**
+ * Determines whether or not delegated catalogs and nextCatalog will be read
+ * when the current catalog is loaded.
+ */
+ static final String CATALOG_DEFER = "javax.xml.catalog.defer";
+
+ /**
+ * Determines the action if there is no matching entry found after
+ * all of the specified catalogs are exhausted.
+ */
+ static final String CATALOG_RESOLVE = "javax.xml.catalog.resolve";
+
+ //values for the prefer property
+ static final String PREFER_SYSTEM = "system";
+ static final String PREFER_PUBLIC = "public";
+
+ //values for the defer property
+ static final String DEFER_TRUE = "true";
+ static final String DEFER_FALSE = "false";
+
+ //values for the Resolve property
+ static final String RESOLVE_STRICT = "strict";
+ static final String RESOLVE_CONTINUE = "continue";
+ static final String RESOLVE_IGNORE = "ignore";
+
+ /**
+ * A Feature type as defined in the
+ * Catalog Features table.
+ */
+ public static enum Feature {
+ /**
+ * The {@code javax.xml.catalog.files} property as described in
+ * item FILES of the
+ * Catalog Features table.
+ */
+ FILES(CATALOG_FILES, null, true),
+ /**
+ * The {@code javax.xml.catalog.prefer} property as described in
+ * item PREFER of the
+ * Catalog Features table.
+ */
+ PREFER(CATALOG_PREFER, PREFER_PUBLIC, false),
+ /**
+ * The {@code javax.xml.catalog.defer} property as described in
+ * item DEFER of the
+ * Catalog Features table.
+ */
+ DEFER(CATALOG_DEFER, DEFER_TRUE, true),
+ /**
+ * The {@code javax.xml.catalog.resolve} property as described in
+ * item RESOLVE of the
+ * Catalog Features table.
+ */
+ RESOLVE(CATALOG_RESOLVE, RESOLVE_STRICT, true);
+
+ private final String name;
+ private final String defaultValue;
+ private String value;
+ private final boolean hasSystem;
+
+ /**
+ * Constructs a CatalogFeature instance.
+ * @param name the name of the feature
+ * @param value the value of the feature
+ * @param hasSystem a flag to indicate whether the feature is supported
+ * with a System property
+ */
+ Feature(String name, String value, boolean hasSystem) {
+ this.name = name;
+ this.defaultValue = value;
+ this.hasSystem = hasSystem;
+ }
+
+ /**
+ * Checks whether the specified property is equal to the current property.
+ * @param propertyName the name of a property
+ * @return true if the specified property is the current property, false
+ * otherwise
+ */
+ boolean equalsPropertyName(String propertyName) {
+ return name.equals(propertyName);
+ }
+
+ /**
+ * Returns the name of the corresponding System Property.
+ *
+ * @return the name of the System Property
+ */
+ public String getPropertyName() {
+ return name;
+ }
+
+ /**
+ * Returns the default value of the property.
+ * @return the default value of the property
+ */
+ String defaultValue() {
+ return defaultValue;
+ }
+
+ /**
+ * Returns the value of the property.
+ * @return the value of the property
+ */
+ String getValue() {
+ return value;
+ }
+
+ /**
+ * Checks whether System property is supported for the feature.
+ * @return true it is supported, false otherwise
+ */
+ boolean hasSystemProperty() {
+ return hasSystem;
+ }
+ }
+
+ /**
+ * States of the settings of a property, in the order: default value,
+ * jaxp.properties file, jaxp system properties, and jaxp api properties
+ */
+ static enum State {
+ /** represents the default state of a feature. */
+ DEFAULT("default"),
+ /** indicates the value of the feature is read from jaxp.properties. */
+ JAXPDOTPROPERTIES("jaxp.properties"),
+ /** indicates the value of the feature is read from its System property. */
+ SYSTEMPROPERTY("system property"),
+ /** indicates the value of the feature is specified through the API. */
+ APIPROPERTY("property"),
+ /** indicates the value of the feature is specified as a catalog attribute. */
+ CATALOGATTRIBUTE("catalog attribute");
+
+ final String literal;
+
+ State(String literal) {
+ this.literal = literal;
+ }
+
+ String literal() {
+ return literal;
+ }
+ }
+
+ /**
+ * Values of the properties
+ */
+ private String[] values;
+
+ /**
+ * States of the settings for each property
+ */
+ private State[] states;
+
+ /**
+ * Private class constructor
+ */
+ private CatalogFeatures() {
+ }
+
+ /**
+ * Returns a CatalogFeatures instance with default settings.
+ * @return a default CatalogFeatures instance
+ */
+ public static CatalogFeatures defaults() {
+ return CatalogFeatures.builder().build();
+ }
+
+ /**
+ * Constructs a new CatalogFeatures instance with the builder.
+ *
+ * @param builder the builder to build the CatalogFeatures
+ */
+ CatalogFeatures(Builder builder) {
+ init();
+ setProperty(Feature.FILES.ordinal(), State.APIPROPERTY, builder.files);
+ setProperty(Feature.PREFER.ordinal(), State.APIPROPERTY, builder.prefer);
+ setProperty(Feature.DEFER.ordinal(), State.APIPROPERTY, builder.defer);
+ setProperty(Feature.RESOLVE.ordinal(), State.APIPROPERTY, builder.resolve);
+ }
+
+ /**
+ * Returns the value of the specified feature.
+ *
+ * @param cf the type of the Catalog feature
+ * @return the value of the feature
+ */
+ public String get(Feature cf) {
+ return values[cf.ordinal()];
+ }
+
+ /**
+ * Initializes the supported properties
+ */
+ private void init() {
+ values = new String[Feature.values().length];
+ states = new State[Feature.values().length];
+ for (Feature cf : Feature.values()) {
+ setProperty(cf.ordinal(), State.DEFAULT, cf.defaultValue());
+ }
+ //read system properties or jaxp.properties
+ readSystemProperties();
+ }
+
+ /**
+ * Sets the value of a property by its index, updates only if it shall override.
+ *
+ * @param index the index of the property
+ * @param state the state of the property
+ * @param value the value of the property
+ * @throws IllegalArgumentException if the value is invalid
+ */
+ private void setProperty(int index, State state, String value) {
+ if (value != null && value.length() != 0) {
+ if (index == Feature.PREFER.ordinal()) {
+ if (!value.equals(PREFER_SYSTEM) && !value.equals(PREFER_PUBLIC)) {
+ CatalogMessages.reportIAE(new Object[]{value, Feature.PREFER.name()}, null);
+ }
+ } else if (index == Feature.DEFER.ordinal()) {
+ if (!value.equals(DEFER_TRUE) && !value.equals(DEFER_FALSE)) {
+ CatalogMessages.reportIAE(new Object[]{value, Feature.DEFER.name()}, null);
+ }
+ } else if (index == Feature.RESOLVE.ordinal()) {
+ if (!value.equals(RESOLVE_STRICT) && !value.equals(RESOLVE_CONTINUE)
+ && !value.equals(RESOLVE_IGNORE)) {
+ CatalogMessages.reportIAE(new Object[]{value, Feature.RESOLVE.name()}, null);
+ }
+ }
+ if (states[index] == null || state.compareTo(states[index]) >= 0) {
+ values[index] = value;
+ states[index] = state;
+ }
+ }
+ }
+
+ /**
+ * Reads from system properties, or those in jaxp.properties
+ */
+ private void readSystemProperties() {
+ for (Feature cf : Feature.values()) {
+ getSystemProperty(cf, cf.getPropertyName());
+ }
+ }
+
+ /**
+ * Reads from system properties, or those in jaxp.properties
+ *
+ * @param cf the type of the property
+ * @param sysPropertyName the name of system property
+ */
+ private boolean getSystemProperty(Feature cf, String sysPropertyName) {
+ if (cf.hasSystemProperty()) {
+ String value = SecuritySupport.getSystemProperty(sysPropertyName);
+ if (value != null && !value.equals("")) {
+ setProperty(cf.ordinal(), State.SYSTEMPROPERTY, value);
+ return true;
+ }
+
+ value = SecuritySupport.readJAXPProperty(sysPropertyName);
+ if (value != null && !value.equals("")) {
+ setProperty(cf.ordinal(), State.JAXPDOTPROPERTIES, value);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns an instance of the builder for creating the CatalogFeatures object.
+ *
+ * @return an instance of the builder
+ */
+ public static Builder builder() {
+ return new CatalogFeatures.Builder();
+ }
+
+ /**
+ * The Builder class for building the CatalogFeatures object.
+ */
+ public static class Builder {
+ /**
+ * Variables for the features supported by CatalogFeatures.
+ */
+ String files, prefer, defer, resolve;
+
+ /**
+ * Instantiation of Builder is not allowed.
+ */
+ private Builder() {}
+
+ /**
+ * Sets the value to a specified Feature.
+ * @param feature the Feature to be set
+ * @param value the value to be set for the Feature
+ * @return this Builder instance
+ * @throws IllegalArgumentException if the value is not valid for the
+ * Feature or has the wrong syntax for the {@code javax.xml.catalog.files}
+ * property
+ */
+ public Builder with(Feature feature, String value) {
+ switch (feature) {
+ case FILES :
+ files = value;
+ break;
+ case PREFER :
+ prefer = value;
+ break;
+ case DEFER :
+ defer = value;
+ break;
+ case RESOLVE :
+ resolve = value;
+ break;
+ }
+ return this;
+ }
+
+ /**
+ * Returns a CatalogFeatures object built by this builder.
+ *
+ * @return an instance of CatalogFeatures
+ */
+ public CatalogFeatures build() {
+ return new CatalogFeatures(this);
+ }
+ }
+}
diff -r d131f4b8433a -r 9f0eef87e8c1 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java Thu Oct 29 21:53:21 2015 -0700
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2015, 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.catalog;
+
+import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import static javax.xml.catalog.BaseEntry.CatalogEntryType;
+import static javax.xml.catalog.CatalogFeatures.DEFER_TRUE;
+import javax.xml.catalog.CatalogFeatures.Feature;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * Implementation of the Catalog.
+ *
+ * @since 9
+ */
+class CatalogImpl extends GroupEntry implements Catalog {
+
+ //Catalog level, 0 means the top catalog
+ int level = 0;
+
+ //Value of the defer attribute to determine if alternative catalogs are read
+ boolean isDeferred = true;
+
+ //Value of the resolve attribute
+ ResolveType resolveType = ResolveType.STRICT;
+
+ //indicate whether the Catalog is empty
+ boolean isEmpty;
+
+ //Current parsed Catalog
+ int current = 0;
+
+ //System Id for this catalog
+ String systemId;
+
+ //The parent
+ CatalogImpl parent = null;
+
+ /*
+ A list of catalog entry files from the input, excluding the current catalog.
+ Paths in the List are normalized.
+ */
+ List