How to make Jetty dynamically load "static" pages
Asked Answered
N

10

28

I am building Java web applications, and I hate the traditional "code-compile-deploy-test" cycle. I want to type in one tiny change, then see the result INSTANTLY, without having to compile and deploy.

Fortunately, Jetty is great for this. It is a pure-java web server. It comes with a really nice maven plugin which lets you launch Jetty reading directly from your build tree -- no need to package a war file or deploy. It even has a scanInterval setting: put this to a non-zero value and it will watch your java files and various config files for changes and automatically re-deploy a few seconds after you make a change.

There's just one thing keeping me from nirvana. I have javascript and css files in my src/main/webapp directory which just get served up by Jetty. I would like to be able to edit these and have the changes show up when I refresh the page in the browser. Unfortunately, Jetty holds these files open so I can't (on Windows) modify them while it is running.

Does anyone know how to make Jetty let go of these files so I can edit them, then serve up the edited files for subsequent requests?

Nativeborn answered 8/10, 2008 at 18:57 Comment(0)
F
18

Jetty uses memory-mapped files to buffer static content, which causes the file-locking in Windows. Try setting useFileMappedBuffer for DefaultServlet to false.

Troubleshooting Locked files on Windows (from the Jetty wiki) has instructions.

Faggoting answered 9/10, 2008 at 2:13 Comment(4)
Thanks! that's exactly what I wanted. I would mark this as the "accepted" answer if stackoverflow would allow it (I'm not sure why it won't).Nativeborn
I tried those instructions, and after a bit of fiddling (mostly figuring out how to specify in my POM that I was using a customized webdefault.xml file) I got it working. Thanks again.Nativeborn
This answer does not work anyt more for Jetty 8. I tested in 8.1.9 and 8.1.10, even though I did have it working in Jetty 7. I will post another answer to avoid the problem in Jetty 8.1.10, and probably other versions too.Trinia
Not using nio like @FUD is more simple.Ormand
C
16

While one of the answers above is exactly right for configuring jetty by xml, if you want to configure this option in code (for an embedded server) the answer is different and not found on that page.

You'll find a number of suggestions online including

context.getInitParams().put("useFileMappedBuffer", "false");

Or overriding the WebAppContext, or using a fully qualified name for the init parameter. None of these suggestions worked for me (using Jetty 7.2.2). Part of the problem was that the useFileMappedBuffer option needs to be set on the servlet that the WebAppContext is using to serve the static files, rather than on the context.

In the end I did something like this on a straightforward ServletContextHandler

// Startup stuff
final Server server = new Server(port);
ServletContextHandler handler = new ServletContextHandler();
handler.setResourceBase(path);

SessionManager sm = new HashSessionManager();
SessionHandler sh = new SessionHandler(sm);
handler.setSessionHandler(sh);

DefaultServlet defaultServlet = new DefaultServlet();
ServletHolder holder = new ServletHolder(defaultServlet);
holder.setInitParameter("useFileMappedBuffer", "false");
handler.addServlet(holder, "/");

server.setHandler(handler);
server.start();
server.join();
Christcross answered 13/2, 2011 at 17:37 Comment(7)
Exacly what I am looking for! Do you have a link to a full exemple?Mcshane
Fraid not, I found it by a mixture of trial and error, and haven't found anyone else explain how to do it. I have a full example that I've created myself (that does jsps, request logging and configures some mimetypes etc), but if you want a little more, I'll add a bit more to the example above.Christcross
The new example is perfect. I had something similar. If I can't get it to work, I'll ask a new question.Mcshane
If you set the parameter on the context, you have to prefix the key with "org.eclipse.jetty.servlet.Default.", so this works for me: webAppContext.setInitParameter("org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false");. Works for me with Jetty 8.1.4.Sanatorium
When I first wrote this code I saw lots of reference online to prefixed parameters and non prefixed parameters. I tried both, and could only get the code I show to work, but presumably it changed between 7.2.2 and 8.1.4. Thanks for the heads up.Christcross
This is what I was writing at the time I was looking for this: github.com/kybernetikos/QuickJettyChristcross
this works but it makes you add some non production junk code.Hessian
L
10

Although this is a Old problem but i found this post very helpful, in short just change your config to

            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <configuration>
                <connectors>
                    <connector implementation="org.eclipse.jetty.server.bio.SocketConnector">
                        <port>8080</port>
                    </connector>
                </connectors>
                </configuration>
            </plugin>

This disables the NIO support in Jetty ( but it should not be problem for debug puropse for simple cases ).

Lavabo answered 12/6, 2012 at 20:34 Comment(2)
This is simple. I don't want to hassle with useFileMappedB‌uffer setting and webdefault.xml. Works great.Ormand
According to GrepCode, the org.eclipse.jetty.server.bio.SocketConnector class exists only for Jetty 7 and Jetty 8.Brashy
B
7

Jetty 9.2 documentation gives a Jetty Embedded example to serve static files using a ResourceHandler instead of a servlet :

// Create a basic Jetty server object that will listen on port 8080.  Note that if you set this to port 0
// then a randomly available port will be assigned that you can either look in the logs for the port,
// or programmatically obtain it for use in test cases.
Server server = new Server(8080);

// Create the ResourceHandler. It is the object that will actually handle the request for a given file. It is
// a Jetty Handler object so it is suitable for chaining with other handlers as you will see in other examples.
ResourceHandler resource_handler = new ResourceHandler();
// Configure the ResourceHandler. Setting the resource base indicates where the files should be served out of.
// In this example it is the current directory but it can be configured to anything that the jvm has access to.
resource_handler.setDirectoriesListed(true);
resource_handler.setWelcomeFiles(new String[]{ "index.html" });
resource_handler.setResourceBase(".");

// Add the ResourceHandler to the server.
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
server.setHandler(handlers);

// Start things up! By using the server.join() the server thread will join with the current thread.
// See "http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()" for more details.
server.start();
server.join();

Jetty uses NIO (in-memory file mapping) and thus locks files on Windows operating systems. This is a known issue and many workarounds can be found for servlets.

However, as this example does not rely on servlets, the associated answers based on webapp parameters (useFileMappedBuffer, maxCachedFiles) do not work.

In order to prevent in-memory file mapping, you need to add the following configuration line:

resource_handler.setMinMemoryMappedContentLength(-1);

Note: as written in the Javadoc (and noticed by nimrodm) : the minimum size in bytes of a file resource that will be served using a memory mapped buffer, or -1 for no memory mapped buffers. I however got the same behavior with value Integer.MAX_VALUE.

Once this parameter is set, your Jetty can serve static files on Windows AND you can edit them.

Brashy answered 21/5, 2015 at 20:45 Comment(3)
Thats the only solution that worked great for me with Embedded Jetty 9 with using various handlers like resource_handler with gzip.Adoration
The Jetty documentation says that passing "-1" to setMin..Length should disable memory mapping (personally I haven't managed to make it work either way...)Aldo
@nimrodm: you are correct, thus I improved the answer.Brashy
W
5

Setting false to useFileMappedBuffer in webdefault.xml did NOT work for me (Jetty 8.1.10.v20130312). Fortunately setting maxCachedFiles to 0 (also in webdefault.xml) did the trick.

Wilcox answered 27/5, 2013 at 14:40 Comment(1)
Thanks dude! This method worked for me as well. I am using Jetty Embedded 8.1.9 WebAppContext root = new WebAppContext(); root.setInitParameter("org.eclipse.jetty.servlet.Default.maxCachedFiles", "0"); with useFileMappedBuffer nothing happenedStroboscope
H
5

I also had this problem.

And I didn't want to create any additional classes and messing with web.xml

So here is what you can do:

Assuming you project is maven based and (lets say) called 'my-web-app'

  1. create a file my-web-app/jetty/jetty-config.xml

  2. put this stuff inside:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configure class="org.eclipse.jetty.webapp.WebAppContext">
       <Call name="setInitParameter">
         <Arg>org.eclipse.jetty.servlet.Default.useFileMappedBuffer</Arg>
         <Arg>false</Arg>
       </Call>
    </Configure>
    
  3. Here is your jetty config:

    <plugin>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <configuration>
            <httpConnector>
                <host>localhost</host>
                <port>8801</port>
            </httpConnector>
            <webApp>
                <contextPath>/${project.artifactId}</contextPath>
            </webApp>
            <contextXml>${project.basedir}/jetty/jetty-config.xml</contextXml>
        </configuration>
    </plugin>
    

This solution will add an attribute to you servlet-context which will disable static resources locking.

Have fun :)

Hessian answered 8/3, 2016 at 9:2 Comment(1)
Thank you! Works great for jetty-maven-plugin 9.3.10.v20160621!Firewood
O
4

Similar to @kybernetikos answer, but without having to recreate the DefaultServlet:

// Startup stuff
final Server server = new Server(port);
WebAppContext webAppContext = new WebAppContext(path, "/")
webAppContext.setInitParam(
        "org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false");

server.setHandler(webAppContext);
server.start();
server.join();

DefaultServlet will look for it's own copy of useFileMappedBuffer, which seems to be set deep inside of Jetty. But by prefixing the property name with as above, this value is preferred.

Oldenburg answered 1/9, 2014 at 15:14 Comment(0)
T
0

When using embedded Jetty 8.1.10, the 'useFileMappedBuffer=false' setting doesn't work any mode. I read the code for DefaultServlet, and it reads the property but it's not used for anything.

Instead I looked at where the buffer creation was configured, and found I could subclass SelectChannelConnector to get the benefits of Continuation, but without locking files on windows. If you simply use org.mortbay.jetty.bio.SocketConnector, then you will not get continuation support.

Here is my example:

import org.eclipse.jetty.io.Buffers.Type;
import org.eclipse.jetty.server.nio.SelectChannelConnector;

/**
 * A Connector that has the advantages NIO, but doesn't lock files in Windows by
 * avoiding memory mapped buffers.
 * <p> 
 * It used to be that you could avoid this problem by setting "useFileMappedBuffer" as described in 
 * https://mcmap.net/q/491028/-how-to-make-jetty-dynamically-load-quot-static-quot-pages
 * However that approach doesn't seem to work in newer versions of jetty.
 * 
 * @author David Roussel
 * 
 */
public class SelectChannelConnectorNonLocking extends SelectChannelConnector {

    public SelectChannelConnectorNonLocking() {
        super();

        // Override AbstractNIOConnector and use all indirect buffers
        _buffers.setRequestBufferType(Type.INDIRECT);
        _buffers.setRequestHeaderType(Type.INDIRECT);
        _buffers.setResponseBufferType(Type.INDIRECT);
        _buffers.setResponseHeaderType(Type.INDIRECT);
    }
}

I've tested this for the locking problem, and it fixes the problem. I've not tested that it works with Continuations yet.

Trinia answered 26/4, 2013 at 11:30 Comment(1)
P
-1

When using IntelliJ and Jetty 9 with a ResourceHandler one of the solutions is to edit the static content in the target directory, instead of the source file.

Pothook answered 10/10, 2015 at 14:59 Comment(1)
The problem is no way related to IDE.Foreside
H
-16

It is probably the browser that is holding on to it.

inside I.E : Tools | Internet Options | Temporary Internet Files > Settings, click the Radio button "Every visit to the page". press OK.

Before you do that, Delete all the temporary internet files.

Howitzer answered 8/10, 2008 at 19:44 Comment(2)
I think he's talking about windows/jetty locking the files so they can't be edited.Twinkle
This answer is completely incorrect. I would down-vote, but cannot.Thermic

© 2022 - 2024 — McMap. All rights reserved.