public interface HandlerDecorator
Handler decorators can be used to contribute to the handler chain from the server registry
.
It is often used by libraries/extensions to participate in request handling in order to set up infrastructure for downstream handlers.
The prepend(Handler)
method is a convenient way to create a decorator that simply prepends a given handler to the application handlers.
import ratpack.handling.Handler;
import ratpack.handling.HandlerDecorator;
import ratpack.handling.Context;
import ratpack.util.Types;
import ratpack.test.embed.EmbeddedApp;
import static junit.framework.Assert.*;
import java.util.LinkedList;
import java.util.Arrays;
public class Example {
public static class AddListToRequestRegistry implements Handler {
public void handle(Context context) {
context.getRequest().add(Types.listOf(String.class), new LinkedList<String>());
context.next();
}
}
public static class AddStringToList implements Handler {
private final String string;
public AddStringToList(String string) { this.string = string; }
public void handle(Context ctx) {
ctx.getRequest().get(Types.listOf(String.class)).add(string);
ctx.next();
}
}
public static void main(String... args) throws Exception {
EmbeddedApp.of(s -> s
.registryOf(r -> r
.add(HandlerDecorator.prepend(new AddListToRequestRegistry()))
.add(HandlerDecorator.prepend(new AddStringToList("foo")))
.add(HandlerDecorator.prepend(new AddStringToList("bar")))
)
.handler(r ->
ctx -> ctx.render(ctx.getRequest().get(Types.listOf(String.class)).toString())
)
).test(httpClient ->
assertEquals(Arrays.asList("foo", "bar").toString(), httpClient.getText())
);
}
}
Handler decorators can't do anything that handlers can't do. In the above example, the same result could have been achieved by just using the handler implementations. Decorators are usually more useful when using something like Guice and where it is desired for a module to contribute handlers.
import ratpack.handling.Handler;
import ratpack.handling.HandlerDecorator;
import ratpack.handling.Context;
import ratpack.registry.Registry;
import ratpack.test.embed.EmbeddedApp;
import ratpack.guice.Guice;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.multibindings.Multibinder;
import static junit.framework.Assert.*;
import java.util.LinkedList;
import java.util.Arrays;
public class Example {
public static class MaintenanceWindow {
public boolean active = true;
}
public static class HandlerDecoratorImpl implements HandlerDecorator {
private final MaintenanceWindow maintenanceWindow;
{@literal @}Inject
public HandlerDecoratorImpl(MaintenanceWindow maintenanceWindow) {
this.maintenanceWindow = maintenanceWindow;
}
public Handler decorate(Registry serverRegistry, Handler rest) {
return ctx -> {
if (maintenanceWindow.active) {
ctx.render("down for maintenance!");
} else {
ctx.insert(rest);
}
};
}
}
public static class MaintenanceWindowModule extends AbstractModule {
protected void configure() {
bind(MaintenanceWindow.class);
// Important to use a multi binding to allow other modules to also contribute handlers
Multibinder.newSetBinder(binder(), HandlerDecorator.class).addBinding().to(HandlerDecoratorImpl.class);
}
}
public static void main(String... args) throws Exception {
EmbeddedApp.of(s -> s
.registry(Guice.registry(b -> b
.module(MaintenanceWindowModule.class)
))
.handler(r ->
ctx -> ctx.render("ok!")
)
).test(httpClient -> {
assertEquals("down for maintenance!", httpClient.getText());
});
}
}
Handler decorators are invoked in the reverse order in which they are defined in the server registry. That is, the reverse of the order that they were added to the server registry. This means that earlier decorators decorate the handlers returned by later decorators. Said another way, the handler returned by the first decorator returned from the server registry will be the first handler to handle requests.
Modifier and Type | Method and Description |
---|---|
Handler |
decorate(Registry serverRegistry,
Handler rest)
Creates a new handler that decorates the application handlers, given as the
rest argument. |
static HandlerDecorator |
prepend(Handler handler)
A factory for decorator impls that effectively inserts the given handler before the “rest” of the handlers.
|
Handler decorate(Registry serverRegistry, Handler rest) throws Exception
rest
argument.
As the rest
argument encapsulates the application handlers, the returned handler should generally delegate to it (via Context.insert(Handler...)
).
serverRegistry
- the server registryrest
- the rest of the handlers of the applicationException
- anystatic HandlerDecorator prepend(Handler handler)
The given handler should call Context.next()
to delegate to the rest of the handlers.
handler
- the handler to prepend