/**
   * Parse an XML Catalog stream.
   *
   * @param catalog The catalog to which this catalog file belongs
   * @param is The input stream from which the catalog will be read
   * @throws MalformedURLException Improper fileUrl
   * @throws IOException Error reading catalog file
   * @throws CatalogException A Catalog exception
   */
  public void readCatalog(Catalog catalog, InputStream is) throws IOException, CatalogException {

    // Create an instance of the parser
    if (parserFactory == null && parserClass == null) {
      debug.message(1, "Cannot read SAX catalog without a parser");
      throw new CatalogException(CatalogException.UNPARSEABLE);
    }

    debug = catalog.getCatalogManager().debug;
    EntityResolver bResolver = catalog.getCatalogManager().getBootstrapResolver();

    this.catalog = catalog;

    try {
      if (parserFactory != null) {
        SAXParser parser = parserFactory.newSAXParser();
        SAXParserHandler spHandler = new SAXParserHandler();
        spHandler.setContentHandler(this);
        if (bResolver != null) {
          spHandler.setEntityResolver(bResolver);
        }
        parser.parse(new InputSource(is), spHandler);
      } else {
        Parser parser =
            (Parser)
                Class.forName(
                        parserClass,
                        true,
                        loader != null ? loader : this.getClass().getClassLoader())
                    .newInstance();
        parser.setDocumentHandler(this);
        if (bResolver != null) {
          parser.setEntityResolver(bResolver);
        }
        parser.parse(new InputSource(is));
      }
    } catch (ClassNotFoundException cnfe) {
      throw new CatalogException(CatalogException.UNPARSEABLE);
    } catch (IllegalAccessException iae) {
      throw new CatalogException(CatalogException.UNPARSEABLE);
    } catch (InstantiationException ie) {
      throw new CatalogException(CatalogException.UNPARSEABLE);
    } catch (ParserConfigurationException pce) {
      throw new CatalogException(CatalogException.UNKNOWN_FORMAT);
    } catch (SAXException se) {
      Exception e = se.getException();
      // FIXME: there must be a better way
      UnknownHostException uhe = new UnknownHostException();
      FileNotFoundException fnfe = new FileNotFoundException();
      if (e != null) {
        if (e.getClass() == uhe.getClass()) {
          throw new CatalogException(CatalogException.PARSE_FAILED, e.toString());
        } else if (e.getClass() == fnfe.getClass()) {
          throw new CatalogException(CatalogException.PARSE_FAILED, e.toString());
        }
      }
      throw new CatalogException(se);
    }
  }
  /**
   * The SAX2 <code>startElement</code> method.
   *
   * <p>The catalog parser is selected based on the namespace of the first element encountered in
   * the catalog.
   */
  public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
      throws SAXException {

    if (abandonHope) {
      return;
    }

    if (saxParser == null) {
      String saxParserClass = getCatalogParser(namespaceURI, localName);

      if (saxParserClass == null) {
        abandonHope = true;
        if (namespaceURI == null) {
          debug.message(2, "No Catalog parser for " + localName);
        } else {
          debug.message(2, "No Catalog parser for " + "{" + namespaceURI + "}" + localName);
        }
        return;
      }

      try {
        saxParser =
            (SAXCatalogParser)
                Class.forName(
                        saxParserClass,
                        true,
                        loader != null ? loader : this.getClass().getClassLoader())
                    .newInstance();

        saxParser.setCatalog(catalog);
        saxParser.startDocument();
        saxParser.startElement(namespaceURI, localName, qName, atts);
      } catch (ClassNotFoundException cnfe) {
        saxParser = null;
        abandonHope = true;
        debug.message(2, cnfe.toString());
      } catch (InstantiationException ie) {
        saxParser = null;
        abandonHope = true;
        debug.message(2, ie.toString());
      } catch (IllegalAccessException iae) {
        saxParser = null;
        abandonHope = true;
        debug.message(2, iae.toString());
      } catch (ClassCastException cce) {
        saxParser = null;
        abandonHope = true;
        debug.message(2, cce.toString());
      }
    } else {
      saxParser.startElement(namespaceURI, localName, qName, atts);
    }
  }
  /**
   * The SAX <code>startElement</code> method.
   *
   * <p>The catalog parser is selected based on the namespace of the first element encountered in
   * the catalog.
   */
  public void startElement(String name, AttributeList atts) throws SAXException {

    if (abandonHope) {
      return;
    }

    if (saxParser == null) {
      String prefix = "";
      if (name.indexOf(':') > 0) {
        prefix = name.substring(0, name.indexOf(':'));
      }

      String localName = name;
      if (localName.indexOf(':') > 0) {
        localName = localName.substring(localName.indexOf(':') + 1);
      }

      String namespaceURI = null;
      if (prefix.equals("")) {
        namespaceURI = atts.getValue("xmlns");
      } else {
        namespaceURI = atts.getValue("xmlns:" + prefix);
      }

      String saxParserClass = getCatalogParser(namespaceURI, localName);

      if (saxParserClass == null) {
        abandonHope = true;
        if (namespaceURI == null) {
          debug.message(2, "No Catalog parser for " + name);
        } else {
          debug.message(2, "No Catalog parser for " + "{" + namespaceURI + "}" + name);
        }
        return;
      }

      try {
        saxParser =
            (SAXCatalogParser)
                Class.forName(
                        saxParserClass,
                        true,
                        loader != null ? loader : this.getClass().getClassLoader())
                    .newInstance();

        saxParser.setCatalog(catalog);
        saxParser.startDocument();
        saxParser.startElement(name, atts);
      } catch (ClassNotFoundException cnfe) {
        saxParser = null;
        abandonHope = true;
        debug.message(2, cnfe.toString());
      } catch (InstantiationException ie) {
        saxParser = null;
        abandonHope = true;
        debug.message(2, ie.toString());
      } catch (IllegalAccessException iae) {
        saxParser = null;
        abandonHope = true;
        debug.message(2, iae.toString());
      } catch (ClassCastException cce) {
        saxParser = null;
        abandonHope = true;
        debug.message(2, cce.toString());
      }
    } else {
      saxParser.startElement(name, atts);
    }
  }