/* ------------------------------------------------------------ */
 @Override
 public void setAttribute(String key, Object value) {
   if (_named == null && key.startsWith("javax.servlet.")) {
     if (key.equals(INCLUDE_PATH_INFO)) _pathInfo = (String) value;
     else if (key.equals(INCLUDE_REQUEST_URI)) _requestURI = (String) value;
     else if (key.equals(INCLUDE_SERVLET_PATH)) _servletPath = (String) value;
     else if (key.equals(INCLUDE_CONTEXT_PATH)) _contextPath = (String) value;
     else if (key.equals(INCLUDE_QUERY_STRING)) _query = (String) value;
     else if (value == null) _attr.removeAttribute(key);
     else _attr.setAttribute(key, value);
   } else if (value == null) _attr.removeAttribute(key);
   else _attr.setAttribute(key, value);
 }
    /* ------------------------------------------------------------ */
    @Override
    public Object getAttribute(String key) {
      if (Dispatcher.this._named == null) {
        if (key.equals(INCLUDE_PATH_INFO)) return _pathInfo;
        if (key.equals(INCLUDE_SERVLET_PATH)) return _servletPath;
        if (key.equals(INCLUDE_CONTEXT_PATH)) return _contextPath;
        if (key.equals(INCLUDE_QUERY_STRING)) return _query;
        if (key.equals(INCLUDE_REQUEST_URI)) return _requestURI;
      } else if (key.startsWith(__INCLUDE_PREFIX)) return null;

      return _attr.getAttribute(key);
    }
    /* ------------------------------------------------------------ */
    @Override
    public Enumeration<String> getAttributeNames() {
      HashSet<String> set = new HashSet<>();
      Enumeration<String> e = _attr.getAttributeNames();
      while (e.hasMoreElements()) {
        String name = e.nextElement();
        if (!name.startsWith(__INCLUDE_PREFIX)) set.add(name);
      }

      if (_named == null) {
        if (_pathInfo != null) set.add(INCLUDE_PATH_INFO);
        else set.remove(INCLUDE_PATH_INFO);
        set.add(INCLUDE_REQUEST_URI);
        set.add(INCLUDE_SERVLET_PATH);
        set.add(INCLUDE_CONTEXT_PATH);
        if (_query != null) set.add(INCLUDE_QUERY_STRING);
        else set.remove(INCLUDE_QUERY_STRING);
      }

      return Collections.enumeration(set);
    }
 /* ------------------------------------------------------------ */
 @Override
 public String toString() {
   return "INCLUDE+" + _attr.toString();
 }
 /* ------------------------------------------------------------ */
 @Override
 public String toString() {
   return "FORWARD+" + _attr.toString();
 }
  /*
   * @see javax.servlet.RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
   */
  protected void forward(ServletRequest request, ServletResponse response, DispatcherType dispatch)
      throws ServletException, IOException {
    Request baseRequest =
        (request instanceof Request)
            ? ((Request) request)
            : HttpChannel.getCurrentHttpChannel().getRequest();
    Response base_response = baseRequest.getResponse();
    base_response.resetForForward();

    if (!(request instanceof HttpServletRequest)) request = new ServletRequestHttpWrapper(request);
    if (!(response instanceof HttpServletResponse))
      response = new ServletResponseHttpWrapper(response);

    final boolean old_handled = baseRequest.isHandled();
    final String old_uri = baseRequest.getRequestURI();
    final String old_context_path = baseRequest.getContextPath();
    final String old_servlet_path = baseRequest.getServletPath();
    final String old_path_info = baseRequest.getPathInfo();
    final String old_query = baseRequest.getQueryString();
    final Attributes old_attr = baseRequest.getAttributes();
    final DispatcherType old_type = baseRequest.getDispatcherType();
    MultiMap<String> old_params = baseRequest.getParameters();

    try {
      baseRequest.setHandled(false);
      baseRequest.setDispatcherType(dispatch);

      if (_named != null)
        _contextHandler.handle(
            _named, baseRequest, (HttpServletRequest) request, (HttpServletResponse) response);
      else {

        // process any query string from the dispatch URL
        String query = _dQuery;
        if (query != null) {
          // force parameter extraction
          if (old_params == null) {
            baseRequest.extractParameters();
            old_params = baseRequest.getParameters();
          }

          baseRequest.mergeQueryString(query);
        }

        ForwardAttributes attr = new ForwardAttributes(old_attr);

        // If we have already been forwarded previously, then keep using the established
        // original value. Otherwise, this is the first forward and we need to establish the values.
        // Note: the established value on the original request for pathInfo and
        // for queryString is allowed to be null, but cannot be null for the other values.
        if (old_attr.getAttribute(FORWARD_REQUEST_URI) != null) {
          attr._pathInfo = (String) old_attr.getAttribute(FORWARD_PATH_INFO);
          attr._query = (String) old_attr.getAttribute(FORWARD_QUERY_STRING);
          attr._requestURI = (String) old_attr.getAttribute(FORWARD_REQUEST_URI);
          attr._contextPath = (String) old_attr.getAttribute(FORWARD_CONTEXT_PATH);
          attr._servletPath = (String) old_attr.getAttribute(FORWARD_SERVLET_PATH);
        } else {
          attr._pathInfo = old_path_info;
          attr._query = old_query;
          attr._requestURI = old_uri;
          attr._contextPath = old_context_path;
          attr._servletPath = old_servlet_path;
        }

        baseRequest.setRequestURI(_uri);
        baseRequest.setContextPath(_contextHandler.getContextPath());
        baseRequest.setServletPath(null);
        baseRequest.setPathInfo(_uri);
        baseRequest.setAttributes(attr);

        _contextHandler.handle(
            _path, baseRequest, (HttpServletRequest) request, (HttpServletResponse) response);

        if (!baseRequest.getHttpChannelState().isAsync()) commitResponse(response, baseRequest);
      }
    } finally {
      baseRequest.setHandled(old_handled);
      baseRequest.setRequestURI(old_uri);
      baseRequest.setContextPath(old_context_path);
      baseRequest.setServletPath(old_servlet_path);
      baseRequest.setPathInfo(old_path_info);
      baseRequest.setAttributes(old_attr);
      baseRequest.setParameters(old_params);
      baseRequest.setQueryString(old_query);
      baseRequest.setDispatcherType(old_type);
    }
  }