public File findWorkDirectory(WebAppContext context) throws IOException {
   if (context.getBaseResource() != null) {
     Resource web_inf = context.getWebInf();
     if (web_inf != null && web_inf.exists()) {
       return new File(web_inf.getFile(), "work");
     }
   }
   return null;
 }
  @Override
  public void configure(WebAppContext context) throws Exception {
    // cannot configure if the context is already started
    if (context.isStarted()) {
      if (LOG.isDebugEnabled())
        LOG.debug("Cannot configure webapp " + context + " after it is started");
      return;
    }

    Resource web_inf = context.getWebInf();

    // Add WEB-INF classes and lib classpaths
    if (web_inf != null
        && web_inf.isDirectory()
        && context.getClassLoader() instanceof WebAppClassLoader) {
      // Look for classes directory
      Resource classes = web_inf.addPath("classes/");
      if (classes.exists()) ((WebAppClassLoader) context.getClassLoader()).addClassPath(classes);

      // Look for jars
      Resource lib = web_inf.addPath("lib/");
      if (lib.exists() || lib.isDirectory())
        ((WebAppClassLoader) context.getClassLoader()).addJars(lib);
    }

    // Look for extra resource
    @SuppressWarnings("unchecked")
    List<Resource> resources = (List<Resource>) context.getAttribute(RESOURCE_URLS);
    if (resources != null) {
      Resource[] collection = new Resource[resources.size() + 1];
      int i = 0;
      collection[i++] = context.getBaseResource();
      for (Resource resource : resources) collection[i++] = resource;
      context.setBaseResource(new ResourceCollection(collection));
    }
  }
  /**
   * Create a canonical name for a webapp temp directory. The form of the name is: <code>
   * "Jetty_"+host+"_"+port+"__"+resourceBase+"_"+context+"_"+virtualhost+base36_hashcode_of_whole_string
   * </code> host and port uniquely identify the server context and virtual host uniquely identify
   * the webapp
   *
   * @return the canonical name for the webapp temp directory
   */
  public static String getCanonicalNameForWebAppTmpDir(WebAppContext context) {
    StringBuffer canonicalName = new StringBuffer();
    canonicalName.append("jetty-");

    // get the host and the port from the first connector
    Server server = context.getServer();
    if (server != null) {
      Connector[] connectors = context.getServer().getConnectors();

      if (connectors.length > 0) {
        // Get the host
        String host = (connectors == null || connectors[0] == null ? "" : connectors[0].getHost());
        if (host == null) host = "0.0.0.0";
        canonicalName.append(host);

        // Get the port
        canonicalName.append("-");
        // try getting the real port being listened on
        int port = (connectors == null || connectors[0] == null ? 0 : connectors[0].getLocalPort());
        // if not available (eg no connectors or connector not started),
        // try getting one that was configured.
        if (port < 0) port = connectors[0].getPort();
        canonicalName.append(port);
        canonicalName.append("-");
      }
    }

    // Resource  base
    try {
      Resource resource = context.getBaseResource();
      if (resource == null) {
        if (context.getWar() == null || context.getWar().length() == 0)
          resource = context.newResource(context.getResourceBase());

        // Set dir or WAR
        resource = context.newResource(context.getWar());
      }

      String tmp = URIUtil.decodePath(resource.getURL().getPath());
      if (tmp.endsWith("/")) tmp = tmp.substring(0, tmp.length() - 1);
      if (tmp.endsWith("!")) tmp = tmp.substring(0, tmp.length() - 1);
      // get just the last part which is the filename
      int i = tmp.lastIndexOf("/");
      canonicalName.append(tmp.substring(i + 1, tmp.length()));
      canonicalName.append("-");
    } catch (Exception e) {
      LOG.warn("Can't generate resourceBase as part of webapp tmp dir name", e);
    }

    // Context name
    String contextPath = context.getContextPath();
    contextPath = contextPath.replace('/', '_');
    contextPath = contextPath.replace('\\', '_');
    canonicalName.append(contextPath);

    // Virtual host (if there is one)
    canonicalName.append("-");
    String[] vhosts = context.getVirtualHosts();
    if (vhosts == null || vhosts.length <= 0) canonicalName.append("any");
    else canonicalName.append(vhosts[0]);

    // sanitize
    for (int i = 0; i < canonicalName.length(); i++) {
      char c = canonicalName.charAt(i);
      if (!Character.isJavaIdentifierPart(c) && "-.".indexOf(c) < 0)
        canonicalName.setCharAt(i, '.');
    }

    canonicalName.append("-");
    return canonicalName.toString();
  }
  public void unpack(WebAppContext context) throws IOException {
    Resource web_app = context.getBaseResource();
    _preUnpackBaseResource = context.getBaseResource();

    if (web_app == null) {
      String war = context.getWar();
      if (war != null && war.length() > 0) web_app = context.newResource(war);
      else web_app = context.getBaseResource();

      // Accept aliases for WAR files
      if (web_app.getAlias() != null) {
        LOG.debug(web_app + " anti-aliased to " + web_app.getAlias());
        web_app = context.newResource(web_app.getAlias());
      }

      if (LOG.isDebugEnabled())
        LOG.debug(
            "Try webapp="
                + web_app
                + ", exists="
                + web_app.exists()
                + ", directory="
                + web_app.isDirectory()
                + " file="
                + (web_app.getFile()));
      // Is the WAR usable directly?
      if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:")) {
        // No - then lets see if it can be turned into a jar URL.
        Resource jarWebApp = JarResource.newJarResource(web_app);
        if (jarWebApp.exists() && jarWebApp.isDirectory()) web_app = jarWebApp;
      }

      // If we should extract or the URL is still not usable
      if (web_app.exists()
          && ((context.isCopyWebDir()
                  && web_app.getFile() != null
                  && web_app.getFile().isDirectory())
              || (context.isExtractWAR()
                  && web_app.getFile() != null
                  && !web_app.getFile().isDirectory())
              || (context.isExtractWAR() && web_app.getFile() == null)
              || !web_app.isDirectory())) {
        // Look for sibling directory.
        File extractedWebAppDir = null;

        if (war != null) {
          // look for a sibling like "foo/" to a "foo.war"
          File warfile = Resource.newResource(war).getFile();
          if (warfile != null && warfile.getName().toLowerCase(Locale.ENGLISH).endsWith(".war")) {
            File sibling =
                new File(
                    warfile.getParent(),
                    warfile.getName().substring(0, warfile.getName().length() - 4));
            if (sibling.exists() && sibling.isDirectory() && sibling.canWrite())
              extractedWebAppDir = sibling;
          }
        }

        if (extractedWebAppDir == null)
          // Then extract it if necessary to the temporary location
          extractedWebAppDir = new File(context.getTempDirectory(), "webapp");

        if (web_app.getFile() != null && web_app.getFile().isDirectory()) {
          // Copy directory
          LOG.info("Copy " + web_app + " to " + extractedWebAppDir);
          web_app.copyTo(extractedWebAppDir);
        } else {
          // Use a sentinel file that will exist only whilst the extraction is taking place.
          // This will help us detect interrupted extractions.
          File extractionLock = new File(context.getTempDirectory(), ".extract_lock");

          if (!extractedWebAppDir.exists()) {
            // it hasn't been extracted before so extract it
            extractionLock.createNewFile();
            extractedWebAppDir.mkdir();
            LOG.info("Extract " + web_app + " to " + extractedWebAppDir);
            Resource jar_web_app = JarResource.newJarResource(web_app);
            jar_web_app.copyTo(extractedWebAppDir);
            extractionLock.delete();
          } else {
            // only extract if the war file is newer, or a .extract_lock file is left behind meaning
            // a possible partial extraction
            if (web_app.lastModified() > extractedWebAppDir.lastModified()
                || extractionLock.exists()) {
              extractionLock.createNewFile();
              IO.delete(extractedWebAppDir);
              extractedWebAppDir.mkdir();
              LOG.info("Extract " + web_app + " to " + extractedWebAppDir);
              Resource jar_web_app = JarResource.newJarResource(web_app);
              jar_web_app.copyTo(extractedWebAppDir);
              extractionLock.delete();
            }
          }
        }
        web_app = Resource.newResource(extractedWebAppDir.getCanonicalPath());
      }

      // Now do we have something usable?
      if (!web_app.exists() || !web_app.isDirectory()) {
        LOG.warn("Web application not found " + war);
        throw new java.io.FileNotFoundException(war);
      }

      context.setBaseResource(web_app);

      if (LOG.isDebugEnabled()) LOG.debug("webapp=" + web_app);
    }

    // Do we need to extract WEB-INF/lib?
    if (context.isCopyWebInf() && !context.isCopyWebDir()) {
      Resource web_inf = web_app.addPath("WEB-INF/");

      File extractedWebInfDir = new File(context.getTempDirectory(), "webinf");
      if (extractedWebInfDir.exists()) IO.delete(extractedWebInfDir);
      extractedWebInfDir.mkdir();
      Resource web_inf_lib = web_inf.addPath("lib/");
      File webInfDir = new File(extractedWebInfDir, "WEB-INF");
      webInfDir.mkdir();

      if (web_inf_lib.exists()) {
        File webInfLibDir = new File(webInfDir, "lib");
        if (webInfLibDir.exists()) IO.delete(webInfLibDir);
        webInfLibDir.mkdir();

        LOG.info("Copying WEB-INF/lib " + web_inf_lib + " to " + webInfLibDir);
        web_inf_lib.copyTo(webInfLibDir);
      }

      Resource web_inf_classes = web_inf.addPath("classes/");
      if (web_inf_classes.exists()) {
        File webInfClassesDir = new File(webInfDir, "classes");
        if (webInfClassesDir.exists()) IO.delete(webInfClassesDir);
        webInfClassesDir.mkdir();
        LOG.info(
            "Copying WEB-INF/classes from "
                + web_inf_classes
                + " to "
                + webInfClassesDir.getAbsolutePath());
        web_inf_classes.copyTo(webInfClassesDir);
      }

      web_inf = Resource.newResource(extractedWebInfDir.getCanonicalPath());

      ResourceCollection rc = new ResourceCollection(web_inf, web_app);

      if (LOG.isDebugEnabled()) LOG.debug("context.resourcebase = " + rc);

      context.setBaseResource(rc);
    }
  }