gt:             SAXParserFactory spf = new SAXParserFactoryImpl();
context: /*
   * Copyright (c) 2015, 2016, 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.IOException;
  import java.net.MalformedURLException;
  import java.net.URI;
  import java.net.URISyntaxException;
  import java.net.URL;
  import java.util.ArrayList;
  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 static javax.xml.catalog.CatalogMessages.formatMessage;
  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);
          if (f == null) {
              throw new NullPointerException(
                      formatMessage(CatalogMessages.ERR_NULL_ARGUMENT, new Object[]{"CatalogFeatures"}));
          }
  
          if (file.length > 0) {
              CatalogMessages.reportNPEOnNull("The path to the catalog file", file[0]);
          }
  
          init(parent, f);
  
          //Path of catalog files
          String[] catalogFile = file;
          if (level == 0 && file.length == 0) {
              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();
                      try {
                          baseURI = new URL(systemId);
                      } catch (MalformedURLException e) {
                          CatalogMessages.reportRunTimeError(CatalogMessages.ERR_INVALID_PATH,
                                  new Object[]{temp}, e);
                      }
                      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);
              }
          }
      }
  
      private void init(CatalogImpl parent, CatalogFeatures f) {
          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));
      }
  
      /**
       * 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) {
          URI temp = null;
  
          try {
              temp = Util.verifyAndGetURI(file, baseURI);
          } catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) {
              CatalogMessages.reportRunTimeError(CatalogMessages.ERR_INVALID_PATH,
                      new Object[]{file}, e);
          }
  
          return temp;
      }
  
      /**
       * Returns a SAXParser instance
       * @return a SAXParser instance
       * @throws CatalogException if constructing a SAXParser failed
       */
      private SAXParser getParser() {
          SAXParser p = null;
          try {
  