/**
   * Resolves an identifier using the catalog. This method interprets that the namespace of the
   * identifier corresponds to uri entries in the catalog. Where both a namespace and an external
   * identifier exist, the namespace takes precedence.
   *
   * @param resourceIdentifier the identifier to resolve
   * @throws XNIException thrown on general error
   * @throws IOException thrown if some i/o error occurs
   */
  public String resolveIdentifier(XMLResourceIdentifier resourceIdentifier)
      throws IOException, XNIException {

    String resolvedId = null;

    // The namespace is useful for resolving namespace aware
    // grammars such as XML schema. Let it take precedence over
    // the external identifier if one exists.
    String namespace = resourceIdentifier.getNamespace();
    if (namespace != null) {
      resolvedId = resolveURI(namespace);
    }

    // Resolve against an external identifier if one exists. This
    // is useful for resolving DTD external subsets and other
    // external entities. For XML schemas if there was no namespace
    // mapping we might be able to resolve a system identifier
    // specified as a location hint.
    if (resolvedId == null) {
      String publicId = resourceIdentifier.getPublicId();
      String systemId =
          getUseLiteralSystemId()
              ? resourceIdentifier.getLiteralSystemId()
              : resourceIdentifier.getExpandedSystemId();
      if (publicId != null && systemId != null) {
        resolvedId = resolvePublic(publicId, systemId);
      } else if (systemId != null) {
        resolvedId = resolveSystem(systemId);
      }
    }
    return resolvedId;
  }
  /**
   * Resolves an external entity. If the entity cannot be resolved, this method should return <code>
   * null</code>. This method only calls <code>resolveIdentifier</code> and returns an input source
   * if an entry was found in the catalog. It should be overrided if other behaviour is required.
   *
   * @param resourceIdentifier location of the XML resource to resolve
   * @throws XNIException thrown on general error
   * @throws IOException thrown if some i/o error occurs
   */
  public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier)
      throws XNIException, IOException {

    String resolvedId = resolveIdentifier(resourceIdentifier);
    if (resolvedId != null) {
      return new XMLInputSource(
          resourceIdentifier.getPublicId(), resolvedId, resourceIdentifier.getBaseSystemId());
    }
    return null;
  }
  /**
   * Resolves an external parsed entity. If the entity cannot be resolved, this method should return
   * null.
   *
   * @param resourceIdentifier description of the resource to be revsoved
   * @throws XNIException Thrown on general error.
   * @throws IOException Thrown if resolved entity stream cannot be opened or some other i/o error
   *     occurs.
   */
  public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier)
      throws XNIException, IOException {
    // resolve entity using DOM entity resolver
    if (fEntityResolver != null) {
      // For entity resolution the type of the resource would be  XML TYPE
      // DOM L3 LS spec mention only the XML 1.0 recommendation right now
      LSInput inputSource =
          resourceIdentifier == null
              ? fEntityResolver.resolveResource(null, null, null, null, null)
              : fEntityResolver.resolveResource(
                  getType(resourceIdentifier),
                  resourceIdentifier.getNamespace(),
                  resourceIdentifier.getPublicId(),
                  resourceIdentifier.getLiteralSystemId(),
                  resourceIdentifier.getBaseSystemId());
      if (inputSource != null) {
        String publicId = inputSource.getPublicId();
        String systemId = inputSource.getSystemId();
        String baseSystemId = inputSource.getBaseURI();
        InputStream byteStream = inputSource.getByteStream();
        Reader charStream = inputSource.getCharacterStream();
        String encoding = inputSource.getEncoding();
        String data = inputSource.getStringData();

        /**
         * An LSParser looks at inputs specified in LSInput in the following order: characterStream,
         * byteStream, stringData, systemId, publicId.
         */
        XMLInputSource xmlInputSource = new XMLInputSource(publicId, systemId, baseSystemId);

        if (charStream != null) {
          xmlInputSource.setCharacterStream(charStream);
        } else if (byteStream != null) {
          xmlInputSource.setByteStream((InputStream) byteStream);
        } else if (data != null && data.length() != 0) {
          xmlInputSource.setCharacterStream(new StringReader(data));
        }
        xmlInputSource.setEncoding(encoding);
        return xmlInputSource;
      }
    }

    // unable to resolve entity
    return null;
  } // resolveEntity(String,String,String):XMLInputSource
  /**
   * Constructs an input source from a XMLResourceIdentifier object, leaving resolution of the
   * entity and opening of the input stream up to the caller.
   *
   * @param resourceIdentifier the XMLResourceIdentifier containing the information
   */
  public XMLInputSource(XMLResourceIdentifier resourceIdentifier) {

    fPublicId = resourceIdentifier.getPublicId();
    fSystemId = resourceIdentifier.getLiteralSystemId();
    fBaseSystemId = resourceIdentifier.getBaseSystemId();
  } // <init>(XMLResourceIdentifier)
 // Constructors:
 public XMLDTDDescription(XMLResourceIdentifier id, String rootName) {
   this.setValues(
       id.getPublicId(), id.getLiteralSystemId(), id.getBaseSystemId(), id.getExpandedSystemId());
   this.fRootName = rootName;
   this.fPossibleRoots = null;
 } // init(XMLResourceIdentifier, String)