In porting my app to jetty 12 I've encountered an issue: I can't find HandlerCollection or a replacement for it.
The structure of the handler tree is with a HandlerCollection containing three child Handlers, all being run sequentially:
private void setup() {
Server server = new Server();
//...
HandlerCollection root = new HandlerCollection();
server.setHandler(root);
root.addHandler(new GreeterHandler(this));
// Create a ContextHandlerCollection to hold contexts
ContextHandlerCollection ctxCol = new ContextHandlerCollection();
root.addHandler(ctxCol);
addHandler(ctxCol, "/", new IndexHandler(this));
addHandler(ctxCol, "/submit", new SubmitHandler(this));
addHandler(ctxCol, "/api", new ApiHandler(this));
addHandler(ctxCol, "/user", new UserProfileHandler(this));
addHandler(ctxCol, "/login", new LoginHandler(this));
addHandler(ctxCol, "/logout", new LogoutHandler(this));
addHandler(ctxCol, "/list", new ListHandler(this));
// the rest of the /public folder
ResourceHandler publicFilesHandler = new ResourceHandler();
publicFilesHandler.setBaseResourceAsString("res/public/");
publicFilesHandler.setDirAllowed(false);
MimeTypes types = new MimeTypes.Mutable();
types.getMimeMap().put("js", "text/javascript; charset=utf-8");
types.getMimeMap().put("css", "text/css; charset=utf-8");
publicFilesHandler.setMimeTypes(types);
addHandler(ctxCol,"/files", publicFilesHandler);
root.addHandler(new LoggingHandler(this));
}
private void addHandler(ContextHandlerCollection handlerCollection, String contextPath, Handler.Abstract handler) {
ContextHandler newContext = new ContextHandler(contextPath);
newContext.setHandler(handler);
handlerCollection.addHandler(newContext);
}
I see that Handler.Sequence is close to what I'm looking for, but it will stop the request from going further down the tree when a handler returns true. The programming guide says ContextHandlerCollection will return true once it found a Handler to process the request. I expect the children of ContextHandlerCollection to return true as well. Will that not prevent the LoggingHandler from running?
How can I make sure all three children run for each request?
There is a migration document you can use at
https://eclipse.dev/jetty/documentation/jetty-12/programming-guide/index.html#pg-migration-11-to-12
The HandlerCollection
was moved to org.eclipse.jetty.server.Handler.Sequence
.
But that's not appropriate for you seem to be using ContextHandler
children.
You should instead use the org.eclipse.jetty.server.handler.ContextHandlerCollection
to add a context.
But even then, using either of those is overly complicated for what they do.
Instead, you should use the org.eclipse.jetty.server.handler.PathMappingsHandler
.
Your code would look like this ...
Server server = new Server();
//...
Handler.Sequence root = new Handler.Sequence();
server.setHandler(root);
root.addHandler(new GreeterHandler(this));
PathMappingsHandler pathMappingsHandler = new PathMappingsHandler();
root.addHandler(pathMappingsHandler);
pathMappingsHandler.addMapping(PathSpec.from("/"), new IndexHandler(this));
pathMappingsHandler.addMapping(PathSpec.from("/submit/*"), new SubmitHandler(this));
pathMappingsHandler.addMapping(PathSpec.from("/api/*"), new ApiHandler(this));
pathMappingsHandler.addMapping(PathSpec.from("/user/*"), new UserProfileHandler(this));
pathMappingsHandler.addMapping(PathSpec.from("/login/*"), new LoginHandler(this));
pathMappingsHandler.addMapping(PathSpec.from("/logout/*"), new LogoutHandler(this));
pathMappingsHandler.addMapping(PathSpec.from("/list/*"), new ListHandler(this));
// the rest of the /public folder
ResourceHandler publicFilesHandler = new ResourceHandler();
publicFilesHandler.setBaseResourceAsString("res/public/");
publicFilesHandler.setDirAllowed(false);
MimeTypes types = new MimeTypes();
types.getMimeMap().put("js", "text/javascript; charset=utf-8");
types.getMimeMap().put("css", "text/css; charset=utf-8");
publicFilesHandler.setMimeTypes(types);
pathMappingsHandler.addMapping(PathSpec.from("/files/*"), publicFilesHandler);
// TODO: you might want to implement server.setRequestLog(new MyLoggingHandler(this)) instead of the following...
root.addHandler(new LoggingHandler(this));
// this final handler will only be called for non-path requests due
// to the existence of a root handler. Either implement this as
// a Handler.Wrapper that wraps the whole request tree, or use
// a RequestLog implementation.
Note: there are 3 different PathSpec implementations that ship with Jetty.
UriTemplatePathSpec
implements RFC6570 URI Template (level 1)RegexPathSpec
allows arbitrary java.util.regex.Pattern
to be used to match pathsServletPathSpec
implements the servlet path spec behaviors.You can mix/match any of the above in a single PathMappingsHandler
.