@DefaultHandler
  public Resolution view() throws JSONException, IOException {
    application = findApplication(name, version);

    if (application == null) {
      getContext()
          .getValidationErrors()
          .addGlobalError(
              new LocalizableError("app.notfound", name + (version != null ? " v" + version : "")));
      return new ForwardResolution("/WEB-INF/jsp/error.jsp");
    }

    RedirectResolution login =
        new RedirectResolution(LoginActionBean.class)
            .addParameter("name", name) // binded parameters not included ?
            .addParameter("version", version)
            .addParameter("debug", debug)
            .includeRequestParameters(true);

    loginUrl = login.getUrl(context.getLocale());

    String username = context.getRequest().getRemoteUser();
    if (application.isAuthenticatedRequired() && username == null) {
      return login;
    }

    if (username != null) {
      user = new JSONObject();
      user.put("name", username);
      JSONObject roles = new JSONObject();
      user.put("roles", roles);
      for (String role : Authorizations.getRoles(context.getRequest())) {
        roles.put(role, Boolean.TRUE);
      }
    }

    buildComponentSourceHTML();

    appConfigJSON = application.toJSON(context.getRequest(), false, false);
    this.viewerType = retrieveViewerType();

    // make hashmap for jsonobject.
    this.globalLayout = new HashMap<String, Object>();
    JSONObject layout = application.getGlobalLayout();
    Iterator<String> keys = layout.keys();
    while (keys.hasNext()) {
      String key = keys.next();
      this.globalLayout.put(key, layout.get(key));
    }
    return new ForwardResolution("/WEB-INF/jsp/app.jsp");
  }
  private void buildComponentSourceHTML() throws IOException {

    StringBuilder sb = new StringBuilder();

    // Sort components by classNames, so order is always the same for debugging
    List<ConfiguredComponent> comps =
        new ArrayList<ConfiguredComponent>(application.getComponents());
    Collections.sort(comps);

    if (isDebug()) {

      Set<String> classNamesDone = new HashSet<String>();
      for (ConfiguredComponent cc : comps) {

        if (!Authorizations.isConfiguredComponentAuthorized(cc, context.getRequest())) {
          continue;
        }

        if (!classNamesDone.contains(cc.getClassName())) {
          classNamesDone.add(cc.getClassName());

          if (cc.getViewerComponent() != null && cc.getViewerComponent().getSources() != null) {
            for (File f : cc.getViewerComponent().getSources()) {
              String url =
                  new ForwardResolution(ComponentActionBean.class, "source")
                      .addParameter("app", name)
                      .addParameter("version", version)
                      .addParameter("className", cc.getClassName())
                      .addParameter("file", f.getName())
                      .getUrl(context.getLocale());

              sb.append("        <script type=\"text/javascript\" src=\"");
              sb.append(HtmlUtil.encode(context.getServletContext().getContextPath() + url));
              sb.append("\"></script>\n");
            }
          }
        }
      }
    } else {
      // If not debugging, create a single script tag with all source
      // for all components for the application for a minimal number of HTTP requests

      // The ComponentActionBean supports conditional HTTP requests using
      // Last-Modified.
      // Create a hash value that will change when the classNames used
      // in the application change, so that a browser will not use a
      // previous version from cache with other contents.

      int hash = 0;
      Set<String> classNamesDone = new HashSet<String>();
      for (ConfiguredComponent cc : comps) {
        if (!Authorizations.isConfiguredComponentAuthorized(cc, context.getRequest())) {
          continue;
        }

        if (!classNamesDone.contains(cc.getClassName())) {
          hash = hash ^ cc.getClassName().hashCode();
        } else {
          classNamesDone.add(cc.getClassName());
        }
      }
      if (user != null) {
        // Update component sources when roles of user change
        hash = hash ^ getRolesCachekey(context.getRequest());

        // Update component sources when roles of configured components
        // may have changed
        hash = hash ^ (int) application.getAuthorizationsModified().getTime();
      }

      String url =
          new ForwardResolution(ComponentActionBean.class, "source")
              .addParameter("app", name)
              .addParameter("version", version)
              .addParameter("minified", true)
              .addParameter("hash", hash)
              .getUrl(context.getLocale());

      sb.append("        <script type=\"text/javascript\" src=\"");
      sb.append(HtmlUtil.encode(context.getServletContext().getContextPath() + url));
      sb.append("\"></script>\n");
    }

    componentSourceHTML = sb.toString();
  }