Starting up embedded jetty server for a JAR file
Asked Answered
A

2

8

What I am trying to do, is to build an executable JAR file which will contain my project. I have included its dependencies right next to it, also in JAR files, so my directory listing looks something like this:

~/Projects/Java/web-app/out:

web-app.jar

dependency1.jar

dependency2.jar

dependency3.jar

I know and am sure that my problem does not arise from dependencies, as my application functions properly, right up to the moment I start up Jetty embedded.

The code I use to start Jetty is like this:

public class ServerExecutionGoal implements ExecutionGoal {    

    private final static Logger logger = Logger.getLogger(ServerExecutionGoal.class);    

    private WebAppContext getWebAppContext() throws IOException {    
        WebAppContext context = new WebAppContext();    
        System.out.println("context = " + context);    
        context.setResourceBase(new PathMatchingResourcePatternResolver().getResource("classpath:/webapp").getURL().toExternalForm());    
        context.setContextPath("/");    
        context.setLogger(new StdErrLog());    
        return context;    
    }    

    @Override    
    public void execute(Map<String, Object> stringObjectMap) throws ExecutionTargetFailureException {    
        logger.info("Instantiating target server ...");    
        final Server server = new Server(8089);    
        final ContextHandlerCollection handlerCollection = new ContextHandlerCollection();    
        try {    
            handlerCollection.setHandlers(new Handler[]{new RequestLogHandler(), getWebAppContext()});    
        } catch (IOException e) {    
            throw new ExecutionTargetFailureException("Could not create web application context", e);    
        }    
        server.setHandler(handlerCollection);    
        try {    
            logger.info("Starting server on port 8089 ...");    
            server.start();    
            server.join();    
            logger.info("Server started. Waiting for requests.");    
        } catch (Exception e) {    
            throw new ExecutionTargetFailureException("Failed to properly start the web server", e);    
        }    
    }    

    public static void main(String[] args) throws ExecutionTargetFailureException {    
        new ServerExecutionGoal().execute(null);    
    }    

}    

I can validate that the "webapp" folder gets relocated correctly inside my JAR to /webapp, and that when running the code through my IDE (IntelliJ IDEA 11) context.setResourceBase(new PathMatchingResourcePatternResolver().getResource("classpath:/webapp").getURL().toExternalForm()) maps validly to the resource in question. Also, I can show that it resolves to something like:

jar:file:~/Projects/Java/web-app/out/web-app.jar!/webapp

and is accessible (I read it).

However, when I start my application's main method, and Jetty starts, on http://localhost:8089 I get the following:

HTTP ERROR: 503

Problem accessing /. Reason:

Service Unavailable

Powered by Jetty://

Where am I going wrong?

I know that by setting "resourceBase" to "." the address "http://localhost:8089" will act as an interface to the location "~/Projects/Java/web-app/out/" where I can see a listing of all the JAR files, including the "web-app.jar", upon clicking on which I am offered to download it.

I have seen the following questions, and the answers do not apply:

  1. Embedded jetty application not working from jar: I get NullPointerException since Start.class.getProtectionDomain().getCodeSource() resolves to null.
  2. Embedded Jetty WebAppContext FilePermission issue: which not only isn't answered, but the situation clearly does not apply, as I do not have permission issues (the fact that I can get a file listing should prove that).
  3. embedding jetty server problems: also unanswered, also not applicable as I don't have any dependency problems (as pointed out previously in my comments above).

I think that I should somehow enable Jetty to access the /webapp folder, which is located under my src/main/resources/ directory and is bundled into my web application. Should I be forsaking a bundled web application and deploy the exploded context path to somewhere accessible by Jetty instead (this is not desirable at all as it poses a multitude of issues for me and my clients).

Achene answered 1/10, 2012 at 11:49 Comment(3)
You could use context.setWar(...) with a WAR file. This would just add one file to your distribution.Accounting
I am also facing a similar issue .when the server is started from eclipse I am getting proper response for the request.But when run it from a jar file from cmd, i get 404.Any help is appreciated.Hashimoto
Its probably a long shot after almost 7 years, but have you found the solution?Aposematic
S
1

I'm not sure, if the WebAppContext of Jetty can be used with PathMatchingResourcePatternResolver!

In one of my projects I solved this problem by writing my own javax.servlet.Filter, which loads the requested resources by Class#getResourceAsStream. Class#getResourceAsStream reads resources from inside a jars as well as inside a resource path (e.g. maven).

Hope this tip is helpful for you, cheers Thilo

Skiplane answered 4/5, 2017 at 18:5 Comment(0)
A
0

I believe, I faced a similar problem a couple months ago, I used Jetty v9.4.12.v20180830.

Here is my solution:

If you have the following generated JAR structure:

 app.jar
   +----- com /
   |        +--- ( classes ... )
   |
   +----- config /
   |        |
   |        +--- display.properties
   |
   +----- webapp /
            |
            +--- index.html

Then the following code will refer to the correct folder:

ServletContextHandler webappContext = new ServletContextHandler(ServletContextHandler.SESSIONS);  
URL webRootLocation = YourJettyStarterClass.class.getResource("/webapp/index.html");  
URI webRootUri = URI.create(webRootLocation.toURI().toASCIIString().replaceFirst("/index.html$", "/"));  
webappContext.setContextPath("/");
webappContext.setBaseResource(Resource.newResource(webRootUri));
webappContext.setWelcomeFiles(new String[] { "index.html" });  

The important part:

URL webRootLocation = YourJettyStarterClass.class.getResource("/webapp/index.html");   
Aposematic answered 28/6, 2019 at 19:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.