/**
   * Creates Application instance from Tomcat Context object. If ResourceResolver is passed the
   * method will also collect additional information about the application such as session count,
   * session attribute count, application attribute count, servlet count, servlet stats summary and
   * datasource usage summary. Collecting additional information can be CPU intensive and time
   * consuming so this should be avoided unless absolutely required. Some datasource implementations
   * (c3p0) are known to be prone to internal deadlocks, so this method can also hang is datasource
   * usage stats is to be collected.
   *
   * @param context the context from which to create the Application
   * @param resourceResolver the resolver to use for resources associated with the given context
   * @param calcSize flag which controls whether to calculate session size
   * @param containerWrapper the wrapper for the context's root containing server
   * @return Application object
   */
  public static Application getApplication(
      Context context,
      ResourceResolver resourceResolver,
      boolean calcSize,
      ContainerWrapperBean containerWrapper) {

    // ContainerWrapperBean containerWrapper
    logger.debug("Querying webapp: " + context.getName());

    Application app = new Application();
    app.setName(context.getName().length() > 0 ? context.getName() : "/");
    app.setDocBase(context.getDocBase());
    app.setDisplayName(context.getDisplayName());

    app.setAvailable(containerWrapper.getTomcatContainer().getAvailable(context));
    app.setDistributable(context.getDistributable());
    app.setSessionTimeout(context.getSessionTimeout());
    app.setServletVersion(
        context.getServletContext().getMajorVersion()
            + "."
            + context.getServletContext().getMinorVersion());

    if (resourceResolver != null) {
      logger.debug("counting servlet attributes");

      int ctxAttrCount = 0;
      for (Enumeration e = context.getServletContext().getAttributeNames();
          e.hasMoreElements();
          e.nextElement()) {
        ctxAttrCount++;
      }
      app.setContextAttributeCount(ctxAttrCount);

      if (app.isAvailable()) {
        logger.debug("collecting session information");

        app.setSessionCount(context.getManager().findSessions().length);

        boolean serializable = true;
        int sessionAttributeCount = 0;
        long size = 0;

        for (Session session : context.getManager().findSessions()) {
          ApplicationSession appSession = getApplicationSession(session, calcSize, false);
          if (appSession != null) {
            sessionAttributeCount += appSession.getObjectCount();
            serializable = serializable && appSession.isSerializable();
            size += appSession.getSize();
          }
        }
        app.setSerializable(serializable);
        app.setSessionAttributeCount(sessionAttributeCount);
        app.setSize(size);
      }

      logger.debug("aggregating servlet stats");

      collectApplicationServletStats(context, app);

      if (resourceResolver.supportsPrivateResources() && app.isAvailable()) {
        int[] scores =
            getApplicationDataSourceUsageScores(context, resourceResolver, containerWrapper);
        app.setDataSourceBusyScore(scores[0]);
        app.setDataSourceEstablishedScore(scores[1]);
      }
    }

    return app;
  }