/**
   * To find out if an uri matches an url pattern in jsp config. If so, then the uri is a JSP page.
   * This is used primarily for jspc.
   *
   * @param uri The path to check
   * @return <code>true</code> if the path denotes a JSP page
   */
  public boolean isJspPage(String uri) {

    init();
    if (jspProperties == null) {
      return false;
    }

    String uriPath = null;
    int index = uri.lastIndexOf('/');
    if (index >= 0) {
      uriPath = uri.substring(0, index + 1);
    }
    String uriExtension = null;
    index = uri.lastIndexOf('.');
    if (index >= 0) {
      uriExtension = uri.substring(index + 1);
    }

    Iterator<JspPropertyGroup> iter = jspProperties.iterator();
    while (iter.hasNext()) {

      JspPropertyGroup jpg = iter.next();

      String extension = jpg.getExtension();
      String path = jpg.getPath();

      if (extension == null) {
        if (uri.equals(path)) {
          // There is an exact match
          return true;
        }
      } else {
        if ((path == null || path.equals(uriPath))
            && (extension.equals("*") || extension.equals(uriExtension))) {
          // Matches *, *.ext, /p/*, or /p/*.ext
          return true;
        }
      }
    }
    return false;
  }
  /**
   * Find a property that best matches the supplied resource.
   *
   * @param uri the resource supplied.
   * @return a JspProperty indicating the best match, or some default.
   */
  public JspProperty findJspProperty(String uri) {

    init();

    // JSP Configuration settings do not apply to tag files
    if (jspProperties == null || uri.endsWith(".tag") || uri.endsWith(".tagx")) {
      return defaultJspProperty;
    }

    String uriPath = null;
    int index = uri.lastIndexOf('/');
    if (index >= 0) {
      uriPath = uri.substring(0, index + 1);
    }
    String uriExtension = null;
    index = uri.lastIndexOf('.');
    if (index >= 0) {
      uriExtension = uri.substring(index + 1);
    }

    Collection<String> includePreludes = new ArrayList<>();
    Collection<String> includeCodas = new ArrayList<>();

    JspPropertyGroup isXmlMatch = null;
    JspPropertyGroup elIgnoredMatch = null;
    JspPropertyGroup scriptingInvalidMatch = null;
    JspPropertyGroup pageEncodingMatch = null;
    JspPropertyGroup deferedSyntaxAllowedAsLiteralMatch = null;
    JspPropertyGroup trimDirectiveWhitespacesMatch = null;
    JspPropertyGroup defaultContentTypeMatch = null;
    JspPropertyGroup bufferMatch = null;
    JspPropertyGroup errorOnUndeclaredNamespaceMatch = null;

    Iterator<JspPropertyGroup> iter = jspProperties.iterator();
    while (iter.hasNext()) {

      JspPropertyGroup jpg = iter.next();
      JspProperty jp = jpg.getJspProperty();

      // (arrays will be the same length)
      String extension = jpg.getExtension();
      String path = jpg.getPath();

      if (extension == null) {
        // exact match pattern: /a/foo.jsp
        if (!uri.equals(path)) {
          // not matched;
          continue;
        }
      } else {
        // Matching patterns *.ext or /p/*
        if (path != null && uriPath != null && !uriPath.startsWith(path)) {
          // not matched
          continue;
        }
        if (!extension.equals("*") && !extension.equals(uriExtension)) {
          // not matched
          continue;
        }
      }
      // We have a match
      // Add include-preludes and include-codas
      if (jp.getIncludePrelude() != null) {
        includePreludes.addAll(jp.getIncludePrelude());
      }
      if (jp.getIncludeCoda() != null) {
        includeCodas.addAll(jp.getIncludeCoda());
      }

      // If there is a previous match for the same property, remember
      // the one that is more restrictive.
      if (jp.isXml() != null) {
        isXmlMatch = selectProperty(isXmlMatch, jpg);
      }
      if (jp.isELIgnored() != null) {
        elIgnoredMatch = selectProperty(elIgnoredMatch, jpg);
      }
      if (jp.isScriptingInvalid() != null) {
        scriptingInvalidMatch = selectProperty(scriptingInvalidMatch, jpg);
      }
      if (jp.getPageEncoding() != null) {
        pageEncodingMatch = selectProperty(pageEncodingMatch, jpg);
      }
      if (jp.isDeferedSyntaxAllowedAsLiteral() != null) {
        deferedSyntaxAllowedAsLiteralMatch =
            selectProperty(deferedSyntaxAllowedAsLiteralMatch, jpg);
      }
      if (jp.isTrimDirectiveWhitespaces() != null) {
        trimDirectiveWhitespacesMatch = selectProperty(trimDirectiveWhitespacesMatch, jpg);
      }
      if (jp.getDefaultContentType() != null) {
        defaultContentTypeMatch = selectProperty(defaultContentTypeMatch, jpg);
      }
      if (jp.getBuffer() != null) {
        bufferMatch = selectProperty(bufferMatch, jpg);
      }
      if (jp.isErrorOnUndeclaredNamespace() != null) {
        errorOnUndeclaredNamespaceMatch = selectProperty(errorOnUndeclaredNamespaceMatch, jpg);
      }
    }

    String isXml = defaultIsXml;
    String isELIgnored = defaultIsELIgnored;
    String isScriptingInvalid = defaultIsScriptingInvalid;
    String pageEncoding = null;
    String isDeferedSyntaxAllowedAsLiteral = defaultDeferedSyntaxAllowedAsLiteral;
    String isTrimDirectiveWhitespaces = defaultTrimDirectiveWhitespaces;
    String defaultContentType = defaultDefaultContentType;
    String buffer = defaultBuffer;
    String errorOnUndelcaredNamespace = defaultErrorOnUndeclaredNamespace;

    if (isXmlMatch != null) {
      isXml = isXmlMatch.getJspProperty().isXml();
    }
    if (elIgnoredMatch != null) {
      isELIgnored = elIgnoredMatch.getJspProperty().isELIgnored();
    }
    if (scriptingInvalidMatch != null) {
      isScriptingInvalid = scriptingInvalidMatch.getJspProperty().isScriptingInvalid();
    }
    if (pageEncodingMatch != null) {
      pageEncoding = pageEncodingMatch.getJspProperty().getPageEncoding();
    }
    if (deferedSyntaxAllowedAsLiteralMatch != null) {
      isDeferedSyntaxAllowedAsLiteral =
          deferedSyntaxAllowedAsLiteralMatch.getJspProperty().isDeferedSyntaxAllowedAsLiteral();
    }
    if (trimDirectiveWhitespacesMatch != null) {
      isTrimDirectiveWhitespaces =
          trimDirectiveWhitespacesMatch.getJspProperty().isTrimDirectiveWhitespaces();
    }
    if (defaultContentTypeMatch != null) {
      defaultContentType = defaultContentTypeMatch.getJspProperty().getDefaultContentType();
    }
    if (bufferMatch != null) {
      buffer = bufferMatch.getJspProperty().getBuffer();
    }
    if (errorOnUndeclaredNamespaceMatch != null) {
      errorOnUndelcaredNamespace =
          errorOnUndeclaredNamespaceMatch.getJspProperty().isErrorOnUndeclaredNamespace();
    }

    return new JspProperty(
        isXml,
        isELIgnored,
        isScriptingInvalid,
        pageEncoding,
        includePreludes,
        includeCodas,
        isDeferedSyntaxAllowedAsLiteral,
        isTrimDirectiveWhitespaces,
        defaultContentType,
        buffer,
        errorOnUndelcaredNamespace);
  }