1

I have been searching without success in how to get an embedded jetty server to serve a handful of html files that are contained within the same jar. Surely this is possible?

I really don't want to go through the hassle of building and working with a war if I don't have to. Ideally I wouldn't have to create a WEB-INFO dir and a web.xml files either, though all solutions I've read seem to point to doing this and using a WebAppContext.

I've read the following links, but haven't found a way to set the ResourceBase or BaseResource property when running from a jar.

Start java application with jetty without WAR file

What is correct URL to specify ResourceBase of JAR "resources/webapp" folder for embedded Jetty?

Embedded Jetty looking for files inside its Jar file

Running through an IDE during DEV it was simple, the code worked and looked something like this..

Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(httpPort);
server.addConnector(connector);

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.setWelcomeFiles(new String[]{"welcome.html"});
server.setHandler(context);

ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class);
holderPwd.setInitParameter("resourceBase","./Relative/Path/To/Html/Files");
holderPwd.setInitParameter("dirAllowed","true");
context.addServlet(holderPwd,"/");

server.start();
server.join();

So, do I have to use WebAppContext instead of ServletContextHandler? If yes, then do I have to add a webapp/WEB-INFO/web.xml directory structure too? And if I do that, then do I have to package as a war?

Community
  • 1
  • 1
user2952021
  • 23
  • 1
  • 3
  • I don't see the `setResourceBase` call from the [3rd question](http://stackoverflow.com/questions/1462953/embedded-jetty-looking-for-files-inside-its-jar-file); that should do it. Or you could just specify your own servlet implementation and use `ClassLoader.getResource()`. – Kenney Nov 20 '15 at 15:02
  • Kenny - I thought I was doing that via the following?. holderPwd.setInitParameter("resourceBase",...) – user2952021 Nov 20 '15 at 15:07
  • You're probably right. Have you tried passing something like `this.class.getClassLoader().getResource("com/company/project/mywebdir").toExternalForm();` as the 2nd parameter? What results are you getting, 404? – Kenney Nov 20 '15 at 15:16
  • Kenney, the externalForm() provides a path but it just results in 404s unfortunately – user2952021 Nov 23 '15 at 08:06

1 Answers1

9

You need to set the Resource Base for the Context to the URL/URI to where your static content can be accessed from.

Note: you set this at the ServletContext level, not the DefaultServlet level, that way all servlets in your context have access to the same information and the various methods in ServletContext related to real file paths and resources are sane.

public static void main(String[] args) throws Exception
{
    Server server = new Server(8080);

    // Figure out what path to serve content from
    ClassLoader cl = MyEmbeddedJettyMain.class.getClassLoader();
    // We look for a file, as ClassLoader.getResource() is not
    // designed to look for directories (we resolve the directory later)
    URL f = cl.getResource("static-root/hello.html");
    if (f == null)
    {
        throw new RuntimeException("Unable to find resource directory");
    }

    // Resolve file to directory
    URI webRootUri = f.toURI().resolve("./").normalize();
    System.err.println("WebRoot is " + webRootUri);

    ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
    context.setContextPath("/");
    context.setBaseResource(Resource.newResource(webRootUri));
    context.setWelcomeFiles(new String[]{"welcome.html"});

    ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class);
    holderPwd.setInitParameter("dirAllowed","true");
    context.addServlet(holderPwd,"/");

    server.setHandler(context);

    server.start();
    server.join();
}
Joakim Erdfelt
  • 41,193
  • 5
  • 78
  • 124
  • 1
    Thanks Joakim, that works fine in the IDE but throws an error when doing the url.toURI() step when in a Jar though. "java.lang.IllegalArgumentException: URI is not absolute". The path of the url is something like this.."file:/C:/dev/Project/Namespace/target/ComponentName-dev-SNAPSHOT-dist/lib/ComponentName-dev-SNAPSHOT.jar!/charts/welcome.html" – user2952021 Nov 22 '15 at 20:12
  • 2
    ok, thanks. solved it with your help and finding the project on github that you posted I think. https://github.com/jetty-project/embedded-jetty-uber-jar.. I hadn't got my html files under a resources directory, that was the problem. – user2952021 Nov 23 '15 at 13:08
  • Any chance to configure static resources from an arbitrary JAR via web.xml for a NON-embedded Jetty? – GullerYA Apr 12 '19 at 15:44
  • @GullerYA `web.xml` is for a formal webapp (aka servlet spec), so no arbitrary resource locations. But you could use `WEB-INF/lib/*.jar!META-INF/resources` (aka servlet web resource jars) – Joakim Erdfelt Apr 12 '19 at 16:30
  • Thanks for a quick answer, to begin with. It's not working that way, Jetty trows "no !/ in spec" exception. I've tried to replace "!" with "!/", but it's still 404, which looks correct, since the jar has no resources in META-INF, the resources located one level up, in the JAR's root... – GullerYA Apr 12 '19 at 17:58
  • I've inspected a bit `JarFileResource` in debug, and looks like i'm close. Starting with `jar:file` followed by relative path is not necessary the webapp's root directory but more like current directory the process was started in (it is not so when, for example, running with jetty maven plugin). Therefore i'm getting 404. Is there any magic `${webapp.home}/WEB-INF/lib` syntax to explicitly get the right path to the JAR? – GullerYA Apr 12 '19 at 18:31