sirius.web.http.WebDispatcher Maven / Gradle / Ivy
Show all versions of sirius-web Show documentation
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/
package sirius.web.http;
import sirius.kernel.commons.Callback;
import sirius.kernel.di.std.Priorized;
import java.util.function.Consumer;
/**
* Participates in the dispatching process for incoming HTTP requests.
*
* Once a HTTP request is fully read by the server it is dispatched calling all available WebDispatcher
* instances available. To provide a WebDispatcher, a subclass therefore needs to wear an
* {@link sirius.kernel.di.std.Register} annotation.
*
* As the first request arrives, all dispatchers are asked for their priority (via {@link #getPriority()} and
* then sorted according to that in an ascending manner. As default priority
* {@link sirius.kernel.commons.PriorityCollector#DEFAULT_PRIORITY} can be used. Note that this will only be done
* once, therefore getPriority() must only return a constant value as it is never re-evaluated. By default,
* a not found handler ({@link sirius.web.dispatch.DefaultDispatcher} is registered with 999 as priority, so higher
* priorities will never be executed.
*
* For each incoming request, the list of dispatchers is iterated and {@link #dispatch(WebContext)} is invoked
* until one of those returns true, to signal that the request was handled.
*
* The dispatchers are invoked in a separate thread so that blocking operations will not block the web-server itself.
*
* If a dispatcher is willing to handle all incoming data (payload of a PUT or POST request) by itself - instead of
* just accumulating this data in memory or on disk, the {@link #preparePreDispatch(WebContext)} method must return
* an appropriate handler for a given request. This needs to install a {@link ContentHandler}. Note that no further
* {@link #dispatch(WebContext)} will be called for a request which received a true for its call
* to {@link #preparePreDispatch(WebContext)}.
*
* Note that {@link #preparePreDispatch(WebContext)} will be invoked within the event loop of the web-server, therefore
* absolutely no blocking operations must be performed. However, the returned Callback is executed in its own
* thread and free of any constraints.
*
*
* @see WebServerHandler
*/
public interface WebDispatcher extends Priorized {
/**
* Returns the priority to determine the position in the dispatcher list.
*
* Dispatchers are sorted ascending (lower is better). The default priority is
* {@link sirius.kernel.commons.PriorityCollector#DEFAULT_PRIORITY}, the max. value is 998 as everything above
* will be handled by the {@link sirius.web.dispatch.DefaultDispatcher}.
*
* @return the priority of the dispatcher
*/
@Override
int getPriority();
/**
* Invoked as soon as the complete request but not its contents are available.
*
* In contrast to {@link #dispatch(WebContext)} this method is invoked before the complete data is accumulated.
* This permits the handler to install an {@link ContentHandler} using {@link WebContext#setContentHandler(ContentHandler)}
* in order to directly process the uploaded data. A request for which true was replied will not
* be dispatched again once it is complete.
*
* Note thatthis method will be invoked within the event loop of the web-server, therefore absolutely no blocking
* operations must be performed. However, the returned Callback is executed in its own thread and free of
* any constraints.
*
* @param ctx the request to handle
* @return the handler which will install the ContentHandler and eventually process the request or
* null to indicate that no pre-dispatching is possible.
* @see sirius.web.controller.ControllerDispatcher#preparePreDispatch(WebContext)
*/
default Callback preparePreDispatch(WebContext ctx) {
return null;
}
/**
* Invoked in order to handle the given request.
*
* If the dispatcher doesn't feel responsible for handling the request, it simply invokes nextStage.
*
* Note that no blocking operation must be performed in this method. For any complex interaction, a new thread
* should be forked using {@link sirius.kernel.async.Tasks#executor(String)}. Note that even
* {@link Response#outputStream(io.netty.handler.codec.http.HttpResponseStatus, String)} might
* block sooner or later to limit heap memory usage - so fork a thread for any serious work besides checking
* responsibilities for handling requests.
*
* @param ctx the request to handle
* @param startOfPipeline the start of the pipeline in order
* @param nextStage the next stage to forward the request to in case the dispatcher isn't interested
* @throws Exception in case of an error when parsing or dispatching the request
*/
default void dispatch(WebContext ctx, Consumer startOfPipeline, Consumer nextStage)
throws Exception {
if (!dispatch(ctx)) {
nextStage.accept(ctx);
}
}
/**
* Invoked in order to handle the given request.
*
* If the dispatcher doesn't feel responsible for handling the request, it simply returns false. Otherwise
* if the request is being handled, true must be returned
*
* Note that no blocking operation must be performed in this method. For any complex interaction, a new thread
* should be forked using {@link sirius.kernel.async.Tasks#executor(String)}. Note that even
* {@link Response#outputStream(io.netty.handler.codec.http.HttpResponseStatus, String)} might
* block sooner or later to limit heap memory usage - so fork a thread for any serious work besides checking
* responsibilities for handling requests.
*
* @param ctx the request to handle
* @return true if the request was handled by this dispatcher, false otherwise.
* @throws Exception in case of an error when parsing or dispatching the request
*/
boolean dispatch(WebContext ctx) throws Exception;
}