Skip to content

Commit

Permalink
Add new interfaces (PreInvocationInterceptor, PostInvocationIntercept…
Browse files Browse the repository at this point in the history
…or, and InvocationBuilderListener) documentation (#4411)

* Add new PreInvocationInterceptor, PostInvocationInterceptor, and InvocationBuilderListener interfaces documentation

Signed-off-by: tvallin <[email protected]>
  • Loading branch information
tvallin authored Mar 28, 2020
1 parent 351a578 commit 5f43f0e
Showing 1 changed file with 131 additions and 0 deletions.
131 changes: 131 additions & 0 deletions docs/src/main/docbook/client.xml
Original file line number Diff line number Diff line change
Expand Up @@ -999,4 +999,135 @@ Client client = ClientBuilder.newBuilder().sslContext(sslContext).build();</prog


</section>

<section>
<title>InvocationInterceptors</title>
<para>
Suppose a case that the start of the request is to be logged and even measured.
This can be done by <literal>ClientRequestFilter</literal>, 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
<literal>#abortWith</literal>!
</para>
<section>
<title>PreInvocationInterceptor</title>
<para>
For this, <literal>PreInvocationInterceptor</literal>, the code that executes before the <literal>ClientRequestFilters</literal>
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 <literal>#beforeRequest</literal> method, which corresponds to <literal>ClientRequestFilter</literal>:
</para>
<programlisting language="java">
/**
* The method invoked before the request starts.
* @param requestContext the request context shared with
* ClientRequestFilter.
*/
void beforeRequest(ClientRequestContext requestContext);
</programlisting>
<para>
Note that only a single <literal>#abortWith</literal> is allowed in all <literal>PreInvocationInterceptors</literal>,
otherwise an <literal>IllegalStateException</literal> is thrown.
All the exceptions accumulated in <literal>PreInvocationInterceptors</literal> are thrown in a single Exception,
available through <literal>#getSuppressed()</literal>.
</para>
</section>
<section>
<title>PostInvocationInterceptor</title>
<para>
Similarly, <literal>ClientResponseFilter</literal> seems to be a good place where the total time of the HTTP request can be measured,
but similarly to <literal>ClientRequestFilter</literal>, the response filter may not be invoked at all.
For this, <literal>PostInvocationInterceptor</literal> has been introduced. Jersey runtime ensures that every
<literal>PostInvocationInterceptor</literal> is called. Since an exception can occur during the HTTP request,
<literal>PostInvocationInterceptor</literal> comes with two methods:
</para>
<programlisting language="java">
/**
* 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);
</programlisting>
<para>
The <literal>#afterRequest</literal> method is executed when no exception has been thrown during the HTTP request,
<literal>#onException</literal> method is executed if the exception has been thrown during the request.
It is possible to set a response in <literal>#onException</literal>, and the consecutive <literal>PostInvocationInterceptor</literal> will
execute its <literal>#afterRequest</literal> method.

The measuring example can looks as follows, then:
</para>
<programlisting language="java" linenumbering="numbered">
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);
</programlisting>
</section>
</section>
<section>
<title>InvocationBuilderListener</title>
<para>
InvocationBuilderListener is an interface that is inspired by Microprofile REST Client <literal>RestClientBuilderListener</literal>
and it contains a single method:
</para>
<programlisting language="java">
/**
* 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);
</programlisting>
<para>
<literal>InvocationBuilderContext</literal> a subset of methods of the <literal>Invocation.Builder</literal>. It can be used to call the default
values of the <literal>Invocation.Builder</literal>. Since it is invoked at the time <literal>Invocation.Builder</literal> is instantiated, any consequent
calls of the <literal>Invocation.Builder</literal>‘s methods will replace the defaults set by the <literal>InvocationBuilderListener</literal>.

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:
</para>
<programlisting language="java" linenumbering="numbered">
public static class MyFeature implements Feature {
@Override
public boolean configure(FeatureContext context) {
context.register(
(InvocationBuilderListener)(l)-&gt;
l.getHeaders().add("MY_HEADER", "MY_VALUE")
);
return true;
}
}
</programlisting>
</section>
</chapter>

0 comments on commit 5f43f0e

Please sign in to comment.