protected File initContext()

in runtime/local_jetty9/src/main/java/com/google/appengine/tools/development/jetty9/JettyContainerService.java [167:276]


  protected File initContext() throws IOException {
    // Register our own slight modification of Jetty's WebAppContext,
    // which maintains ApiProxy's environment ThreadLocal.
    this.context =
        new DevAppEngineWebAppContext(
            appDir, externalResourceDir, devAppServerVersion, apiProxyDelegate, devAppServer);

    context.addEventListener(
        new ContextHandler.ContextScopeListener() {
          @Override
          public void enterScope(ContextHandler.Context context, Request request, Object reason) {
            // We should have a request that use its associated environment, if there is no request
            // we cannot select a local environment as picking the wrong one could result in
            // waiting on the LocalEnvironment API call semaphore forever.
            LocalEnvironment env =
                request == null
                    ? null
                    : (LocalEnvironment) request.getAttribute(LocalEnvironment.class.getName());
            if (env != null) {
              ApiProxy.setEnvironmentForCurrentThread(env);
              DevAppServerModulesFilter.injectBackendServiceCurrentApiInfo(
                  backendName, backendInstance, portMappingProvider.getPortMapping());
            }
          }

          @Override
          public void exitScope(ContextHandler.Context context, Request request) {
            ApiProxy.clearEnvironmentForCurrentThread();
          }
        });
    this.appContext = new JettyAppContext();

    // Set the location of deployment descriptor.  This value might be null,
    // which is fine, it just means Jetty will look for it in the default
    // location (WEB-INF/web.xml).
    context.setDescriptor(webXmlLocation == null ? null : webXmlLocation.getAbsolutePath());

    // Override the web.xml that Jetty automatically prepends to other
    // web.xml files.  This is where the DefaultServlet is registered,
    // which serves static files.  We override it to disable some
    // other magic (e.g. JSP compilation), and to turn off some static
    // file functionality that Prometheus won't support
    // (e.g. directory listings) and turn on others (e.g. symlinks).
    String webDefaultXml =
        devAppServer
            .getServiceProperties()
            .getOrDefault("appengine.webdefault.xml", WEB_DEFAULTS_XML);
    context.setDefaultsDescriptor(webDefaultXml);

    // Disable support for jetty-web.xml.
    context.setConfigurationClasses(CONFIG_CLASSES);
    // Create the webapp ClassLoader.
    // We need to load appengine-web.xml to initialize the class loader.
    File appRoot = determineAppRoot();
    installLocalInitializationEnvironment();

    // Create the webapp ClassLoader.
    // ADD TLDs that must be under WEB-INF for Jetty9.
    // We make it non fatal, and emit a warning when it fails, as the user can add this dependency
    // in the application itself.
    if (applicationContainsJSP(appDir, JSP_REGEX)) {
      for (File file : AppengineSdk.getSdk().getUserJspLibFiles()) {
        if (file.getName().startsWith(JETTY_TAG_LIB_JAR_PREFIX)) {
          // Jetty provided tag lib jars are currently
          // org.apache.taglibs.taglibs-standard-spec-1.2.5.jar and
          // org.apache.taglibs.taglibs-standard-impl-1.2.5.jar.
          // For jars provided by a Maven or Gradle builder, the prefix org.apache.taglibs.taglibs-
          // is not present, so the jar names are:
          // standard-spec-1.2.5.jar and
          // standard-impl-1.2.5.jar.
          // We check if these jars are provided by the web app, or we copy them from Jetty distro.
          File jettyProvidedDestination = new File(appDir + "/WEB-INF/lib/" + file.getName());
          if (!jettyProvidedDestination.exists()) {
            File mavenProvidedDestination =
                new File(
                    appDir
                        + "/WEB-INF/lib/"
                        + file.getName().substring(JETTY_TAG_LIB_JAR_PREFIX.length()));
            if (!mavenProvidedDestination.exists()) {
              log.log(
                  Level.WARNING,
                  "Adding jar "
                      + file.getName()
                      + " to WEB-INF/lib."
                      + " You might want to add a dependency in your project build system to avoid"
                      + " this warning.");
              try {
                Files.copy(file, jettyProvidedDestination);
              } catch (IOException e) {
                log.log(
                    Level.WARNING,
                    "Cannot copy org.apache.taglibs.taglibs jar file to WEB-INF/lib.",
                    e);
              }
            }
          }
        }
      }
    }

    URL[] classPath = getClassPathForApp(appRoot);
    context.setClassLoader(
        new IsolatedAppClassLoader(
            appRoot, externalResourceDir, classPath, JettyContainerService.class.getClassLoader()));
    if (Boolean.parseBoolean(System.getProperty("appengine.allowRemoteShutdown"))) {
      context.addServlet(new ServletHolder(new ServerShutdownServlet()), "/_ah/admin/quit");
    }

    return appRoot;
  }