Chapter 48. Returning Information to the Consumer
Abstract
RESTful requests require that at least an HTTP response code be returned to the consumer. In many cases, a request can be satisfied by returning a plain JAXB object or a GenericEntity
object. When the resource method needs to return additional metadata along with the response entity, JAX-RS resource methods can return a Response
object containing any needed HTTP headers or other metadata.
48.1. Return Types
The information returned to the consumer determines the exact type of object a resource method returns. This may seem obvious, but the mapping between Java return objects and what is returned to a RESTful consumer is not one-to-one. At a minimum, RESTful consumers need to be returned a valid HTTP return code in addition to any response entity body. The mapping of the data contained within a Java object to a response entity is effected by the MIME types a consumer is willing to accept.
To address the issues involved in mapping Java object to RESTful response messages, resource methods are allowed to return four types of Java constructs:
- Section 48.2, “Returning plain Java constructs” return basic information with HTTP return codes determined by the JAX-RS runtime.
- Section 48.2, “Returning plain Java constructs” return complex information with HTTP return codes determined by the JAX-RS runtime.
-
Section 48.3, “Fine tuning an application’s responses” return complex information with a programmatically determined HTTP return status. The
Response
object also allows HTTP headers to be specified. -
Section 48.4, “Returning entities with generic type information” return complex information with HTTP return codes determined by the JAX-RS runtime. The
GenericEnitity
object provides more information to the runtime components serializing the data.
48.2. Returning plain Java constructs
Overview
In many cases a resource class can return a standard Java type, a JAXB object, or any object for which the application has an entity provider. In these cases the runtime determines the MIME type information using the Java class of the object being returned. The runtime also determines the appropriate HTTP return code to send to the consumer.
Returnable types
Resource methods can return void
or any Java type for which an entity writer is provided. By default, the runtime has providers for the following:
- the Java primitives
-
the
Number
representations of the Java primitives - JAXB objects
the section called “Natively supported types” lists all of the return types supported by default. the section called “Custom writers” describes how to implement a custom entity writer.
MIME types
The runtime determines the MIME type of the returned entity by first checking the resource method and resource class for a @Produces
annotation. If it finds one, it uses the MIME type specified in the annotation. If it does not find one specified by the resource implementation, it relies on the entity providers to determine the proper MIME type.
By default the runtime assign MIME types as follows:
-
Java primitives and their
Number
representations are assigned a MIME type ofapplication/octet-stream
. -
JAXB objects are assigned a MIME type of
application/xml
.
Applications can use other mappings by implementing custom entity providers as described in the section called “Custom writers”.
Response codes
When resource methods return plain Java constructs, the runtime automatically sets the response’s status code if the resource method completes without throwing an exception. The status code is set as follows:
-
204
(No Content)—the resource method’s return type isvoid
-
204
(No Content)—the value of the returned entity isnull
-
200
(OK)—the value of the returned entity is notnull
If an exception is thrown before the resource method completes the return status code is set as described in Chapter 50, Handling Exceptions.
48.3. Fine tuning an application’s responses
48.3.1. Basics of building responses
Overview
RESTful services often need more precise control over the response returned to a consumer than is allowed when a resource method returns a plain Java construct. The JAX-RS Response
class allows a resource method to have some control over the return status sent to the consumer and to specify HTTP message headers and cookies in the response.
Response
objects wrap the object representing the entity that is returned to the consumer. Response
objects are instantiated using the ResponseBuilder
class as a factory.
The ResponseBuilder
class also has many of the methods used to manipulate the response’s metadata. For instance the ResonseBuilder
class contains the methods for setting HTTP headers and cache control directives.
Relationship between a response and a response builder
The Response
class has a protected constructor, so they cannot be instantiated directly. They are created using the ResponseBuilder
class enclosed by the Response
class. The ResponseBuilder
class is a holder for all of the information that will be encapsulated in the response created from it. The ResponseBuilder
class also has all of the methods responsible for setting HTTP header properties on the message.
The Response
class does provide some methods that ease setting the proper response code and wrapping the entity. There are methods for each of the common response status codes. The methods corresponding to status that include an entity body, or required metadata, include versions that allow for directly setting the information into the associated response builder.
The ResponseBuilder
class' build()
method returns a response object containing the information stored in the response builder at the time the method is invoked. After the response object is returned, the response builder is returned to a clean state.
Getting a response builder
There are two ways to get a response builder:
Using the static methods of the
Response
class as shown in Getting a response builder using theResponse
class.Getting a response builder using the
Response
classimport javax.ws.rs.core.Response; Response r = Response.ok().build();
When getting a response builder this way you do not get access to an instance you can manipulate in multiple steps. You must string all of the actions into a single method call.
Using the Apache CXF specific
ResponseBuilderImpl
class. This class allows you to work directly with a response builder. However, it requires that you manually set all of the response builders information manually.Example 48.1, “Getting a response builder using the
ResponseBuilderImpl
class” shows how Getting a response builder using theResponse
class could be rewritten using theResponseBuilderImpl
class.Example 48.1. Getting a response builder using the
ResponseBuilderImpl
classimport javax.ws.rs.core.Response; import org.apache.cxf.jaxrs.impl.ResponseBuilderImpl; ResponseBuilderImpl builder = new ResponseBuilderImpl(); builder.status(200); Response r = builder.build();
NoteYou could also simply assign the
ResponseBuilder
returned from aResponse
class' method to aResponseBuilderImpl
object.
More information
For more information about the Response
class see the Response
class' Javadoc.
For more information about the ResponseBuilder
class see the ResponseBuilder
class' Javadoc.
For more information on the Apache CXF ResponseBuilderIml
class see the ResponseBuilderImpl
Javadoc.
48.3.2. Creating responses for common use cases
Overview
The Response
class provides shortcut methods for handling the more common responses that a RESTful service will need. These methods handle setting the proper headers using either provided values or default values. They also handle populating the entity body when appropriate.
Creating responses for successful requests
When a request is successfully processed the application needs to send a response to acknowledge that the request has been fulfilled. That response may contain an entity.
The most common response when successfully completing a response is OK
. An OK
response typically contains an entity that corresponds to the request. The Response
class has an overloaded ok()
method that sets the response status to 200
and adds a supplied entity to the enclosed response builder. There are five versions of the ok()
method. The most commonly used variant are:
-
Response.ok()
—creates a response with a status of200
and an empty entity body. -
Response.ok(java.lang.Object entity)
—creates a response with a status of200
, stores the supplied object in the responses entity body, and determines the entities media type by introspecting the object.
Creating a response with an 200
response shows an example of creating a response with an OK
status.
Creating a response with an 200
response
import javax.ws.rs.core.Response; import demo.jaxrs.server.Customer; ... Customer customer = new Customer("Jane", 12); return Response.ok(customer).build();
For cases where the requester is not expecting an entity body, it may be more appropriate to send a 204 No Content
status instead of an 200 OK
status. The Response.noContent()
method will create an appropriate response object.
Creating a response with a 204
status shows an example of creating a response with an 204
status.
Creating a response with a 204
status
import javax.ws.rs.core.Response; return Response.noContent().build();
Creating responses for redirection
The Response
class provides methods for handling three of the redirection response statuses.
303 See Other
The
303 See Other
status is useful when the requested resource needs to permanently redirect the consumer to a new resource to process the request.The
Response
classesseeOther()
method creates a response with a303
status and places the new resource URI in the message’sLocation
field. TheseeOther()
method takes a single parameter that specifies the new URI as ajava.net.URI
object.304 Not Modified
The
304 Not Modified
status can be used for different things depending on the nature of the request. It can be used to signify that the requested resource has not changed since a previousGET
request. It can also be used to signify that a request to modify the resource did not result in the resource being changed.The
Response
classesnotModified()
methods creates a response with a304
status and sets the modified date property on the HTTP message. There are three versions of thenotModified()
method:-
notModified
-
notModified
javax.ws.rs.core.Entity
tag
-
notModified
java.lang.String
tag
-
307 Temporary Redirect
The
307 Temporary Redirect
status is useful when the requested resource needs to direct the consumer to a new resource, but wants the consumer to continue using this resource to handle future requests.The
Response
classestemporaryRedirect()
method creates a response with a307
status and places the new resource URI in the message’sLocation
field. ThetemporaryRedirect()
method takes a single parameter that specifies the new URI as ajava.net.URI
object.
Creating a response with a 304
status shows an example of creating a response with an 304
status.
Creating a response with a 304
status
import javax.ws.rs.core.Response; return Response.notModified().build();
Creating responses to signal errors
The Response
class provides methods to create responses for two basic processing errors:
-
serverError
—creates a response with a status of500 Internal Server Error
. -
notAcceptable
java.util.List<javax.ws.rs.core.Variant>
variants
—creates a response with a406 Not Acceptable
status and an entity body containing a list of acceptable resource types.
Creating a response with a 500
status shows an example of creating a response with an 500
status.
Creating a response with a 500
status
import javax.ws.rs.core.Response; return Response.serverError().build();
48.3.3. Handling more advanced responses
Overview
The Response
class methods provide short cuts for creating responses for common cases. When you need to address more complicated cases such as specifying cache control directives, adding custom HTTP headers, or sending a status not handled by the Response
class, you need to use the ResponseBuilder
classes methods to populate the response before using the build()
method to generate the response object.
As discussed in the section called “Getting a response builder”, you can use the Apache CXF ResponseBuilderImpl
class to create a response builder instance that can be manipulated directly.
Adding custom headers
Custom headers are added to a response using the ResponseBuilder
class' header()
method. The header()
method takes two parameters:
-
name
—a string specifying the name of the header -
value
—a Java object containing the data stored in the header
You can set multiple headers on the message by calling the header()
method repeatedly.
Adding a header to a response shows code for adding a header to a response.
Adding a header to a response
import javax.ws.rs.core.Response; import org.apache.cxf.jaxrs.impl.ResponseBuilderImpl; ResponseBuilderImpl builder = new ResponseBuilderImpl(); builder.header("username", "joe"); Response r = builder.build();
Adding a cookie
Custom headers are added to a response using the ResponseBuilder
class' cookie()
method. The cookie()
method takes one or more cookies. Each cookie is stored in a javax.ws.rs.core.NewCookie
object. The easiest of the NewCookie
class' contructors to use takes two parameters:
-
name
—a string specifying the name of the cookie -
value
—a string specifying the value of the cookie
You can set multiple cookies by calling the cookie()
method repeatedly.
Adding a cookie to a response shows code for adding a cookie to a response.
Adding a cookie to a response
import javax.ws.rs.core.Response; import javax.ws.rs.core.NewCookie; NewCookie cookie = new NewCookie("username", "joe"); Response r = Response.ok().cookie(cookie).build();
Calling the cookie()
method with a null
parameter list erases any cookies already associated with the response.
Setting the response status
When you want to return a status other than one of the statuses supported by the Response
class' helper methods, you can use the ResponseBuilder
class' status()
method to set the response’s status code. The status()
method has two variants. One takes an int
that specifies the response code. The other takes a Response.Status
object to specify the response code.
The Response.Status
class is an enumeration enclosed in the Response
class. It has entries for most of the defined HTTP response codes.
Adding a header to a response shows code for setting the response status to 404 Not Found
.
Adding a header to a response
import javax.ws.rs.core.Response; import org.apache.cxf.jaxrs.impl.ResponseBuilderImpl; ResponseBuilderImpl builder = new ResponseBuilderImpl(); builder.status(404); Response r = builder.build();
Setting cache control directives
The ResponseBuilder
class' cacheControl()
method allows you to set the cache control headers on the response. The cacheControl()
method takes a javax.ws.rs.CacheControl
object that specifies the cache control directives for the response.
The CacheControl
class has methods that correspond to all of the cache control directives supported by the HTTP specification. Where the directive is a simple on or off value the setter method takes a boolean
value. Where the directive requires a numeric value, such as the max-age
directive, the setter takes an int
value.
Adding a header to a response shows code for setting the no-store
cache control directive.
Adding a header to a response
import javax.ws.rs.core.Response; import javax.ws.rs.core.CacheControl; import org.apache.cxf.jaxrs.impl.ResponseBuilderImpl; CacheControl cache = new CacheControl(); cache.setNoCache(true); ResponseBuilderImpl builder = new ResponseBuilderImpl(); builder.cacheControl(cache); Response r = builder.build();
48.4. Returning entities with generic type information
Overview
There are occasions where the application needs more control over the MIME type of the returned object or the entity provider used to serialize the response. The JAX-RS javax.ws.rs.core.GenericEntity<T>
class provides finer control over the serializing of entities by providing a mechanism for specifying the generic type of the object representing the entity.
Using a GenericEntity<T> object
One of the criteria used for selecting the entity provider that serializes a response is the generic type of the object. The generic type of an object represents the Java type of the object. When a common Java type or a JAXB object is returned, the runtime can use Java reflection to determine the generic type. However, when a JAX-RS Response
object is returned, the runtime cannot determine the generic type of the wrapped entity and the actual Java class of the object is used as the Java type.
To ensure that the entity provider is provided with correct generic type information, the entity can be wrapped in a GenericEntity<T>
object before being added to the Response
object being returned.
Resource methods can also directly return a GenericEntity<T>
object. In practice, this approach is rarely used. The generic type information determined by reflection of an unwrapped entity and the generic type information stored for an entity wrapped in a GenericEntity<T>
object are typically the same.
Creating a GenericEntity<T> object
There are two ways to create a GenericEntity<T>
object:
Create a subclass of the
GenericEntity<T>
class using the entity being wrapped. Creating a GenericEntity<T> object using a subclass shows how to create aGenericEntity<T>
object containing an entity of typeList<String>
whose generic type will be available at runtime.Creating a GenericEntity<T> object using a subclass
import javax.ws.rs.core.GenericEntity; List<String> list = new ArrayList<String>(); ... GenericEntity<List<String>> entity = new GenericEntity<List<String>>(list) {}; Response response = Response.ok(entity).build();
The subclass used to create a
GenericEntity<T>
object is typically anonymous.Create an instance directly by supplying the generic type information with the entity. Example 48.2, “Directly instantiating a GenericEntity<T> object” shows how to create a response containing an entity of type
AtomicInteger
.Example 48.2. Directly instantiating a GenericEntity<T> object
import javax.ws.rs.core.GenericEntity; AtomicInteger result = new AtomicInteger(12); GenericEntity<AtomicInteger> entity = new GenericEntity<AtomicInteger>(result, result.getClass().getGenericSuperclass()); Response response = Response.ok(entity).build();
48.5. Asynchronous Response
48.5.1. Asynchronous Processing on the Server
Overview
The purpose of asynchronous processing of invocations on the server side is to enable more efficient use of threads and, ultimately, to avoid the scenario where client connection attempts are refused because all of the server’s request threads are blocked. When an invocation is processed asynchronously, the request thread is freed up almost immediately.
Note that even when asynchronous processing is enabled on the server side, a client will still remain blocked until it receives a response from the server. If you want to see asynchronous behaviour on the client side, you must implement client-side asynchronous processing. See Section 49.6, “Asynchronous Processing on the Client”.
Basic model for asynchronous processing
Figure 48.1, “Threading Model for Asynchronous Processing” shows an overview of the basic model for asynchronous processing on the server side.
Figure 48.1. Threading Model for Asynchronous Processing
In outline, a request is processed as follows in the asynchronous model:
-
An asynchronous resource method is invoked within a request thread (and receives a reference to an
AsyncResponse
object, which will be needed later to send back the response). -
The resource method encapsulates the suspended request in a
Runnable
object, which contains all of the information and processing logic required to process the request. - The resource method pushes the Runnable object onto the blocking queue of the executor thread pool.
- The resource method can now return, thus freeing up the request thread.
-
When the
Runnable
object gets to the top of the queue, it is processed by one of the threads in the executor thread pool. The encapsulatedAsyncResponse
object is then used to send the response back to the client.
Thread pool implementation with Java executor
The java.util.concurrent
API is a powerful API that enables you to create a complete thread pool implementation very easily. In the terminology of the Java concurrency API, a thread pool is called an executor. It requires only a single line of code to create a complete working thread pool, including the working threads and the blocking queue that feeds them.
For example, to create a complete working thread pool like the Executor Thread Pool shown in Figure 48.1, “Threading Model for Asynchronous Processing”, create a java.util.concurrent.Executor
instance, as follows:
Executor executor = new ThreadPoolExecutor( 5, // Core pool size 5, // Maximum pool size 0, // Keep-alive time TimeUnit.SECONDS, // Time unit new ArrayBlockingQueue<Runnable>(10) // Blocking queue );
This constructor creates a new thread pool with five threads, fed by a single blocking queue with which can hold up to 10 Runnable
objects. To submit a task to the thread pool, call the executor.execute
method, passing in a reference to a Runnable
object (which encapsulates the asynchronous task).
Defining an asynchronous resource method
To define a resource method that is asynchronous, inject an argument of type javax.ws.rs.container.AsyncResponse
using the @Suspended
annotation and make sure that the method returns void
. For example:
// Java ... import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; @Path("/bookstore") public class BookContinuationStore { ... @GET @Path("{id}") public void handleRequestInPool(@PathParam("id") String id, @Suspended AsyncResponse response) { ... } ... }
Note that the resource method must return void
, because the injected AsyncResponse
object will be used to return the response at a later time.
AsyncResponse class
The javax.ws.rs.container.AsyncResponse
class provides an a abstract handle on an incoming client connection. When an AsyncResponse
object is injected into a resource method, the underlying TCP client connection is initially in a suspended state. At a later time, when you are ready to return the response, you can re-activate the underlying TCP client connection and pass back the response, by calling resume
on the AsyncResponse
instance. Alternatively, if you need to abort the invocation, you could call cancel
on the AsyncResponse
instance.
Encapsulating a suspended request as a Runnable
In the asynchronous processing scenario shown in Figure 48.1, “Threading Model for Asynchronous Processing”, you push the suspended request onto a queue, from where it can be processed at a later time by a dedicated thread pool. In order for this approach to work, however, you need to have some way of encapsulating the suspended request in an object. The suspended request object needs to encapsulate the following things:
- Parameters from the incoming request (if any).
-
The
AsyncResponse
object, which provides a handle on the incoming client connection and a way of sending back the response. - The logic of the invocation.
A convenient way to encapsulate these things is to define a Runnable
class to represent the suspended request, where the Runnable.run()
method encapsulates the logic of the invocation. The most elegant way to do this is to implement the Runnable
as a local class, as shown in the following example.
Example of asynchronous processing
To implement the asynchronous processing scenario, the implementation of the resource method must pass a Runnable
object (representing the suspended request) to the executor thread pool. In Java 7 and 8, you can exploit some novel syntax to define the Runnable
class as a local class, as shown in the following example:
// Java package org.apache.cxf.systest.jaxrs; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.CompletionCallback; import javax.ws.rs.container.ConnectionCallback; import javax.ws.rs.container.Suspended; import javax.ws.rs.container.TimeoutHandler; import org.apache.cxf.phase.PhaseInterceptorChain; @Path("/bookstore") public class BookContinuationStore { private Map<String, String> books = new HashMap<String, String>(); private Executor executor = new ThreadPoolExecutor(5, 5, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); public BookContinuationStore() { init(); } ... @GET @Path("{id}") public void handleRequestInPool(final @PathParam("id") String id, final @Suspended AsyncResponse response) { executor.execute(new Runnable() { public void run() { // Retrieve the book data for 'id' // which is presumed to be a very slow, blocking operation // ... bookdata = ... // Re-activate the client connection with 'resume' // and send the 'bookdata' object as the response response.resume(bookdata); } }); } ... }
Note how the resource method arguments, id
and response
, are passed straight into the definition of the Runnable
local class. This special syntax enables you to use the resource method arguments directly in the Runnable.run()
method, without having to define corresponding fields in the local class.
In order for this special syntax to work, the resource method parameters must be declared as final
(which implies that they must not be changed in the method implementation).
48.5.2. Timeouts and Timeout Handlers
Overview
The asynchronous processing model also provides support for imposing timeouts on REST invocations. By default, a timeout results in a HTTP error response being sent back to the client. But you also have the option of registering a timeout handler callback, which enables you to customize the response to a timeout event.
Example of setting a timeout without a handler
To define a simple invocation timeout, without specifying a timeout handler, call the setTimeout
method on the AsyncResponse
object, as shown in the following example:
// Java // Java ... import java.util.concurrent.TimeUnit; ... import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; import javax.ws.rs.container.TimeoutHandler; @Path("/bookstore") public class BookContinuationStore { ... @GET @Path("/books/defaulttimeout") public void getBookDescriptionWithTimeout(@Suspended AsyncResponse async) { async.setTimeout(2000, TimeUnit.MILLISECONDS); // Optionally, send request to executor queue for processing // ... } ... }
Note that you can specify the timeout value using any time unit from the java.util.concurrent.TimeUnit
class. The preceding example does not show the code for sending the request to the executor thread pool. If you just wanted to test the timeout behaviour, you could include just the call to async.SetTimeout
in the resource method body, and the timeout would be triggered on every invocation.
The AsyncResponse.NO_TIMEOUT
value represents an infinite timeout.
Default timeout behaviour
By default, if the invocation timeout is triggered, the JAX-RS runtime raises a ServiceUnavailableException
exception and sends back a HTTP error response with the status 503
.
TimeoutHandler interface
If you want to customize the timeout behaviour, you must define a timeout handler, by implementing the TimeoutHandler
interface:
// Java package javax.ws.rs.container; public interface TimeoutHandler { public void handleTimeout(AsyncResponse asyncResponse); }
When you override the handleTimeout
method in your implementation class, you can choose between the following approaches to dealing with the timeout:
-
Cancel the response, by calling the
asyncResponse.cancel
method. -
Send a response, by calling the
asyncResponse.resume
method with the response value. -
Extend the waiting period, by calling the
asyncResponse.setTimeout
method. (For example, to wait for a further 10 seconds, you could callasyncResponse.setTimeout(10, TimeUnit.SECONDS)
).
Example of setting a timeout with a handler
To define an invocation timeout with a timeout handler, call both the setTimeout
method and the setTimeoutHandler
method on the AsyncResponse
object, as shown in the following example:
// Java ... import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; import javax.ws.rs.container.TimeoutHandler; @Path("/bookstore") public class BookContinuationStore { ... @GET @Path("/books/cancel") public void getBookDescriptionWithCancel(@PathParam("id") String id, @Suspended AsyncResponse async) { async.setTimeout(2000, TimeUnit.MILLISECONDS); async.setTimeoutHandler(new CancelTimeoutHandlerImpl()); // Optionally, send request to executor queue for processing // ... } ... }
Where this example registers an instance of the CancelTimeoutHandlerImpl
timeout handler to handle the invocation timeout.
Using a timeout handler to cancel the response
The CancelTimeoutHandlerImpl
timeout handler is defined as follows:
// Java ... import javax.ws.rs.container.AsyncResponse; ... import javax.ws.rs.container.TimeoutHandler; @Path("/bookstore") public class BookContinuationStore { ... private class CancelTimeoutHandlerImpl implements TimeoutHandler { @Override public void handleTimeout(AsyncResponse asyncResponse) { asyncResponse.cancel(); } } ... }
The effect of calling cancel
on the AsyncResponse
object is to send a HTTP 503 (Service unavailable
) error response to the client. You can optionally specify an argument to the cancel
method (either an int
or a java.util.Date
value), which would be used to set a Retry-After:
HTTP header in the response message. Clients often ignore the Retry-After:
header, however.
Dealing with a cancelled response in the Runnable instance
If you have encapsulated a suspended request as a Runnable
instance, which is queued for processing in an executor thread pool, you might find that the AsyncResponse
has been cancelled by the time the thread pool gets around to processing the request. For this reason, you ought to add some code to your Runnable
instance, which enables it to cope with a cancelled AsyncResponse
object. For example:
// Java ... @Path("/bookstore") public class BookContinuationStore { ... private void sendRequestToThreadPool(final String id, final AsyncResponse response) { executor.execute(new Runnable() { public void run() { if ( !response.isCancelled() ) { // Process the suspended request ... // ... } } }); } ... }
48.5.3. Handling Dropped Connections
Overview
It is possible to add a callback to deal with the case where the client connection is lost.
ConnectionCallback interface
To add a callback for dropped connections, you must implement the javax.ws.rs.container.ConnectionCallback
interface, which is defined as follows:
// Java package javax.ws.rs.container; public interface ConnectionCallback { public void onDisconnect(AsyncResponse disconnected); }
Registering a connection callback
After implementing a connection callback, you must register it with the current AsyncResponse
object, by calling one of the register
methods. For example, to register a connection callback of type, MyConnectionCallback
:
asyncResponse.register(new MyConnectionCallback());
Typical scenario for connection callback
Typically, the main reason for implementing a connection callback would be to free up resources associated with the dropped client connection (where you could use the AsyncResponse
instance as the key to identify the resources that need to be freed).
48.5.4. Registering Callbacks
Overview
You can optionally add a callback to an AsyncResponse
instance, in order to be notified when the invocation has completed. There are two alternative points in the processing when this callback can be invoked, either:
- After the request processing is finished and the response has already been sent back to the client, or
-
After the request processing is finished and an unmapped
Throwable
has been propagated to the hosting I/O container.
CompletionCallback interface
To add a completion callback, you must implement the javax.ws.rs.container.CompletionCallback
interface, which is defined as follows:
// Java package javax.ws.rs.container; public interface CompletionCallback { public void onComplete(Throwable throwable); }
Usually, the throwable
argument is null
. However, if the request processing resulted in an unmapped exception, throwable
contains the unmapped exception instance.
Registering a completion callback
After implementing a completion callback, you must register it with the current AsyncResponse
object, by calling one of the register
methods. For example, to register a completion callback of type, MyCompletionCallback
:
asyncResponse.register(new MyCompletionCallback());