This would be problematic.
The JAR itself would change.
The runtime would not see the change (as JAR contents are cached in Java)
The binary would need to be restart to pick up the changes.
If you have content that can change at runtime, either put that content outside of the jar in the filesystem, or provide a filesystem override for static jar contents.
For serving content outside of the JAR, see prior answer ...
Serving static files from alternate path in embedded Jetty
For having alternate paths for override, just use a org.eclipse.jetty.util.resource.ResourceCollection
for your context.setBaseResource()
Like this ...
package jetty;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
public class ResourceCollectionDefaultServlet
{
public static void main(String[] args) throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);
// Jar Resource
String resourceExample = "/webroot/index.html";
URL jarUrl = server.getClass().getResource(resourceExample);
if(jarUrl == null)
{
throw new FileNotFoundException("Unable to find JAR Resource: " + resourceExample);
}
URI jarUriBase = jarUrl.toURI().resolve("./");
Resource jarResource = Resource.newResource(jarUriBase);
// FileSystem Resource
// Example here uses Path: $TEMP/resource/
// You can pick a location on disk of your own choice (use a System property if you want)
Path fsPath = new File(System.getProperty("java.io.tmpdir")).toPath().resolve("resource");
if(!Files.exists(fsPath))
Files.createDirectory(fsPath);
Resource fsResource = new PathResource(fsPath);
// Resource Collection
ResourceCollection resourceCollection = new ResourceCollection(
fsResource, // check FileSystem first
jarResource // fall back to jar for all content not on filesystem
);
System.out.println("Resource Collection: " + resourceCollection);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.setBaseResource(resourceCollection);
server.setHandler(context);
context.setWelcomeFiles(new String[] { "index.html" });
// TODO: Your servlets and filters here
// Lastly, the default servlet for root content (always needed, to satisfy servlet spec)
// It is important that this is last.
ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class);
holderPwd.setInitParameter("dirAllowed","true");
context.addServlet(holderPwd,"/");
server.setDumpAfterStart(true);
server.start();
server.join(); // wait on server to stop
}
}
This sets up a ResourceCollection
with 2 entries.
- Check the FileSystem first
$TEMP/resource/<requestedResource>
- Check the JAR file
$JARBASEURI/<requestedResource>
The output of above tells you how it works.
The server dump has details of what the ServletContextHandler
resource base is running with.
2018-04-27 10:25:02.314:INFO::main: Logging initialized @338ms to org.eclipse.jetty.util.log.StdErrLog
Resource Collection: [file:///C:/Users/joakim/AppData/Local/Temp/resource/, jar:file:///C:/code/jetty-examples/target/project.jar!/webroot/]
2018-04-27 10:25:02.422:INFO:oejs.Server:main: jetty-9.4.9.v20180320; built: 2018-03-20T07:21:10-05:00; git: 1f8159b1e4a42d3f79997021ea1609f2fbac6de5; jvm 9.0.4+11
2018-04-27 10:25:02.477:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@13c10b87{/,[file:///C:/Users/joakim/AppData/Local/Temp/resource/, jar:file:///C:/code/jetty-examples/target/project.jar!/webroot/],AVAILABLE}
2018-04-27 10:25:02.609:INFO:oejs.AbstractConnector:main: Started ServerConnector@c267ef4{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
org.eclipse.jetty.server.Server@473b46c3[9.4.9.v20180320] - STARTING
...(snip)...
+= o.e.j.s.ServletContextHandler@13c10b87{/,[file:///C:/Users/joakim/AppData/Local/Temp/resource/, jar:file:///C:/code/jetty-examples/target/project.jar!/webroot/],AVAILABLE} - STARTED
| += org.eclipse.jetty.servlet.ServletHandler@1aa7ecca - STARTED
| | += default@5c13d641==org.eclipse.jetty.servlet.DefaultServlet,jsp=null,order=-1,inst=false - STARTED
| | | +- dirAllowed=true
| | +- [/]=>default
| +> No ClassLoader
| +> Handler attributes o.e.j.s.ServletContextHandler@13c10b87{/,[file:///C:/Users/joakim/AppData/Local/Temp/resource/, jar:file:///C:/code/jetty-examples/target/project.jar!/webroot/],AVAILABLE}
| | +- org.eclipse.jetty.server.Executor=QueuedThreadPool[qtp1018298342]@3cb1ffe6{STARTED,8<=8<=200,i=3,q=0}
| +> Context attributes o.e.j.s.ServletContextHandler@13c10b87{/,[file:///C:/Users/joakim/AppData/Local/Temp/resource/, jar:file:///C:/code/jetty-examples/target/project.jar!/webroot/],AVAILABLE}
| | +- org.eclipse.jetty.util.DecoratedObjectFactory=org.eclipse.jetty.util.DecoratedObjectFactory[decorators=1]
| +> Initparams o.e.j.s.ServletContextHandler@13c10b87{/,[file:///C:/Users/joakim/AppData/Local/Temp/resource/, jar:file:///C:/code/jetty-examples/target/project.jar!/webroot/],AVAILABLE}
2018-04-27 10:25:02.651:INFO:oejs.Server:main: Started @682ms
In this execution I can see that the ResourceCollection
has 2 bases.
- FileSystem Base:
file:///C:/Users/joakim/AppData/Local/Temp/resource/
- Jar Base:
jar:file:///C:/code/jetty-examples/target/project.jar!/webroot/
So if a request arrives for say https://myapp.com/js/config.js
then the following happens ...
- Does
file:///C:/Users/joakim/AppData/Local/Temp/resource/js/config.js
exist? If so, serve it.
- Does
jar:file:///C:/code/jetty-examples/target/project.jar!/webroot/js/config.js
exist? If so, serve it.
- Report 404 Not Found