@Override
  public void deconfigure(WebAppContext context) throws Exception {
    // delete temp directory if we had to create it or if it isn't called work
    Boolean tmpdirConfigured = (Boolean) context.getAttribute(TEMPDIR_CONFIGURED);

    if (context.getTempDirectory() != null
        && (tmpdirConfigured == null || !tmpdirConfigured.booleanValue())
        && !isTempWorkDirectory(context.getTempDirectory())) {
      IO.delete(context.getTempDirectory());
      context.setTempDirectory(null);

      // clear out the context attributes for the tmp dir only if we had to
      // create the tmp dir
      context.setAttribute(TEMPDIR_CONFIGURED, null);
      context.setAttribute(WebAppContext.TEMPDIR, null);
    }

    // reset the base resource back to what it was before we did any unpacking of resources
    context.setBaseResource(_preUnpackBaseResource);
  }
  @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));
    }
  }
  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);
    }
  }