ratpack.handling.Context Maven / Gradle / Ivy
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ratpack.handling;
import com.google.common.base.Predicate;
import com.google.common.reflect.TypeToken;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import ratpack.api.NonBlocking;
import ratpack.api.Nullable;
import ratpack.exec.*;
import ratpack.func.Action;
import ratpack.handling.direct.DirectChannelAccess;
import ratpack.http.Request;
import ratpack.http.Response;
import ratpack.launch.LaunchConfig;
import ratpack.parse.NoSuchParserException;
import ratpack.parse.Parse;
import ratpack.parse.ParserException;
import ratpack.path.PathTokens;
import ratpack.registry.NotInRegistryException;
import ratpack.registry.Registry;
import ratpack.render.NoSuchRendererException;
import ratpack.server.BindAddress;
import java.nio.file.Path;
import java.util.Date;
import java.util.concurrent.Callable;
/**
* The context of an individual {@link Handler} invocation.
*
* It provides:
*
* - Access the HTTP {@link #getRequest() request} and {@link #getResponse() response}
* - Delegation (via the {@link #next} and {@link #insert} family of methods)
* - Access to contextual objects (see below)
* - Convenience for common handler operations
*
*
* Contextual objects
*
* A context is also a {@link Registry} of objects.
* Arbitrary objects can be "pushed" into the context for use by downstream handlers.
*
* There are some significant contextual objects that drive key infrastructure.
* For example, error handling is based on informing the contextual {@link ratpack.error.ServerErrorHandler} of exceptions.
* The error handling strategy for an application can be changed by pushing a new implementation of this interface into the context that is used downstream.
*
* See {@link #insert(Handler...)} for more on how to do this.
*
Default contextual objects
* There is also a set of default objects that are made available via the Ratpack infrastructure:
*
* - The effective {@link ratpack.launch.LaunchConfig}
* - A {@link ratpack.file.FileSystemBinding} that is the application {@link ratpack.launch.LaunchConfig#getBaseDir()}
* - A {@link ratpack.file.MimeTypes} implementation
* - A {@link ratpack.error.ServerErrorHandler}
* - A {@link ratpack.error.ClientErrorHandler}
* - A {@link ratpack.file.FileRenderer}
* - A {@link ratpack.server.BindAddress}
* - A {@link ratpack.server.PublicAddress}
* - A {@link Redirector}
*
*/
public interface Context extends ExecControl, Registry {
/**
* Returns this.
*
* @return this.
*/
Context getContext();
/**
* The execution of handling this request.
*
* @return the execution of handling this request
*/
Execution getExecution();
LaunchConfig getLaunchConfig();
/**
* The HTTP request.
*
* @return The HTTP request.
*/
Request getRequest();
/**
* The HTTP response.
*
* @return The HTTP response.
*/
Response getResponse();
/**
* Delegate handling to the next handler in line.
*
* The request and response of this object should not be accessed after this method is called.
*/
@NonBlocking
void next();
/**
* Invokes the next handler, after adding the given registry.
*
* The given registry is appended to the existing.
* This means that it can shadow objects previously available.
*
* import ratpack.handling.Handler;
* import ratpack.handling.Handlers;
* import ratpack.handling.Chain;
* import ratpack.handling.ChainAction;
* import ratpack.handling.Context;
* import ratpack.launch.HandlerFactory;
* import ratpack.launch.LaunchConfig;
* import ratpack.launch.LaunchConfigBuilder;
* import ratpack.func.Factory;
*
* import static ratpack.registry.Registries.just;
*
* public interface SomeThing {}
* public class SomeThingImpl implements SomeThing {}
*
* public class UpstreamHandler implements Handler {
* public void handle(Context context) {
* context.next(just(SomeThing.class, new SomeThingImpl()));
* }
* }
*
* public class DownstreamHandler implements Handler {
* public void handle(Context context) {
* SomeThing someThing = context.get(SomeThing.class); // instance provided upstream
* assert someThing instanceof SomeThingImpl;
* // …
* }
* }
*
* LaunchConfigBuilder.baseDir(new File("base")).build(new HandlerFactory() {
* public Handler create(LaunchConfig launchConfig) {
* return Handlers.chain(launchConfig, new ChainAction() {
* protected void execute() {
* handler(new UpstreamHandler());
* handler(new DownstreamHandler());
* }
* });
* }
* });
*
*
* @param registry The registry to make available for subsequent handlers.
*/
@NonBlocking
void next(Registry registry);
/**
* Inserts some handlers into the pipeline, then delegates to the first.
*
* The request and response of this object should not be accessed after this method is called.
*
* @param handlers The handlers to insert.
*/
@NonBlocking
void insert(Handler... handlers);
/**
* Inserts some handlers into the pipeline to execute with the given registry, then delegates to the first.
*
* The given registry is only applicable to the inserted handlers.
*
* Almost always, the registry should be a super set of the current registry.
*
* @param handlers The handlers to insert
* @param registry The registry for the inserted handlers
*/
@NonBlocking
void insert(Registry registry, Handler... handlers);
/**
* Respond to the request based on the request method.
*
*
* import ratpack.handling.Handler;
* import ratpack.handling.Context;
* import ratpack.handling.ByMethodSpec;
* import ratpack.func.Action;
*
* import ratpack.test.UnitTest;
* import ratpack.test.handling.HandlingResult;
* import ratpack.test.handling.RequestFixture;
*
* public class Example {
*
* public static class MultiMethodHandler implements Handler {
* public void handle(final Context context) throws Exception {
* final String message = "hello!";
*
* context.byMethod(new Action<ByMethodSpec>() {
* public void execute(ByMethodSpec spec) {
* spec.get(new Handler() {
* public void handle(Context context) {
* context.render(message + " from GET request");
* }
* }).
* post(new Handler() {
* public void handle(Context context) {
* context.render(message + " from POST request");
* }
* });
* }
* });
* }
* }
*
* public static void main(String[] args) {
* Handler handler = new MultiMethodHandler();
*
* HandlingResult result = UnitTest.handle(handler, new Action<RequestFixture>() {
* public void execute(RequestFixture fixture) {
* fixture.method("get");
* }
* });
* assert result.rendered(String.class).equals("hello! from GET request");
*
* result = UnitTest.handle(handler, new Action<RequestFixture>() {
* public void execute(RequestFixture fixture) {
* fixture.method("post");
* }
* });
* assert result.rendered(String.class).equals("hello! from POST request");
* }
*
* }
*
*
*
* Only the last added handler for a method will be used.
* Adding a subsequent handler for the same method will replace the previous.
*
*
* If no handler has been registered for the actual request method, a {@code 405} will be issued by {@link #clientError(int)}.
*
* If the handler only needs to respond to one HTTP method it can be more convenient to use {@link Chain#get(Handler)} and friends.
*
* @param action the specification of how to handle the request based on the request method
* @throws Exception any thrown by action
*/
@NonBlocking
void byMethod(Action super ByMethodSpec> action) throws Exception;
/**
* Respond to the request based on the requested content type (i.e. the request Accept header).
*
* This is useful when a given handler can provide content of more than one type (i.e. content negotiation).
*
* The handler to use will be selected based on parsing the "Accepts" header, respecting quality weighting and wildcard matching.
* The order that types are specified is significant for wildcard matching.
* The earliest registered type that matches the wildcard will be used.
*
*
* import ratpack.handling.Handler;
* import ratpack.handling.Context;
* import ratpack.handling.ByContentSpec;
* import ratpack.func.Action;
*
* import ratpack.test.UnitTest;
* import ratpack.test.handling.HandlingResult;
* import ratpack.test.handling.RequestFixture;
*
* public class Example {
*
* public static class ContentNegotiatingHandler implements Handler {
* public void handle(final Context context) throws Exception {
* final String message = "hello!";
*
* context.byContent(new Action<ByContentSpec>() {
* public void execute(ByContentSpec spec) {
* spec.json(new Handler() {
* public void handle(Context context) {
* context.render("{\"msg\": \"" + message + "\"}");
* }
* }).
* html(new Handler() {
* public void handle(Context context) {
* context.render("<p>" + message + "</p>");
* }
* });
* }
* });
* }
* }
*
* public static void main(String[] args) {
* Handler handler = new ContentNegotiatingHandler();
*
* HandlingResult result = UnitTest.handle(handler, new Action<RequestFixture>() {
* public void execute(RequestFixture fixture) {
* fixture.header("Accept", "application/json");
* }
* });
* assert result.rendered(String.class).equals("{\"msg\": \"hello!\"}");
* assert result.getHeaders().get("Content-Type").equals("application/json");
*
* result = UnitTest.handle(handler, new Action<RequestFixture>() {
* public void execute(RequestFixture fixture) {
* fixture.header("Accept", "text/plain; q=1.0, text/html; q=0.8, application/json; q=0.7");
* }
* });
* assert result.rendered(String.class).equals("<p>hello!</p>");
* assert result.getHeaders().get("content-type").equals("text/html;charset=UTF-8");
* }
*
* }
*
* If there is no type registered, or if the client does not accept any of the given types, a {@code 406} will be issued with {@link Context#clientError(int)}.
*
* Only the last specified handler for a type will be used.
* That is, adding a subsequent handler for the same type will replace the previous.
*
* @param action the specification of how to handle the request based on the clients preference of content type
* @throws Exception any thrown by action
*/
void byContent(Action super ByContentSpec> action) throws Exception;
// Shorthands for common service lookups
/**
* Forwards the exception to the {@link ratpack.error.ServerErrorHandler} in this service.
*
* The default configuration of Ratpack includes a {@link ratpack.error.ServerErrorHandler} in all contexts.
* A {@link NotInRegistryException} will only be thrown if a very custom service setup is being used.
*
* @param throwable The exception that occurred
* @throws NotInRegistryException if no {@link ratpack.error.ServerErrorHandler} can be found in the service
*/
@NonBlocking
void error(Throwable throwable);
/**
* Executes a blocking operation, returning a promise for its result.
*
* This method executes asynchronously, in that it does not invoke the {@code operation} before returning the promise.
* When the returned promise is subscribed to (i.e. its {@link ratpack.exec.SuccessPromise#then(Action)} method is called),
* the given {@code operation} will be submitted to a thread pool that is different to the request handling thread pool.
* Therefore, if the returned promise is never subscribed to, the {@code operation} will never be initiated.
*
* The promise returned by this method, has the same default error handling strategy as those returned by {@link ratpack.exec.ExecControl#promise(ratpack.func.Action)}.
*
*
* import ratpack.handling.*;
* import ratpack.func.Action;
* import java.util.concurrent.Callable;
*
* public class BlockingJavaHandler implements Handler {
* void handle(final Context context) {
* context.blocking(new Callable<String>() {
* public String call() {
* // perform some kind of blocking IO in here, such as accessing a database
* return "hello world!";
* }
* }).then(new Action<String>() {
* public void execute(String result) {
* context.render(result);
* }
* });
* }
* }
*
* public class BlockingGroovyHandler implements Handler {
* void handle(final Context context) {
* context.blocking {
* "hello world!"
* } then { String result ->
* context.render(result)
* }
* }
* }
*
* // Test (Groovy) …
*
* import static ratpack.test.http.TestHttpClients.testHttpClient
* import static ratpack.groovy.test.embed.EmbeddedApplications.embeddedApp
*
* def app = embeddedApp {
* handlers {
* get("java", new BlockingJavaHandler())
* get("groovy", new BlockingGroovyHandler())
* }
* }
*
* def client = testHttpClient(app)
*
* assert client.getText("java") == "hello world!"
* assert client.getText("groovy") == "hello world!"
*
* app.close()
*
*
* @param blockingOperation The operation to perform
* @param The type of result object that the operation produces
* @return a promise for the return value of the callable.
*/
@Override
Promise blocking(Callable blockingOperation);
/**
* Creates a promise of a value that will made available asynchronously.
*
* The {@code action} given to this method receives a {@link Fulfiller}, which can be used to fulfill the promise at any time in the future.
* The {@code action} is not required to fulfill the promise during the execution of the {@code execute()} method (i.e. it can be asynchronous).
* The {@code action} MUST call one of the fulfillment methods.
* Otherwise, the promise will go unfulfilled.
* There is no time limit or timeout on fulfillment.
*
* The promise returned has a default error handling strategy of forwarding exceptions to {@link #error(Throwable)} of this context.
* To use a different error strategy, supply it to the {@link ratpack.exec.Promise#onError(Action)} method.
*
* The promise will always be fulfilled on a thread managed by Ratpack.
*
* import ratpack.handling.*;
* import ratpack.exec.Fulfiller;
* import ratpack.func.Action;
*
* public class PromiseUsingJavaHandler implements Handler {
* public void handle(final Context context) {
* context.promise(new Action<Fulfiller<String>>() {
* public void execute(final Fulfiller<String> fulfiller) {
* new Thread(new Runnable() {
* public void run() {
* fulfiller.success("hello world!");
* }
* }).start();
* }
* }).then(new Action<String>() {
* public void execute(String string) {
* context.render(string);
* }
* });
* }
* }
*
* class PromiseUsingGroovyHandler implements Handler {
* void handle(Context context) {
* context.promise { Fulfiller<String> fulfiller ->
* Thread.start {
* fulfiller.success("hello world!")
* }
* } then { String string ->
* context.render(string)
* }
* }
* }
*
* // Test (Groovy) …
*
* import static ratpack.test.http.TestHttpClients.testHttpClient
* import static ratpack.groovy.test.embed.EmbeddedApplications.embeddedApp
*
* def app = embeddedApp {
* handlers {
* get("java", new PromiseUsingJavaHandler())
* get("groovy", new PromiseUsingGroovyHandler())
* }
* }
*
* def client = testHttpClient(app)
*
* assert client.getText("java") == "hello world!"
* assert client.getText("groovy") == "hello world!"
*
* app.close()
*
* @param the type of value promised
*/
@Override
Promise promise(Action super Fulfiller> action);
/**
* Forks a new execution, detached from the current.
*
* This can be used to launch a one time background job during request processing.
* The forked execution does not inherit anything from the current execution.
*
* Forked executions MUST NOT write to the response or participate in the handler pipeline at all.
* That is, they should not call methods like {@link #next()} or {@link #insert(Handler...)}.
*
* When using forking to process work in parallel, use {@link #promise(ratpack.func.Action)} to continue request handling when the parallel work is done.
*
*
* import ratpack.handling.Handler;
* import ratpack.handling.Context;
* import ratpack.func.Action;
* import ratpack.func.Actions;
* import ratpack.exec.Execution;
* import ratpack.exec.Fulfiller;
*
* import java.util.Collections;
* import java.util.concurrent.atomic.AtomicInteger;
* import java.util.concurrent.atomic.AtomicReference;
*
* import ratpack.test.UnitTest;
* import ratpack.test.handling.HandlingResult;
* import ratpack.test.handling.RequestFixture;
*
* public class Example {
* public static class ForkingHandler implements Handler {
* public void handle(final Context context) {
* final int numJobs = 3;
* final Integer failOnIteration = context.getPathTokens().asInt("failOn");
*
* context.promise(new Action<Fulfiller<Integer>>() {
* private final AtomicInteger counter = new AtomicInteger();
* private final AtomicReference<Throwable> error = new AtomicReference<>();
*
* private void completeJob(Fulfiller<Integer> fulfiller) {
* if (counter.incrementAndGet() == numJobs) {
* Throwable throwable = error.get();
* if (throwable == null) {
* fulfiller.success(numJobs);
* } else {
* fulfiller.error(throwable);
* }
* }
* }
*
* public void execute(final Fulfiller<Integer> fulfiller) {
* for (int i = 0; i < numJobs; ++i) {
* final int iteration = i;
*
* context.fork(new Action<Execution>() {
* public void execute(Execution execution) throws Exception {
* if (failOnIteration != null && failOnIteration.intValue() == iteration) {
* throw new Exception("bang!");
* } else {
* completeJob(fulfiller);
* }
* }
*
*
* }, new Action<Throwable>() {
* public void execute(Throwable throwable) {
* error.compareAndSet(null, throwable); // just take the first error
* completeJob(fulfiller);
* }
* });
* }
* }
* }).then(new Action<Integer>() {
* public void execute(Integer integer) {
* context.render(integer.toString());
* }
* });
* }
* }
*
* public static void main(String[] args) {
* HandlingResult result = UnitTest.handle(new ForkingHandler(), Actions.noop());
* assert result.rendered(String.class).equals("3");
*
* result = UnitTest.handle(new ForkingHandler(), new Action<RequestFixture>() {
* public void execute(RequestFixture fixture) {
* fixture.pathBinding(Collections.singletonMap("failOn", "2"));
* }
* });
*
* assert result.getException().getMessage().equals("bang!");
* }
* }
*
*
* @param action the initial execution segment
*/
@Override
void fork(Action super Execution> action);
@Override
ExecController getController();
@Override
void addInterceptor(ExecInterceptor execInterceptor, Action super Execution> continuation) throws Exception;
@Override
void fork(Action super Execution> action, Action super Throwable> onError);
@Override
void fork(Action super Execution> action, Action super Throwable> onError, Action super Execution> onComplete);
void stream(Publisher publisher, Subscriber super T> subscriber);
/**
* Forwards the error to the {@link ratpack.error.ClientErrorHandler} in this service.
*
* The default configuration of Ratpack includes a {@link ratpack.error.ClientErrorHandler} in all contexts.
* A {@link ratpack.registry.NotInRegistryException} will only be thrown if a very custom service setup is being used.
*
* @param statusCode The 4xx range status code that indicates the error type
* @throws NotInRegistryException if no {@link ratpack.error.ClientErrorHandler} can be found in the service
*/
@NonBlocking
void clientError(int statusCode) throws NotInRegistryException;
/**
* Render the given object, using the rendering framework.
*
* The first {@link ratpack.render.Renderer}, that is able to render the given object will be delegated to.
* If the given argument is {@code null}, this method will have the same effect as {@link #clientError(int) clientError(404)}.
*
* If no renderer can be found for the given type, a {@link NoSuchRendererException} will be given to {@link #error(Throwable)}.
*
* If a renderer throws an exception during its execution it will be wrapped in a {@link ratpack.render.RendererException} and given to {@link #error(Throwable)}.
*
* Ratpack has built in support for rendering the following types:
*
* - {@link java.nio.file.Path} (see {@link ratpack.file.FileRenderer})
* - {@link java.lang.CharSequence} (see {@link ratpack.render.CharSequenceRenderer})
*
*
* See {@link ratpack.render.Renderer} for more on how to contribute to the rendering framework.
*
* @param object The object to render
* @throws NoSuchRendererException if no suitable renderer can be found
*/
@NonBlocking
void render(Object object) throws NoSuchRendererException;
/**
* Sends a temporary redirect response (i.e. statusCode 302) to the client using the specified redirect location URL.
*
* @param location the redirect location URL
* @throws NotInRegistryException if there is no {@link Redirector} in the current service but one is provided by default
*/
void redirect(String location) throws NotInRegistryException;
/**
* Sends a redirect response location URL and status code (which should be in the 3xx range).
*
* @param code The status code of the redirect
* @param location the redirect location URL
* @throws NotInRegistryException if there is no {@link Redirector} in the current service but one is provided by default
*/
void redirect(int code, String location) throws NotInRegistryException;
/**
* Convenience method for handling last-modified based HTTP caching.
*
* The given date is the "last modified" value of the response.
* If the client sent an "If-Modified-Since" header that is of equal or greater value than date, a 304
* will be returned to the client. Otherwise, the given runnable will be executed (it should send a response)
* and the "Last-Modified" header will be set by this method.
*
* @param date The effective last modified date of the response
* @param runnable The response sending action if the response needs to be sent
*/
@NonBlocking
void lastModified(Date date, Runnable runnable);
/**
* Parse the request into the given type, using no options (or more specifically an instance of {@link ratpack.parse.NullParseOpts} as the options).
*
* The code sample is functionally identical to the sample given for the {@link #parse(Parse)} variant…
*
* import ratpack.handling.Handler;
* import ratpack.handling.Context;
* import ratpack.form.Form;
*
* public class FormHandler implements Handler {
* public void handle(Context context) {
* Form form = context.parse(Form.class);
* context.render(form.get("someFormParam"));
* }
* }
*
*
* That is, it is a convenient form of {@code parse(Parse.of(T))}.
*
* @param type the type to parse to
* @param the type to parse to
* @return The parsed object
* @throws NoSuchParserException if no suitable parser could be found in the registry
* @throws ParserException if a suitable parser was found, but it threw an exception while parsing
*/
T parse(Class type) throws NoSuchParserException, ParserException;
/**
* Parse the request into the given type, using no options (or more specifically an instance of {@link ratpack.parse.NullParseOpts} as the options).
*
* The code sample is functionally identical to the sample given for the {@link #parse(Parse)} variant…
*
* import ratpack.handling.Handler;
* import ratpack.handling.Context;
* import ratpack.form.Form;
* import com.google.common.reflect.TypeToken;
*
* public class FormHandler implements Handler {
* public void handle(Context context) {
* Form form = context.parse(new TypeToken<Form>() {});
* context.render(form.get("someFormParam"));
* }
* }
*
*
* That is, it is a convenient form of {@code parse(Parse.of(T))}.
*
* @param type the type to parse to
* @param the type to parse to
* @return The parsed object
* @throws NoSuchParserException if no suitable parser could be found in the registry
* @throws ParserException if a suitable parser was found, but it threw an exception while parsing
*/
T parse(TypeToken type) throws NoSuchParserException, ParserException;
/**
* Constructs a {@link Parse} from the given args and delegates to {@link #parse(Parse)}.
*
* @param type The type to parse to
* @param options The parse options
* @param The type to parse to
* @param The type of the parse opts
* @return The parsed object
* @throws NoSuchParserException if no suitable parser could be found in the registry
* @throws ParserException if a suitable parser was found, but it threw an exception while parsing
*/
T parse(Class type, O options) throws NoSuchParserException, ParserException;
/**
* Constructs a {@link Parse} from the given args and delegates to {@link #parse(Parse)}.
*
* @param type The type to parse to
* @param options The parse options
* @param The type to parse to
* @param The type of the parse opts
* @return The parsed object
* @throws NoSuchParserException if no suitable parser could be found in the registry
* @throws ParserException if a suitable parser was found, but it threw an exception while parsing
*/
T parse(TypeToken type, O options) throws NoSuchParserException, ParserException;
/**
* Parses the request body into an object.
*
* How to parse the request is determined by the given {@link Parse} object.
*
Parser Resolution
*
* Parser resolution happens as follows:
*
* - All {@link ratpack.parse.Parser parsers} are retrieved from the context registry (i.e. {@link #getAll(Class) getAll(Parser.class)});
* - Found parsers are checked (in order returned by {@code getAll()}) for compatibility with the current request content type and options type;
* - If a parser is found that is compatible, its {@link ratpack.parse.Parser#parse(Context, ratpack.http.TypedData, Parse)} method is called;
* - If the parser returns {@code null} the next parser will be tried, if it returns a value it will be returned by this method;
* - If no compatible parser could be found, a {@link NoSuchParserException} will be thrown.
*
* Parser Compatibility
*
* A parser is compatible if all of the following hold true:
*
* - Its {@link ratpack.parse.Parser#getContentType()} is exactly equal to {@link ratpack.http.MediaType#getType() getRequest().getBody().getContentType().getType()}
* - The opts of the given {@code parse} object is an {@code instanceof} its {@link ratpack.parse.Parser#getOptsType()} ()}
* - The {@link ratpack.parse.Parser#parse(Context, ratpack.http.TypedData, Parse)} method returns a non null value.
*
*
* If the request has no declared content type, {@code text/plain} will be assumed.
*
Core Parsers
*
* Ratpack core provides implicit {@link ratpack.parse.NoOptParserSupport no opt parsers} for the following types and content types:
*
* - {@link ratpack.form.Form}
* -
*
* - multipart/form-data
* - application/x-www-form-urlencoded
*
*
*
* Example Usage
*
* import ratpack.handling.Handler;
* import ratpack.handling.Context;
* import ratpack.form.Form;
* import ratpack.parse.Parse;
* import ratpack.parse.NullParseOpts;
*
* public class FormHandler implements Handler {
* public void handle(Context context) {
* Form form = context.parse(Parse.of(Form.class));
* context.render(form.get("someFormParam"));
* }
* }
*
* @param parse The specification of how to parse the request
* @param The type of object the request is parsed into
* @param the type of the parse options object
* @return The parsed object
* @throws NoSuchParserException if no suitable parser could be found in the registry
* @throws ParserException if a suitable parser was found, but it threw an exception while parsing
* @see #parse(Class)
* @see #parse(Class, Object)
* @see ratpack.parse.Parser
*/
T parse(Parse parse) throws NoSuchParserException, ParserException;
/**
* Provides direct access to the backing Netty channel.
*
* General only useful for low level extensions. Avoid if possible.
*
* @return Direct access to the underlying channel.
*/
DirectChannelAccess getDirectChannelAccess();
/**
* The address that this request was received on.
*
* @return The address that this request was received on.
*/
BindAddress getBindAddress();
/**
* The contextual path tokens of the current {@link ratpack.path.PathBinding}.
*
* Shorthand for {@code get(PathBinding.class).getPathTokens()}.
*
* @return The contextual path tokens of the current {@link ratpack.path.PathBinding}.
* @throws NotInRegistryException if there is no {@link ratpack.path.PathBinding} in the current service
*/
PathTokens getPathTokens() throws NotInRegistryException;
/**
* The contextual path tokens of the current {@link ratpack.path.PathBinding}.
*
* Shorthand for {@code get(PathBinding.class).getAllPathTokens()}.
*
* @return The contextual path tokens of the current {@link ratpack.path.PathBinding}.
* @throws NotInRegistryException if there is no {@link ratpack.path.PathBinding} in the current service
*/
PathTokens getAllPathTokens() throws NotInRegistryException;
/**
* Registers a callback to be notified when the request for this context is “closed” (i.e. responded to).
*
* @param onClose A notification callback
*/
void onClose(Action super RequestOutcome> onClose);
/**
* Gets the file relative to the contextual {@link ratpack.file.FileSystemBinding}.
*
* Shorthand for {@code get(FileSystemBinding.class).file(path)}.
*
* The default configuration of Ratpack includes a {@link ratpack.file.FileSystemBinding} in all contexts.
* A {@link NotInRegistryException} will only be thrown if a very custom service setup is being used.
*
* @param path The path to pass to the {@link ratpack.file.FileSystemBinding#file(String)} method.
* @return The file relative to the contextual {@link ratpack.file.FileSystemBinding}
* @throws NotInRegistryException if there is no {@link ratpack.file.FileSystemBinding} in the current service
*/
Path file(String path) throws NotInRegistryException;
/**
* {@inheritDoc}
*/
@Override
O get(Class type) throws NotInRegistryException;
/**
* {@inheritDoc}
*/
@Nullable
@Override
O maybeGet(Class type);
/**
* {@inheritDoc}
*/
@Override
Iterable extends O> getAll(Class type);
/**
* {@inheritDoc}
*/
@Override
O get(TypeToken type) throws NotInRegistryException;
/**
* {@inheritDoc}
*/
@Nullable
@Override
O maybeGet(TypeToken type);
/**
* {@inheritDoc}
*/
@Override
Iterable extends O> getAll(TypeToken type);
/**
* {@inheritDoc}
*/
@Nullable
@Override
T first(TypeToken type, Predicate super T> predicate);
/**
* {@inheritDoc}
*/
@Override
Iterable extends T> all(TypeToken type, Predicate super T> predicate);
/**
* {@inheritDoc}
*/
@Override
boolean each(TypeToken type, Predicate super T> predicate, Action super T> action) throws Exception;
}