ent's first pull request. Injecting the async parameter via the @Suspended annotation de-
taches HTTP response processing from this request thread.
The method then begins by defining a synchronized block on the messages variable. This
block allows the receive() method to perform atomic actions that do not conflict with the
writer thread. Within the block, the code looks up the current query parameter in the mes-
sages map. If the message is null , then the code sets this variable to the first member
variable of the class. Otherwise, it sets the message to the found message's next field. If the
message is still null , then there is no message available and the AsyncResponse is queued
for the writer thread to pick up when a message is available.
Finally, after the synchronized block, if the message is not null , it is sent immediately
back to the chat client.
void queue ( AsyncResponse async )
listeners . add ( async );
The queue() method just adds the AsyncResponse to the listeners list so the writer thread
can pick it up.
void send ( UriBuilder base , AsyncResponse async , Message message )
URI nextUri = base . clone (). path ( CustomerChat . class )
. queryParam ( "current" , message . id ). build ();
Link next = Link . fromUri ( nextUri ). rel ( "next" ). build ();
Response response = Response . ok ( message . message , MediaType . TEXT_PLAIN_TYPE )
. links ( next ). build ();
async . resume ( response );
The send() method can be called by the writer thread or the receive() method. It creates a
Response populated with the message that will be sent back to the chat client. It also calcu-
lates and adds a next Link header to send back with the response. At the end of the method,
the AsyncResponse.resume() method is invoked with the built Response .
Build and Run the Example Program
You'll need multiple console windows to run this example. In the first console window, per-
form the following steps:
1. Change to the ex13_1 directory of the workbook example code.