protected String getPathsToRequiredBundles(String requireTldBundles) throws Exception {
      if (requireTldBundles == null) return null;

      ServiceReference ref =
          _bundle
              .getBundleContext()
              .getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class.getName());
      PackageAdmin packageAdmin =
          (ref == null) ? null : (PackageAdmin) _bundle.getBundleContext().getService(ref);
      if (packageAdmin == null)
        throw new IllegalStateException(
            "Unable to get PackageAdmin reference to locate required Tld bundles");

      StringBuilder paths = new StringBuilder();
      String[] symbNames = requireTldBundles.split(", ");

      for (String symbName : symbNames) {
        Bundle[] bs = packageAdmin.getBundles(symbName, null);
        if (bs == null || bs.length == 0) {
          throw new IllegalArgumentException(
              "Unable to locate the bundle '"
                  + symbName
                  + "' specified by "
                  + OSGiWebappConstants.REQUIRE_TLD_BUNDLE
                  + " in manifest of "
                  + (_bundle == null ? "unknown" : _bundle.getSymbolicName()));
        }

        File f =
            BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bs[0]);
        if (paths.length() > 0) paths.append(", ");
        paths.append(f.toURI().toURL().toString());
        LOG.debug(
            "getPathsToRequiredBundles: bundle path=" + bs[0].getLocation() + " uri=" + f.toURI());
      }

      return paths.toString();
    }
    public void configureContextHandler() throws Exception {
      if (_configured) return;

      _configured = true;

      // Override for bundle root may have been set
      String bundleOverrideLocation =
          (String) _properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
      if (bundleOverrideLocation == null)
        bundleOverrideLocation =
            (String)
                _properties.get(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE);

      // Location on filesystem of bundle or the bundle override location
      File bundleLocation =
          BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle);
      File root =
          (bundleOverrideLocation == null ? bundleLocation : new File(bundleOverrideLocation));
      Resource rootResource =
          Resource.newResource(
              BundleFileLocatorHelperFactory.getFactory()
                  .getHelper()
                  .getLocalURL(root.toURI().toURL()));

      // try and make sure the rootResource is useable - if its a jar then make it a jar file url
      if (rootResource.exists()
          && !rootResource.isDirectory()
          && !rootResource.toString().startsWith("jar:")) {
        Resource jarResource = JarResource.newJarResource(rootResource);
        if (jarResource.exists() && jarResource.isDirectory()) rootResource = jarResource;
      }

      // Set the base resource of the ContextHandler, if not already set, can also be overridden by
      // the context xml file
      if (_contextHandler != null && _contextHandler.getBaseResource() == null) {
        _contextHandler.setBaseResource(rootResource);
      }

      // Use a classloader that knows about the common jetty parent loader, and also the bundle
      OSGiClassLoader classLoader =
          new OSGiClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps(), _bundle);

      // if there is a context file, find it and apply it
      if (_contextFile == null && _contextHandler == null)
        throw new IllegalStateException("No context file or ContextHandler");

      if (_contextFile != null) {
        // apply the contextFile, creating the ContextHandler, the DeploymentManager will register
        // it in the ContextHandlerCollection
        Resource res = null;

        // try to find the context file in the filesystem
        if (_contextFile.startsWith("/")) res = getFileAsResource(_contextFile);

        // try to find it relative to jetty home
        if (res == null) {
          // See if the specific server we are related to has jetty.home set
          String jettyHome =
              (String)
                  getServerInstanceWrapper()
                      .getServer()
                      .getAttribute(OSGiServerConstants.JETTY_HOME);
          if (jettyHome != null) res = getFileAsResource(jettyHome, _contextFile);

          // try to see if a SystemProperty for jetty.home is set
          if (res == null) {
            jettyHome = System.getProperty(OSGiServerConstants.JETTY_HOME);

            if (jettyHome != null) {
              if (jettyHome.startsWith("\"") || jettyHome.startsWith("'"))
                jettyHome = jettyHome.substring(1);
              if (jettyHome.endsWith("\"") || (jettyHome.endsWith("'")))
                jettyHome = jettyHome.substring(0, jettyHome.length() - 1);

              res = getFileAsResource(jettyHome, _contextFile);
              if (LOG.isDebugEnabled()) LOG.debug("jetty home context file:" + res);
            }
          }
        }

        // try to find it relative to an override location that has been specified
        if (res == null) {
          if (bundleOverrideLocation != null) {
            res =
                getFileAsResource(
                    Resource.newResource(bundleOverrideLocation).getFile(), _contextFile);
            if (LOG.isDebugEnabled()) LOG.debug("Bundle override location context file:" + res);
          }
        }

        // try to find it relative to the bundle in which it is being deployed
        if (res == null) {
          if (_contextFile.startsWith("./")) _contextFile = _contextFile.substring(1);

          if (!_contextFile.startsWith("/")) _contextFile = "/" + _contextFile;

          URL contextURL = _bundle.getEntry(_contextFile);
          if (contextURL != null) res = Resource.newResource(contextURL);
        }

        // apply the context xml file, either to an existing ContextHandler, or letting the
        // it create the ContextHandler as necessary
        if (res != null) {
          ClassLoader cl = Thread.currentThread().getContextClassLoader();

          LOG.debug("Context classloader = " + cl);
          try {
            Thread.currentThread().setContextClassLoader(classLoader);

            XmlConfiguration xmlConfiguration = new XmlConfiguration(res.getInputStream());
            HashMap properties = new HashMap();
            // put the server instance in
            properties.put("Server", getServerInstanceWrapper().getServer());
            // put in the location of the bundle root
            properties.put("bundle.root", rootResource.toString());

            // insert the bundle's location as a property.
            xmlConfiguration.getProperties().putAll(properties);

            if (_contextHandler == null)
              _contextHandler = (ContextHandler) xmlConfiguration.configure();
            else xmlConfiguration.configure(_contextHandler);
          } finally {
            Thread.currentThread().setContextClassLoader(cl);
          }
        }
      }

      // Set up the class loader we created
      _contextHandler.setClassLoader(classLoader);

      // If a bundle/service property specifies context path, let it override the context xml
      String contextPath = (String) _properties.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
      if (contextPath == null)
        contextPath = (String) _properties.get(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH);
      if (contextPath != null) _contextHandler.setContextPath(contextPath);

      // osgi Enterprise Spec r4 p.427
      _contextHandler.setAttribute(
          OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext());

      // make sure we protect also the osgi dirs specified by OSGi Enterprise spec
      String[] targets = _contextHandler.getProtectedTargets();
      int length = (targets == null ? 0 : targets.length);

      String[] updatedTargets = null;
      if (targets != null) {
        updatedTargets =
            new String[length + OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
        System.arraycopy(targets, 0, updatedTargets, 0, length);

      } else updatedTargets = new String[OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
      System.arraycopy(
          OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS,
          0,
          updatedTargets,
          length,
          OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length);
      _contextHandler.setProtectedTargets(updatedTargets);
    }
    public void configureWebApp() throws Exception {
      // TODO turn this around and let any context.xml file get applied first, and have the
      // properties override
      _webApp.setContextPath(_contextPath);

      // osgi Enterprise Spec r4 p.427
      _webApp.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext());

      String overrideBundleInstallLocation =
          (String) _properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
      File bundleInstallLocation =
          (overrideBundleInstallLocation == null
              ? BundleFileLocatorHelperFactory.getFactory()
                  .getHelper()
                  .getBundleInstallLocation(_bundle)
              : new File(overrideBundleInstallLocation));
      URL url = null;
      Resource rootResource =
          Resource.newResource(
              BundleFileLocatorHelperFactory.getFactory()
                  .getHelper()
                  .getLocalURL(bundleInstallLocation.toURI().toURL()));
      // try and make sure the rootResource is useable - if its a jar then make it a jar file url
      if (rootResource.exists()
          && !rootResource.isDirectory()
          && !rootResource.toString().startsWith("jar:")) {
        Resource jarResource = JarResource.newJarResource(rootResource);
        if (jarResource.exists() && jarResource.isDirectory()) rootResource = jarResource;
      }

      // if the path wasn't set or it was ., then it is the root of the bundle's installed location
      if (_webAppPath == null || _webAppPath.length() == 0 || ".".equals(_webAppPath)) {
        url = bundleInstallLocation.toURI().toURL();
      } else {
        // Get the location of the root of the webapp inside the installed bundle
        if (_webAppPath.startsWith("/") || _webAppPath.startsWith("file:")) {
          url = new File(_webAppPath).toURI().toURL();
        } else if (bundleInstallLocation != null && bundleInstallLocation.isDirectory()) {
          url = new File(bundleInstallLocation, _webAppPath).toURI().toURL();
        } else if (bundleInstallLocation != null) {
          Enumeration<URL> urls =
              BundleFileLocatorHelperFactory.getFactory()
                  .getHelper()
                  .findEntries(_bundle, _webAppPath);
          if (urls != null && urls.hasMoreElements()) url = urls.nextElement();
        }
      }

      if (url == null) {
        throw new IllegalArgumentException(
            "Unable to locate "
                + _webAppPath
                + " in "
                + (bundleInstallLocation != null
                    ? bundleInstallLocation.getAbsolutePath()
                    : "unlocated bundle '" + _bundle.getSymbolicName() + "'"));
      }

      // Sets the location of the war file
      // converts bundleentry: protocol if necessary
      _webApp.setWar(
          BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(url).toString());

      // Set up what has been configured on the provider
      _webApp.setParentLoaderPriority(isParentLoaderPriority());
      _webApp.setExtractWAR(isExtract());
      if (getConfigurationClasses() != null)
        _webApp.setConfigurationClasses(getConfigurationClasses());
      else _webApp.setConfigurationClasses(__defaultConfigurations);

      if (getDefaultsDescriptor() != null) _webApp.setDefaultsDescriptor(getDefaultsDescriptor());

      // Set up configuration from manifest headers
      // extra classpath
      String tmp = (String) _properties.get(OSGiWebappConstants.JETTY_EXTRA_CLASSPATH);
      if (tmp != null) _webApp.setExtraClasspath(tmp);

      // web.xml
      tmp = (String) _properties.get(OSGiWebappConstants.JETTY_WEB_XML_PATH);
      if (tmp != null && tmp.trim().length() != 0) {
        File webXml = getFile(tmp, bundleInstallLocation);
        if (webXml != null && webXml.exists()) _webApp.setDescriptor(webXml.getAbsolutePath());
      }

      // webdefault.xml
      tmp = (String) _properties.get(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH);
      if (tmp != null) {
        File defaultWebXml = getFile(tmp, bundleInstallLocation);
        if (defaultWebXml != null) {
          if (defaultWebXml.exists())
            _webApp.setDefaultsDescriptor(defaultWebXml.getAbsolutePath());
          else LOG.warn(defaultWebXml.getAbsolutePath() + " does not exist");
        }
      }

      // Handle Require-TldBundle
      // This is a comma separated list of names of bundles that contain tlds that this webapp uses.
      // We add them to the webapp classloader.
      String requireTldBundles = (String) _properties.get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
      String pathsToTldBundles = getPathsToRequiredBundles(requireTldBundles);

      // make sure we provide access to all the jetty bundles by going
      // through this bundle.
      OSGiWebappClassLoader webAppLoader =
          new OSGiWebappClassLoader(
              _serverWrapper.getParentClassLoaderForWebapps(), _webApp, _bundle);

      if (pathsToTldBundles != null) webAppLoader.addClassPath(pathsToTldBundles);
      _webApp.setClassLoader(webAppLoader);

      // apply any META-INF/context.xml file that is found to configure
      // the webapp first
      applyMetaInfContextXml(rootResource);

      // pass the value of the require tld bundle so that the TagLibOSGiConfiguration
      // can pick it up.
      _webApp.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundles);

      // Set up some attributes
      // rfc66
      _webApp.setAttribute(
          OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT, _bundle.getBundleContext());

      // spring-dm-1.2.1 looks for the BundleContext as a different attribute.
      // not a spec... but if we want to support
      // org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext
      // then we need to do this to:
      _webApp.setAttribute(
          "org.springframework.osgi.web." + BundleContext.class.getName(),
          _bundle.getBundleContext());

      // also pass the bundle directly. sometimes a bundle does not have a
      // bundlecontext.
      // it is still useful to have access to the Bundle from the servlet
      // context.
      _webApp.setAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE, _bundle);
    }