/*
     Saves the result of the current request on the session, does a 302
     redirect into a direct action to clear the browser history.  In the
     handler of redirect request, it returns the page that was saved on
     the request.
  */
  protected AWResponse clearBrowserHistory(
      AWRequestContext requestContext, AWComponent actionResultsComponent) {
    AWPage actionResultsPage = actionResultsComponent.page();
    actionResultsPage.ensureAwake(requestContext);
    // This rewrites the DirectAction request URL into a ComponentAction
    // request URL in the browser by using a redirect.
    // Note [sessionless requests]: ordering of condition is important.  Let
    // component declare "non-refresh" (no cache or no redirect) before
    // attempting to interact with the session -- allows for "sessionless"
    // direct actions.  This is important since we always attempt to
    // rendevous with the session id now.  Fixes race condition at logout
    // in suite integrated mode.  LogoutAck from another app starts processing
    // before ClientLogout for authenticator is complete.  RequestContext for
    // LogoutAck starts off with a valid sessionid, but by the time it gets
    // here, the session has been invalidated.  LogoutAck needs to be
    // completely sessionless.
    if (AWComponentActionRequestHandler.IsFormPostRedirectEnabled
        && actionResultsComponent.shouldCachePage()
        && actionResultsComponent.shouldRedirect()
        && requestContext.session(false) != null
        && !requestContext.isIncrementalUpdateRequest()) {
      // This saves the actual page and not the redirect page.  When the
      // redirect fires it will restore the saved page, which should be
      // treated as a refreshRequest (no applyValues/invokeAction).

      // associate a response id with the current request for page
      // history maintenance
      AWSession session = requestContext.session();
      session.incrementResponseId();

      AWApplication application = application();
      AWRedirect redirectComponent =
          (AWRedirect) application.createPageWithName(AWRedirect.PageName, requestContext);
      String effectiveUrl =
          AWComponentActionRequestHandler.SharedInstance.refreshUrl(requestContext);
      effectiveUrl = AWUtil.urlAddingQueryValue(effectiveUrl, DirectActionRedirectKey, "1");
      redirectComponent.setUrl(effectiveUrl);
      redirectComponent.setSelfRedirect(true);
      requestContext.setPage(redirectComponent.page());
      actionResultsPage.ensureAsleep();
      Log.aribaweb.debug("Sending redirect to clear browser history");
    } else {
      requestContext.setPage(actionResultsPage);
    }

    // We need to check for the existence of a session and save the page
    // before generateResponse in order to maintain uniformity with
    // AWComponentActionRequestHandler.
    // Since generateResponse() can cause a new session to be
    // associated with the request, we need to make sure we try save
    // the page after generateResponse if the page was not already saved.
    boolean pageSaved = attemptSavePage(requestContext, actionResultsPage);

    AWResponse response = requestContext.generateResponse();

    if (!pageSaved) {
      attemptSavePage(requestContext, actionResultsPage);
    }
    return response;
  }
  private String[] parseDirectActionRequest(AWRequest request) {
    String actionName = DefaultActionName;
    String className = DefaultDirectActionClassName;
    AWApplication application = application();

    Class directActionClass = null;
    String[] requestHandlerPathComponents = request.requestHandlerPath();
    if (requestHandlerPathComponents != null) {
      AWNodeManager nodeManager = application.getNodeManager();
      if (nodeManager != null) {
        requestHandlerPathComponents =
            nodeManager.filterUrlForNodeCallback(requestHandlerPathComponents);
      }
      int requestHandlerPathComponentsLength = requestHandlerPathComponents.length;
      if (requestHandlerPathComponentsLength > 0) {
        actionName = requestHandlerPathComponents[0];
      }
      // Hack -- check explicitly for awres so we can use
      // path rather than query string -- for webserver caching of resources --
      // example: http://host/ACM/Main/ad/awres/realm/imagename.jpg
      // if we can modify the webserver cache to understand query strings
      // then we can switch to
      // http://host/ACM/Main/ad/awimg?realm=xxxx&filename=xxxx
      if (requestHandlerPathComponentsLength > 1
          && !AWDirectAction.AWResActionName.equals(actionName)) {
        className = application.directActionClassNameForKey(requestHandlerPathComponents[1]);

        // try to find a class for the className
        if (StringUtil.nullOrEmptyOrBlankString(className)) {
          className = DefaultDirectActionClassName;
        } else {
          directActionClass = AWUtil.classForName(className);
          if (directActionClass == null) {
            directActionClass = application.resourceManager().classForName(className);
            if (directActionClass == null) {
              className = DefaultDirectActionClassName;
            }
          }
        }
      }
    }
    String[] directActionName = new String[2];
    directActionName[ClassNameIndex] = className;
    directActionName[ActionNameIndex] = actionName;
    return directActionName;
  }
  public AWResponseGenerating processAction(AWRequest request, AWRequestContext requestContext) {
    AWApplication application = application();
    AWResponseGenerating response = null;

    String[] directActionName = parseDirectActionRequest(request);

    // isReloadable() returns true if we have hotswap reloading enabled
    String className = application.directActionClassNameForKey(directActionName[ClassNameIndex]);
    directActionName[ClassNameIndex] = className;

    Class directActionClass = application.resourceManager().classForName(className);

    if (AWUtil.getClassLoader().isReloadable(className)) {
      Class reloadedClass = AWUtil.getClassLoader().checkReloadClass(directActionClass);
      if (reloadedClass != directActionClass) {
        application.resourceManager().removeClass(className);
        directActionClass = reloadedClass;
      }
    }
    String actionName = directActionName[ActionNameIndex];
    requestContext.setCurrentDirectAction(className, actionName);
    AWDirectAction directAction = null;
    try {
      directAction = (AWDirectAction) directActionClass.newInstance();
    } catch (IllegalAccessException illegalAccessException) {
      throw new AWGenericException(illegalAccessException);
    } catch (InstantiationException instantiationException) {
      throw new AWGenericException(
          "*** Error: cannot instantiate direct action class named \""
              + directActionName[ClassNameIndex]
              + "\"",
          instantiationException);
    }

    directAction.init(requestContext);

    try {
      if (request.formValueForKey(AWRequestContext.RefreshRequestKey) != null) {
        // if this is a refresh request (ie. forward track over a redirect from
        // another app, then see if we have a valid session and we have a
        // page to refresh.  Otherwise, this app must have been restarted but
        // the other app was not so there is a mismatch in state.  In this case,
        // actually execute the direct action.
        AWSession session = requestContext.session(false);
        if (session != null) {
          AWPage page = session.restoreCurrentPage();
          if (page != null) {
            if (page.pageComponent().isBoundary()) {
              // need to forward track here and then redirect to
              // refresh the page ...
              requestContext.setHistoryAction(AWSession.ForwardTrackRequest);
              session.initRequestType();
              page = session.restoreNextPage(page);
            }
            AWRedirect redirectComponent =
                (AWRedirect) application.createPageWithName(AWRedirect.PageName, requestContext);
            String effectiveUrl =
                AWComponentActionRequestHandler.SharedInstance.refreshUrl(requestContext);

            redirectComponent.setUrl(effectiveUrl);
            redirectComponent.setSelfRedirect(true);
            requestContext.setPage(redirectComponent.page());
            response = requestContext.generateResponse();
          }
        }
      }

      if (response == null) {
        AWResponseGenerating actionResults = null;

        if (!request.hasHandler()) {
          // If there is not handler specified, then the user is
          // accessing the /Main page and that is the only time
          // that we want to execute the filters.
          for (int i = 0; i < _defaultRequestFilter.size(); i++) {
            AWDefaultRequestFilter filter = (AWDefaultRequestFilter) _defaultRequestFilter.get(i);
            filter.execute(requestContext);
          }
        }
        if (!directAction.skipValidation(actionName)) {
          if (directAction.shouldValidateTopFrame(actionName)) {
            response = directAction.validateTopFramePost(requestContext);
            if (response != null) {
              return response;
            }
          }

          if (!AWDirectAction.isServerManagementAction(request)
              && directAction.shouldValidateNode(actionName)) {
            directAction.validateNode(requestContext, directActionName[ClassNameIndex], actionName);
          }

          if (directAction.shouldValidateSession(actionName)) {
            directAction.validateSession(requestContext);
          }

          if (directAction.shouldValidateRequest(actionName)) {
            directAction.validateRequest(requestContext);
          }
        }

        actionResults = directAction.performActionNamed(directActionName[ActionNameIndex]);

        Assert.that(actionResults != null, "Direct action result cannot be null.");

        // Allow response to replace itself (see AWRedirect for example)
        if (actionResults instanceof AWResponseGenerating.ResponseSubstitution) {
          actionResults =
              ((AWResponseGenerating.ResponseSubstitution) actionResults).replacementResponse();
        }

        return actionResults;
      }
    } catch (AWNodeChangeException e) {
      AWNodeValidator nv = e.getNodeValidator();
      AWResponseGenerating handlerResults = nv.handleNodeValidationException(requestContext);
      nv.terminateCurrentSession(requestContext);
      response = handlerResults.generateResponse();
    } catch (AWSessionValidationException exception) {
      try {
        if (AWConcreteApplication.IsDebuggingEnabled) {
          Log.aribaweb.debug(
              "AWDirectActionRequestHandler: handling session " + "validation exception");
        }

        // if there is a default validator, run it here
        AWNodeValidator nv = AWNodeManager.getDefaultNodeValidator();
        if (nv != null && !nv.isValid(requestContext)) {
          Log.aribaweb_nodeValidate.debug(
              "AWDirectActionRequestHandler: invalid node. "
                  + "NodeValidator generating response.");
          AWResponseGenerating handlerResults = nv.handleNodeValidationException(requestContext);
          nv.terminateCurrentSession(requestContext);
          response = handlerResults.generateResponse();
        } else {
          AWResponseGenerating handlerResults =
              handleSessionValidationError(requestContext, exception);
          // If there is not valid HttpSession, create a new one to enable
          // load balancers which use the sessionid.
          if (requestContext.httpSession(false) == null) {
            // request.getSession(true);
            requestContext.createHttpSession();
            Log.aribaweb_session.debug("AWDirectActionRequestHandler: create HttpSession");
          }
          if (exception instanceof AWClearBrowserHistoryException) {
            AWComponent actionResultsComponent = (AWComponent) handlerResults;
            response = clearBrowserHistory(requestContext, actionResultsComponent);
          } else if (requestContext.session(false) != null
              && handlerResults instanceof AWComponent) {
            AWComponent actionResultsComponent = (AWComponent) handlerResults;
            AWPage actionResultsPage = actionResultsComponent.page();
            attemptSavePage(requestContext, actionResultsPage);
          }
          if (response == null) {
            response = handlerResults.generateResponse();
          }
        }
      } catch (RuntimeException e) {
        AWGenericException newException =
            new AWGenericException(
                "Error occurred while handling session validation.  Please make"
                    + " sure session validation is configured properly.",
                e);
        return handleException(requestContext, newException).generateResponse();
      }
    } catch (AWSessionRestorationException exception) {
      requestContext.createHttpSession();
      response = handleSessionRestorationError(requestContext).generateResponse();
    } catch (AWSiteUnavailableException e) {
      response = handleSiteUnavailableException(requestContext);
    } catch (AWRemoteHostMismatchException exception) {
      response = handleRemoteHostMismatchException(requestContext, exception);
    } catch (Throwable t) {
      response = handleUncaughtException(requestContext, t);
    }
    return response;
  }