/**
   * Analyze a request and split this request's URI to get useful information then keep it in
   * following properties of PortalRequestContext :<br>
   * 1. <code>requestURI</code> : The decoded URI of this request <br>
   * 2. <code>portalOwner</code> : The portal name ( "classic" for instance )<br>
   * 3. <code>portalURI</code> : The URI to current portal ( "/portal/public/classic/ for instance )
   * <br>
   * 4. <code>nodePath</code> : The path that is used to reflect to a navigation node
   */
  public PortalRequestContext(
      WebuiApplication app,
      ControllerContext controllerContext,
      String requestSiteType,
      String requestSiteName,
      String requestPath,
      Locale requestLocale)
      throws Exception {
    super(app);

    //
    this.urlFactory = (URLFactoryService) PortalContainer.getComponent(URLFactoryService.class);
    this.controllerContext = controllerContext;

    //
    request_ = controllerContext.getRequest();
    response_ = controllerContext.getResponse();
    response_.setBufferSize(1024 * 100);
    setSessionId(request_.getSession().getId());

    // The encoding needs to be set before reading any of the parameters since the parameters's
    // encoding
    // is set at the first access.

    // TODO use the encoding from the locale-config.xml file
    response_.setContentType("text/html; charset=UTF-8");
    try {
      request_.setCharacterEncoding("UTF-8");
    } catch (UnsupportedEncodingException e) {
      log.error("Encoding not supported", e);
    }

    // Query parameters from the request will be set in the servlet container url encoding and not
    // necessarly in utf-8 format. So we need to directly parse the parameters from the query
    // string.
    parameterMap = new HashMap<String, String[]>();
    parameterMap.putAll(request_.getParameterMap());
    String queryString = request_.getQueryString();
    if (queryString != null) {
      // The QueryStringParser currently only likes & and not &amp;
      queryString = queryString.replace("&amp;", "&");
      Map<String, String[]> queryParams =
          QueryStringParser.getInstance().parseQueryString(queryString);
      parameterMap.putAll(queryParams);
    }

    ajaxRequest_ = "true".equals(request_.getParameter("ajaxRequest"));
    String cache = request_.getParameter(CACHE_LEVEL);
    if (cache != null) {
      cacheLevel_ = cache;
    }

    requestURI_ = request_.getRequestURI();
    /*
          String decodedURI = URLDecoder.decode(requestURI_, "UTF-8");

          // req.getPathInfo will already have the encoding set from the server.
          // We need to use the UTF-8 value since this is how we store the portal name.
          // Reconstructing the getPathInfo from the non server decoded values.
          String servletPath = URLDecoder.decode(request_.getServletPath(), "UTF-8");
          String contextPath = URLDecoder.decode(request_.getContextPath(), "UTF-8");
          String pathInfo = "/";
          if (requestURI_.length() > servletPath.length() + contextPath.length())
             pathInfo = decodedURI.substring(servletPath.length() + contextPath.length());

          int colonIndex = pathInfo.indexOf("/", 1);
          if (colonIndex < 0)
          {
             colonIndex = pathInfo.length();
          }
          portalOwner_ = pathInfo.substring(1, colonIndex);
          nodePath_ = pathInfo.substring(colonIndex, pathInfo.length());
    */
    //
    this.siteKey = new SiteKey(SiteType.valueOf(requestSiteType.toUpperCase()), requestSiteName);
    this.nodePath_ = requestPath;
    this.requestLocale = requestLocale;

    //
    NodeURL url = createURL(NodeURL.TYPE);
    url.setResource(new NavigationResource(siteKey, ""));
    portalURI = url.toString();

    //
    urlBuilder = new PortalURLBuilder(this, createURL(ComponentURL.TYPE));
  }
 public RequestNavigationData getNavigationData() {
   return new RequestNavigationData(
       controllerContext.getParameter(RequestNavigationData.REQUEST_SITE_TYPE),
       controllerContext.getParameter(RequestNavigationData.REQUEST_SITE_NAME),
       controllerContext.getParameter(RequestNavigationData.REQUEST_PATH));
 }
  @Override
  public boolean execute(ControllerContext context) throws Exception {
    String resourceParam = context.getParameter(RESOURCE_QN);
    String scopeParam = context.getParameter(SCOPE_QN);

    //
    if (scopeParam != null && resourceParam != null) {
      String compressParam = context.getParameter(COMPRESS_QN);
      String lang = context.getParameter(LANG_QN);
      String moduleParam = context.getParameter(MODULE_QN);

      //
      Locale locale = null;
      if (lang != null && lang.length() > 0) {
        locale = I18N.parseTagIdentifier(lang);
      }

      //
      ResourceScope scope;
      try {
        scope = ResourceScope.valueOf(ResourceScope.class, scopeParam);
      } catch (IllegalArgumentException e) {
        HttpServletResponse response = context.getResponse();
        String msg = "Unrecognized scope " + scopeParam;
        log.error(msg);
        response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        return true;
      }

      //
      ResourceId resource = new ResourceId(scope, resourceParam);

      ScriptKey key = new ScriptKey(resource, moduleParam, "min".equals(compressParam), locale);

      //
      ScriptResult result = cache.get(context, key);
      HttpServletResponse response = context.getResponse();
      HttpServletRequest request = context.getRequest();

      //
      if (result instanceof ScriptResult.Resolved) {
        ScriptResult.Resolved resolved = (ScriptResult.Resolved) result;

        // Content type + charset
        response.setContentType("text/javascript");
        response.setCharacterEncoding("UTF-8");

        // One hour caching
        // make this configurable later
        response.setHeader("Cache-Control", "max-age:3600");
        response.setDateHeader("Expires", System.currentTimeMillis() + 3600 * 1000);

        // Set content length
        response.setContentLength(resolved.bytes.length);

        long ifModifiedSince = request.getDateHeader(IF_MODIFIED_SINCE);
        if (resolved.isModified(ifModifiedSince)) {
          response.setDateHeader(ResourceRequestFilter.LAST_MODIFIED, resolved.lastModified);
          // Send bytes
          ServletOutputStream out = response.getOutputStream();
          try {
            out.write(resolved.bytes);
          } finally {
            Safe.close(out);
          }
        } else {
          response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
        }
      } else if (result instanceof ScriptResult.Error) {
        ScriptResult.Error error = (ScriptResult.Error) result;
        log.error("Could not render script " + key + "\n:" + error.message);
        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      } else {
        String msg = "Resource " + key + " cannot be found";
        log.error(msg);
        response.sendError(HttpServletResponse.SC_NOT_FOUND, msg);
      }
    } else {
      HttpServletResponse response = context.getResponse();
      String msg = "Missing scope or resource param";
      log.error(msg);
      response.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }

    //
    return true;
  }