@Test
  public void testExtensionMatchServletWithGlobalFilter() throws IOException, ServletException {

    DeploymentInfo builder = new DeploymentInfo();

    final PathHandler root = new PathHandler();
    final ServletContainer container = ServletContainer.Factory.newInstance();

    builder.addServlet(new ServletInfo("*.jsp", PathMappingServlet.class).addMapping("*.jsp"));

    builder.addFilter(new FilterInfo("/*", PathFilter.class));
    builder.addFilterUrlMapping("/*", "/*", DispatcherType.REQUEST);

    builder
        .setClassIntrospecter(TestClassIntrospector.INSTANCE)
        .setClassLoader(FilterPathMappingTestCase.class.getClassLoader())
        .setContextPath("/servletContext")
        .setDeploymentName("servletContext.war");

    final DeploymentManager manager = container.addDeployment(builder);
    manager.deploy();
    root.addPrefixPath(builder.getContextPath(), manager.start());

    DefaultServer.setRootHandler(root);

    TestHttpClient client = new TestHttpClient();
    try {
      runTest(client, "aa.jsp", "*.jsp - /aa.jsp - null", "/*");

    } finally {
      client.getConnectionManager().shutdown();
    }
  }
  private static GracefulShutdownHandler getHandlersPipe(
      final IdentityManager identityManager, final AccessManager accessManager) {
    PipedHttpHandler coreHandlerChain =
        new DbPropsInjectorHandler(
            new CollectionPropsInjectorHandler(new RequestDispacherHandler()));

    PathHandler paths = path();

    configuration
        .getMongoMounts()
        .stream()
        .forEach(
            m -> {
              String url = (String) m.get(Configuration.MONGO_MOUNT_WHERE_KEY);
              String db = (String) m.get(Configuration.MONGO_MOUNT_WHAT_KEY);

              paths.addPrefixPath(
                  url,
                  new CORSHandler(
                      new RequestContextInjectorHandler(
                          url,
                          db,
                          new OptionsHandler(
                              new BodyInjectorHandler(
                                  new SecurityHandlerDispacher(
                                      coreHandlerChain, identityManager, accessManager))))));

              LOGGER.info("URL {} bound to MongoDB resource {}", url, db);
            });

    pipeStaticResourcesHandlers(configuration, paths, identityManager, accessManager);

    pipeApplicationLogicHandlers(configuration, paths, identityManager, accessManager);

    // pipe the auth tokens invalidation handler
    paths.addPrefixPath(
        "/_authtokens",
        new CORSHandler(
            new SecurityHandlerDispacher(
                new AuthTokenHandler(), identityManager, new FullAccessManager())));

    return new GracefulShutdownHandler(
        new RequestLimitingHandler(
            new RequestLimit(configuration.getRequestLimit()),
            new AllowedMethodsHandler(
                new BlockingHandler(
                    new GzipEncodingHandler(
                        new ErrorHandler(new HttpContinueAcceptingHandler(paths)),
                        configuration.isForceGzipEncoding())), // allowed methods
                HttpString.tryFromString(RequestContext.METHOD.GET.name()),
                HttpString.tryFromString(RequestContext.METHOD.POST.name()),
                HttpString.tryFromString(RequestContext.METHOD.PUT.name()),
                HttpString.tryFromString(RequestContext.METHOD.DELETE.name()),
                HttpString.tryFromString(RequestContext.METHOD.PATCH.name()),
                HttpString.tryFromString(RequestContext.METHOD.OPTIONS.name()))));
  }
  // 配置Undertow服务
  public void configServer(Properties configuration, List<FrontController> frontControllers) {
    int ioThread =
        Integer.parseInt(
            configuration.getProperty(
                "io_thread_number",
                String.valueOf(Runtime.getRuntime().availableProcessors() + 1)));
    int workerThread =
        Integer.parseInt(
            configuration.getProperty(
                "work_thread_number",
                String.valueOf(Runtime.getRuntime().availableProcessors() * 200)));
    String httpHost = configuration.getProperty("http.host", "0.0.0.0");
    int httpPort = Integer.parseInt(configuration.getProperty("http.port", "7080"));
    String staticResourcePath = configuration.getProperty("server.context.path.static", "static");

    PathHandler pathHandler = new PathHandler();

    // 静态资源,压缩
    ResourceManager resourceManager = new FileResourceManager(new File(staticResourcePath), 10240);
    ContentEncodedResourceManager encoder =
        new ContentEncodedResourceManager(
            Paths.get(staticResourcePath),
            new CachingResourceManager(100, 10000, null, resourceManager, -1),
            new ContentEncodingRepository()
                .addEncodingHandler("gzip", new GzipEncodingProvider(), 50, null),
            1024,
            1024 * 500,
            null);
    ResourceHandler resourceHandler = new ResourceHandler(resourceManager);

    if (configuration.getProperty("http.gzip", "false").equals("true")) {
      resourceHandler.setContentEncodedResourceManager(encoder);
    }
    pathHandler.addPrefixPath("/", resourceHandler);

    // API
    for (FrontController frontController : frontControllers) {
      logger.info("Setup Undertow server path:" + frontController.getPath());
      pathHandler.addPrefixPath(
          frontController.getPath(), new FrontControllerHandler(frontController));
    }

    undertow =
        Undertow.builder()
            .addHttpListener(httpPort, httpHost)
            .setIoThreads(ioThread)
            .setWorkerThreads(workerThread)
            .setHandler(pathHandler)
            .build();
    logger.info(
        "Setup Undertow server static resources at path:"
            + staticResourcePath
            + " at location:"
            + staticResourcePath);
  }
  protected PathHandler mountMethods(PathHandler pathHandler, final Class<?> handlerClass) {
    Controller controllerAnnotation = handlerClass.getAnnotation(Controller.class);

    Method[] methods = handlerClass.getMethods();

    final List<Method> beforeTranslationMethods = identifyBeforeTranslationMethod(methods);
    for (final Method method : methods) {
      Page methodPagePath = method.getAnnotation(Page.class);
      if (methodPagePath != null) {
        HttpHandler h =
            new HandlerCreator()
                .forPageClass(handlerClass)
                .withPathMethod(method)
                .withExecuteBeforeMethods(beforeTranslationMethods)
                .mount();

        String pageRoot = controllerAnnotation.path();
        for (String methodRoot : methodPagePath.value()) {
          pathHandler.addExactPath(pageRoot + "/" + methodRoot, h);
        }
      }
    }

    return pathHandler;
  }
  @BeforeClass
  public static void setup() throws Exception {
    js =
        UndertowJS.builder()
            .addResources(
                new ClassPathResourceManager(
                    JavascriptSecurityTestCase.class.getClassLoader(),
                    JavascriptSecurityTestCase.class.getPackage()),
                "security.js")
            .build();
    js.start();

    final ServletContainer container = ServletContainer.Factory.newInstance();

    ServletIdentityManager identityManager = new ServletIdentityManager();
    identityManager.addUser("user1", "password1", "admin");
    identityManager.addUser("user2", "password2", "user");

    DeploymentInfo builder =
        new DeploymentInfo()
            .setClassLoader(JavascriptSecurityTestCase.class.getClassLoader())
            .setContextPath("/servletContext")
            .setDeploymentName("servletContext.war")
            .setIdentityManager(identityManager)
            .setLoginConfig(new LoginConfig("BASIC", "Test Realm"))
            .addInnerHandlerChainWrapper(
                new HandlerWrapper() {
                  @Override
                  public HttpHandler wrap(HttpHandler handler) {
                    return js.getHandler(handler);
                  }
                });

    DeploymentManager manager = container.addDeployment(builder);
    manager.deploy();
    PathHandler root = new PathHandler();
    root.addPrefixPath(builder.getContextPath(), manager.start());

    DefaultServer.setRootHandler(root);
  }
  private void deployServlet(final ServerWebSocketContainer deployment) throws ServletException {

    final DeploymentInfo builder;
    builder =
        new DeploymentInfo()
            .setClassLoader(getClass().getClassLoader())
            .setContextPath("/")
            .setClassIntrospecter(TestClassIntrospector.INSTANCE)
            .setDeploymentName("websocket.war")
            .addFilter(new FilterInfo("filter", JsrWebSocketFilter.class))
            .addFilterUrlMapping("filter", "/*", DispatcherType.REQUEST)
            .addServletContextAttribute(
                javax.websocket.server.ServerContainer.class.getName(), deployment);

    final PathHandler root = new PathHandler();
    final ServletContainer container = ServletContainer.Factory.newInstance();
    DeploymentManager manager = container.addDeployment(builder);
    manager.deploy();
    root.addPath(builder.getContextPath(), manager.start());

    DefaultServer.setRootHandler(root);
  }
  @BeforeClass
  public static void setup() throws ServletException {

    final PathHandler root = new PathHandler();
    final ServletContainer container = ServletContainer.Factory.newInstance();

    ServletInfo s = new ServletInfo("servlet", HelloServlet.class).addMapping("/aa");

    DeploymentInfo builder =
        new DeploymentInfo()
            .setClassLoader(MockRequestTestCase.class.getClassLoader())
            .setContextPath("/servletContext")
            .setClassIntrospecter(TestClassIntrospector.INSTANCE)
            .setDeploymentName("servletContext.war")
            .addServlet(s);

    DeploymentManager manager = container.addDeployment(builder);
    manager.deploy();
    deployment = manager.getDeployment();
    root.addPrefixPath(builder.getContextPath(), manager.start());

    DefaultServer.setRootHandler(root);
  }
  @Test
  public void testBasicPathHanding() throws IOException {
    TestHttpClient client = new TestHttpClient();
    try {
      final PathHandler handler = new PathHandler();
      handler.addPath("a", new RemainingPathHandler("/a"));
      handler.addPath("/aa", new RemainingPathHandler("/aa"));
      handler.addPath("/aa/anotherSubPath", new RemainingPathHandler("/aa/anotherSubPath"));

      final PathHandler sub = new PathHandler();

      handler.addPath("/path", sub);
      sub.addPath("/subpath", new RemainingPathHandler("/subpath"));
      sub.setDefaultHandler(new RemainingPathHandler("/path"));

      DefaultServer.setRootHandler(handler);

      HttpGet get = new HttpGet(DefaultServer.getDefaultServerAddress() + "/notamatchingpath");
      HttpResponse result = client.execute(get);
      Assert.assertEquals(404, result.getStatusLine().getStatusCode());
      HttpClientUtils.readResponse(result);

      get = new HttpGet(DefaultServer.getDefaultServerAddress() + "/");
      result = client.execute(get);
      Assert.assertEquals(404, result.getStatusLine().getStatusCode());
      HttpClientUtils.readResponse(result);

      runPathTest(client, "/path", "/path", "");
      runPathTest(client, "/path/a", "/path", "/a");
      runPathTest(client, "/path/subpath", "/subpath", "");
      runPathTest(client, "/path/subpath/", "/subpath", "/");
      runPathTest(client, "/path/subpath/foo", "/subpath", "/foo");
      runPathTest(client, "/a", "/a", "");
      runPathTest(client, "/aa/anotherSubPath", "/aa/anotherSubPath", "");
      runPathTest(client, "/aa/anotherSubPath/bob", "/aa/anotherSubPath", "/bob");
      runPathTest(client, "/aa?a=b", "/aa", "", Collections.singletonMap("a", "b"));

    } finally {
      client.getConnectionManager().shutdown();
    }
  }
  protected PathHandler mountServerEndpoints(
      final PathHandler pathHandler, List<Class<?>> serverEndpoints) throws ServletException {
    if (!serverEndpoints.isEmpty()) {
      DeploymentInfo builder =
          new DeploymentInfo().setClassLoader(this.getClass().getClassLoader()).setContextPath("/");
      WebSocketDeploymentInfo wsDeployInfo = new WebSocketDeploymentInfo();
      wsDeployInfo.setBuffers(new ByteBufferSlicePool(100, 1000));
      for (Class<?> serverEndpoint : serverEndpoints) {
        wsDeployInfo.addEndpoint(serverEndpoint);
      }
      builder.addServletContextAttribute(WebSocketDeploymentInfo.ATTRIBUTE_NAME, wsDeployInfo);
      builder.setDeploymentName("websocketDeploy.war");

      final ServletContainer container = ServletContainer.Factory.newInstance();
      DeploymentManager manager = container.addDeployment(builder);
      manager.deploy();
      pathHandler.addPrefixPath("/", manager.start());
    }
    return pathHandler;
  }
  private static void setupOpenListener(
      HttpOpenListener listener,
      ModelController modelController,
      ConsoleMode consoleMode,
      String consoleSlot,
      ControlledProcessStateService controlledProcessStateService,
      int securePort,
      SecurityRealm securityRealm,
      final ChannelUpgradeHandler upgradeHandler) {

    CanonicalPathHandler canonicalPathHandler = new CanonicalPathHandler();
    listener.setRootHandler(canonicalPathHandler);

    PathHandler pathHandler = new PathHandler();
    HttpHandler current = pathHandler;
    if (upgradeHandler != null) {
      upgradeHandler.setNonUpgradeHandler(current);
      current = upgradeHandler;
    }

    if (securePort > 0) {
      current = new SinglePortConfidentialityHandler(current, securePort);
    }
    // caching handler, used for static resources
    current =
        new CacheHandler(
            new DirectBufferCache(
                1024, 1024 * 10, 1024 * 1000, BufferAllocator.BYTE_BUFFER_ALLOCATOR),
            current);
    current = new SimpleErrorPageHandler(current);

    canonicalPathHandler.setNext(current);

    ResourceHandlerDefinition consoleHandler = null;
    try {
      consoleHandler = consoleMode.createConsoleHandler(consoleSlot);
    } catch (ModuleLoadException e) {
      ROOT_LOGGER.consoleModuleNotFound(consoleSlot == null ? "main" : consoleSlot);
    }

    try {
      pathHandler.addPrefixPath(
          ErrorContextHandler.ERROR_CONTEXT, ErrorContextHandler.createErrorContext(consoleSlot));
    } catch (ModuleLoadException e) {
      ROOT_LOGGER.errorContextModuleNotFound(consoleSlot == null ? "main" : consoleSlot);
    }

    ManagementRootConsoleRedirectHandler rootConsoleRedirectHandler =
        new ManagementRootConsoleRedirectHandler(consoleHandler);
    DomainApiCheckHandler domainApiHandler =
        new DomainApiCheckHandler(modelController, controlledProcessStateService);
    pathHandler.addPrefixPath("/", rootConsoleRedirectHandler);
    if (consoleHandler != null) {
      HttpHandler readinessHandler =
          new RedirectReadinessHandler(
              securityRealm, consoleHandler.getHandler(), ErrorContextHandler.ERROR_CONTEXT);
      pathHandler.addPrefixPath(consoleHandler.getContext(), readinessHandler);
    }

    HttpHandler readinessHandler =
        new DmrFailureReadinessHandler(
            securityRealm,
            secureDomainAccess(domainApiHandler, securityRealm),
            ErrorContextHandler.ERROR_CONTEXT);
    pathHandler.addPrefixPath(DomainApiCheckHandler.PATH, readinessHandler);
    pathHandler.addExactPath("management-upload", readinessHandler);

    if (securityRealm != null) {
      pathHandler.addPrefixPath(LogoutHandler.PATH, new LogoutHandler(securityRealm.getName()));
    }
  }
  @Test
  public void testBasicFilterMappings() throws IOException, ServletException {

    DeploymentInfo builder = new DeploymentInfo();

    final PathHandler root = new PathHandler();
    final ServletContainer container = ServletContainer.Factory.newInstance();

    builder.addServlet(new ServletInfo("/a/*", PathMappingServlet.class).addMapping("/a/*"));

    builder.addServlet(new ServletInfo("/aa", PathMappingServlet.class).addMapping("/aa"));

    builder.addServlet(new ServletInfo("/", PathMappingServlet.class).addMapping("/"));

    builder.addServlet(new ServletInfo("contextRoot", PathMappingServlet.class).addMapping(""));

    builder.addServlet(
        new ServletInfo("/myservlet/*", PathMappingServlet.class).addMapping("/myservlet/*"));

    builder.addServlet(new ServletInfo("*.jsp", PathMappingServlet.class).addMapping("*.jsp"));

    builder.addServlet(
        new ServletInfo("/hello/*", PathMappingServlet.class).addMapping("/hello/*"));

    builder.addServlet(new ServletInfo("/test/*", PathMappingServlet.class).addMapping("/test/*"));

    builder.addFilter(new FilterInfo("/*", PathFilter.class));
    builder.addFilterUrlMapping("/*", "/*", DispatcherType.REQUEST);

    // non standard, but we still support it
    builder.addFilter(new FilterInfo("*", PathFilter.class));
    builder.addFilterUrlMapping("*", "*", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("/a/*", PathFilter.class));
    builder.addFilterUrlMapping("/a/*", "/a/*", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("/aa", PathFilter.class));
    builder.addFilterUrlMapping("/aa", "/aa", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("*.bop", PathFilter.class));
    builder.addFilterUrlMapping("*.bop", "*.bop", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("/myservlet/myfilter/*", PathFilter.class));
    builder.addFilterUrlMapping(
        "/myservlet/myfilter/*", "/myservlet/myfilter/*", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("/myfilter/*", PathFilter.class));
    builder.addFilterUrlMapping("/myfilter/*", "/myfilter/*", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("contextRoot", PathFilter.class));
    builder.addFilterServletNameMapping("contextRoot", "contextRoot", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("defaultName", PathFilter.class));
    builder.addFilterServletNameMapping("defaultName", "/", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("/helloworld/index.html", PathFilter.class));
    builder.addFilterUrlMapping(
        "/helloworld/index.html", "/helloworld/index.html", DispatcherType.REQUEST);

    builder.addFilter(new FilterInfo("/test", PathFilter.class));
    builder.addFilterUrlMapping("/test", "/test", DispatcherType.REQUEST);

    builder
        .setClassIntrospecter(TestClassIntrospector.INSTANCE)
        .setClassLoader(FilterPathMappingTestCase.class.getClassLoader())
        .setContextPath("/servletContext")
        .setDeploymentName("servletContext.war");

    final DeploymentManager manager = container.addDeployment(builder);
    manager.deploy();
    root.addPrefixPath(builder.getContextPath(), manager.start());

    DefaultServer.setRootHandler(root);

    TestHttpClient client = new TestHttpClient();
    try {
      runTest(client, "test", "/test/* - /test - null", "/*", "*", "/test");
      runTest(client, "aa", "/aa - /aa - null", "/*", "*", "/aa");
      runTest(client, "a/c", "/a/* - /a - /c", "/*", "*", "/a/*");
      runTest(client, "a", "/a/* - /a - null", "/*", "*", "/a/*");
      runTest(client, "aa/b", "/ - /aa/b - null", "/*", "*", "defaultName");
      runTest(client, "a/b/c/d", "/a/* - /a - /b/c/d", "/*", "*", "/a/*");
      runTest(client, "defaultStuff", "/ - /defaultStuff - null", "/*", "*", "defaultName");
      runTest(client, "", "contextRoot - / - null", "/*", "*", "contextRoot");
      runTest(client, "yyyy.bop", "/ - /yyyy.bop - null", "/*", "*", "*.bop", "defaultName");
      runTest(client, "a/yyyy.bop", "/a/* - /a - /yyyy.bop", "/*", "*", "*.bop", "/a/*");
      runTest(
          client,
          "myservlet/myfilter/file.dat",
          "/myservlet/* - /myservlet - /myfilter/file.dat",
          "/*",
          "*",
          "/myservlet/myfilter/*");
      runTest(
          client,
          "myservlet/myfilter/file.jsp",
          "/myservlet/* - /myservlet - /myfilter/file.jsp",
          "/*",
          "*",
          "/myservlet/myfilter/*");
      runTest(
          client,
          "otherservlet/myfilter/file.jsp",
          "*.jsp - /otherservlet/myfilter/file.jsp - null",
          "/*",
          "*");
      runTest(
          client,
          "myfilter/file.jsp",
          "*.jsp - /myfilter/file.jsp - null",
          "/*",
          "*",
          "/myfilter/*");
      runTest(
          client,
          "helloworld/index.html",
          "/ - /helloworld/index.html - null",
          "/*",
          "*",
          "/helloworld/index.html",
          "defaultName");

    } finally {
      client.getConnectionManager().shutdown();
    }
  }
  private static void pipeApplicationLogicHandlers(
      final Configuration conf,
      final PathHandler paths,
      final IdentityManager identityManager,
      final AccessManager accessManager) {
    if (conf.getApplicationLogicMounts() != null) {
      conf.getApplicationLogicMounts()
          .stream()
          .forEach(
              al -> {
                try {
                  String alClazz = (String) al.get(Configuration.APPLICATION_LOGIC_MOUNT_WHAT_KEY);
                  String alWhere = (String) al.get(Configuration.APPLICATION_LOGIC_MOUNT_WHERE_KEY);
                  boolean alSecured =
                      (Boolean) al.get(Configuration.APPLICATION_LOGIC_MOUNT_SECURED_KEY);
                  Object alArgs = al.get(Configuration.APPLICATION_LOGIC_MOUNT_ARGS_KEY);

                  if (alWhere == null || !alWhere.startsWith("/")) {
                    LOGGER.error(
                        "Cannot pipe application logic handler {}. parameter 'where' must start with /",
                        alWhere);
                    return;
                  }

                  if (alArgs != null && !(alArgs instanceof Map)) {
                    LOGGER.error(
                        "Cannot pipe application logic handler {}."
                            + "args are not defined as a map. it is a ",
                        alWhere,
                        alWhere.getClass());
                    return;
                  }

                  Object o =
                      Class.forName(alClazz)
                          .getConstructor(PipedHttpHandler.class, Map.class)
                          .newInstance(null, (Map) alArgs);

                  if (o instanceof ApplicationLogicHandler) {
                    ApplicationLogicHandler alHandler = (ApplicationLogicHandler) o;

                    PipedHttpHandler handler =
                        new RequestContextInjectorHandler("/_logic", "*", alHandler);

                    if (alSecured) {
                      paths.addPrefixPath(
                          "/_logic" + alWhere,
                          new CORSHandler(
                              new SecurityHandlerDispacher(
                                  handler, identityManager, accessManager)));
                    } else {
                      paths.addPrefixPath(
                          "/_logic" + alWhere,
                          new CORSHandler(
                              new SecurityHandlerDispacher(
                                  handler, identityManager, new FullAccessManager())));
                    }

                    LOGGER.info(
                        "URL {} bound to application logic handler {}." + " access manager: {}",
                        "/_logic" + alWhere,
                        alClazz,
                        alSecured);
                  } else {
                    LOGGER.error(
                        "Cannot pipe application logic handler {}."
                            + " class {} does not extend ApplicationLogicHandler",
                        alWhere,
                        alClazz);
                  }

                } catch (Throwable t) {
                  LOGGER.error(
                      "Cannot pipe application logic handler {}",
                      al.get(Configuration.APPLICATION_LOGIC_MOUNT_WHERE_KEY),
                      t);
                }
              });
    }
  }
  private static void pipeStaticResourcesHandlers(
      final Configuration conf,
      final PathHandler paths,
      final IdentityManager identityManager,
      final AccessManager accessManager) {
    // pipe the static resources specified in the configuration file
    if (conf.getStaticResourcesMounts() != null) {
      conf.getStaticResourcesMounts()
          .stream()
          .forEach(
              sr -> {
                try {
                  String path = (String) sr.get(Configuration.STATIC_RESOURCES_MOUNT_WHAT_KEY);
                  String where = (String) sr.get(Configuration.STATIC_RESOURCES_MOUNT_WHERE_KEY);
                  String welcomeFile =
                      (String) sr.get(Configuration.STATIC_RESOURCES_MOUNT_WELCOME_FILE_KEY);
                  boolean embedded =
                      (Boolean) sr.get(Configuration.STATIC_RESOURCES_MOUNT_EMBEDDED_KEY);
                  boolean secured =
                      (Boolean) sr.get(Configuration.STATIC_RESOURCES_MOUNT_SECURED_KEY);

                  if (where == null || !where.startsWith("/")) {
                    LOGGER.error(
                        "Cannot bind static resources to {}. parameter 'where' must start with /",
                        where);
                    return;
                  }

                  if (welcomeFile == null) {
                    welcomeFile = "index.html";
                  }

                  File file;

                  if (embedded) {
                    if (path.startsWith("/")) {
                      LOGGER.error(
                          "Cannot bind embedded static resources to {}. parameter 'where'"
                              + "cannot start with /. the path is relative to the jar root dir or classpath directory",
                          where);
                      return;
                    }

                    try {
                      file = ResourcesExtractor.extract(path);

                      if (ResourcesExtractor.isResourceInJar(path)) {
                        TMP_EXTRACTED_FILES.put(path, file);
                        LOGGER.info(
                            "Embedded static resources {} extracted in {}", path, file.toString());
                      }
                    } catch (URISyntaxException | IOException ex) {
                      LOGGER.error("Error extracting embedded static resource {}", path, ex);
                      return;
                    } catch (IllegalStateException ex) {
                      LOGGER.error("Error extracting embedded static resource {}", path, ex);

                      if ("browser".equals(path)) {
                        LOGGER.error(
                            "**** Did you downloaded the browser submodule before building?");
                        LOGGER.error(
                            "**** to fix, run this command: $ git submodule update --init --recursive");
                      }
                      return;
                    }
                  } else {
                    if (!path.startsWith("/")) {
                      // this is to allow specifying the configuration file path relative to the jar
                      // (also working when running from classes)
                      URL location =
                          Bootstrapper.class.getProtectionDomain().getCodeSource().getLocation();
                      File locationFile = new File(location.getPath());
                      file = new File(locationFile.getParent() + File.separator + path);
                    } else {
                      file = new File(path);
                    }
                  }

                  ResourceHandler handler =
                      resource(new FileResourceManager(file, 3))
                          .addWelcomeFiles(welcomeFile)
                          .setDirectoryListingEnabled(false);

                  if (secured) {
                    paths.addPrefixPath(
                        where,
                        new SecurityHandlerDispacher(
                            new PipedWrappingHandler(null, handler),
                            identityManager,
                            accessManager));
                  } else {
                    paths.addPrefixPath(where, handler);
                  }

                  LOGGER.info(
                      "URL {} bound to static resources {}. access manager: {}",
                      where,
                      path,
                      secured);

                } catch (Throwable t) {
                  LOGGER.error(
                      "Cannot bind static resources to {}",
                      sr.get(Configuration.STATIC_RESOURCES_MOUNT_WHERE_KEY),
                      t);
                }
              });
    }
  }