Java Reference
In-Depth Information
}
};
Message
objects are stored in a
java.util.LinkedHashMap
so that they can be easily
looked up when a chat client makes a GET request. The key of this map is the
id
of the
Mes-
sage
. The service will always queue the last 10 messages posted to the server. We use a
LinkedHashMap
so that we can easily evict the oldest chat message when the maximum
number of buffered messages is reached. The
removeEldestEntry()
method is used to de-
termine when to evict the oldest entry in the map. It simply checks to see if the size of the
map is greater than the maximum amount of messages. It then resets what the
first
mes-
sage is. Returning
true
triggers the removal of the eldest entry.
protected
protected
AtomicLong counter
=
new
new
AtomicLong
(
0
);
The
AtomicLong counter
variable is used to generate message IDs.
LinkedList
<
AsyncResponse
>
listeners
=
new
new
LinkedList
<
AsyncResponse
>();
The
listeners
variable stores a list of waiting chat clients. We'll see how this is used later.
ExecutorService writer
=
Executors
.
newSingleThreadExecutor
();
We will have one and only one thread that is responsible for writing response messages back
to the chat clients. Having one
writer
thread is what makes this whole application scale very
well. Without asynchronous JAX-RS, this service would require a thread per blocking chat
client. While most modern operating systems can handle one or two thousand threads, sys-
tem performance starts to degrade quickly with all the context switching the operating sys-
tem has to do. Asynchronous JAX-RS allows us to scale to a much larger number of concur-
rent users.
Posting a new message
Let's look at how the service handles a new chat message:
@Context
protected
protected
UriInfo uriInfo
;
@POST
@Consumes
(
"text/plain"
)
public
public
void
void
post
(
final
final
String text
)
{
final
final
UriBuilder base
=
uriInfo
.
getBaseUriBuilder
();
writer
.
submit
(
new
new
Runnable
());