public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    String contextPath = req.getContextPath();
    if (contextPath.equals("/")) {
      contextPath = "";
    }
    String path = RequestUtil.getPath(req);
    if (!processDirectAccess(request, response, chain, path)) {
      return;
    }
    reloadRoutes();

    if (path.indexOf('.') < 0) {
      // If the request pass via reverse proxy, the original path must be gotten from HTTP header.
      if (!contextSensitive) {
        path = getOriginalPath(req);
      }
      try {
        Options options = Routes.recognizePath(path);
        String controller = options.getString("controller");
        String action = options.getString("action");
        Options params = options.except("controller", "action");

        String actionPath = ControllerUtil.fromClassNameToPath(controller);
        S2Container container = SingletonS2ContainerFactory.getContainer();
        if (container.hasComponentDef(actionPath.replace('/', '_').concat("Action"))) {
          S2ExecuteConfig executeConfig;
          if (StringUtil.equals(action, "index")) {
            executeConfig = S2ExecuteConfigUtil.findExecuteConfig("/" + actionPath, req);
            action = executeConfig.getMethod().getName();
          } else {
            executeConfig = S2ExecuteConfigUtil.findExecuteConfig("/" + actionPath, action);
          }
          if (executeConfig != null) {
            StringBuilder forwardPath = new StringBuilder(256);
            forwardPath
                .append("/")
                .append(actionPath)
                .append(".do?SAStruts.method=")
                .append(URLEncoderUtil.encode(action));
            for (String key : params.keySet()) {
              forwardPath
                  .append("&")
                  .append(URLEncoderUtil.encode(key))
                  .append("=")
                  .append(URLEncoderUtil.encode(params.getString(key)));
            }
            logger.debug(String.format("recognize route %s as %s#%s.", path, actionPath, action));
            req.getRequestDispatcher(forwardPath.toString()).forward(req, res);
            return;
          }
        }
      } catch (RoutingException e) {
        if (!fallThrough) throw e;
      }
    }
    chain.doFilter(request, response);
  }
 private void reloadRoutes() {
   if (loading || routesIsNotFile()) {
     return;
   }
   if (lastLoaded < 0
       || checkInterval >= 0 && System.currentTimeMillis() > lastLoaded + checkInterval * 1000) {
     synchronized (this) {
       if (!loading) loading = true;
       else return;
     }
     if (loading) {
       try {
         logger.debug("check update for routes.");
         if (routes.lastModified() > lastLoaded) {
           long t1 = System.currentTimeMillis();
           Routes.load(routes);
           long t2 = System.currentTimeMillis();
           logger.debug(String.format("reload routes(%dms).", (t2 - t1)));
         }
         lastLoaded = System.currentTimeMillis();
       } finally {
         loading = false;
       }
     }
   }
 }
  public void init(FilterConfig config) throws ServletException {
    String access = config.getInitParameter("jspDirectAccess");
    if (StringUtil.isNotBlank(access)) {
      jspDirectAccess = Boolean.valueOf(access);
    }

    String routesPath = config.getInitParameter("routes");
    if (StringUtil.isNotEmpty(routesPath)) {
      String realRoutesPath = config.getServletContext().getRealPath(routesPath);
      if (realRoutesPath != null) {
        routes = new File(realRoutesPath);
      }
      InputStream routesStream = config.getServletContext().getResourceAsStream(routesPath);
      try {
        Routes.load(routesStream);
      } finally {
        InputStreamUtil.close(routesStream);
      }
      lastLoaded = System.currentTimeMillis();
    }

    String interval = config.getInitParameter("checkInterval");
    if (StringUtil.isNotEmpty(interval)) {
      checkInterval = LongConversionUtil.toLong(interval);
    }
    if (checkInterval == null || checkInterval < 0) {
      checkInterval = -1L;
    }

    String contextSensitiveParam = config.getInitParameter("contextSensitive");
    if (StringUtil.isNotBlank(contextSensitiveParam)) {
      contextSensitive = Boolean.valueOf(contextSensitiveParam);
    }
    if (contextSensitive) {
      try {
        Method getContextPath = ReflectionUtil.getMethod(ServletContext.class, "getContextPath");
        UrlRewriter.contextPath =
            (String) MethodUtil.invoke(getContextPath, config.getServletContext(), null);
      } catch (NoSuchMethodRuntimeException e) {
        UrlRewriter.contextPath = config.getServletContext().getServletContextName();
      }
    }
    requestUriHeader = config.getInitParameter("requestUriHeader");

    String fallThroughParam = config.getInitParameter("fallThrough");
    if (StringUtil.isNotBlank(fallThroughParam)) {
      fallThrough = Boolean.valueOf(fallThroughParam);
    }
  }