/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package org.glassfish.jersey.client.spi;
import org.glassfish.jersey.Beta;
import org.glassfish.jersey.spi.Contract;
import javax.ws.rs.ConstrainedTo;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.core.Response;
import java.util.Deque;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
The interceptor of a client request invocation that is executed after the request invocation itself, i.e. after the ClientResponseFilters
are executed. It is ensured that all PostInvocationInterceptors
are executed after the request, in the reverse order given by the Priority
, the higher the priority the later the execution. Any Throwable
thrown when the afterRequest(ClientRequestContext, ClientResponseContext)
or onException(ClientRequestContext, ExceptionContext)
is being processed is accumulated and a multi RuntimeException with other exceptions supressed
is being thrown at the end (possibly encapsulated in a ProcessingException
if not a single RuntimeException
), unless resolved by onException(ClientRequestContext, ExceptionContext)
. During the PostInvocationInterceptor
processing, the accumulated Deque
of the Throwables
is available in the ExceptionContext
. For asynchronous invocation, the PostInvocationInterceptor
is invoked in the request thread, i.e. in the thread provided by ExecutorService
. When the lowest priority PostInvocationInterceptor
is executed first, one of the two methods can be invoked. afterRequest(ClientRequestContext, ClientResponseContext)
in a usual case when no previous Throwable
was caught, or onException(ClientRequestContext, ExceptionContext)
when the Throwable
was caught. Should the ExceptionContext.resolve(Response)
be utilized in that case, the next PostInvocationInterceptor
's afterRequest
method will be invoked. Similarly, when a Throwable
is caught during the PostInvocationInterceptor
execution, the next PostInvocationInterceptor
's onException
method will be invoked. Since: 2.30
/**
* The interceptor of a client request invocation that is executed after the request invocation itself, i.e. after the
* {@link javax.ws.rs.client.ClientResponseFilter ClientResponseFilters} are executed.
* <p/>
* It is ensured that all {@code PostInvocationInterceptors} are executed after the request, in the reverse order given by the
* {@link javax.annotation.Priority}, the higher the priority the later the execution. Any {@code Throwable} thrown when
* the {@link PostInvocationInterceptor#afterRequest(ClientRequestContext, ClientResponseContext)} or
* {@link PostInvocationInterceptor#onException(ClientRequestContext, ExceptionContext)} is being processed is accumulated and
* a multi RuntimeException with other {@link Throwable#addSuppressed(Throwable) exceptions supressed} is being thrown at the end
* (possibly encapsulated in a {@link javax.ws.rs.ProcessingException} if not a single {@code RuntimeException}),
* unless resolved by {@link PostInvocationInterceptor#onException(ClientRequestContext, ExceptionContext)}. During the
* {@link PostInvocationInterceptor} processing, the accumulated {@link Deque} of the {@code Throwables} is available in the
* {@link ExceptionContext}.
* <p/>
* For asynchronous invocation, the {@code PostInvocationInterceptor} is invoked in the request thread, i.e. in the thread
* provided by {@link javax.ws.rs.client.ClientBuilder#executorService(ExecutorService) ExecutorService}.
* <p/>
* When the lowest priority {@code PostInvocationInterceptor} is executed first, one of the two methods can be invoked.
* {@link PostInvocationInterceptor#afterRequest(ClientRequestContext, ClientResponseContext)} in a usual case when no previous
* {@code Throwable} was caught, or {@link PostInvocationInterceptor#onException(ClientRequestContext, ExceptionContext)} when
* the {@code Throwable} was caught. Should the {@link ExceptionContext#resolve(Response)} be utilized in that case,
* the next {@code PostInvocationInterceptor}'s
* {@link PostInvocationInterceptor#afterRequest(ClientRequestContext, ClientResponseContext) afterRequest} method will be
* invoked. Similarly, when a {@code Throwable} is caught during the {@code PostInvocationInterceptor} execution, the next
* {@code PostInvocationInterceptor}'s
* {@link PostInvocationInterceptor#onException(ClientRequestContext, ExceptionContext) onException} method will be invoked.
*
* @since 2.30
*/
@Beta
@Contract
@ConstrainedTo(RuntimeType.CLIENT)
public interface PostInvocationInterceptor {
The context providing information when the Throwable
(typically, the RuntimeException
) is caught. /**
* The context providing information when the {@code Throwable} (typically, the {@code RuntimeException}) is caught.
*/
interface ExceptionContext {
If the ClientResponseContext
has been available at the time of the Throwable
occurrence, such as when the PostInvocationInterceptor
is processed, it will be available. Returns: ClientResponseContext
if available.
/**
* If the {@link ClientResponseContext} has been available at the time of the {@code Throwable} occurrence,
* such as when the {@link PostInvocationInterceptor} is processed, it will be available.
*
* @return {@link ClientResponseContext} if available.
*/
Optional<ClientResponseContext> getResponseContext();
Get the mutable Deque
of unhandled Throwables
occurred during the request (including previous PostInvocationInterceptor
processing). Returns: Unhandled Throwables
occurred during the request.
/**
* Get the mutable {@link Deque} of unhandled {@code Throwables} occurred during the request (including previous
* {@code PostInvocationInterceptor} processing).
*
* @return Unhandled {@code Throwables} occurred during the request.
*/
Deque<Throwable> getThrowables();
Resolve the Throwables
with a provided Response
. The Throwables in the ExceptionContext
will be cleared. Params:
/**
* Resolve the {@code Throwables} with a provided {@link Response}. The Throwables in the {@code ExceptionContext}
* will be cleared.
*
* @param response the provided {@link Response} to be passed to a next {@code PostInvocationInterceptor} or the
* {@link javax.ws.rs.client.Client}.
*/
void resolve(Response response);
}
The method is invoked after a request when no Throwable
is thrown, or the Throwables
are resolved
by previous PostInvocationInterceptor
. Params:
/**
* The method is invoked after a request when no {@code Throwable} is thrown, or the {@code Throwables} are
* {@link ExceptionContext#resolve(Response) resolved} by previous {@code PostInvocationInterceptor}.
*
* @param requestContext the request context.
* @param responseContext the response context of the original {@link javax.ws.rs.core.Response} or response context
* defined by the new {@link ExceptionContext#resolve(Response) resolving}
* {@link javax.ws.rs.core.Response}.
*/
void afterRequest(ClientRequestContext requestContext, ClientResponseContext responseContext);
The method is invoked after a Throwable
is caught during the client request chain processing. Params: - requestContext – the request context.
- exceptionContext – the context available to handle the caught
Throwables
.
/**
* The method is invoked after a {@code Throwable} is caught during the client request chain processing.
*
* @param requestContext the request context.
* @param exceptionContext the context available to handle the caught {@code Throwables}.
*/
void onException(ClientRequestContext requestContext, ExceptionContext exceptionContext);
}