Merge
authorlana
Thu, 05 Nov 2015 13:42:14 -0800
changeset 33544 bbe6f7195a37
parent 33541 b21dec69735a (current diff)
parent 33543 cd228512f933 (diff)
child 33545 cef7927d9672
Merge
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/AltCatalog.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/BaseEntry.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Catalog.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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
+ * <a
+ * href="https://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html">
+ * XML Catalogs, OASIS Standard V1.1, 7 October 2005</a>.
+ * <p>
+ * 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.
+ *
+ * <p>
+ * A catalog can be used in two situations:
+ * <ul>
+ * <li>Locate the replacement text for an external entity;
+ * </li>
+ * <li>Locate an alternate URI reference for a resource.
+ * </li>
+ * </ul>
+ * <p>
+ * For case 1, the standard defines 6 External Identifier Entries:<br>
+ * {@code public, system, rewriteSystem, systemSuffix, delegatePublic, and
+ * delegateSystem}.
+ * <p>
+ * While for case 2, it defines 4 URI Entries:<br>
+ * {@code uri, rewriteURI, uriSuffix and delegateURI}.
+ * <p>
+ * In addition to the above entry types, a catalog may define nextCatalog
+ * entries to add additional catalog entry files.
+ * <p>
+ *
+ * @since 9
+ */
+public interface Catalog {
+
+    /**
+     * Attempts to find a matching entry in the catalog by systemId.
+     *
+     * <p>
+     * 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.
+     * <p>
+     * Resolution follows the steps listed below: <br>
+     * <ul>
+     * <li>If a matching {@code system} entry exists, it is returned immediately.</li>
+     * <li>If more than one {@code rewriteSystem} entry matches, the matching entry with
+     * the longest normalized {@code systemIdStartString} value is returned.</li>
+     * <li>If more than one {@code systemSuffix} entry matches, the matching entry
+     * with the longest normalized {@code systemIdSuffix} value is returned.</li>
+     * <li>If more than one {@code delegateSystem} entry matches, the matching entry
+     * with the longest matching {@code systemIdStartString} value is returned.</li>
+     * </ul>
+     *
+     * @param systemId the system identifier of the entity to be matched
+     *
+     * @return an URI string if a mapping is found, or null otherwise
+     */
+    public String matchSystem(String systemId);
+
+    /**
+     * Attempts to find a matching entry in the catalog by publicId. The method
+     * searches through the public-type entries, including {@code public,
+     * delegatePublic}, and {@code group} entries in the current catalog in order to find
+     * a match.
+     * <p>
+     * Refer to the description about <a href="CatalogFeatures.html#PREFER">
+     * Feature PREFER in the table Catalog Features</a> in class
+     * {@link CatalogFeatures}. Public entries are only considered if the
+     * {@code prefer} is {@code public} and {@code system} entries are not found.
+     * <p>
+     * Resolution follows the steps listed below: <br>
+     * <ul>
+     * <li>If a matching {@code public} entry is found, it is returned immediately.</li>
+     * <li>If more than one {@code delegatePublic} entry matches, the matching entry
+     * with the longest matching {@code publicIdStartString} value is returned.</li>
+     * </ul>
+     *
+     * @param publicId the public identifier of the entity to be matched
+     * @see CatalogFeatures.Feature
+     * @return an URI string if a mapping is found, or null otherwise
+     */
+    public String matchPublic(String publicId);
+
+    /**
+     * Attempts to find a matching entry in the catalog by the uri element.
+     *
+     * <p>
+     * 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.
+     *
+     * <p>
+     * Resolution follows the steps listed below: <br>
+     * <ul>
+     * <li>If a matching {@code uri} entry is found, it is returned immediately.</li>
+     * <li>If more than one {@code rewriteURI} entry matches, the matching entry with
+     * the longest normalized {@code uriStartString} value is returned.</li>
+     * <li>If more than one {@code uriSuffix} entry matches, the matching entry with
+     * the longest normalized {@code uriSuffix} value is returned.</li>
+     * <li>If more than one {@code delegatePublic} entry matches, the matching entry
+     * with the longest matching {@code uriStartString} value is returned.</li>
+     * </ul>
+     *
+     * @param uri the URI reference of the entity to be matched
+     *
+     * @return an URI string if a mapping is found, or null otherwise
+     */
+    public String matchURI(String uri);
+
+    /**
+     * Returns a sequential Stream of alternative Catalogs specified using the
+     * {@code nextCatalog} entries in the current catalog, and as the input of
+     * catalog files excluding the current catalog (that is, the first in the
+     * input list) when the Catalog object is created by the {@link CatalogManager}.
+     * <p>
+     * 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> catalogs();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogEntry.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,50 @@
+/*
+ * 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 the catalog element or entry of a catalog file
+ *
+ * @since 9
+ */
+class CatalogEntry extends GroupEntry {
+
+    /**
+     * Construct a catalog entry.
+     *
+     * @param base The baseURI attribute
+     * @param attributes The attributes
+     */
+    public CatalogEntry(String base, String... attributes) {
+        super(base, attributes);
+        setType(CatalogEntryType.CATALOGENTRY);
+    }
+
+    @Override
+    public String match(String match) {
+        throw new UnsupportedOperationException("Unsupported operation.");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogException.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+/**
+ * The exception class handles errors that may happen while processing or using
+ * a catalog.
+ *
+ * @since 9
+ */
+public class CatalogException extends RuntimeException {
+
+    private static final long serialVersionUID = 653231525876459057L;
+
+    /**
+     * Constructs a new CatalogException with the specified detail message. The
+     * cause is not initialized, and may subsequently be initialized by a call
+     * to {@link #initCause}.
+     *
+     * @param message the detail message
+     */
+    public CatalogException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new CatalogException with the specified detail message and
+     * cause.
+     *
+     * @param message the detail message (which is saved for later retrieval by
+     * the {@link #getMessage()} method)
+     * @param cause the cause (which is saved for later retrieval by the
+     * {@link #getCause()} method). (A {@code null} value is permitted, and
+     * indicates that the cause is nonexistent or unknown.)
+     */
+    public CatalogException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,534 @@
+/*
+ * 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;
+
+/**
+ * The CatalogFeatures holds a collection of features and properties.
+ * <p>
+ *
+ * <center><h2><a name="CatalogFeatures">Catalog Features</a></h2></center></p>
+ *
+ * <table border="1">
+ * <thead>
+ * <tr>
+ * <th rowspan="2">Feature</th>
+ * <th rowspan="2">Description</th>
+ * <th rowspan="2">Property Name</th>
+ * <th rowspan="2">System Property [1]</th>
+ * <th rowspan="2">jaxp.properties [1]</th>
+ * <th colspan="2" align="center">Value [2]</th>
+ * <th rowspan="2">Action</th>
+ * </tr>
+ * <tr>
+ * <th>Type</th>
+ * <th>Value</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ *
+ * <tr>
+ * <td><a name="FILES">FILES</a></td>
+ * <td>A semicolon-delimited list of catalog files. Relative file paths are
+ * considered relative to ${user.dir}.
+ * </td>
+ * <td>javax.xml.catalog.files</td>
+ * <td>javax.xml.catalog.files</td>
+ * <td>javax.xml.catalog.files</td>
+ * <td>String</td>
+ * <td>File paths</td>
+ * <td>
+ * Reads the first catalog as the current catalog; Loads others if no match
+ * is found in the current catalog including delegate catalogs if any.
+ * </td>
+ * </tr>
+ *
+ * <tr>
+ * <td rowspan="2"><a name="PREFER">PREFER</a></td>
+ * <td rowspan="2">Indicates the preference between the public and system
+ * identifiers. The default value is public [3].</td>
+ * <td rowspan="2">javax.xml.catalog.prefer</td>
+ * <td rowspan="2">N/A</td>
+ * <td rowspan="2">N/A</td>
+ * <td rowspan="2">String</td>
+ * <td>{@code system}</td>
+ * <td>Searches system entries for a match; Searches public entries when
+ * external identifier specifies only a public identifier</td>
+ * </tr>
+ * <tr>
+ * <td>{@code public}</td>
+ * <td>Searches system entries for a match; Searches public entries when
+ * there is no matching system entry.</td>
+ * </tr>
+ *
+ * <tr>
+ * <td rowspan="2"><a name="DEFER">DEFER</a></td>
+ * <td rowspan="2">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.</td>
+ * <td rowspan="2">javax.xml.catalog.defer [4]</td>
+ * <td rowspan="2">javax.xml.catalog.defer</td>
+ * <td rowspan="2">javax.xml.catalog.defer</td>
+ * <td rowspan="2">String</td>
+ * <td>{@code true}</td>
+ * <td>Loads alternative catalogs as needed.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>{@code false}</td>
+ * <td>Loads all catalogs[5]. </td>
+ * </tr>
+ *
+ * <tr>
+ * <td rowspan="3"><a name="RESOLVE">RESOLVE</a></td>
+ * <td rowspan="3">Determines the action if there is no matching entry found after
+ * all of the specified catalogs are exhausted. The default is strict.</td>
+ * <td rowspan="3">javax.xml.catalog.resolve [4]</td>
+ * <td rowspan="3">javax.xml.catalog.resolve</td>
+ * <td rowspan="3">javax.xml.catalog.resolve</td>
+ * <td rowspan="3">String</td>
+ * <td>{@code strict}</td>
+ * <td>Throws CatalogException if there is no match.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>{@code continue}</td>
+ * <td>Allows the XML parser to continue as if there is no match.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>{@code ignore}</td>
+ * <td>Tells the XML parser to skip the external references if there no match.
+ * </td>
+ * </tr>
+ *
+ * </tbody>
+ * </table>
+ * <p>
+ * <b>[1]</b> There is no System property for the features that marked as "N/A".
+ *
+ * <p>
+ * <b>[2]</b> The value shall be exactly as listed in this table, case-sensitive.
+ * Any unspecified value will result in {@link IllegalArgumentException}.
+ * <p>
+ * <b>[3]</b> The Catalog specification defined complex rules on
+ * <a href="https://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html#attrib.prefer">
+ * the prefer attribute</a>. 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).
+ * <p>
+ * <b>[4]</b> 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.
+  * <p>
+ * <b>[5]</b> 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.
+ * <p>
+ * <h3>Scope and Order</h3>
+ * Features and properties can be set through the catalog file, the Catalog API,
+ * system properties, and {@code jaxp.properties}, with a preference in the same order.
+ * <p>
+ * 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 <catalog prefer="public">}, any other input for the "prefer" property
+ * is not necessary or will be ignored.
+ * <p>
+ * 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}.
+ *
+ * <p>
+ * System properties when set shall override those in {@code jaxp.properties}.
+ * <p>
+ * 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.
+ * <p>
+ * A CatalogFeatures instance can be created through its builder as illustrated
+ * in the following sample code:
+ * <pre>{@code
+                CatalogFeatures f = CatalogFeatures.builder()
+                        .with(Feature.FILES, "catalog.xml")
+                        .with(Feature.PREFER, "public")
+                        .with(Feature.DEFER, "true")
+                        .with(Feature.RESOLVE, "ignore")
+                        .build();
+ * }</pre>
+ *
+ * @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
+     * <a href="CatalogFeatures.html#CatalogFeatures">Catalog Features table</a>.
+     */
+    public static enum Feature {
+        /**
+         * The {@code javax.xml.catalog.files} property as described in
+         * item <a href="CatalogFeatures.html#FILES">FILES</a> of the
+         * Catalog Features table.
+         */
+        FILES(CATALOG_FILES, null, true),
+        /**
+         * The {@code javax.xml.catalog.prefer} property as described in
+         * item <a href="CatalogFeatures.html#PREFER">PREFER</a> of the
+         * Catalog Features table.
+         */
+        PREFER(CATALOG_PREFER, PREFER_PUBLIC, false),
+        /**
+         * The {@code javax.xml.catalog.defer} property as described in
+         * item <a href="CatalogFeatures.html#DEFER">DEFER</a> of the
+         * Catalog Features table.
+         */
+        DEFER(CATALOG_DEFER, DEFER_TRUE, true),
+        /**
+         * The {@code javax.xml.catalog.resolve} property as described in
+         * item <a href="CatalogFeatures.html#RESOLVE">RESOLVE</a> 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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<String> inputFiles;
+
+    //A list of catalogs specified using the nextCatalog element
+    List<NextCatalog> nextCatalogs;
+
+    //reuse the parser
+    SAXParser parser;
+
+    /**
+     * Construct a Catalog with specified path.
+     *
+     * @param file The path to a catalog file.
+     * @throws CatalogException If an error happens while parsing the specified
+     * catalog file.
+     */
+    public CatalogImpl(CatalogFeatures f, String... file) throws CatalogException {
+        this(null, f, file);
+    }
+
+    /**
+     * Construct a Catalog with specified path.
+     *
+     * @param parent The parent catalog
+     * @param file The path to a catalog file.
+     * @throws CatalogException If an error happens while parsing the specified
+     * catalog file.
+     */
+    public CatalogImpl(CatalogImpl parent, CatalogFeatures f, String... file) throws CatalogException {
+        super(CatalogEntryType.CATALOG);
+        this.parent = parent;
+        if (parent == null) {
+            level = 0;
+        } else {
+            level = parent.level + 1;
+        }
+        if (f == null) {
+            this.features = CatalogFeatures.defaults();
+        } else {
+            this.features = f;
+        }
+        setPrefer(features.get(Feature.PREFER));
+        setDeferred(features.get(Feature.DEFER));
+        setResolve(features.get(Feature.RESOLVE));
+
+        //Path of catalog files
+        String[] catalogFile = file;
+        if (level == 0
+                && (file == null || (file.length == 0 || file[0] == null))) {
+            String files = features.get(Feature.FILES);
+            if (files != null) {
+                catalogFile = files.split(";[ ]*");
+            }
+        }
+
+        /*
+         In accordance with 8. Resource Failures of the Catalog spec, missing
+         Catalog entry files are to be ignored.
+         */
+        if ((catalogFile != null && catalogFile.length > 0)) {
+            int start = 0;
+            URI uri = null;
+            for (String temp : catalogFile) {
+                uri = getSystemId(temp);
+                start++;
+                if (verifyCatalogFile(uri)) {
+                    systemId = uri.toASCIIString();
+                    break;
+                }
+            }
+
+            //Save the rest of input files as alternative catalogs
+            if (level == 0 && catalogFile.length > start) {
+                inputFiles = new ArrayList<>();
+                for (int i = start; i < catalogFile.length; i++) {
+                    if (catalogFile[i] != null) {
+                        inputFiles.add(catalogFile[i]);
+                    }
+                }
+            }
+
+            if (systemId != null) {
+                parse(systemId);
+            }
+        }
+    }
+
+    /**
+     * Resets the Catalog instance to its initial state.
+     */
+    @Override
+    public void reset() {
+        super.reset();
+        current = 0;
+        if (level == 0) {
+            catalogsSearched.clear();
+        }
+        entries.stream().filter((entry) -> (entry.type == CatalogEntryType.GROUP)).forEach((entry) -> {
+            ((GroupEntry) entry).reset();
+        });
+
+        if (parent != null) {
+            this.loadedCatalogs = parent.loadedCatalogs;
+            this.catalogsSearched = parent.catalogsSearched;
+        }
+    }
+
+    /**
+     * Returns whether this Catalog instance is the top (main) Catalog.
+     *
+     * @return true if the instance is the top Catalog, false otherwise
+     */
+    boolean isTop() {
+        return level == 0;
+    }
+
+    /**
+     * Gets the parent of this catalog.
+     *
+     * @returns The parent catalog
+     */
+    public Catalog getParent() {
+        return this.parent;
+    }
+
+    /**
+     * Sets the defer property. If the value is null or empty, or any String
+     * other than the defined, it will be assumed as the default value.
+     *
+     * @param value The value of the defer attribute
+     */
+    public final void setDeferred(String value) {
+        isDeferred = DEFER_TRUE.equals(value);
+    }
+
+    /**
+     * Queries the defer attribute
+     *
+     * @return true if the prefer attribute is set to system, false if not.
+     */
+    public boolean isDeferred() {
+        return isDeferred;
+    }
+
+    /**
+     * Sets the resolve property. If the value is null or empty, or any String
+     * other than the defined, it will be assumed as the default value.
+     *
+     * @param value The value of the resolve attribute
+     */
+    public final void setResolve(String value) {
+        resolveType = ResolveType.getType(value);
+    }
+
+    /**
+     * Gets the value of the resolve attribute
+     *
+     * @return The value of the resolve attribute
+     */
+    public final ResolveType getResolve() {
+        return resolveType;
+    }
+
+    /**
+     * Marks the Catalog as being searched already.
+     */
+    void markAsSearched() {
+        catalogsSearched.add(systemId);
+    }
+
+    /**
+     * Parses the catalog.
+     *
+     * @param systemId The systemId of the catalog
+     * @throws CatalogException if parsing the catalog failed
+     */
+    private void parse(String systemId) {
+        if (parser == null) {
+            parser = getParser();
+        }
+
+        try {
+            CatalogReader reader = new CatalogReader(this, parser);
+            parser.parse(systemId, reader);
+        } catch (SAXException | IOException ex) {
+            CatalogMessages.reportRunTimeError(CatalogMessages.ERR_PARSING_FAILED, ex);
+        }
+    }
+
+    /**
+     * Resolves the specified file path to an absolute systemId. If it is
+     * relative, it shall be resolved using the base or user.dir property if
+     * base is not specified.
+     *
+     * @param file The specified file path
+     * @return The systemId of the file
+     * @throws CatalogException if the specified file path can not be converted
+     * to a system id
+     */
+    private URI getSystemId(String file) {
+        URL filepath;
+        if (file != null && file.length() > 0) {
+            try {
+                File f = new File(file);
+                if (baseURI != null && !f.isAbsolute()) {
+                    filepath = new URL(baseURI, fixSlashes(file));
+                    return filepath.toURI();
+                } else {
+                    return resolveURI(file);
+                }
+            } catch (MalformedURLException | URISyntaxException e) {
+                CatalogMessages.reportRunTimeError(CatalogMessages.ERR_INVALID_PATH,
+                        new Object[]{file}, e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Resolves the specified uri. If the uri is relative, makes it absolute by
+     * the user.dir directory.
+     *
+     * @param uri The specified URI.
+     * @return The resolved URI
+     */
+    private URI resolveURI(String uri) throws MalformedURLException {
+        if (uri == null) {
+            uri = "";
+        }
+
+        URI temp = toURI(uri);
+        String str = temp.toASCIIString();
+        String base = str.substring(0, str.lastIndexOf('/') + 1);
+        baseURI = new URL(str);
+
+        return temp;
+    }
+
+    /**
+     * Converts an URI string or file path to URI.
+     *
+     * @param uri an URI string or file path
+     * @return an URI
+     */
+    private URI toURI(String uri) {
+        URI temp = null;
+        try {
+            URL url = new URL(uri);
+            temp = url.toURI();
+        } catch (MalformedURLException | URISyntaxException mue) {
+            File file = new File(uri);
+            temp = file.toURI();
+        }
+        return temp;
+    }
+
+    /**
+     * Returns a SAXParser instance
+     * @return a SAXParser instance
+     * @throws CatalogException if constructing a SAXParser failed
+     */
+    private SAXParser getParser() {
+        SAXParser p = null;
+        try {
+            SAXParserFactory spf = new SAXParserFactoryImpl();
+            spf.setNamespaceAware(true);
+            spf.setValidating(false);
+            spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+            p = spf.newSAXParser();
+        } catch (ParserConfigurationException | SAXException e) {
+            CatalogMessages.reportRunTimeError(CatalogMessages.ERR_PARSING_FAILED, e);
+        }
+        return p;
+    }
+
+    /**
+     * Indicate that the catalog is empty
+     *
+     * @return True if the catalog is empty; False otherwise.
+     */
+    public boolean isEmpty() {
+        return isEmpty;
+    }
+
+    @Override
+    public Stream<Catalog> catalogs() {
+        Iterator<Catalog> iter = new Iterator<Catalog>() {
+            Catalog nextCatalog = null;
+
+            //Current index of the input files
+            int inputFilesIndex = 0;
+
+            //Next catalog
+            int nextCatalogIndex = 0;
+
+            @Override
+            public boolean hasNext() {
+                if (nextCatalog != null) {
+                    return true;
+                } else {
+                    nextCatalog = nextCatalog();
+                    return (nextCatalog != null);
+                }
+            }
+
+            @Override
+            public Catalog next() {
+                if (nextCatalog != null || hasNext()) {
+                    Catalog catalog = nextCatalog;
+                    nextCatalog = null;
+                    return catalog;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            /**
+             * Returns the next alternative catalog.
+             *
+             * @return the next catalog if any
+             */
+            private Catalog nextCatalog() {
+                Catalog c = null;
+
+                //Check those specified in nextCatalogs
+                if (nextCatalogs != null) {
+                    while (c == null && nextCatalogIndex < nextCatalogs.size()) {
+                        c = getCatalog(nextCatalogs.get(nextCatalogIndex++).getCatalogURI());
+                    }
+                }
+
+                //Check the input list
+                if (c == null && inputFiles != null) {
+                    while (c == null && inputFilesIndex < inputFiles.size()) {
+                        c = getCatalog(getSystemId(inputFiles.get(inputFilesIndex++)));
+                    }
+                }
+
+                return c;
+            }
+        };
+
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
+    }
+
+    /**
+     * Adds the catalog to the nextCatalog list
+     *
+     * @param catalog a catalog specified in a nextCatalog entry
+     */
+    void addNextCatalog(NextCatalog catalog) {
+        if (catalog == null) {
+            return;
+        }
+
+        if (nextCatalogs == null) {
+            nextCatalogs = new ArrayList<>();
+        }
+
+        nextCatalogs.add(catalog);
+    }
+
+    /**
+     * Loads all alternative catalogs.
+     */
+    void loadNextCatalogs() {
+        //loads catalogs specified in nextCatalogs
+        if (nextCatalogs != null) {
+            for (NextCatalog next : nextCatalogs) {
+                getCatalog(next.getCatalogURI());
+            }
+        }
+
+        //loads catalogs from the input list
+        if (inputFiles != null) {
+            for (String file : inputFiles) {
+                getCatalog(getSystemId(file));
+            }
+        }
+    }
+
+    /**
+     * Returns a Catalog object by the specified path.
+     *
+     * @param path the path to a catalog
+     * @return a Catalog object
+     */
+    Catalog getCatalog(URI uri) {
+        if (uri == null) {
+            return null;
+        }
+
+        Catalog c = null;
+        String path = uri.toASCIIString();
+
+        if (verifyCatalogFile(uri)) {
+            c = getLoadedCatalog(path);
+            if (c == null) {
+                c = new CatalogImpl(this, features, path);
+                saveLoadedCatalog(path, c);
+            }
+        }
+        return c;
+    }
+
+    /**
+     * Saves a loaded Catalog.
+     *
+     * @param catalogId the catalogId associated with the Catalog object
+     * @param c the Catalog to be saved
+     */
+    void saveLoadedCatalog(String catalogId, Catalog c) {
+        loadedCatalogs.put(catalogId, c);
+    }
+
+    /**
+     * Returns a count of all loaded catalogs, including delegate catalogs.
+     *
+     * @return a count of all loaded catalogs
+     */
+    int loadedCatalogCount() {
+        return loadedCatalogs.size() + delegateCatalogs.size();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,132 @@
+/*
+ * 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;
+
+
+/**
+ * The Catalog Manager manages the creation of XML Catalogs and Catalog Resolvers.
+ *
+ * @since 9
+ */
+public final class CatalogManager {
+    /**
+     * Creating CatalogManager instance is not allowed.
+     */
+    private CatalogManager() {
+    }
+
+    /**
+     * Creates a Catalog object 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogMessages.properties	Thu Nov 05 13:42:14 2015 -0800
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogReader.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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("")));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolver.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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.
+     * <p>
+     * For resolving external entities, system entries will be matched before
+     * the public entries.
+     * <p>
+     * <b>The {@code prefer} attribute</b>: 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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogResolverImpl.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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.
+ *
+ * <p>
+ * 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<Catalog> iter = catalog.catalogs().iterator();
+            while (iter.hasNext()) {
+                resolvedSystemId = resolve((CatalogImpl)iter.next(), publicId, systemId);
+                if (resolvedSystemId != null) {
+                    break;
+                }
+
+            }
+        }
+
+        return resolvedSystemId;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolver.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,58 @@
+/*
+ * 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 javax.xml.transform.Source;
+import javax.xml.transform.URIResolver;
+
+/**
+ * A JAXP URIResolver that uses catalogs to resolve references.
+ *
+ * @since 9
+ */
+public interface CatalogUriResolver extends URIResolver {
+
+    /**
+     * The method searches through the catalog entries in the main and
+     * alternative catalogs to attempt to find a match with the specified URI.
+     *
+     * @param href an href attribute, which may be relative or absolute
+     * @param base The base URI against which the href attribute will be made
+     * absolute if the absolute URI is required
+     *
+     * @return a {@link javax.xml.transform.Source} object if a mapping is found.
+     * If no mapping is found, returns a {@link javax.xml.transform.Source} object
+     * containing an empty {@link java.io.Reader} if the
+     * {@code javax.xml.catalog.resolve} property is set to {@code ignore};
+     * returns a {@link javax.xml.transform.Source} object with the original URI
+     * (href, or href resolved with base if base is not 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 Source resolve(String href, String base);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolverImpl.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,176 @@
+/*
+ * 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.StringReader;
+import java.net.URL;
+import java.util.Iterator;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Source;
+import javax.xml.transform.sax.SAXSource;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+/**
+ * A SAX EntityResolver/JAXP URIResolver that uses catalogs.
+ * <p>
+ * 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<Catalog> iter = catalog.catalogs().iterator();
+            while (iter.hasNext()) {
+                result = resolve((CatalogImpl)iter.next(), href);
+                if (result != null) {
+                    break;
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Establish an entityResolver for newly resolved URIs.
+     * <p>
+     * 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:
+     * <p>
+     * {@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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegatePublic.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegateSystem.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/DelegateUri.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/GroupEntry.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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<BaseEntry> entries = new ArrayList<>();
+
+    //loaded delegated catalog by system id
+    Map<String, Catalog> delegateCatalogs = new HashMap<>();
+
+    //A list of all loaded Catalogs, including this, and next catalogs
+    Map<String, Catalog> loadedCatalogs = new HashMap<>();
+
+    /*
+     A list of Catalog Ids that have already been searched in a matching
+     operation. Check this list before constructing new Catalog to avoid circular
+     reference.
+     */
+    List<String> catalogsSearched = new ArrayList<>();
+
+    //A flag to indicate whether the current match is a system or uri
+    boolean isInstantMatch = false;
+
+    //A match of a rewrite type
+    String rewriteMatch = null;
+
+    //The length of the longest match of a rewrite type
+    int longestRewriteMatch = 0;
+
+    //A match of a suffix type
+    String suffixMatch = null;
+
+    //The length of the longest match of a suffix type
+    int longestSuffixMatch = 0;
+
+    /**
+     * PreferType represents possible values of the prefer property
+     */
+    public static enum PreferType {
+        PUBLIC("public"),
+        SYSTEM("system");
+
+        final String literal;
+
+        PreferType(String literal) {
+            this.literal = literal;
+        }
+
+        public boolean prefer(String prefer) {
+            return literal.equals(prefer);
+        }
+    }
+
+    /**
+     * PreferType represents possible values of the resolve property
+     */
+    public static enum ResolveType {
+        STRICT(CatalogFeatures.RESOLVE_STRICT),
+        CONTINUE(CatalogFeatures.RESOLVE_CONTINUE),
+        IGNORE(CatalogFeatures.RESOLVE_IGNORE);
+
+        final String literal;
+
+        ResolveType(String literal) {
+            this.literal = literal;
+        }
+
+        static public ResolveType getType(String resolveType) {
+            for (ResolveType type : ResolveType.values()) {
+                if (type.isType(resolveType)) {
+                    return type;
+                }
+            }
+            return null;
+        }
+
+        public boolean isType(String type) {
+            return literal.equals(type);
+        }
+    }
+
+    /**
+     * Constructs a GroupEntry
+     *
+     * @param type The type of the entry
+     */
+    public GroupEntry(CatalogEntryType type) {
+        super(type);
+    }
+
+    /**
+     * Constructs a group entry.
+     *
+     * @param base The baseURI attribute
+     * @param attributes The attributes
+     */
+    public GroupEntry(String base, String... attributes) {
+        this(null, base, attributes);
+    }
+
+    /**
+     * Resets the group entry to its initial state.
+     */
+    public void reset() {
+        isInstantMatch = false;
+        rewriteMatch = null;
+        longestRewriteMatch = 0;
+        suffixMatch = null;
+        longestSuffixMatch = 0;
+    }
+    /**
+     * Constructs a group entry.
+     * @param catalog The parent catalog
+     * @param base The baseURI attribute
+     * @param attributes The attributes
+     */
+    public GroupEntry(CatalogImpl catalog, String base, String... attributes) {
+        super(CatalogEntryType.GROUP, base);
+        setPrefer(attributes[ATTRIBUTE_PREFER]);
+        this.catalog = catalog;
+    }
+
+    /**
+     * Adds an entry.
+     *
+     * @param entry The entry to be added.
+     */
+    public void addEntry(BaseEntry entry) {
+        entries.add(entry);
+    }
+
+    /**
+     * Sets the prefer property. If the value is null or empty, or any String
+     * other than the defined, it will be assumed as the default value.
+     *
+     * @param value The value of the prefer attribute
+     */
+    public final void setPrefer(String value) {
+        isPreferPublic = PreferType.PUBLIC.prefer(value);
+    }
+
+    /**
+     * Queries the prefer attribute
+     *
+     * @return true if the prefer attribute is set to system, false if not.
+     */
+    public boolean isPreferPublic() {
+        return isPreferPublic;
+    }
+
+    /**
+     * Attempt to find a matching entry in the catalog by systemId.
+     *
+     * <p>
+     * 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.
+     *
+     * <p>
+     * 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.
+     *
+     * <p>
+     * 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.
+     * <p>
+     * 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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/NextCatalog.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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.");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Normalizer.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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
+ *  * <a
+ * href="https://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html">
+ * XML Catalogs, OASIS Standard V1.1, 7 October 2005</a>.
+ *
+ * @since 9
+ */
+class Normalizer {
+
+    /**
+     * Normalize a public identifier in accordance with section 6.2 of the
+     * Catalog specification.
+     *
+     * <p>
+     * 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();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/PublicEntry.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/SystemEntry.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/SystemSuffix.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/UriEntry.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/UriSuffix.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/Util.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/package.html	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+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. 
+-->
+</head>
+<body bgcolor="white">
+
+    Provides the classes for implementing 
+    <a href="https://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html">
+        XML Catalogs OASIS Standard V1.1, 7 October 2005</a>. 
+
+    <p>
+        Unless otherwise noted, passing a null argument to 
+        a constructor or method in any class or interface in this package will 
+        cause a <tt>NullPointerException</tt> to be thrown.
+    </p>
+
+@since 9
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,153 @@
+/*
+ * 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 jdk.xml.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+/**
+ * This class contains utility methods for reading resources in the JAXP packages
+ */
+public class SecuritySupport {
+    /**
+     * Cache for properties in java.home/conf/jaxp.properties
+     */
+    static final Properties cacheProps = new Properties();
+
+    /**
+     * Flag indicating whether java.home/conf/jaxp.properties has been read
+     */
+    static volatile boolean firstTime = true;
+
+    private SecuritySupport() {}
+
+    public static String getErrorMessage(Locale locale, String bundle, String key,
+            Object[] arguments) {
+        ResourceBundle rb;
+        if (locale != null) {
+            rb = ResourceBundle.getBundle(bundle,locale);
+        } else {
+            rb = ResourceBundle.getBundle(bundle);
+        }
+
+        String msg = rb.getString(key);
+        if (arguments != null) {
+            msg = MessageFormat.format(msg, arguments);
+        }
+        return msg;
+    }
+
+    /**
+     * Reads JAXP system property with privilege
+     *
+     * @param propName the name of the property
+     * @return the value of the property
+     */
+    public static String getSystemProperty(final String propName) {
+        return
+        AccessController.doPrivileged(
+                (PrivilegedAction<String>) () -> (String)System.getProperty(propName));
+    }
+
+    /**
+     * Reads JAXP system property in this order: system property,
+     * $java.home/conf/jaxp.properties if the system property is not specified
+     *
+     * @param propName the name of the property
+     * @return the value of the property
+     */
+    public static String getJAXPSystemProperty(String propName) {
+        String value = getSystemProperty(propName);
+        if (value == null) {
+            value = readJAXPProperty(propName);
+        }
+        return value;
+    }
+
+    /**
+     * Reads the specified property from $java.home/conf/jaxp.properties
+     *
+     * @param propName the name of the property
+     * @return the value of the property
+     */
+    public static String readJAXPProperty(String propName) {
+        String value = null;
+        InputStream is = null;
+        try {
+            if (firstTime) {
+                synchronized (cacheProps) {
+                    if (firstTime) {
+                        String configFile = getSystemProperty("java.home") + File.separator
+                                + "conf" + File.separator + "jaxp.properties";
+                        File f = new File(configFile);
+                        if (getFileExists(f)) {
+                            is = getFileInputStream(f);
+                            cacheProps.load(is);
+                        }
+                        firstTime = false;
+                    }
+                }
+            }
+            value = cacheProps.getProperty(propName);
+
+        } catch (IOException ex) {
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException ex) {}
+            }
+        }
+
+        return value;
+    }
+
+//------------------- private methods ---------------------------
+    static boolean getFileExists(final File f) {
+        return (AccessController.doPrivileged((PrivilegedAction<Boolean>) ()
+                -> f.exists() ? Boolean.TRUE : Boolean.FALSE));
+    }
+
+    static FileInputStream getFileInputStream(final File file)
+            throws FileNotFoundException {
+        try {
+            return AccessController.doPrivileged((PrivilegedExceptionAction<FileInputStream>) ()
+                    -> new FileInputStream(file));
+        } catch (PrivilegedActionException e) {
+            throw (FileNotFoundException) e.getException();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/CatalogReferCircularityTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+
+import javax.xml.catalog.CatalogException;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Via nextCatalog entry, the catalog reference chain may be
+ *          a (partial) closed circuit. For instance, a catalog may use itself
+ *          as an additional catalog specified in its own nextCatalog entry.
+ *          This case tests if the implementation handles this issue.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ */
+public class CatalogReferCircularityTest {
+
+    @Test(dataProvider = "catalogName",
+            expectedExceptions = CatalogException.class)
+    public void testReferCircularity(String catalogFile) {
+        catalogResolver(catalogFile).resolveEntity(null,
+                "http://remote/dtd/ghost/docGhost.dtd");
+    }
+
+    @DataProvider(name = "catalogName")
+    private Object[][] catalogName() {
+        return new Object[][] {
+                // This catalog defines itself as next catalog.
+                { "catalogReferCircle-itself.xml" },
+
+                // This catalog defines catalogReferCircle-right.xml as its next
+                // catalog. And catalogReferCircle-right.xml also defines
+                // catalogReferCircle-left.xml as its next catalog, too.
+                { "catalogReferCircle-left.xml" } };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/DefaultFeaturesTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import javax.xml.catalog.CatalogFeatures;
+import javax.xml.catalog.CatalogFeatures.Feature;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary This case tests if the default feature values are expected.
+ */
+public class DefaultFeaturesTest {
+
+    private CatalogFeatures defaultFeature;
+
+    @BeforeClass
+    public void init() {
+        defaultFeature = CatalogFeatures.defaults();
+    }
+
+    @Test(dataProvider="feature-value")
+    public void testDefaultFeatures(Feature feature, String expected) {
+        String featureValue = defaultFeature.get(feature);
+        if (expected != null) {
+            Assert.assertEquals(featureValue, expected);
+        } else {
+            Assert.assertNull(featureValue);
+        }
+    }
+
+    @DataProvider(name = "feature-value")
+    private Object[][] data() {
+        return new Object[][] {
+                { Feature.FILES, null },
+                { Feature.PREFER, CatalogTestUtils.PREFER_PUBLIC },
+                { Feature.DEFER, CatalogTestUtils.DEFER_TRUE },
+                { Feature.RESOLVE, CatalogTestUtils.RESOLVE_STRICT } };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/DeferFeatureTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.DEFER_FALSE;
+import static catalog.CatalogTestUtils.DEFER_TRUE;
+import static catalog.CatalogTestUtils.getCatalogPath;
+import static javax.xml.catalog.CatalogFeatures.Feature.DEFER;
+import static javax.xml.catalog.CatalogManager.catalog;
+
+import java.lang.reflect.Method;
+
+import javax.xml.catalog.Catalog;
+import javax.xml.catalog.CatalogFeatures;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary This case tests whether the catalogs specified in delegateSystem,
+ *          delegatePublic, delegateURI and nextCatalog entries are used lazily
+ *          in resolution via defer feature.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ */
+public class DeferFeatureTest {
+
+    @Test(dataProvider = "catalog-countOfLoadedCatalogFile")
+    public void testDeferFeature(Catalog catalog, int catalogCount)
+            throws Exception {
+        Assert.assertEquals(loadedCatalogCount(catalog), catalogCount);
+    }
+
+    @DataProvider(name = "catalog-countOfLoadedCatalogFile")
+    private Object[][] data() {
+        return new Object[][] {
+                // This catalog specifies null catalog explicitly,
+                // and the count of loaded catalogs should be 0.
+                { createCatalog(null), 0 },
+
+                // This catalog specifies null catalog implicitly,
+                // and the count of loaded catalogs should be 0.
+                { createCatalog(CatalogFeatures.defaults()), 0 },
+
+                // This catalog loads null catalog with true DEFER,
+                // and the count of loaded catalogs should be 0.
+                { createCatalog(createDeferFeature(DEFER_TRUE)), 0 },
+
+                // This catalog loads null catalog with false DEFER.
+                // It should load all of none-current catalogs and the
+                // count of loaded catalogs should be 3.
+                { createCatalog(createDeferFeature(DEFER_FALSE)), 3 } };
+    }
+
+    private CatalogFeatures createDeferFeature(String defer) {
+        return CatalogFeatures.builder().with(DEFER, defer).build();
+    }
+
+    private Catalog createCatalog(CatalogFeatures feature) {
+        return catalog(feature, getCatalogPath("deferFeature.xml"));
+    }
+
+    private int loadedCatalogCount(Catalog catalog) throws Exception {
+        Method method = catalog.getClass().getDeclaredMethod(
+                "loadedCatalogCount");
+        method.setAccessible(true);
+        return (int) method.invoke(catalog);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/DelegatePublicTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkPubIdResolution;
+import static catalog.ResolutionChecker.expectExceptionOnPubId;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from DelegatePublic entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class DelegatePublicTest {
+
+    @Test(dataProvider = "publicId-matchedUri")
+    public void testMatch(String publicId, String matchedUri) {
+        checkPubIdResolution(createResolver(), publicId, matchedUri);
+    }
+
+    @DataProvider(name = "publicId-matchedUri")
+    private Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified public id is defined in
+                // a delegate catalog file of the current catalog file.
+                { "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                        "http://local/dtd/docAlicePub.dtd" },
+
+                // The current catalog file defines two delegatePublic entries
+                // with the same publicIdStartString, and both of them match the
+                // specified public id. But the matched URI should be in the
+                // delegate catalog file, which is defined in the upper
+                // delegatePublic entry.
+                { "-//REMOTE//DTD BOB DOCBOB XML//EN",
+                        "http://local/base/dtd/bob/docBobPub.dtd" },
+
+                // The current catalog file defines two delegatePublic entries,
+                // and both of them match the specified public id. But the
+                // matched URI should be in the delegate catalog file, which is
+                // defined in the longest matched delegatePublic entry.
+                { "-//REMOTE//DTD CARL DOCCARL XML//EN",
+                        "http://local/base/dtd/carl/docCarlPub.dtd" } };
+    }
+
+    @Test(dataProvider = "publicId-expectedExceptionClass")
+    public void testException(String publicId,
+            Class<? extends Throwable> expectedExceptionClass) {
+        expectExceptionOnPubId(createResolver(), publicId,
+                expectedExceptionClass);
+    }
+
+    @DataProvider(name = "publicId-expectedExceptionClass")
+    private Object[][] dataOnException() {
+        return new Object[][] {
+                // The matched delegatePublic entry of the specified public id
+                // defines a non-existing delegate catalog file. That should
+                // raise a RuntimeException.
+                { "-//REMOTE//DTD DAVID DOCDAVID XML//EN",
+                        RuntimeException.class },
+
+                // There's no match of the specified public id in the catalog
+                // structure. That should raise a CatalogException.
+                { "-//REMOTE//DTD GHOST DOCGHOST XML//EN",
+                        CatalogException.class } };
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver("delegatePublic.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/DelegateSystemTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+import static catalog.ResolutionChecker.expectExceptionOnSysId;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from delegateSystem entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class DelegateSystemTest {
+
+    @Test(dataProvider = "systemId-matchedUri")
+    public void testMatch(String systemId, String matchedUri) {
+        checkSysIdResolution(createResolver(), systemId, matchedUri);
+    }
+
+    @DataProvider(name = "systemId-matchedUri")
+    private Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified system id is defined in
+                // a delegate catalog file of the current catalog file.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/base/dtd/alice/docAliceDS.dtd" },
+
+                // The current catalog file defines two delegateSystem entries
+                // with the same systemIdStartString, and both of them match the
+                // specified system id. But the matched URI should be in the
+                // delegate catalog file, which is defined in the upper
+                // delegateSystem entry.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/bob/docBobDS.dtd" },
+
+                // The current catalog file defines two delegateSystem entries,
+                // and both of them match the specified system id. But the
+                // matched URI should be in the delegate catalog file, which is
+                // defined in the longest matched delegateSystem entry.
+                { "http://remote/dtd/carl/docCarl.dtd",
+                        "http://local/base/dtd/carl/docCarlDS.dtd"} };
+    }
+
+    @Test(dataProvider = "systemId-expectedExceptionClass")
+    public void testException(String systemId,
+            Class<? extends Throwable> expectedExceptionClass) {
+        expectExceptionOnSysId(createResolver(), systemId,
+                expectedExceptionClass);
+    }
+
+    @DataProvider(name = "systemId-expectedExceptionClass")
+    private Object[][] dataOnException() {
+        return new Object[][] {
+                // The matched delegateSystem entry of the specified system id
+                // defines a non-existing delegate catalog file. That should
+                // raise a RuntimeException.
+                { "http://remote/dtd/david/docDavidDS.dtd",
+                        RuntimeException.class },
+
+                // There's no match of the specified system id in the catalog
+                // structure. That should raise a CatalogException.
+                { "http://ghost/xml/dtd/ghost/docGhostDS.dtd",
+                        CatalogException.class } };
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver("delegateSystem.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/DelegateUriTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkUriResolution;
+import static catalog.ResolutionChecker.expectExceptionOnUri;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from delegateURI entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class DelegateUriTest {
+
+    @Test(dataProvider = "uri-matchedUri")
+    public void testMatch(String uri, String matchedUri) {
+        checkUriResolution(createResolver(), uri, matchedUri);
+    }
+
+    @DataProvider(name = "uri-matchedUri")
+    private Object[][] data() {
+        return new Object[][] {
+                // The matched URI of the specified URI reference is defined in
+                // a delegate catalog file of the current catalog file.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/base/dtd/alice/docAliceDU.dtd" },
+
+                // The current catalog file defines two delegateURI entries
+                // with the same uriStartString, and both of them match the
+                // specified URI reference. But the matched URI should be in
+                // the delegate catalog file, which is defined in the upper
+                // delegateURI entry.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/bob/docBobDU.dtd" },
+
+                // The current catalog file defines two delegateURI entries,
+                // and both of them match the specified URI reference. But the
+                // matched URI should be in the delegate catalog file, which is
+                // defined in the longest matched delegateURI entry.
+                { "http://remote/dtd/carl/docCarl.dtd",
+                        "http://local/base/dtd/carl/docCarlDU.dtd"} };
+    }
+
+    @Test(dataProvider = "uri-expectedExceptionClass")
+    public void testException(String uri,
+            Class<? extends Throwable> expectedExceptionClass) {
+        expectExceptionOnUri(createResolver(), uri, expectedExceptionClass);
+    }
+
+    @DataProvider(name = "uri-expectedExceptionClass")
+    private Object[][] dataOnException() {
+        return new Object[][] {
+                // The matched delegateURI entry of the specified URI reference
+                // defines a non-existing delegate catalog file. That should
+                // raise a RuntimeException.
+                { "http://remote/dtd/david/docDavidDU.dtd",
+                        RuntimeException.class },
+
+                // There's no match of the specified URI reference in the
+                // catalog structure. That should raise a CatalogException.
+                { "http://ghost/xml/dtd/ghost/docGhostDS.dtd",
+                        CatalogException.class } };
+    }
+
+    private CatalogUriResolver createResolver() {
+        return catalogUriResolver("delegateUri.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/GroupTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkPubIdResolution;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from system, public and uri entries respectively,
+ *          and some of the entries are enclosed by group entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class GroupTest {
+
+    private static final String CATALOG_GROUP = "group.xml";
+
+    @Test(dataProvider = "systemId-matchedUri")
+    public void testMatchOnSysId(String uri, String matchedUri) {
+        checkSysIdResolution(createResolver(), uri, matchedUri);
+    }
+
+    @DataProvider(name = "systemId-matchedUri")
+    private Object[][] dataOnSysId() {
+        return new Object[][] {
+                // The matched URI of the specified system id is enclosed by a
+                // group entry.
+                { "http://remote/dtd/sys/alice/docAlice.dtd",
+                        "http://local/base/dtd/docAliceSys.dtd" },
+
+                // The matched URI of the specified system id is enclosed by a
+                // group entry, which defines another base.
+                { "http://remote/dtd/sys/bob/docBob.dtd",
+                        "http://local/bobBase/dtd/docBobSys.dtd" },
+
+                // The catalog file defines a set of system entries. Some of
+                // them are enclosed by a group entry, and others are out of the
+                // group entry. All of them can match the specified system id.
+                // But the returned matched URI should be in the first one.
+                { "http://remote/dtd/sys/carl/docCarl.dtd",
+                        "http://local/base/dtd/docCarlSys1.dtd" } };
+    }
+
+    @Test(dataProvider = "publicId-matchedUri")
+    public void testMatchOnPubId(String uri, String matchedUri) {
+        checkPubIdResolution(createResolver(), uri, matchedUri);
+    }
+
+    @DataProvider(name = "publicId-matchedUri")
+    private Object[][] dataOnPubId() {
+        return new Object[][] {
+                // The matched URI of the specified public id is enclosed by a
+                // group entry.
+                { "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                        "http://local/base/dtd/docAlicePub.dtd" },
+
+                // The matched URI of the specified public id is enclosed by a
+                // group entry, which defines another base.
+                { "-//REMOTE//DTD BOB DOCBOB XML//EN",
+                        "http://local/bobBase/dtd/docBobPub.dtd" },
+
+                // The catalog file defines a set of public entries. Some of
+                // them are enclosed by a group entry, and others are out of the
+                // group entry. All of them can match the specified public id.
+                // But the returned matched URI should be in the first one.
+                { "-//REMOTE//DTD CARL DOCCARL XML//EN",
+                        "http://local/base/dtd/docCarlPub1.dtd" } };
+    }
+
+    @Test(dataProvider = "uri-matchedUri")
+    public void testMatchOnUri(String uri, String matchedUri) {
+        checkUriResolution(catalogUriResolver(CATALOG_GROUP), uri, matchedUri);
+    }
+
+    @DataProvider(name = "uri-matchedUri")
+    private Object[][] dataOnUri() {
+        return new Object[][] {
+                // The matched URI of the specified URI reference is enclosed by
+                // a group entry.
+                { "http://remote/dtd/uri/alice/docAlice.dtd",
+                        "http://local/base/dtd/docAliceURI.dtd" },
+
+                // The matched URI of the specified URI reference is enclosed by
+                // a group entry, which defines another base.
+                { "http://remote/dtd/uri/bob/docBob.dtd",
+                        "http://local/bobBase/dtd/docBobURI.dtd" },
+
+                // The catalog file defines a set of uri entries. Some of
+                // them are enclosed by a group entry, and others are out of the
+                // group entry. All of them can match the specified URI reference.
+                // But the returned matched URI should be in the first one.
+                { "http://remote/dtd/uri/alice/docAlice.dtd",
+                        "http://local/base/dtd/docAliceURI.dtd" } };
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver(CATALOG_GROUP);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/LoadCatalogTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.CATALOG_PUBLIC;
+import static catalog.CatalogTestUtils.CATALOG_SYSTEM;
+import static catalog.CatalogTestUtils.CATALOG_URI;
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary When catalog resolver loads catalog files, the current catalog file
+ *          and the catalog files specified by the nextCatalog entries may not
+ *          accessible. This case tests how does the resolver handle this issue.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class LoadCatalogTest {
+
+    private static final String CATALOG_LOADCATALOGFILES = "loadCatalogFiles.xml";
+    private static final String CATALOG_DUMMY = "dummy.xml";
+
+    private static final String ID_ALICE = "http://remote/dtd/alice/docAlice.dtd";
+    private static final String ID_DUMMY = "http://remote/dtd/doc.dtd";
+
+    @Test(dataProvider = "entityResolver")
+    public void testMatchOnEntityResolver(CatalogResolver resolver) {
+        checkSysIdResolution(resolver, ID_ALICE,
+                "http://local/dtd/docAliceSys.dtd");
+    }
+
+    @DataProvider(name = "entityResolver")
+    private Object[][] entityResolver() {
+        return new Object[][] {
+                // This EntityResolver loads multiple catalog files one by one.
+                // All of the files are available.
+                { catalogResolver(CATALOG_PUBLIC, CATALOG_URI,
+                        CATALOG_SYSTEM) },
+
+                // This EntityResolver loads multiple catalog files one by one,
+                // but the middle one isn't existing.
+                { catalogResolver(CATALOG_PUBLIC, CATALOG_DUMMY,
+                        CATALOG_SYSTEM) } };
+    }
+
+    @Test(dataProvider = "uriResolver")
+    public void testMatchOnUriResolver(CatalogUriResolver resolver) {
+        checkUriResolution(resolver, ID_ALICE,
+                "http://local/dtd/docAliceURI.dtd");
+    }
+
+    @DataProvider(name = "uriResolver")
+    private Object[][] uriResolver() {
+        return new Object[][] {
+                // This URIResolver loads multiple catalog files one by one.
+                // All of the files are available.
+                { catalogUriResolver(CATALOG_PUBLIC, CATALOG_SYSTEM,
+                        CATALOG_URI) },
+
+                // This URIResolver loads multiple catalog files one by one,
+                // but the middle one isn't existing.
+                { catalogUriResolver(CATALOG_PUBLIC, CATALOG_DUMMY,
+                        CATALOG_URI) } };
+    }
+
+    @Test(dataProvider = "catalogName",
+            expectedExceptions = CatalogException.class)
+    public void testExceptionOnEntityResolver(String[] catalogName) {
+        catalogResolver(catalogName).resolveEntity(null, ID_DUMMY);
+    }
+
+    @Test(dataProvider = "catalogName",
+            expectedExceptions = CatalogException.class)
+    public void testExceptionOnUriResolver(String[] catalogName) {
+        catalogUriResolver(catalogName).resolve(ID_DUMMY, null);
+    }
+
+    @DataProvider(name = "catalogName")
+    private Object[][] catalogName() {
+        return new Object[][] {
+                // This catalog file set includes null catalog files.
+                { (String[]) null },
+
+                // This catalog file set includes one catalog file, but this
+                // catalog defines a non-existing next catalog.
+                { new String[] { CATALOG_LOADCATALOGFILES } } };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/NextCatalogTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkPubIdResolution;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from system, public and uri entries respectively,
+ *          but some of the entries are defined in none-current catalog files.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class NextCatalogTest {
+
+    private static final String CATALOG_NEXTCATALOGLEFT
+            = "nextCatalog-left.xml";
+    private static final String CATALOG_NEXTCATALOGRIGHT
+            = "nextCatalog-right.xml";
+
+    @Test(dataProvider = "systemId-matchedUri")
+    public void testNextCatalogOnSysId(String sytemId, String matchedUri) {
+        checkSysIdResolution(createEntityResolver(), sytemId, matchedUri);
+    }
+
+    @DataProvider(name = "systemId-matchedUri")
+    private Object[][] dataOnSysId() {
+        return new Object[][] {
+                // This matched URI of the specified system id is defined in a
+                // next catalog file.
+                { "http://remote/dtd/sys/docAlice.dtd",
+                        "http://local/base/dtd/docAliceNextLeftSys.dtd" },
+
+                // There are two matches of the specified system id. One is in
+                // the current catalog file, and the other is in a next catalog
+                // file. But finally, the returned matched URI is the one in the
+                // current catalog file.
+                { "http://remote/dtd/sys/docBob.dtd",
+                        "http://local/base/dtd/docBobLeftSys.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // two-level next catalog file.
+                { "http://remote/dtd/sys/docCarl.dtd",
+                        "http://local/base/dtd/docCarlSys.dtd" },
+
+                // Multiple catalog files, which are defined as next catalog,
+                // have the matched system entries of the specified system id.
+                // But finally, the returned matched URI is the first found.
+                { "http://remote/dtd/sys/docDuplicate.dtd",
+                        "http://local/base/dtd/docDuplicateLeftSys.dtd" } };
+    }
+
+    @Test(dataProvider = "publicId-matchedUri")
+    public void testNextCatalogOnPubId(String publicId, String matchedUri) {
+        checkPubIdResolution(createEntityResolver(), publicId, matchedUri);
+    }
+
+    @DataProvider(name = "publicId-matchedUri")
+    private Object[][] dataOnPubId() {
+        return new Object[][] {
+                // This matched URI of the specified public id is defined in a
+                // next catalog file.
+                { "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                        "http://local/base/dtd/docAliceNextLeftPub.dtd" },
+
+                // There are two matches of the specified public id. One is in
+                // the current catalog file, and the other is in a next catalog
+                // file. But finally, the returned matched URI is the one in the
+                // current catalog file.
+                { "-//REMOTE//DTD BOB DOCBOB XML//EN",
+                        "http://local/base/dtd/docBobLeftPub.dtd" },
+
+                // The matched URI of the specified public id is defined in a
+                // two-level next catalog file.
+                { "-//REMOTE//DTD CARL DOCCARL XML//EN",
+                        "http://local/base/dtd/docCarlPub.dtd" },
+
+                // Multiple catalog files, which are defined as next catalog,
+                // have the matched public entries of the specified public id.
+                // But finally, the returned matched URI is the first found.
+                { "-//REMOTE//DTD DUPLICATE DOCDUPLICATE XML//EN",
+                        "http://local/base/dtd/docDuplicateLeftPub.dtd" } };
+    }
+
+    @Test(dataProvider = "uri-matchedUri")
+    public void testNextCatalogOnUri(String uri, String matchedUri) {
+        checkUriResolution(createUriResolver(), uri, matchedUri);
+    }
+
+    @DataProvider(name = "uri-matchedUri")
+    private Object[][] dataOnUri() {
+        return new Object[][] {
+                // This matched URI of the specified URI reference is defined in
+                // a next catalog file.
+                { "http://remote/dtd/uri/docAlice.dtd",
+                        "http://local/base/dtd/docAliceNextLeftURI.dtd" },
+
+                // There are two matches of the specified URI reference. One is
+                // in the current catalog file, and the other is in a next
+                // catalog file. But finally, the returned matched URI is the
+                // one in the current catalog file.
+                { "http://remote/dtd/uri/docBob.dtd",
+                        "http://local/base/dtd/docBobLeftURI.dtd" },
+
+                // The matched URI of the specified URI reference is defined in
+                // a two-level next catalog file.
+                { "http://remote/dtd/uri/docCarl.dtd",
+                        "http://local/base/dtd/docCarlURI.dtd" },
+
+                // Multiple catalog files, which are defined as next catalog,
+                // have the matched uri entries of the specified URI reference.
+                // But finally, the returned matched URI is the first found.
+                { "http://remote/dtd/uri/docDuplicate.dtd",
+                        "http://local/base/dtd/docDuplicateLeftURI.dtd" } };
+    }
+
+    private CatalogResolver createEntityResolver() {
+        return catalogResolver(CATALOG_NEXTCATALOGLEFT,
+                CATALOG_NEXTCATALOGRIGHT);
+    }
+
+    private CatalogUriResolver createUriResolver() {
+        return catalogUriResolver(CATALOG_NEXTCATALOGLEFT,
+                CATALOG_NEXTCATALOGRIGHT);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/NormalizationTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkPubIdResolution;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Before matching identifiers and URI references, it has to normalize
+ *          the passed identifiers and URI references. And then the catalog
+ *          resolver uses the normalized stuff to search the counterparts in
+ *          catalog files.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class NormalizationTest {
+
+    private static final String CATALOG_NORMALIZATION = "normalization.xml";
+
+    @Test(dataProvider = "systemId_uri-matchedUri")
+    public void testNormalizationOnSysId(String sytemId, String matchedUri) {
+        checkSysIdResolution(createEntityResolver(), sytemId, matchedUri);
+    }
+
+    @Test(dataProvider = "publicId-matchedUri")
+    public void testNormalizationOnPubId(String publicId, String matchedUri) {
+        checkPubIdResolution(createEntityResolver(), publicId, matchedUri);
+    }
+
+    @Test(dataProvider = "systemId_uri-matchedUri")
+    public void testNormalizationOnUri(String uri, String matchedUri) {
+        checkUriResolution(createUriResolver(), uri, matchedUri);
+    }
+
+    @DataProvider(name = "systemId_uri-matchedUri")
+    private Object[][] dataOnSysIdAndUri() {
+        return new Object[][] {
+                // The specified system id/URI reference contains spaces. And
+                // the counterparts in system/uri entries also contain spaces.
+                { "  http://remote/dtd/alice/docAlice.dtd  ",
+                        "http://local/base/dtd/docAliceSys.dtd" },
+
+                // The specified system id/URI reference doesn't contain space.
+                // But the counterparts in system/uri entries contain spaces.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/base/dtd/docAliceSys.dtd" },
+
+                // The specified system id/URI reference contains special chars.
+                { "http://remote/dtd/bob/docBob<>\\^`{|}.dtd",
+                        "http://local/base/dtd/docBobSys.dtd" },
+
+                // The specified system identifier/uri contains normalized chars.
+                { "http://remote/dtd/bob/docBob%3C%3E%5C%5E%60%7B%7C%7D.dtd",
+                        "http://local/base/dtd/docBobSys.dtd" } };
+    }
+
+    @DataProvider(name = "publicId-matchedUri")
+    private Object[][] dataOnPubId() {
+        return new Object[][] {
+                // The specified public id contains spaces. And the counterparts
+                // in public entry also contains spaces.
+                { "   -//REMOTE//DTD    ALICE DOCALICE   XML//EN  ",
+                        "http://local/base/dtd/docAlicePub.dtd" },
+
+                // The specified public id doesn't contain space. But the
+                // counterpart in public entry contains spaces.
+                { "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                        "http://local/base/dtd/docAlicePub.dtd" },
+
+                // The specified public id contains spaces.
+                { "  -//REMOTE//DTD   BOB  DOCBOB  XML//EN",
+                        "http://local/base/dtd/docBobPub.dtd" } };
+    }
+
+    private CatalogResolver createEntityResolver() {
+        return catalogResolver(CATALOG_NORMALIZATION);
+    }
+
+    private CatalogUriResolver createUriResolver() {
+        return catalogUriResolver(CATALOG_NORMALIZATION);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/PreferFeatureTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.PREFER_PUBLIC;
+import static catalog.CatalogTestUtils.PREFER_SYSTEM;
+import static catalog.CatalogTestUtils.catalogResolver;
+import static javax.xml.catalog.CatalogFeatures.Feature.PREFER;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogFeatures;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary This case tests how does the feature affect the catalog resolution,
+ *          and tests the priority between this feature and attribute prefer
+ *          in catalog file.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ */
+public class PreferFeatureTest {
+
+    @Test(dataProvider = "prefer-publicId-systemId",
+            expectedExceptions = CatalogException.class)
+    public void testPreferFeature(String prefer, String systemId,
+            String publicId) {
+        createResolver(prefer).resolveEntity(systemId, publicId);
+    }
+
+    @DataProvider(name = "prefer-publicId-systemId")
+    private Object[][] data() {
+        return new Object[][] {
+                // The feature prefer is system. There's a match for the
+                // specified public id, and no match for the specified system id.
+                // But the resolver cannot find the expected match, and raises a
+                // CatalogException.
+                { PREFER_SYSTEM, "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                        "http://remote/dtd/alice/docAliceDummy.dtd" },
+
+                // The feature prefer is public, and the prefer attribute of a
+                // group entry is system. There's a match for the specified
+                // public id, and no match for the specified system id. But the
+                // resolver still cannot find the expected match, and raises a
+                // CatalogException.
+                { PREFER_PUBLIC, "-//REMOTE//DTD BOB DOCBOB XML//EN",
+                         "http://remote/dtd/bob/docBobDummy.dtd"} };
+    }
+
+    private CatalogResolver createResolver(String prefer) {
+        return catalogResolver(
+                CatalogFeatures.builder().with(PREFER, prefer).build(),
+                "preferFeature.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/PreferTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkExtIdResolution;
+
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from system and public family entries, which
+ *          specify the prefer attribute. It tests how does the prefer attribute
+ *          affect the resolution procedure. The test rule is based on OASIS
+ *          Standard V1.1 section 4.1.1. "The prefer attribute".
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class PreferTest {
+
+    @Test(dataProvider = "publicId-systemId-matchedUri")
+    public void testPrefer(String publicId, String systemId,
+            String expected) {
+        checkExtIdResolution(createResolver(), publicId, systemId, expected);
+    }
+
+    @DataProvider(name = "publicId-systemId-matchedUri")
+    private Object[][] data() {
+        return new Object[][] {
+                // The prefer attribute is public. Both of the specified public
+                // id and system id have matches in the catalog file. But
+                // finally, the returned URI is the system match.
+                { "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                        "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/base/dtd/docAliceSys.dtd" },
+
+                // The prefer attribute is public, and only the specified system
+                // id has match. The returned URI is the system match.
+                { "-//REMOTE//DTD ALICE DOCALICEDUMMY XML//EN",
+                        "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/base/dtd/docAliceSys.dtd"},
+
+                // The prefer attribute is public, and only the specified public
+                // id has match. The returned URI is the system match.
+                { "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                        "http://remote/dtd/alice/docAliceDummy.dtd",
+                        "http://local/base/dtd/docAlicePub.dtd" },
+
+                // The prefer attribute is system, and both of the specified
+                // system id and public id have matches. But the returned URI is
+                // the system match.
+                { "-//REMOTE//DTD BOB DOCBOB XML//EN",
+                        "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/docBobSys.dtd" },
+
+                // The prefer attribute is system, and only system id has match.
+                // The returned URI is the system match.
+                { "-//REMOTE//DTD BOB DOCBOBDUMMY XML//EN",
+                        "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/docBobSys.dtd" } };
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver("prefer.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/PublicFamilyTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkPubIdResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from public and delegatePublic entries.
+ *          It tests the resolution priorities among the public family entries.
+ *          The test rule is based on OASIS Standard V1.1 section 7.1.2.
+ *          "Resolution of External Identifiers".
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class PublicFamilyTest {
+
+    /*
+     * Gets the best match from public and delegatePublic entries.
+     * The match in public entry is prior to the match in delegatePublic entry.
+     */
+    @Test
+    public void testMatch() {
+        checkPubIdResolution(createResolver(),
+                "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                "http://local/base/dtd/docAlicePub.dtd");
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatched() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver("publicFamily.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/PublicTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.CATALOG_PUBLIC;
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkPubIdResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from public entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class PublicTest {
+
+    @Test(dataProvider = "publicId-matchedUri")
+    public void testPublic(String publicId, String matchedUri) {
+        checkPubIdResolution(createResolver(), publicId, matchedUri);
+    }
+
+    @DataProvider(name = "publicId-matchedUri")
+    public Object[][] data() {
+        return new Object[][] {
+                // The matched URI of the specified public id is defined in a
+                // public entry. The match is an absolute path.
+                { "-//REMOTE//DTD ALICE DOCALICE XML//EN",
+                        "http://local/dtd/docAlicePub.dtd" },
+
+                // The matched URI of the specified public id is defined in a
+                // public entry. But the match isn't an absolute path, so the
+                // returned URI should include the base, which is defined by the
+                // catalog file, as the prefix.
+                { "-//REMOTE//DTD BOB DOCBOB XML//EN",
+                        "http://local/base/dtd/docBobPub.dtd" },
+
+                // The matched URI of the specified public id is defined in a
+                // public entry. The match isn't an absolute path, and the
+                // public entry defines alternative base. So the returned URI
+                // should include the alternative base.
+                { "-//REMOTE//DTD CARL DOCCARL XML//EN",
+                        "http://local/carlBase/dtd/docCarlPub.dtd" },
+
+                // The catalog file defines two public entries, and both of them
+                // match the specified public id. But the first matched URI
+                // should be returned.
+                { "-//REMOTE//DTD DAVID DOCDAVID XML//EN",
+                        "http://local/base/dtd/docDavidPub1.dtd" } };
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver(CATALOG_PUBLIC);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/ResolveFeatureTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.CATALOG_SYSTEM;
+import static catalog.CatalogTestUtils.CATALOG_URI;
+import static catalog.CatalogTestUtils.RESOLVE_CONTINUE;
+import static catalog.CatalogTestUtils.RESOLVE_IGNORE;
+import static catalog.CatalogTestUtils.RESOLVE_STRICT;
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+import static catalog.ResolutionChecker.checkUriResolution;
+import static javax.xml.catalog.CatalogFeatures.builder;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogFeatures;
+import javax.xml.catalog.CatalogFeatures.Feature;
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary This case tests how does resolve feature affect the catalog
+ *          resolution.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class ResolveFeatureTest {
+
+    /*
+     * For strict external identifier resolution, if no match is found,
+     * it should throw CatalogException.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testStrictResolutionOnEntityResolver() {
+        createEntityResolver(RESOLVE_STRICT).resolveEntity(null,
+                "http://remote/dtd/alice/docAliceDummy.dtd");
+    }
+
+    /*
+     * For strict URI reference resolution, if no match is found,
+     * it should throw CatalogException.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testStrictResolutionOnUriResolver() {
+        createUriResolver(RESOLVE_STRICT).resolve(
+                "http://remote/dtd/alice/docAliceDummy.dtd", null);
+    }
+
+    /*
+     * For continue external identifier resolution, if no match is found,
+     * it should continue the process.
+     */
+    @Test
+    public void testContinueResolutionOnEntityResolver() {
+        CatalogResolver resolver = createEntityResolver(RESOLVE_CONTINUE);
+        resolver.resolveEntity(null, "http://remote/dtd/bob/docBobDummy.dtd");
+        checkSysIdResolution(resolver, "http://remote/dtd/bob/docBob.dtd",
+                "http://local/base/dtd/docBobSys.dtd");
+    }
+
+    /*
+     * For continue URI reference resolution, if no match is found,
+     * it should continue the process.
+     */
+    @Test
+    public void testContinueResolutionOnUriResolver() {
+        CatalogUriResolver resolver = createUriResolver(RESOLVE_CONTINUE);
+        resolver.resolve("http://remote/dtd/bob/docBobDummy.dtd", null);
+        checkUriResolution(resolver, "http://remote/dtd/bob/docBob.dtd",
+                "http://local/base/dtd/docBobURI.dtd");
+    }
+
+    /*
+     * For ignore external identifier resolution, if no match is found,
+     * it should break the process and return null.
+     */
+    @Test
+    public void testIgnoreResolutionOnEntityResolver() {
+        checkSysIdResolution(createEntityResolver(RESOLVE_IGNORE),
+                "http://remote/dtd/carl/docCarlDummy.dtd", null);
+    }
+
+    /*
+     * For ignore URI reference resolution, if no match is found,
+     * it should break the process and return null.
+     */
+    @Test
+    public void testIgnoreResolutionOnUriResolver() {
+        checkUriResolution(createUriResolver(RESOLVE_IGNORE),
+                "http://remote/dtd/carl/docCarlDummy.dtd", null);
+    }
+
+    private CatalogResolver createEntityResolver(String resolve) {
+        return catalogResolver(createFeature(resolve), CATALOG_SYSTEM);
+    }
+
+    private CatalogUriResolver createUriResolver(String resolve) {
+        return catalogUriResolver(createFeature(resolve), CATALOG_URI);
+    }
+
+    private CatalogFeatures createFeature(String resolve) {
+        return builder().with(Feature.RESOLVE, resolve).build();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/RewriteSystemTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from rewriteSystem entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class RewriteSystemTest {
+
+    @Test(dataProvider = "systemId-matchedUri")
+    public void testMatch(String systemId, String matchedUri) {
+        checkSysIdResolution(createResolver(), systemId, matchedUri);
+    }
+
+    @DataProvider(name = "systemId-matchedUri")
+    public Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified system id is defined in a
+                // rewriteSystem entry. The match is an absolute path.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/dtd/alice/rs/docAlice.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // rewriteSystem entry. The match isn't an absolute path.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/bob/rs/docBob.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // rewriteSystem entry. The match isn't an absolute path, and
+                // the rewriteSystem entry defines alternative base. So the
+                // returned URI should include the alternative base.
+                { "http://remote/dtd/carl/docCarl.dtd",
+                        "http://local/carlBase/dtd/carl/rs/docCarl.dtd" },
+
+                // The catalog file defines two rewriteSystem entries, and both
+                // of them match the specified system id. But the first matched
+                // URI should be returned.
+                { "http://remote/dtd/david/docDavid.dtd",
+                        "http://local/base/dtd/david1/rs/docDavid.dtd" },
+
+                // The catalog file defines two rewriteSystem entries, and both
+                // of them match the specified system id. But the longest match
+                // should be used.
+                { "http://remote/dtd/ella/docElla.dtd",
+                        "http://local/base/dtd/ella/rs/docElla.dtd" } };
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver("rewriteSystem.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/RewriteUriTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from rewriteURI entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class RewriteUriTest {
+
+    @Test(dataProvider = "uri-matchedUri")
+    public void testMatch(String uri, String matchedUri) {
+        checkUriResolution(createResolver(), uri, matchedUri);
+    }
+
+    @DataProvider(name = "uri-matchedUri")
+    public Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified URI reference is defined in
+                // a rewriteURI entry. The match is an absolute path.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/dtd/alice/ru/docAlice.dtd" },
+
+                // The matched URI of the specified URI reference is defined in
+                // a rewriteURI entry. The match isn't an absolute path.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/bob/ru/docBob.dtd" },
+
+                // The matched URI of the specified URI reference is defined in
+                // a rewriteURI entry. The match isn't an absolute path, and the
+                // rewriteURI entry defines alternative base. So the returned
+                // URI should include the alternative base.
+                { "http://remote/dtd/carl/docCarl.dtd",
+                        "http://local/carlBase/dtd/carl/ru/docCarl.dtd" },
+
+                // The catalog file defines two rewriteURI entries, and both of
+                // them match the specified URI reference. But the first matched
+                // URI should be returned.
+                { "http://remote/dtd/david/docDavid.dtd",
+                        "http://local/base/dtd/david1/ru/docDavid.dtd" },
+
+                // The catalog file defines two rewriteURI entries, and both
+                // of them match the specified URI reference. But the longest
+                // match should be used.
+                { "http://remote/dtd/ella/docElla.dtd",
+                        "http://local/base/dtd/ella/ru/docElla.dtd" } };
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogUriResolver createResolver() {
+        return catalogUriResolver("rewriteUri.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/SpecifyCatalogTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.FEATURE_FILES;
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.CatalogTestUtils.getCatalogPath;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+import static catalog.ResolutionChecker.checkUriResolution;
+import static javax.xml.catalog.CatalogFeatures.builder;
+import static javax.xml.catalog.CatalogFeatures.Feature.FILES;
+
+import javax.xml.catalog.CatalogFeatures;
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary This case tests how to specify the catalog files.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class SpecifyCatalogTest {
+
+    private static final String ID_URI = "http://remote/dtd/uri/doc.dtd";
+    private static final String ID_SYS = "http://remote/dtd/sys/doc.dtd";
+
+    private static final CatalogFeatures FILES_FEATURE = createFeature(
+            "specifyCatalog-feature.xml");
+
+    /*
+     * CatalogResolver specifies catalog via feature javax.xml.catalog.files.
+     */
+    @Test
+    public void specifyCatalogOnEntityResolver() {
+        checkSysIdResolution(catalogResolver(FILES_FEATURE, (String[]) null),
+                ID_SYS, "http://local/base/dtd/docFeatureSys.dtd");
+    }
+
+    /*
+     * CatalogUriResolver specifies catalog via feature javax.xml.catalog.files.
+     */
+    @Test
+    public void specifyCatalogOnUriResolver() {
+        checkUriResolution(catalogUriResolver(FILES_FEATURE, (String[]) null),
+                ID_URI, "http://local/base/dtd/docFeatureURI.dtd");
+    }
+
+    /*
+     * Resolver specifies catalog via system property javax.xml.catalog.files.
+     */
+    @Test
+    public void specifyCatalogViaSysProps() {
+        System.setProperty(FEATURE_FILES,
+                getCatalogPath("specifyCatalog-sysProps.xml"));
+
+        checkResolutionOnEntityResolver(catalogResolver((String[]) null),
+                "http://local/base/dtd/docSysPropsSys.dtd");
+        checkResolutionOnEntityResolver(
+                catalogResolver(FILES_FEATURE, "specifyCatalog-api.xml"),
+                "http://local/base/dtd/docAPISys.dtd");
+
+        checkResolutionOnUriResolver(catalogUriResolver((String[]) null),
+                "http://local/base/dtd/docSysPropsURI.dtd");
+        checkResolutionOnUriResolver(
+                catalogUriResolver(FILES_FEATURE, "specifyCatalog-api.xml"),
+                "http://local/base/dtd/docAPIURI.dtd");
+    }
+
+    private void checkResolutionOnEntityResolver(CatalogResolver resolver,
+            String matchedUri) {
+        checkSysIdResolution(resolver, ID_SYS, matchedUri);
+    }
+
+    private void checkResolutionOnUriResolver(CatalogUriResolver resolver,
+            String matchedUri) {
+        checkUriResolution(resolver, ID_URI, matchedUri);
+    }
+
+    private static CatalogFeatures createFeature(String catalogName) {
+        return builder().with(FILES, getCatalogPath(catalogName)).build();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/SystemFamilyTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from system, rewriteSystem, systemSuffix and
+ *          delegateSystem entries. It tests the resolution priorities among
+ *          the system family entries. The test rule is based on OASIS
+ *          Standard V1.1 section 7.1.2. "Resolution of External Identifiers".
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class SystemFamilyTest {
+
+    @Test(dataProvider = "systemId-matchedUri")
+    public void testMatch(String systemId, String matchedUri) {
+        checkSysIdResolution(createResolver(), systemId, matchedUri);
+    }
+
+    @DataProvider(name = "systemId-matchedUri")
+    public Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified system id is defined in a
+                // system entry.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/base/dtd/docAliceSys.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // rewriteSystem entry.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/rs/docBob.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // systemSuffix entry.
+                { "http://remote/dtd/carl/docCarl.dtd",
+                         "http://local/base/dtd/docCarlSS.dtd" } };
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver("systemFamily.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/SystemSuffixTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from systemSuffix entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class SystemSuffixTest {
+
+    @Test(dataProvider = "systemId-matchedUri")
+    public void testMatch(String systemId, String matchedUri) {
+        checkSysIdResolution(createResolver(), systemId, matchedUri);
+    }
+
+    @DataProvider(name = "systemId-matchedUri")
+    public Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified system id is defined in a
+                // systemIdSuffix entry. The match is an absolute path.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/dtd/docAliceSS.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // systemIdSuffix entry. The match isn't an absolute path.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/docBobSS.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // systemIdSuffix entry. The match isn't an absolute path, and
+                // the systemIdSuffix entry defines alternative base. So the
+                // returned URI should include the alternative base.
+                { "http://remote/dtd/carl/cdocCarl.dtd",
+                        "http://local/carlBase/dtd/docCarlSS.dtd" },
+
+                // The catalog file defines two systemIdSuffix entries, and both
+                // of them match the specified system id. But the first matched
+                // URI should be returned.
+                { "http://remote/dtd/david/docDavid.dtd",
+                        "http://local/base/dtd/docDavidSS1.dtd" },
+
+                // The catalog file defines two systemIdSuffix entries, and both
+                // of them match the specified system id. But the longest match
+                // should be used.
+                { "http://remote/dtd/ella/docElla.dtd",
+                        "http://local/base/dtd/docEllaSS.dtd" } };
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver("systemSuffix.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/SystemTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.CATALOG_SYSTEM;
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from system entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class SystemTest {
+
+    @Test(dataProvider = "systemId-matchedUri")
+    public void testMatch(String systemId, String matchedUri) {
+        checkSysIdResolution(createResolver(), systemId, matchedUri);
+    }
+
+    @DataProvider(name = "systemId-matchedUri")
+    public Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified system id is defined in a
+                // system entry. The match is an absolute path.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/dtd/docAliceSys.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // public entry. But the match isn't an absolute path, so the
+                // returned URI should include the base, which is defined by the
+                // catalog file, as the prefix.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/docBobSys.dtd" },
+
+                // The matched URI of the specified system id is defined in a
+                // system entry. The match isn't an absolute path, and the
+                // system entry defines alternative base. So the returned URI
+                // should include the alternative base.
+                { "http://remote/dtd/carl/docCarl.dtd",
+                        "http://local/carlBase/dtd/docCarlSys.dtd" },
+
+                // The catalog file defines two system entries, and both of them
+                // match the specified system id. But the first matched URI
+                // should be returned.
+                { "http://remote/dtd/david/docDavid.dtd",
+                        "http://local/base/dtd/docDavidSys1.dtd" } };
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver(CATALOG_SYSTEM);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/UriFamilyTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from uri, rewriteURI, uriSuffix and delegateURI
+ *          entries. It tests the resolution priorities among the uri family
+ *          entries. The test rule is based on OASIS Standard V1.1 section
+ *          7.2.2. "Resolution of External Identifiers".
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class UriFamilyTest {
+
+    @Test(dataProvider = "uri-matchedUri")
+    public void testMatch(String systemId, String matchedUri) {
+        checkUriResolution(createResolver(), systemId, matchedUri);
+    }
+
+    @DataProvider(name = "uri-matchedUri")
+    public Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified URI reference is defined in
+                // a uri entry.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/base/dtd/docAliceURI.dtd" },
+
+                // The matched URI of the specified URI reference is defined in
+                // a rewriteURI entry.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/ru/docBob.dtd" },
+
+                // The matched URI of the specified URI reference is defined in
+                // a uriSuffix entry.
+                { "http://remote/dtd/carl/docCarl.dtd",
+                        "http://local/base/dtd/docCarlUS.dtd" } };
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogUriResolver createResolver() {
+        return catalogUriResolver("uriFamily.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/UriSuffixTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from rewriteURI entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class UriSuffixTest {
+
+    @Test(dataProvider = "uri-matchedUri")
+    public void testMatch(String uri, String matchedUri) {
+        checkUriResolution(createResolver(), uri, matchedUri);
+    }
+
+    @DataProvider(name = "uri-matchedUri")
+    public Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified URI reference is defined in
+                // a uriSuffix entry. The match is an absolute path.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/dtd/docAliceUS.dtd" },
+
+                // The matched URI of the specified URI reference is defined in
+                // a uriSuffix entry. The match isn't an absolute path.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/docBobUS.dtd" },
+
+                // The matched URI of the specified URI reference is defined in
+                // a uriSuffix entry. The match isn't an absolute path, and the
+                // uriSuffix entry defines alternative base. So the returned
+                // URI should include the alternative base.
+                { "http://remote/dtd/carl/cdocCarl.dtd",
+                        "http://local/carlBase/dtd/docCarlUS.dtd" },
+
+                // The catalog file defines two uriSuffix entries, and both of
+                // them match the specified URI reference. But the first matched
+                // URI should be returned.
+                { "http://remote/dtd/david/docDavid.dtd",
+                        "http://local/base/dtd/docDavidUS1.dtd" },
+
+                // The catalog file defines two uriSuffix entries, and both
+                // of them match the specified URI reference. But the longest
+                // match should be used.
+                { "http://remote/dtd/ella/docElla.dtd",
+                        "http://local/base/dtd/docEllaUS.dtd" } };
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogUriResolver createResolver() {
+        return catalogUriResolver("uriSuffix.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/UriTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.CATALOG_URI;
+import static catalog.CatalogTestUtils.RESOLVE_CONTINUE;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkNoMatch;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogException;
+import javax.xml.catalog.CatalogFeatures;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary Get matched URIs from uri entries.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class UriTest {
+
+    @Test(dataProvider = "uri-matchedUri")
+    public void testMatch(String uri, String matchedUri) {
+        checkUriResolution(createResolver(), uri, matchedUri);
+    }
+
+    @DataProvider(name = "uri-matchedUri")
+    public Object[][] dataOnMatch() {
+        return new Object[][] {
+                // The matched URI of the specified URI reference is defined in
+                // a uri entry. The match is an absolute path.
+                { "http://remote/dtd/alice/docAlice.dtd",
+                        "http://local/dtd/docAliceURI.dtd" },
+
+                // The matched URI of the specified URI reference is defined in
+                // a uri entry. But the match isn't an absolute path, so the
+                // returned URI should include the base, which is defined by the
+                // catalog file, as the prefix.
+                { "http://remote/dtd/bob/docBob.dtd",
+                        "http://local/base/dtd/docBobURI.dtd" },
+
+                // The catalog file defines two uri entries, and both of them
+                // match the specified URI reference. But the first matched URI
+                // should be returned.
+                { "http://remote/dtd/david/docDavid.dtd",
+                        "http://local/base/dtd/docDavidURI1.dtd" } };
+    }
+
+    /*
+     * Specify base location via method CatalogUriResolver.resolve(href, base).
+     */
+    @Test
+    public void testSpecifyBaseByAPI() {
+        checkUriResolution(createResolver(),
+                "http://remote/dtd/carl/docCarl.dtd",
+                "http://local/carlBase/dtd/docCarlURI.dtd");
+
+        CatalogUriResolver continueResolver = catalogUriResolver(
+                CatalogFeatures.builder().with(CatalogFeatures.Feature.RESOLVE,
+                        RESOLVE_CONTINUE).build(), CATALOG_URI);
+        checkUriResolution(continueResolver, "docCarl.dtd",
+                "http://local/alternativeBase/dtd/",
+                "http://local/alternativeBase/dtd/docCarl.dtd");
+    }
+
+    /*
+     * If no match is found, a CatalogException should be thrown.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void testNoMatch() {
+        checkNoMatch(createResolver());
+    }
+
+    private CatalogUriResolver createResolver() {
+        return catalogUriResolver(CATALOG_URI);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/UrnUnwrappingTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.ResolutionChecker.checkPubIdResolution;
+
+import javax.xml.catalog.CatalogResolver;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary If the passed public identifier is started with "urn:publicid:",
+ *          it has to be regarded as URN and normalized. And then the catalog
+ *          resolver uses the normalized stuff to do matching.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class UrnUnwrappingTest {
+
+    @Test(dataProvider = "urn-matchedUri")
+    public void testUnwrapping(String urn, String matchedUri) {
+        checkPubIdResolution(createResolver(), urn, matchedUri);
+    }
+
+    @DataProvider(name = "urn-matchedUri")
+    private Object[][] data() {
+        return new Object[][] {
+                // The specified public id is URN format.
+                { "urn:publicid:-:REMOTE:DTD+ALICE+DOCALICE+XML:EN",
+                        "http://local/base/dtd/docAlicePub.dtd" },
+
+                // The specified public id includes some special URN chars.
+                { "urn:publicid:-:REMOTE:DTD+BOB+DOCBOB+;+%2B+%3A+%2F+%3B+%27"
+                        + "+%3F+%23+%25:EN",
+                        "http://local/base/dtd/docBobPub.dtd" } };
+    }
+
+    private CatalogResolver createResolver() {
+        return catalogResolver("urnUnwrapping.xml");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/ValidateCatalogTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.CATALOG_SYSTEM;
+import static catalog.CatalogTestUtils.CATALOG_URI;
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.ResolutionChecker.checkSysIdResolution;
+import static catalog.ResolutionChecker.checkUriResolution;
+
+import javax.xml.catalog.CatalogException;
+
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @bug 8077931
+ * @summary A legal catalog file must be well-formed XML, the root element
+ *          must be catalog, and the naming space of the root element must be
+ *          urn:oasis:names:tc:entity:xmlns:xml:catalog.
+ * @compile ../../libs/catalog/CatalogTestUtils.java
+ * @compile ../../libs/catalog/ResolutionChecker.java
+ */
+public class ValidateCatalogTest {
+
+    private static final String CATALOG_WRONGROOT = "validateCatalog-wrongRoot.xml";
+    private static final String CATALOG_MALFORMED = "validateCatalog-malformed.xml";
+
+    /*
+     * EntityResolver tries to load catalog with wrong root,
+     * it should throw CatalogException.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void validateWrongRootCatalogOnEntityResolver() {
+        catalogResolver(CATALOG_WRONGROOT);
+    }
+
+    /*
+     * URIResolver tries to load catalog with wrong root,
+     * it should throw CatalogException.
+     */
+    @Test(expectedExceptions = CatalogException.class)
+    public void validateWrongRootCatalogOnUriResolver() {
+        catalogUriResolver(CATALOG_WRONGROOT);
+    }
+
+    /*
+     * EntityResolver tries to load malformed catalog,
+     * it should throw RuntimeException.
+     */
+    @Test(expectedExceptions = RuntimeException.class)
+    public void validateMalformedCatalogOnEntityResolver() {
+        catalogResolver(CATALOG_MALFORMED);
+    }
+
+    /*
+     * UriResolver tries to load malformed catalog,
+     * it should throw RuntimeException.
+     */
+    @Test(expectedExceptions = RuntimeException.class)
+    public void validateMalformedCatalogOnUriResolver() {
+        catalogUriResolver(CATALOG_MALFORMED);
+    }
+
+    /*
+     * Resolver should ignore the catalog which doesn't declare the correct
+     * naming space.
+     */
+    @Test
+    public void validateWrongNamingSpaceCatalog() {
+        String catalogName = "validateCatalog-noNamingSpace.xml";
+        checkSysIdResolution(catalogResolver(catalogName, CATALOG_SYSTEM),
+                "http://remote/dtd/alice/docAlice.dtd",
+                "http://local/dtd/docAliceSys.dtd");
+        checkUriResolution(catalogUriResolver(catalogName, CATALOG_URI),
+                "http://remote/dtd/alice/docAlice.dtd",
+                "http://local/dtd/docAliceURI.dtd");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/catalogReferCircle-itself.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <nextCatalog catalog="catalogReferCircle-itself.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/catalogReferCircle-left.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <nextCatalog catalog="catalogReferCircle-right.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/catalogReferCircle-right.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <nextCatalog catalog="catalogReferCircle-left.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/deferFeature.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <system systemId="http://remote/dtd/alice/docAlice.dtd" uri="http://local/dtd/docAliceSys.dtd" />
+    <uri name="http://remote/dtd/alice/docAlice.dtd" uri="http://local/dtd/docAliceURI.dtd" />
+
+    <delegateSystem systemIdStartString="http://remote/dtd/alice/" catalog="delegateSystem-alice.xml" />
+    <delegatePublic publicIdStartString="-//REMOTE//DTD ALICE DOCALICE" catalog="delegatePublic-alice.xml" />
+    <nextCatalog catalog="nextCatalog-rightAlice.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegatePublic-alice.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="http://local/dtd/docAlicePub.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegatePublic-bob.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/bob/">
+    <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobPub.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegatePublic-carl.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/carl/">
+    <public publicId="-//REMOTE//DTD CARL DOCCARL XML//EN" uri="docCarlPub.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegatePublic.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <delegatePublic publicIdStartString="-//REMOTE//DTD ALICE DOCALICE" catalog="delegatePublic-alice.xml" />
+
+    <!-- delegateSystem-bobDummy.xml is not existing -->
+    <delegatePublic publicIdStartString="-//REMOTE//DTD BOB DOCBOB" catalog="delegatePublic-bob.xml" />
+    <delegatePublic publicIdStartString="-//REMOTE//DTD BOB DOCBOB" catalog="delegatePublic-bobDummy.xml" />
+
+    <!-- delegateSystem-carlDummy.xml is not existing -->
+    <delegatePublic publicIdStartString="-//REMOTE//DTD CARL DOCCARL" catalog="delegatePublic-carlDummy.xml" />
+    <delegatePublic publicIdStartString="-//REMOTE//DTD CARL DOCCARL XML" catalog="delegatePublic-carl.xml" />
+
+    <!-- delegateSystem-david.xml is not existing -->
+    <delegatePublic publicIdStartString="-//REMOTE//DTD DAVID DOCDAVID" catalog="delegatePublic-david.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegateSystem-alice.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/alice/">
+    <system systemId="http://remote/dtd/alice/docAlice.dtd" uri="docAliceDS.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegateSystem-bob.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/bob/">
+    <system systemId="http://remote/dtd/bob/docBob.dtd" uri="docBobDS.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegateSystem-carl.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/carl/">
+    <system systemId="http://remote/dtd/carl/docCarl.dtd" uri="docCarlDS.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegateSystem.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <delegateSystem systemIdStartString="http://remote/dtd/alice/" catalog="delegateSystem-alice.xml" />
+
+    <!-- delegateSystem-bobDummy.xml is not existing -->
+    <delegateSystem systemIdStartString="http://remote/dtd/" catalog="delegateSystem-bobDummy.xml" />
+    <delegateSystem systemIdStartString="http://remote/dtd/bob/" catalog="delegateSystem-bob.xml" />
+
+    <!-- delegateSystem-carlDummy.xml is not existing -->
+    <delegateSystem systemIdStartString="http://remote/dtd/carl/" catalog="delegateSystem-carl.xml" />
+    <delegateSystem systemIdStartString="http://remote/dtd/carl/" catalog="delegateSystem-carlDummy.xml" />
+
+    <!-- delegateSystem-carlDummy.xml is not existing -->
+    <delegateSystem systemIdStartString="http://remote/dtd/david/" catalog="delegateSystem-davidDummy.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegateUri-alice.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/alice/">
+    <uri name="http://remote/dtd/alice/docAlice.dtd" uri="docAliceDU.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegateUri-bob.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/bob/">
+    <uri name="http://remote/dtd/bob/docBob.dtd" uri="docBobDU.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegateUri-carl.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/carl/">
+    <uri name="http://remote/dtd/carl/docCarl.dtd" uri="docCarlDU.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/delegateUri.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <delegateURI uriStartString="http://remote/dtd/alice/" catalog="delegateUri-alice.xml" />
+
+    <delegateURI uriStartString="http://remote/dtd/" catalog="delegateUri-bobDummy.xml" />
+    <delegateURI uriStartString="http://remote/dtd/bob/" catalog="delegateUri-bob.xml" />
+
+    <delegateURI uriStartString="http://remote/dtd/carl/" catalog="delegateUri-carl.xml" />
+    <delegateURI uriStartString="http://remote/dtd/carl/" catalog="delegateUri-carlDummy.xml" />
+
+    <delegateURI uriStartString="http://remote/dtd/david/" catalog="delegateUri-davidDummy.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/group.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <group>
+        <system systemId="http://remote/dtd/sys/alice/docAlice.dtd" uri="docAliceSys.dtd" />
+        <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="docAlicePub.dtd" />
+        <uri name="http://remote/dtd/uri/alice/docAlice.dtd" uri="docAliceURI.dtd" />
+    </group>
+
+    <group xml:base="http://local/bobBase/dtd/">
+        <system systemId="http://remote/dtd/sys/bob/docBob.dtd" uri="docBobSys.dtd" />
+        <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobPub.dtd" />
+        <uri name="http://remote/dtd/uri/bob/docBob.dtd" uri="docBobURI.dtd" />
+    </group>
+
+    <system systemId="http://remote/dtd/sys/carl/docCarl.dtd" uri="docCarlSys1.dtd" />
+    <public publicId="-//REMOTE//DTD CARL DOCCARL XML//EN" uri="docCarlPub1.dtd" />
+    <uri name="http://remote/dtd/uri/carl/docCarl.dtd" uri="docCarlURI1.dtd" />
+    <group>
+        <system systemId="http://remote/dtd/sys/carl/docCarl.dtd" uri="docCarlSys2.dtd" />
+        <public publicId="-//REMOTE//DTD CARL DOCCARL XML//EN" uri="docCarlPub2.dtd" />
+        <uri name="http://remote/dtd/uri/carl/docCarl.dtd" uri="docCarlURI2.dtd" />
+    </group>
+    <system systemId="http://remote/dtd/sys/carl/docCarl.dtd" uri="docCarlSys3.dtd" />
+    <public publicId="-//REMOTE//DTD CARL DOCCARL XML//EN" uri="docCarlPub3.dtd" />
+    <uri name="http://remote/dtd/uri/carl/docCarl.dtd" uri="docCarlURI3.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/loadCatalogFiles.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE catalog
+  PUBLIC "-//OASIS//DTD XML Catalogs V1.1//EN"
+         "http://www.oasis-open.org/committees/entity/release/1.1/catalog.dtd">
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <nextCatalog catalog="nextCatalog-dummy.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/nextCatalog-left.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <nextCatalog catalog="nextCatalog-leftAlice.xml" />
+
+    <nextCatalog catalog="nextCatalog-leftBob.xml" />
+    <group xml:base="http://local/base/dtd/">
+        <system systemId="http://remote/dtd/sys/docBob.dtd" uri="docBobLeftSys.dtd" />
+        <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobLeftPub.dtd" />
+        <uri name="http://remote/dtd/uri/docBob.dtd" uri="docBobLeftURI.dtd" />
+    </group>
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/nextCatalog-leftAlice.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/sys/docAlice.dtd" uri="docAliceNextLeftSys.dtd" />
+    <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="docAliceNextLeftPub.dtd" />
+    <uri name="http://remote/dtd/uri/docAlice.dtd" uri="docAliceNextLeftURI.dtd" />
+
+    <system systemId="http://remote/dtd/sys/docDuplicate.dtd" uri="docDuplicateLeftSys.dtd" />
+    <public publicId="-//REMOTE//DTD DUPLICATE DOCDUPLICATE XML//EN" uri="docDuplicateLeftPub.dtd" />
+    <uri name="http://remote/dtd/uri/docDuplicate.dtd" uri="docDuplicateLeftURI.dtd" />
+
+    <systemSuffix systemIdSuffix="ss/doc.dtd" uri="docSSShorter.dtd" />
+    <rewriteSystem systemIdStartString="http://remote/dtd/rs/" rewritePrefix="http://local/base/dtd/rsShorter/" />
+    <uriSuffix uriSuffix="us/doc.dtd" uri="docUSShorter.dtd" />
+    <rewriteURI uriStartString="http://remote/dtd/ru/" rewritePrefix="http://local/base/dtd/ruShorter/" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/nextCatalog-leftBob.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <group xml:base="http://local/base/dtd/">
+        <system systemId="http://remote/dtd/sys/docBob.dtd" uri="docBobNextLeftSys.dtd" />
+        <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobNextLeftPub.dtd" />
+        <uri name="http://remote/dtd/uri/docAlice.dtd" uri="docAliceNextLeftURI.dtd" />
+    </group>
+
+    <nextCatalog catalog="nextCatalog-leftCarl.xml" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/nextCatalog-leftCarl.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/sys/docCarl.dtd" uri="docCarlSys.dtd" />
+    <public publicId="-//REMOTE//DTD CARL DOCCARL XML//EN" uri="docCarlPub.dtd" />
+    <uri name="http://remote/dtd/uri/docCarl.dtd" uri="docCarlURI.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/nextCatalog-right.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <nextCatalog catalog="nextCatalog-rightAlice.xml" />
+
+    <nextCatalog catalog="nextCatalog-rightAlice.xml" />
+    <group xml:base="http://local/base/dtd/">
+        <system systemId="http://remote/dtd/sys/docBob.dtd" uri="docBobLeftSys.dtd" />
+        <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobLeftPub.dtd" />
+        <uri name="http://remote/dtd/uri/docBob.dtd" uri="docBobLeftURI.dtd" />
+    </group>
+
+    <system systemId="http://remote/dtd/sys/docDuplicate.dtd" uri="docDuplicateRightSys.dtd" />
+    <public publicId="-//REMOTE//DTD DUPLICATE DOCDUPLICATE XML//EN" uri="docDuplicateRightPub.dtd" />
+    <uri name="http://remote/dtd/uri/docDuplicate.dtd" uri="docDuplicateRightURI.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/nextCatalog-rightAlice.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/sys/docAlice.dtd" uri="docAliceNextRightSys.dtd" />
+    <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="docAliceNextRightPub.dtd" />
+    <uri name="http://remote/dtd/uri/docAlice.dtd" uri="docAliceNextRightURI.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/nextCatalog-rightBob.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/sys/docBob.dtd" uri="docBobNextRightSys.dtd" />
+    <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobNextRightPub.dtd" />
+    <uri name="http://remote/dtd/uri/docAlice.dtd" uri="docAliceNextRightURI.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/normalization.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId=" http://remote/dtd/alice/docAlice.dtd " uri="docAliceSys.dtd" />
+    <system systemId="http://remote/dtd/bob/docBob&lt;&gt;\^`{|}.dtd" uri="docBobSys.dtd" />
+
+    <uri name=" http://remote/dtd/alice/docAlice.dtd " uri="docAliceSys.dtd" />
+    <uri name="http://remote/dtd/bob/docBob&lt;&gt;\^`{|}.dtd" uri="docBobSys.dtd" />
+
+    <public publicId=" -//REMOTE//DTD  ALICE DOCALICE XML//EN " uri="docAlicePub.dtd" />
+    <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobPub.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/prefer.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <group prefer="public">
+        <system systemId="http://remote/dtd/alice/docAlice.dtd" uri="docAliceSys.dtd" />
+        <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="docAlicePub.dtd" />
+    </group>
+
+    <group prefer="system">
+        <system systemId="http://remote/dtd/bob/docBob.dtd" uri="docBobSys.dtd" />
+        <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobPub.dtd" />
+    </group>
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/preferFeature.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/alice/docAlice.dtd" uri="docAliceSys.dtd" />
+    <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="docAlicePub.dtd" />
+
+    <group prefer="system">
+        <system systemId="http://remote/dtd/bob/docBob.dtd" uri="docBobSys.dtd" />
+        <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobPub.dtd" />
+    </group>
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/public.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="http://local/dtd/docAlicePub.dtd" />
+
+    <public publicId="-//REMOTE//DTD BOB DOCBOB XML//EN" uri="docBobPub.dtd" />
+
+    <public publicId="-//REMOTE//DTD CARL DOCCARL XML//EN" uri="docCarlPub.dtd" xml:base="http://local/carlBase/dtd/" />
+
+    <public publicId="-//REMOTE//DTD DAVID DOCDAVID XML//EN" uri="docDavidPub1.dtd" />
+    <public publicId="-//REMOTE//DTD DAVID DOCDAVID XML//EN" uri="docDavidPub2.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/publicFamily.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <delegatePublic publicIdStartString="-//REMOTE//DTD ALICE DOCALICE" catalog="delegatePublic-alice.xml" />
+    <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="docAlicePub.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/rewriteSystem.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <rewriteSystem systemIdStartString="http://remote/dtd/alice/" rewritePrefix="http://local/dtd/alice/rs/" />
+
+    <rewriteSystem systemIdStartString="http://remote/dtd/bob/" rewritePrefix="bob/rs/" />
+
+    <rewriteSystem systemIdStartString="http://remote/dtd/carl/" rewritePrefix="carl/rs/"
+        xml:base="http://local/carlBase/dtd/" />
+
+    <rewriteSystem systemIdStartString="http://remote/dtd/david/" rewritePrefix="david1/rs/" />
+    <rewriteSystem systemIdStartString="http://remote/dtd/david/" rewritePrefix="david2/rs/" />
+
+    <rewriteSystem systemIdStartString="http://remote/dtd/" rewritePrefix="ella/" />
+    <rewriteSystem systemIdStartString="http://remote/dtd/ella/" rewritePrefix="ella/rs/" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/rewriteUri.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <rewriteURI uriStartString="http://remote/dtd/alice/" rewritePrefix="http://local/dtd/alice/ru/" />
+
+    <rewriteURI uriStartString="http://remote/dtd/bob/" rewritePrefix="bob/ru/" />
+
+    <rewriteURI uriStartString="http://remote/dtd/carl/" rewritePrefix="carl/ru/"
+        xml:base="http://local/carlBase/dtd/" />
+
+    <rewriteURI uriStartString="http://remote/dtd/david/" rewritePrefix="david1/ru/" />
+    <rewriteURI uriStartString="http://remote/dtd/david/" rewritePrefix="david2/ru/" />
+
+    <rewriteURI uriStartString="http://remote/dtd/" rewritePrefix="ella/" />
+    <rewriteURI uriStartString="http://remote/dtd/ella/" rewritePrefix="ella/ru/" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/specifyCatalog-api.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/sys/doc.dtd" uri="docAPISys.dtd" />
+    <uri name="http://remote/dtd/uri/doc.dtd" uri="docAPIURI.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/specifyCatalog-feature.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/sys/doc.dtd" uri="docFeatureSys.dtd" />
+    <uri name="http://remote/dtd/uri/doc.dtd" uri="docFeatureURI.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/specifyCatalog-sysProps.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/sys/doc.dtd" uri="docSysPropsSys.dtd" />
+    <uri name="http://remote/dtd/uri/doc.dtd" uri="docSysPropsURI.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/system.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/alice/docAlice.dtd" uri="http://local/dtd/docAliceSys.dtd" />
+
+    <system systemId="http://remote/dtd/bob/docBob.dtd" uri="docBobSys.dtd" />
+
+    <system systemId="http://remote/dtd/carl/docCarl.dtd" uri="docCarlSys.dtd" xml:base="http://local/carlBase/dtd/" />
+
+    <system systemId="http://remote/dtd/david/docDavid.dtd" uri="docDavidSys1.dtd" />
+    <system systemId="http://remote/dtd/david/docDavid.dtd" uri="docDavidSys2.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/systemFamily.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <delegateSystem systemIdStartString="http://remote/dtd/alice/" catalog="delegateSystem-alice.xml" />
+    <systemSuffix systemIdSuffix="docAlice.dtd" uri="docAliceSS.dtd" />
+    <rewriteSystem systemIdStartString="http://remote/dtd/alice/" rewritePrefix="http://local/base/rs/" />
+    <system systemId="http://remote/dtd/alice/docAlice.dtd" uri="docAliceSys.dtd" />
+
+    <delegateSystem systemIdStartString="http://remote/dtd/bob/" catalog="delegateSystem-bob.xml" />
+    <systemSuffix systemIdSuffix="docBob.dtd" uri="docBobSS.dtd" />
+    <rewriteSystem systemIdStartString="http://remote/dtd/bob/" rewritePrefix="http://local/base/dtd/rs/" />
+
+    <delegateSystem systemIdStartString="http://remote/dtd/carl/" catalog="delegateSystem-carl.xml" />
+    <systemSuffix systemIdSuffix="docCarl.dtd" uri="docCarlSS.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/systemSuffix.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <systemSuffix systemIdSuffix="docAlice.dtd" uri="http://local/dtd/docAliceSS.dtd" />
+
+    <systemSuffix systemIdSuffix="docBob.dtd" uri="docBobSS.dtd" />
+
+    <systemSuffix systemIdSuffix="docCarl.dtd" uri="docCarlSS.dtd" xml:base="http://local/carlBase/dtd/" />
+
+    <systemSuffix systemIdSuffix="docDavid.dtd" uri="docDavidSS1.dtd" />
+    <systemSuffix systemIdSuffix="docDavid.dtd" uri="docDavidSS2.dtd" />
+
+    <systemSuffix systemIdSuffix="docElla.dtd" uri="/" />
+    <systemSuffix systemIdSuffix="ella/docElla.dtd" uri="docEllaSS.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/uri.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <uri name="http://remote/dtd/alice/docAlice.dtd" uri="http://local/dtd/docAliceURI.dtd" />
+
+    <uri name="http://remote/dtd/bob/docBob.dtd" uri="docBobURI.dtd" />
+
+    <uri name="http://remote/dtd/carl/docCarl.dtd" uri="docCarlURI.dtd" xml:base="http://local/carlBase/dtd/" />
+
+    <uri name="http://remote/dtd/david/docDavid.dtd" uri="docDavidURI1.dtd" />
+    <uri name="http://remote/dtd/david/docDavid.dtd" uri="docDavidURI2.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/uriFamily.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <delegateURI uriStartString="http://remote/dtd/alice/" catalog="delegateURI-alice.xml" />
+    <uriSuffix uriSuffix="docAlice.dtd" uri="docAliceUS.dtd" />
+    <rewriteURI uriStartString="http://remote/dtd/alice/" rewritePrefix="http://local/base/ru/" />
+    <uri name="http://remote/dtd/alice/docAlice.dtd" uri="docAliceURI.dtd" />
+
+    <delegateURI uriStartString="http://remote/dtd/bob/" catalog="delegateURI-bob.xml" />
+    <uriSuffix uriSuffix="docBob.dtd" uri="docBobUS.dtd" />
+    <rewriteURI uriStartString="http://remote/dtd/bob/" rewritePrefix="http://local/base/dtd/ru/" />
+
+    <delegateURI uriStartString="http://remote/dtd/carl/" catalog="delegateURI-carl.xml" />
+    <uriSuffix uriSuffix="docCarl.dtd" uri="docCarlUS.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/uriSuffix.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <uriSuffix uriSuffix="docAlice.dtd" uri="http://local/dtd/docAliceUS.dtd" />
+
+    <uriSuffix uriSuffix="docBob.dtd" uri="docBobUS.dtd" />
+
+    <uriSuffix uriSuffix="docCarl.dtd" uri="docCarlUS.dtd" xml:base="http://local/carlBase/dtd/" />
+
+    <uriSuffix uriSuffix="docDavid.dtd" uri="docDavidUS1.dtd" />
+    <uriSuffix uriSuffix="docDavid.dtd" uri="docDavidUS2.dtd" />
+
+    <uriSuffix uriSuffix="docElla.dtd" uri="/" />
+    <uriSuffix uriSuffix="ella/docElla.dtd" uri="docEllaUS.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/urnUnwrapping.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <public publicId="-//REMOTE//DTD ALICE DOCALICE XML//EN" uri="docAlicePub.dtd" />
+    <public publicId="-//REMOTE//DTD BOB DOCBOB :: + : / ; ' ? # %//EN" uri="docBobPub.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/validateCatalog-malformed.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This catalog is malformed XML -->
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <system systemId="http://remote/dtd/doc.dtd" uri="docSys.dtd" />
+</cat>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/validateCatalog-noNamingSpace.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This catalog doesn't define the correct naming space -->
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog1">
+    <system systemId="http://remote/dtd/alice/docAlice.dtd" uri="http://local/dtd/docAliceSysWrongNS.dtd" />
+    <uri name="http://remote/dtd/alice/docAlice.dtd" uri="http://local/dtd/docAliceURIWrongNS.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/functional/catalog/catalogFiles/validateCatalog-wrongRoot.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- The root of this catalog isn't named "catalog" -->
+<cat xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+    <system systemId="http://remote/dtd/doc.dtd" uri="docSys.dtd" />
+</cat>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/isolatedjdk/IsolatedJDK.sh	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+# 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.
+#
+# 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.
+
+if [ $# = 0 ]; then
+  echo "The suffix of ISOLATED_JDK is mandatory"
+  exit 1
+fi
+
+checkVariable() {
+  variable='$'$1
+
+  if [ "${variable}" = "" ]; then
+    echo "Failed due to $1 is not set."
+    exit 1
+  fi
+}
+
+checkVariables() {
+  for variable in $*
+  do
+    checkVariable ${variable}
+  done
+}
+
+# Check essential variables
+checkVariables TESTJAVA TESTSRC TESTCLASSES TESTCLASSPATH
+
+echo "TESTJAVA=${TESTJAVA}"
+echo "TESTSRC=${TESTSRC}"
+echo "TESTCLASSES=${TESTCLASSES}"
+echo "TESTCLASSPATH=${TESTCLASSPATH}"
+
+# Make an isolated copy of the testing JDK
+ISOLATED_JDK="./ISOLATED_JDK_$1"
+echo "ISOLATED_JDK=${ISOLATED_JDK}"
+
+echo "Copy testing JDK started"
+cp -H -R ${TESTJAVA} ${ISOLATED_JDK} || exit 1
+chmod -R +w ${ISOLATED_JDK} || exit 1
+echo "Copy testing JDK ended"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/isolatedjdk/TEST.properties	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,4 @@
+lib.dirs=/javax/xml/jaxp/libs
+
+# Declare module dependency
+modules=java.xml
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/isolatedjdk/catalog/PropertiesTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import static catalog.CatalogTestUtils.DEFER_FALSE;
+import static catalog.CatalogTestUtils.FEATURE_DEFER;
+import static catalog.CatalogTestUtils.FEATURE_FILES;
+import static catalog.CatalogTestUtils.FEATURE_PREFER;
+import static catalog.CatalogTestUtils.FEATURE_RESOLVE;
+import static catalog.CatalogTestUtils.PREFER_SYSTEM;
+import static catalog.CatalogTestUtils.RESOLVE_CONTINUE;
+import static catalog.CatalogTestUtils.catalogResolver;
+import static catalog.CatalogTestUtils.catalogUriResolver;
+import static catalog.CatalogTestUtils.createPropsContent;
+import static catalog.CatalogTestUtils.deleteJAXPProps;
+import static catalog.CatalogTestUtils.generateJAXPProps;
+import static catalog.CatalogTestUtils.getCatalogPath;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.catalog.CatalogUriResolver;
+
+/*
+ * This case tests if the properties FILES, DEFER, PREFER, RESOLVE in
+ * jaxp.properties and system properties could be cared.
+ */
+public class PropertiesTest {
+
+    private static final String CATALOG_PROPERTIES = "properties.xml";
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("testJAXPProperties started");
+        testJAXPProperties();
+        System.out.println("testJAXPProperties ended");
+
+        System.out.println("testSystemProperties started");
+        testSystemProperties();
+        System.out.println("testSystemProperties ended");
+
+        System.out.println("Test passed");
+    }
+
+    /*
+     * Tests how does jaxp.properties affects the resolution.
+     */
+    private static void testJAXPProperties() throws IOException {
+        generateJAXPProps(createJAXPPropsContent());
+        testProperties();
+        deleteJAXPProps();
+    }
+
+    /*
+     * Tests how does system properties affects the resolution.
+     */
+    private static void testSystemProperties() {
+        setSystemProperties();
+        testProperties();
+    }
+
+    private static void testProperties() {
+        testPropertiesOnEntityResolver();
+        testPropertiesOnUriResolver();
+    }
+
+    private static void testPropertiesOnEntityResolver() {
+        CatalogResolver entityResolver = catalogResolver((String[]) null);
+        entityResolver.resolveEntity("-//REMOTE//DTD DOCDUMMY XML//EN",
+                "http://remote/sys/dtd/docDummy.dtd");
+        "http://local/base/dtd/docSys.dtd".equals(
+                entityResolver.resolveEntity("-//REMOTE//DTD DOC XML//EN",
+                        "http://remote/dtd/doc.dtd").getSystemId());
+    }
+
+    private static void testPropertiesOnUriResolver() {
+        CatalogUriResolver uriResolver = catalogUriResolver((String[]) null);
+        uriResolver.resolve("http://remote/uri/dtd/docDummy.dtd", null);
+        "http://local/base/dtd/docURI.dtd".equals(uriResolver.resolve(
+                "http://remote/dtd/doc.dtd", null).getSystemId());
+    }
+
+    // The properties in jaxp.properties don't use default values
+    private static String createJAXPPropsContent() {
+        Map<String, String> props = new HashMap<>();
+        props.put(FEATURE_FILES, getCatalogPath(CATALOG_PROPERTIES));
+        props.put(FEATURE_DEFER, DEFER_FALSE);
+        props.put(FEATURE_PREFER, PREFER_SYSTEM);
+        props.put(FEATURE_RESOLVE, RESOLVE_CONTINUE);
+        return createPropsContent(props);
+    }
+
+    // The system properties don't use default values
+    private static void setSystemProperties() {
+        System.setProperty(FEATURE_FILES, getCatalogPath(CATALOG_PROPERTIES));
+        System.setProperty(FEATURE_DEFER, DEFER_FALSE);
+        System.setProperty(FEATURE_PREFER, PREFER_SYSTEM);
+        System.setProperty(FEATURE_RESOLVE, RESOLVE_CONTINUE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/isolatedjdk/catalog/PropertiesTest.sh	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# 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.
+#
+# 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.
+
+# @test
+# @bug 8077931
+# @summary This case tests if the properties FILES, DEFER, PREFER, RESOLVE in
+#          jaxp.properties and system properties could be used.
+# @library ../../libs/
+# @build catalog.CatalogTestUtils
+# @build PropertiesTest
+# @run shell/timeout=600 ../IsolatedJDK.sh JAXP_PROPS
+# @run shell/timeout=600 PropertiesTest.sh
+
+echo "Copies properties.xml to class path"
+TEST_CATALOG_PATH=${TESTCLASSES}/catalog/catalogFiles
+echo "TEST_CATALOG_PATH=${TEST_CATALOG_PATH}"
+mkdir -p ${TEST_CATALOG_PATH}
+cp ${TESTSRC}/catalogFiles/properties.xml ${TEST_CATALOG_PATH}/properties.xml
+
+# Execute test
+ISOLATED_JDK=./ISOLATED_JDK_JAXP_PROPS
+echo "Executes PropertiesTest"
+${ISOLATED_JDK}/bin/java -Dtest.src="${TESTSRC}/.." ${TESTVMOPTS} -cp "${TESTCLASSPATH}" catalog.PropertiesTest
+exitCode=$?
+
+# Cleanup ISOLATED_JDK
+rm -rf ${ISOLATED_JDK}
+
+# Results
+echo ''
+if [ $exitCode -gt 0 ]; then
+  echo "PropertiesTest failed";
+else
+  echo "PropertiesTest passed";
+fi
+exit $exitCode
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/isolatedjdk/catalog/catalogFiles/properties.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" xml:base="http://local/base/dtd/">
+    <system systemId="http://remote/dtd/doc.dtd" uri="docSys.dtd" />
+    <public publicId="-//REMOTE//DTD DOC XML//EN" uri="docPub.dtd" />
+    <uri name="http://remote/dtd/doc.dtd" uri="docURI.dtd" />
+</catalog>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.xml.catalog.CatalogFeatures;
+import javax.xml.catalog.CatalogManager;
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.catalog.CatalogUriResolver;
+
+/*
+ * Utilities for testing XML Catalog API.
+ */
+final class CatalogTestUtils {
+
+    /* catalog files */
+    static final String CATALOG_PUBLIC = "public.xml";
+    static final String CATALOG_SYSTEM = "system.xml";
+    static final String CATALOG_URI = "uri.xml";
+
+    /* features */
+    static final String FEATURE_FILES = "javax.xml.catalog.files";
+    static final String FEATURE_PREFER = "javax.xml.catalog.prefer";
+    static final String FEATURE_DEFER = "javax.xml.catalog.defer";
+    static final String FEATURE_RESOLVE = "javax.xml.catalog.resolve";
+
+    /* values of prefer feature */
+    static final String PREFER_SYSTEM = "system";
+    static final String PREFER_PUBLIC = "public";
+
+    /* values of defer feature */
+    static final String DEFER_TRUE = "true";
+    static final String DEFER_FALSE = "false";
+
+    /* values of resolve feature */
+    static final String RESOLVE_STRICT = "strict";
+    static final String RESOLVE_CONTINUE = "continue";
+    static final String RESOLVE_IGNORE = "ignore";
+
+    private static final String JAXP_PROPS = "jaxp.properties";
+    private static final String JAXP_PROPS_BAK = JAXP_PROPS + ".bak";
+
+    /*
+     * Force using slash as File separator as we always use cygwin to test in
+     * Windows platform.
+     */
+    private static final String FILE_SEP = "/";
+
+    private CatalogTestUtils() { }
+
+    /* ********** create resolver ********** */
+
+    /*
+     * Creates CatalogResolver with a set of catalogs.
+     */
+    static CatalogResolver catalogResolver(String... catalogName) {
+        return catalogResolver(null, catalogName);
+    }
+
+    /*
+     * Creates CatalogResolver with a feature and a set of catalogs.
+     */
+    static CatalogResolver catalogResolver(CatalogFeatures features,
+            String... catalogName) {
+        return CatalogManager.catalogResolver(features,
+                getCatalogPaths(catalogName));
+    }
+
+    /*
+     * Creates catalogUriResolver with a set of catalogs.
+     */
+    static CatalogUriResolver catalogUriResolver(String... catalogName) {
+        return catalogUriResolver(null, catalogName);
+    }
+
+    /*
+     * Creates catalogUriResolver with a feature and a set of catalogs.
+     */
+    static CatalogUriResolver catalogUriResolver(
+            CatalogFeatures features, String... catalogName) {
+        return CatalogManager.catalogUriResolver(features,
+                getCatalogPaths(catalogName));
+    }
+
+    // Gets the paths of the specified catalogs.
+    private static String[] getCatalogPaths(String... catalogNames) {
+        return catalogNames == null
+                ? null
+                : Stream.of(catalogNames).map(
+                        catalogName -> getCatalogPath(catalogName)).collect(
+                                Collectors.toList()).toArray(new String[0]);
+    }
+
+    // Gets the paths of the specified catalogs.
+    static String getCatalogPath(String catalogName) {
+        return catalogName == null
+                ? null
+                : getPathByClassName(CatalogTestUtils.class, "catalogFiles")
+                        + catalogName;
+    }
+
+    /*
+     * Acquire a full path string by given class name and relative path string.
+     */
+    private static String getPathByClassName(Class<?> clazz,
+            String relativeDir) {
+        String packageName = FILE_SEP
+                + clazz.getPackage().getName().replaceAll("[.]", FILE_SEP);
+        String javaSourcePath = System.getProperty("test.src").replaceAll(
+                "\\" + File.separator, FILE_SEP) + packageName + FILE_SEP;
+        String normalizedPath = Paths.get(javaSourcePath,
+                relativeDir).normalize().toAbsolutePath().toString();
+        return normalizedPath.replace("\\", FILE_SEP) + FILE_SEP;
+    }
+
+    /* ********** jaxp.properties ********** */
+
+    /*
+     * Generates the jaxp.properties with the specified content.
+     */
+    static void generateJAXPProps(String content) throws IOException {
+        Path filePath = getJAXPPropsPath();
+        Path bakPath = filePath.resolveSibling(JAXP_PROPS_BAK);
+        if (Files.exists(filePath) && !Files.exists(bakPath)) {
+            Files.move(filePath, bakPath);
+        }
+
+        Files.write(filePath, content.getBytes());
+    }
+
+    /*
+     * Deletes the jaxp.properties.
+     */
+    static void deleteJAXPProps() throws IOException {
+        Path filePath = getJAXPPropsPath();
+        Files.delete(filePath);
+        Path bakFilePath = filePath.resolveSibling(JAXP_PROPS_BAK);
+        if (Files.exists(bakFilePath)) {
+            Files.move(bakFilePath, filePath);
+        }
+    }
+
+    /*
+     * Gets the path of jaxp.properties.
+     */
+    private static Path getJAXPPropsPath() {
+        return Paths.get(System.getProperty("java.home") + File.separator
+                + "conf" + File.separator + JAXP_PROPS);
+    }
+
+    /*
+     * Creates the content of properties file with the specified
+     * property-value pairs.
+     */
+    static String createPropsContent(Map<String, String> props) {
+        return props.entrySet().stream().map(
+                entry -> String.format("%s=%s%n", entry.getKey(),
+                        entry.getValue())).reduce(
+                                (line1, line2) -> line1 + line2).get();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/libs/catalog/ResolutionChecker.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.catalog.CatalogUriResolver;
+
+import org.testng.Assert;
+
+/*
+ * Utilities for checking catalog resolution.
+ */
+class ResolutionChecker {
+
+    /* ********** Checks normal resolution ********** */
+
+    /*
+     * Checks the resolution result for specified external identifier.
+     */
+    static void checkExtIdResolution(CatalogResolver resolver,
+            String publicId, String systemId, String matchedUri) {
+        Assert.assertEquals(
+                resolver.resolveEntity(publicId, systemId).getSystemId(),
+                matchedUri);
+    }
+
+    /*
+     * Checks the resolution result for specified system identifier.
+     */
+    static void checkSysIdResolution(CatalogResolver resolver,
+            String systemId, String matchedUri) {
+        checkExtIdResolution(resolver, null, systemId, matchedUri);
+    }
+
+    /*
+     * Checks the resolution result for specified public identifier.
+     */
+    static void checkPubIdResolution(CatalogResolver resolver,
+            String publicId, String matchedUri) {
+        checkExtIdResolution(resolver, publicId, null, matchedUri);
+    }
+
+    /*
+     * Checks the resolution result for specified URI references
+     * with the specified base location.
+     */
+    static void checkUriResolution(CatalogUriResolver resolver,
+            String href, String base, String matchedUri) {
+        Assert.assertEquals(resolver.resolve(href, base).getSystemId(),
+                matchedUri);
+    }
+
+    /*
+     * Checks the resolution result for specified URI references.
+     */
+    static void checkUriResolution(CatalogUriResolver resolver,
+            String href, String matchedUri) {
+        checkUriResolution(resolver, href, null, matchedUri);
+    }
+
+    /* ********** Checks no match is found ********** */
+
+    /*
+     * With strict resolution, if no match is found,
+     * CatalogResolver should throw CatalogException.
+     */
+    static void checkNoMatch(CatalogResolver resolver) {
+        resolver.resolveEntity("-//EXTID//DTD NOMATCH DOCNOMATCH XML//EN",
+                "http://extId/noMatch/docNoMatch.dtd");
+    }
+
+    /*
+     * With strict resolution, if no match is found,
+     * CatalogUriResolver should throw CatalogException.
+     */
+    static void checkNoMatch(CatalogUriResolver resolver) {
+        resolver.resolve("http://uri/noMatch/docNoMatch.dtd", null);
+    }
+
+    /* ********** Checks expected exception ********** */
+
+    /*
+     * Checks the expected exception during the resolution for specified
+     * external identifier.
+     */
+    static <T extends Throwable> void expectExceptionOnExtId(
+            CatalogResolver resolver, String publicId, String systemId,
+            Class<T> expectedExceptionClass) {
+        expectThrows(expectedExceptionClass, () -> {
+            resolver.resolveEntity(publicId, systemId);
+        });
+    }
+
+    /*
+     * Checks the expected exception during the resolution for specified
+     * system identifier.
+     */
+    static <T extends Throwable> void expectExceptionOnSysId(
+            CatalogResolver resolver, String systemId,
+            Class<? extends Throwable> expectedExceptionClass) {
+        expectExceptionOnExtId(resolver, null, systemId,
+                expectedExceptionClass);
+    }
+
+    /*
+     * Checks the expected exception during the resolution for specified
+     * public identifier.
+     */
+    static <T extends Throwable> void expectExceptionOnPubId(
+            CatalogResolver resolver, String publicId,
+            Class<T> expectedExceptionClass) {
+        expectExceptionOnExtId(resolver, publicId, null,
+                expectedExceptionClass);
+    }
+
+    /*
+     * Checks the expected exception during the resolution for specified
+     * URI reference with a specified base location.
+     */
+    static <T extends Throwable> void expectExceptionOnUri(
+            CatalogUriResolver resolver, String href, String base,
+            Class<T> expectedExceptionClass) {
+        expectThrows(expectedExceptionClass, () -> {
+            resolver.resolve(href, base);
+        });
+    }
+
+    /*
+     * Checks the expected exception during the resolution for specified
+     * URI reference without any specified base location.
+     */
+    static <T extends Throwable> void expectExceptionOnUri(
+            CatalogUriResolver resolver, String href,
+            Class<T> expectedExceptionClass) {
+        expectExceptionOnUri(resolver, href, null, expectedExceptionClass);
+    }
+
+    // The TestNG distribution in current JTREG build doesn't support
+    // method Assert.expectThrows().
+    private static <T extends Throwable> T expectThrows(Class<T> throwableClass,
+            ThrowingRunnable runnable) {
+        try {
+            runnable.run();
+        } catch (Throwable t) {
+            if (throwableClass.isInstance(t)) {
+                return throwableClass.cast(t);
+            } else {
+                String mismatchMessage = String.format(
+                        "Expected %s to be thrown, but %s was thrown",
+                        throwableClass.getSimpleName(),
+                        t.getClass().getSimpleName());
+
+                throw new AssertionError(mismatchMessage, t);
+            }
+        }
+
+        String message = String.format(
+                "Expected %s to be thrown, but nothing was thrown",
+                throwableClass.getSimpleName());
+        throw new AssertionError(message);
+    }
+
+    private interface ThrowingRunnable {
+        void run() throws Throwable;
+    }
+}
--- a/jaxp/test/javax/xml/jaxp/unittest/TEST.properties	Thu Nov 05 08:15:39 2015 -0800
+++ b/jaxp/test/javax/xml/jaxp/unittest/TEST.properties	Thu Nov 05 13:42:14 2015 -0800
@@ -1,6 +1,8 @@
 # jaxp test uses TestNG
 TestNG.dirs = .
 
+lib.dirs = /javax/xml/jaxp/libs
+
 # Declare module dependency
 modules=java.xml
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ *
+ * 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 catalog;
+
+import java.io.IOException;
+import javax.xml.catalog.CatalogFeatures;
+import javax.xml.catalog.CatalogFeatures.Feature;
+import javax.xml.catalog.CatalogManager;
+import javax.xml.catalog.CatalogResolver;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import static jaxp.library.JAXPTestUtilities.getPathByClassName;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.w3c.dom.Element;
+import org.xml.sax.Attributes;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.DefaultHandler2;
+
+/*
+ * @bug 8081248
+ * @summary Tests basic Catalog functions.
+ */
+
+public class CatalogTest {
+    /*
+       Tests basic catalog feature by using a CatalogResolver instance to
+    resolve a DTD reference to a locally specified DTD file. If the resolution
+    is successful, the Handler shall return the value of the entity reference
+    that matches the expected value.
+     */
+    @Test(dataProvider = "catalog")
+    public void testCatalogResolver(String test, String expected, String catalogFile, String xml, SAXParser saxParser) {
+        String catalog = null;
+        if (catalogFile != null) {
+            catalog = getClass().getResource(catalogFile).getFile();
+        }
+        String url = getClass().getResource(xml).getFile();
+        try {
+            CatalogResolver cr = CatalogManager.catalogResolver(null, catalog);
+            XMLReader reader = saxParser.getXMLReader();
+            reader.setEntityResolver(cr);
+            MyHandler handler = new MyHandler(saxParser);
+            reader.setContentHandler(handler);
+            reader.parse(url);
+            System.out.println(test + ": expected [" + expected + "] <> actual [" + handler.getResult() + "]");
+            Assert.assertEquals(handler.getResult(), expected);
+        } catch (SAXException | IOException e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+    /*
+       Verifies that when there's no match, in this case only an invalid
+    catalog is provided, the resolver will throw an exception by default.
+    */
+    @Test
+    public void testInvalidCatalog() {
+        String catalog = getClass().getResource("catalog_invalid.xml").getFile();
+
+        String test = "testInvalidCatalog";
+        try {
+            CatalogResolver resolver = CatalogManager.catalogResolver(null, catalog);
+            String actualSystemId = resolver.resolveEntity(null, "http://remote/xml/dtd/sys/alice/docAlice.dtd").getSystemId();
+        } catch (Exception e) {
+            String msg = e.getMessage();
+            if (msg != null) {
+                if (msg.contains("No match found for publicId")) {
+                    Assert.assertEquals(msg, "No match found for publicId 'null' and systemId 'http://remote/xml/dtd/sys/alice/docAlice.dtd'.");
+                    System.out.println(test + ": expected [No match found for publicId 'null' and systemId 'http://remote/xml/dtd/sys/alice/docAlice.dtd'.]");
+                    System.out.println("actual [" + msg + "]");
+                }
+            }
+        }
+    }
+
+    /*
+       Verifies that if resolve is "ignore", an empty InputSource will be returned
+    when there's no match. The systemId is then null.
+    */
+    @Test
+    public void testIgnoreInvalidCatalog() {
+        String catalog = getClass().getResource("catalog_invalid.xml").getFile();
+        CatalogFeatures f = CatalogFeatures.builder()
+                .with(Feature.FILES, catalog)
+                .with(Feature.PREFER, "public")
+                .with(Feature.DEFER, "true")
+                .with(Feature.RESOLVE, "ignore")
+                .build();
+
+        String test = "testInvalidCatalog";
+        try {
+            CatalogResolver resolver = CatalogManager.catalogResolver(f, "");
+            String actualSystemId = resolver.resolveEntity(null, "http://remote/xml/dtd/sys/alice/docAlice.dtd").getSystemId();
+            System.out.println("testIgnoreInvalidCatalog: expected [null]");
+            System.out.println("testIgnoreInvalidCatalog: expected [null]");
+            System.out.println("actual [" + actualSystemId + "]");
+            Assert.assertEquals(actualSystemId, null);
+        } catch (Exception e) {
+            Assert.fail(e.getMessage());
+        }
+    }
+
+
+    /*
+       DataProvider: provides test name, expected string, the catalog, and XML
+       document.
+     */
+    @DataProvider(name = "catalog")
+    Object[][] getCatalog() {
+        return new Object[][]{
+            {"testSystem", "Test system entry", "catalog.xml", "system.xml", getParser()},
+            {"testRewriteSystem", "Test rewritesystem entry", "catalog.xml", "rewritesystem.xml", getParser()},
+            {"testRewriteSystem1", "Test rewritesystem entry", "catalog.xml", "rewritesystem1.xml", getParser()},
+            {"testSystemSuffix", "Test systemsuffix entry", "catalog.xml", "systemsuffix.xml", getParser()},
+            {"testDelegateSystem", "Test delegatesystem entry", "catalog.xml", "delegatesystem.xml", getParser()},
+            {"testPublic", "Test public entry", "catalog.xml", "public.xml", getParser()},
+            {"testDelegatePublic", "Test delegatepublic entry", "catalog.xml", "delegatepublic.xml", getParser()},
+        };
+    }
+
+    SAXParser getParser() {
+        SAXParser saxParser = null;
+        try {
+            SAXParserFactory factory = SAXParserFactory.newInstance();
+            factory.setNamespaceAware(true);
+            saxParser = factory.newSAXParser();
+        } catch (ParserConfigurationException | SAXException e) {
+        }
+
+        return saxParser;
+    }
+
+
+    /**
+     * SAX handler
+     */
+    public class MyHandler extends DefaultHandler2 implements ErrorHandler {
+
+        StringBuilder textContent = new StringBuilder();
+        SAXParser saxParser;
+
+        MyHandler(SAXParser saxParser) {
+            textContent.setLength(0);
+            this.saxParser = saxParser;
+        }
+
+        String getResult() {
+            return textContent.toString();
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+            textContent.delete(0, textContent.length());
+            try {
+                System.out.println("Element: " + uri + ":" + localName + " " + qName);
+            } catch (Exception e) {
+                throw new SAXException(e);
+            }
+
+        }
+
+        @Override
+        public void characters(char ch[], int start, int length) throws SAXException {
+            textContent.append(ch, start, length);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/catalog.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<catalog
+  xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+
+    <public publicId="-//W3C//DTD XHTML 1.0 Strict//EN" 
+            uri="catalog/xhtml1-strict.dtd"/>
+
+    <systemSuffix systemIdSuffix="html1-strict.dtd"
+                  uri="file:///share/mirrors/w3c/xhtml1/xhtml1-strict.dtd"/>
+
+    <public publicId="-//OPENJDK//XML CATALOG DTD//1.0" uri="public.dtd"/>
+    <system systemId="http://openjdk.java.net/xml/catalog/dtd/system.dtd" uri="system.dtd"/>
+    
+    <rewriteSystem systemIdStartString="http://openjdk.java.net/" 
+                   rewritePrefix="files" />
+    
+    <rewriteSystem systemIdStartString="http://openjdk.java.net/xml/catalog/dtd/" 
+                   rewritePrefix="files" />
+    
+    <systemSuffix systemIdSuffix="systemsuffix.dtd" uri="systemsuffix.dtd"/>
+    
+    <delegatePublic publicIdStartString="-//JAVASE//XML CATALOG DTD//DELEGATEPULIC" catalog="files/delegatecatalog.xml"/>
+    <delegateSystem systemIdStartString="http://java.com/xml/catalog/dtd/" catalog="files/delegatecatalog.xml"/>
+    
+    <group resolve="continue">
+        <system systemId="http://remote/dtd/alice/docAlice.dtd" uri="http://local/dtd/docAliceSys.dtd" />
+    </group> 
+
+</catalog>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/catalog_invalid.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<catalog
+  xmlns="xyz">
+
+    <public publicId="-//W3C//DTD XHTML 1.0 Strict//EN" 
+            uri="catalog/xhtml1-strict.dtd"/>
+
+</catalog>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/delegatepublic.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE  catalogtest  PUBLIC  "-//JAVASE//XML CATALOG DTD//DELEGATEPULIC"  
+     "http://java.com/xml/catalog/dtd/delegatepublic.dtd">
+
+<catalogtest>Test &delegatepublic; entry</catalogtest>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/delegatesystem.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE  catalogtest  PUBLIC  "-//JAVASE//XML CATALOG DTD//DELEGATESYSTEM"  
+     "http://java.com/xml/catalog/dtd/delegatesystem.dtd">
+
+<catalogtest>Test &delegatesystem; entry</catalogtest>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/files/delegatecatalog.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<catalog
+  xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+
+    <public publicId="-//W3C//DTD XHTML 1.0 Strict//EN" 
+            uri="catalog/xhtml1-strict.dtd"/>
+
+    <systemSuffix systemIdSuffix="html1-strict.dtd"
+                  uri="file:///share/mirrors/w3c/xhtml1/xhtml1-strict.dtd"/>
+
+    <public publicId="-//OPENJDK//XML CATALOG DTD//1.0" uri="public.dtd"/>
+    
+    <system systemId="http://openjdk.java.net/xml/catalog/dtd/system.dtd" uri="system.dtd"/>
+    
+    <rewriteSystem systemIdStartString="http://openjdk.java.net/" 
+                   rewritePrefix="/C:/cygwin/home/huizwang/openjdk/jdk9-dev/jaxp1/" />
+    
+    <rewriteSystem systemIdStartString="http://openjdk.java.net/xml/catalog/dtd/" 
+                   rewritePrefix="/C:/cygwin/home/huizwang/openjdk/jdk9-dev/jaxp1/jaxp-ri/src/unit-test/acatalogapi/" />
+    
+    <public publicId="-//JAVASE//XML CATALOG DTD//DELEGATEPULIC" uri="delegatepublic.dtd"/>
+    
+    <system systemId="http://java.com/xml/catalog/dtd/delegatesystem.dtd" uri="delegatesystem.dtd"/>
+    
+</catalog>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/files/delegatepublic.dtd	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+
+<!ENTITY delegatepublic "delegatepublic">
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/files/delegatesystem.dtd	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+
+<!ENTITY delegatesystem "delegatesystem">
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/files/rewritesystem.dtd	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+
+<!ENTITY rewritesystem "rewritesystem">
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/files/systemsuffix.dtd	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+
+<!ENTITY systemsuffix "systemsuffix">
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/public.dtd	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+
+<!ENTITY public "public">
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/public.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!-- make java.net java123.net to make sure no system match -->
+<!DOCTYPE  catalogtest  PUBLIC  "-//OPENJDK//XML CATALOG DTD//1.0"  
+     "http://openjdk.java123.net/catalog/public.dtd">
+
+<catalogtest>Test &public; entry</catalogtest>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/rewritesystem.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE  catalogtest  PUBLIC  "-//OPENJDK//XML CATALOG DTD//REWRITE"  
+     "http://openjdk.java.net/xml/catalog/dtd/rewritesystem.dtd">
+     
+<catalogtest>Test &rewritesystem; entry</catalogtest>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/rewritesystem1.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE  catalogtest  PUBLIC  "-//OPENJDK//XML CATALOG DTD//REWRITE"  
+     "http://openjdk.java.net/rewritesystem.dtd">
+     
+<catalogtest>Test &rewritesystem; entry</catalogtest>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/system.dtd	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+
+<!ENTITY system "system">
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/system.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE  catalogtest  PUBLIC  "-//OPENJDK//XML CATALOG DTD//1.0"  
+     "http://openjdk.java.net/xml/catalog/dtd/system.dtd">
+     
+<catalogtest>Test &system; entry</catalogtest>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/systemsuffix.xml	Thu Nov 05 13:42:14 2015 -0800
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<!DOCTYPE  catalogtest  PUBLIC  "-//OPENJDK//XML CATALOG DTD//REWRITE"  
+     "http://openjdk.java.net/xml/catalog/dtd/systemsuffix.dtd">
+     
+<catalogtest>Test &systemsuffix; entry</catalogtest>
\ No newline at end of file