diff --git a/docs/src/main/docbook/client.xml b/docs/src/main/docbook/client.xml index 90964a3b0a..e0b01cb86b 100644 --- a/docs/src/main/docbook/client.xml +++ b/docs/src/main/docbook/client.xml @@ -999,4 +999,135 @@ Client client = ClientBuilder.newBuilder().sslContext(sslContext).build(); + +
+ InvocationInterceptors + + Suppose a case that the start of the request is to be logged and even measured. + This can be done by ClientRequestFilter, which is usually invoked before the request is wired on the network. + However, the filter may be called as a last of the filters in the chain. Sure, it can have the highest priority, + but the other filters can have the very same priority! Some long-running operations can be performed before the + measuring can actually start. Even worse, the filter may even be skipped from the chain by the previous + #abortWith! + +
+ PreInvocationInterceptor + + For this, PreInvocationInterceptor, the code that executes before the ClientRequestFilters + are invoked, has been added to the client request chain. Jersey ensures all the interceptors are invoked with each request. + The interceptor contains a single #beforeRequest method, which corresponds to ClientRequestFilter: + + + /** + * The method invoked before the request starts. + * @param requestContext the request context shared with + * ClientRequestFilter. + */ + void beforeRequest(ClientRequestContext requestContext); + + + Note that only a single #abortWith is allowed in all PreInvocationInterceptors, + otherwise an IllegalStateException is thrown. + All the exceptions accumulated in PreInvocationInterceptors are thrown in a single Exception, + available through #getSuppressed(). + +
+
+ PostInvocationInterceptor + + Similarly, ClientResponseFilter seems to be a good place where the total time of the HTTP request can be measured, + but similarly to ClientRequestFilter, the response filter may not be invoked at all. + For this, PostInvocationInterceptor has been introduced. Jersey runtime ensures that every + PostInvocationInterceptor is called. Since an exception can occur during the HTTP request, + PostInvocationInterceptor comes with two methods: + + + /** + * The method is invoked after a request when no + * is thrown, or the Throwables are resolved + * by previous PostInvocationInterceptor. + * + * @param requestContext the request context. + * @param responseContext the response context + * of the original Response or response context + * defined by the new resolving Response. + */ + void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext); + + /** + * The method is invoked after a Throwable is caught + * during the client request chain processing. + * + * @param requestContext the request context. + * @param exceptionContext the context available to handle the + * caught Throwables. + */ + void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext); + + + The #afterRequest method is executed when no exception has been thrown during the HTTP request, + #onException method is executed if the exception has been thrown during the request. + It is possible to set a response in #onException, and the consecutive PostInvocationInterceptor will + execute its #afterRequest method. + + The measuring example can looks as follows, then: + + + String response = ClientBuilder.newClient().target("path") + .register(new PreInvocationInterceptor() { + @Override + public void beforeRequest(ClientRequestContext requestContext) { + startTime = System.currentTimeMillis(); + } + }) + .register(new PostInvocationInterceptor() { + @Override + public void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext) { + logDuration(System.currentTimeMillis() - startTime); + } + @Override + public void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext) { + logDuration(System.currentTimeMillis() - startTime); + } + }) + .request().get().readEntity(String.class); + +
+
+
+ InvocationBuilderListener + + InvocationBuilderListener is an interface that is inspired by Microprofile REST Client RestClientBuilderListener + and it contains a single method: + + + /** + * Whenever an Invocation.Builder is created, (i.e. when + * WebTarget#request() is called, this method would be invoked. + * + * @param context the updated InvocationBuilderContext. + */ + void onNewBuilder(InvocationBuilderContext context); + + + InvocationBuilderContext a subset of methods of the Invocation.Builder. It can be used to call the default + values of the Invocation.Builder. Since it is invoked at the time Invocation.Builder is instantiated, any consequent + calls of the Invocation.Builder‘s methods will replace the defaults set by the InvocationBuilderListener. + + For instance, if all the HTTP requests should contain a custom HTTP header, + there can be created a feature that would be registered on the client: + + + public static class MyFeature implements Feature { + @Override + public boolean configure(FeatureContext context) { + context.register( + (InvocationBuilderListener)(l)-> + l.getHeaders().add("MY_HEADER", "MY_VALUE") + ); + return true; + } + } + +