/**
   * Adds an attribute.
   *
   * @param name the attribute name
   * @param value the attribute value
   */
  public void addAttribute(QName name, String value) throws JspParseException {
    if (IS_EL_IGNORED.equals(name)) {
      boolean isIgnored = value.equals("true");

      if (_parseState.isELIgnoredPageSpecified() && isIgnored != _parseState.isELIgnored())
        throw error(L.l("isELIgnored values conflict"));

      _parseState.setELIgnored(isIgnored);
      _parseState.setELIgnoredPageSpecified(true);
    }

    /*
    else if (name.equals("isScriptingInvalid"))
      _parseState.setScriptingInvalid(value.equals("true"));
    */
    else if (IS_VELOCITY_ENABLED.equals(name)) _parseState.setVelocityEnabled(value.equals("true"));
    else if (INFO.equals(name)) {
      String oldInfo = _parseState.getInfo();

      if (oldInfo != null && !value.equals(oldInfo))
        throw error(
            L.l(
                "info '{0}' conflicts with previous value of info '{1}'.  Check the .jsp and any included .jsp files for conflicts.",
                value, oldInfo));

      _parseState.setInfo(value);
    } else if (CONTENT_TYPE.equals(name)) {
      String oldContentType = _parseState.getContentType();

      if (oldContentType != null && !value.equals(oldContentType))
        throw error(
            L.l(
                "contentType '{0}' conflicts with previous value of contentType '{1}'.  Check the .jsp and any included .jsp files for conflicts.",
                value, oldContentType));

      _parseState.setContentType(value);
      String charEncoding = parseCharEncoding(value);
      if (charEncoding != null) _parseState.setCharEncoding(charEncoding);
    } else if (PAGE_ENCODING.equals(name)) {
      String oldEncoding = _parseState.getPageEncoding();

      /*
           // jsp/01f1
           if (oldEncoding != null) {
      String oldCanonical = Encoding.getMimeName(oldEncoding);
      String newCanonical = Encoding.getMimeName(value);

      if (! newCanonical.equals(oldCanonical))
        throw error(L.l("pageEncoding '{0}' conflicts with previous value of pageEncoding '{1}'.  Check the .jsp and any included .jsp files for conflicts.", value, oldEncoding));
           }
           */

      try {
        _parseState.setPageEncoding(value);
        // _parseState.setCharEncoding(value);
      } catch (JspParseException e) {
        log.log(Level.FINER, e.toString(), e);

        throw error(e.getMessage());
      }
    } else if (LANGUAGE.equals(name)) {
      if (!value.equals("java"))
        throw error(L.l("'{0}' is not supported as a JSP scripting language.", value));
    } else if (IMPORT.equals(name)) {
      _parseState.addImport(value);
    } else if (SESSION.equals(name)) {
      boolean isValid = false;

      if (value.equals("true")) isValid = _parseState.setSession(true);
      else if (value.equals("false")) isValid = _parseState.setSession(false);
      else throw error(L.l("session expects 'true' or 'false' at '{0}'", value));

      _parseState.markSessionSet();

      if (!isValid) throw error(L.l("session is assigned different values."));
    } else if (BUFFER.equals(name)) {
      boolean isValid = _parseState.setBuffer(processBufferSize(value));

      _parseState.markBufferSet();

      if (!isValid) throw error(L.l("buffer is assigned different values."));

      if (_parseState.getBuffer() == 0 && !_parseState.isAutoFlush())
        throw error(L.l("buffer must be non-zero when autoFlush is false."));
    } else if (ERROR_PAGE.equals(name)) {
      String errorPage = _parseState.getErrorPage();

      String newErrorPage = getRelativeUrl(value);

      _parseState.setErrorPage(newErrorPage);

      if (errorPage != null && !errorPage.equals(newErrorPage)) {
        _parseState.setErrorPage(null);
        throw error(L.l("errorPage is assigned different value '{0}'.", newErrorPage));
      }
    } else if (IS_ERROR_PAGE.equals(name)) {
      boolean isValid = false;

      if (value.equals("true")) isValid = _parseState.setErrorPage(true);
      else if (value.equals("false")) isValid = _parseState.setErrorPage(false);
      else throw error(L.l("isErrorPage expects 'true' or 'false' at '{0}'", value));

      _parseState.markErrorPage();

      if (!isValid) throw error(L.l("isErrorPage is assigned different values."));
    } else if (AUTO_FLUSH.equals(name)) {
      boolean isValid = false;

      if (value.equals("true")) isValid = _parseState.setAutoFlush(true);
      else if (value.equals("false")) isValid = _parseState.setAutoFlush(false);
      else throw error(L.l("autoFlush expects 'true' or 'false' at '{0}'", value));

      if (!isValid) throw error(L.l("autoFlush is assigned different values."));

      if (_parseState.getBuffer() == 0 && !_parseState.isAutoFlush())
        throw error(L.l("buffer must be non-zero when autoFlush is false."));

      _parseState.markAutoFlushSet();
    } else if (IS_THREAD_SAFE.equals(name)) {
      boolean isValid = false;

      if (value.equals("true")) isValid = _parseState.setThreadSafe(true);
      else if (value.equals("false")) isValid = _parseState.setThreadSafe(false);
      else throw error(L.l("isThreadSafe expects 'true' or 'false' at '{0}'", value));

      _parseState.markThreadSafeSet();

      if (!isValid) throw error(L.l("isThreadSafe is assigned different values."));
    } else if (EXTENDS.equals(name)) {
      Class cl = null;

      try {
        cl = CauchoSystem.loadClass(value);
      } catch (Exception e) {
        throw error(e);
      }

      if (!HttpJspPage.class.isAssignableFrom(cl))
        throw error(
            L.l(
                "'{0}' must implement HttpJspPage.  The class named by jsp:directive.page extends='...' must implement HttpJspPage.",
                value));

      Class oldExtends = _parseState.getExtends();

      if (oldExtends != null && !cl.equals(oldExtends))
        throw error(
            L.l(
                "extends '{0}' conflicts with previous value of extends '{1}'.  Check the .jsp and any included .jsp files for conflicts.",
                value, oldExtends.getName()));

      _parseState.setExtends(cl);
    } else if (TRIM_WS.equals(name)) {
      if (value.equals("true")) _parseState.setTrimWhitespace(true);
      else if (value.equals("false")) _parseState.setTrimWhitespace(false);
      else throw error(L.l("trimDirectiveWhitespaces expects 'true' or 'false' at '{0}'", value));
    } else if (DEFER.equals(name)) {
      if (value.equals("true")) _parseState.setDeferredSyntaxAllowedAsLiteral(true);
      else if (value.equals("false")) _parseState.setDeferredSyntaxAllowedAsLiteral(false);
      else
        throw error(
            L.l("deferredSyntaxAllowedAsLiteral expects 'true' or 'false' at '{0}'", value));
    } else {
      throw error(
          L.l(
              "'{0}' is an unknown JSP page directive attribute.  See the JSP documentation for a complete list of page directive attributes.",
              name.getName()));
    }
  }