face to create the pair of interfaces
IObservable<T> and IObserver<T>
that model asynchronous data
streams with values of type T. This
corresponds to the well-known Subject/Observer design pattern. The article then shows how to write a simple
Ajax-style application by exposing UI
events and Web services as asynchronous data streams and composing
them using a fluent API.
figure 1. 1 Big-data cube.
volume
small
big
velocity push
fk/pk
variety
k/v
Crossing futures And Callbacks
The GWT developer documentation
contains a slightly apologetic section
called “Getting Used to Asynchronous
Calls,”
3 which explains that while asynchronous calls at first sight look cruel
and unnatural to the developer, they
are a necessary evil to prevent the UI
from locking up and allow a client to
have multiple concurrent outstanding
server requests.
In GWT the asynchronous counter-
part of a synchronous method, say Per-
son[] getPeople(…), that makes a syn-
chronous cross-network call and blocks
until it returns an array of Person, would
return void and take an additional call-
back argument void getPeople(…,
AsyncCallback<Person[]> call-
back). The callback interface has two
methods: void onFailure(Throwable
error), which is called when the asyn-
chronous call throws an exception; and
void onSuccess(T result), which is
called when the asynchronous call suc-
cessfully returns a result value. Given
an asynchronous function such as get-
People, an invocation typically passes
an anonymous interface implementa-
tion that handles the success and fail-
ure callbacks, respectively, as illustrat-
ed in Figure 2.
figure 2. Asynchronous fetching data from a service.
service.getPeople(startRow, maxRows, new AsyncCallback<Person[]>() {
void onFailure(Throwable error) { …code to handle failure… }
void onSuccess(Person[] result) { …code to handle success… }
});
figure 3. Possible sequences of interaction when using Observer<T>.
successful completion after n steps.
unsuccessful completion after i steps.
infinite stream of values
that asynchronous calls deliver their
results in one shot. In the example,
however, returning the elements of the
Person array incrementally in a streaming fashion makes perfect sense, especially when the result set is large or
even infinite. You can asynchronously
stream back results by allowing the
onSuccess method to be called multiple times, once for each additional
chunk of the result array, and by adding a method void onCompleted(),
which is called when all chunks have
been delivered successfully. Let’s call
this derived interface Observer<T> to
indicate that it can observe multiple
T values before completing and to reflect the standard Java nongeneric
observer interface.
With Observer<T> instead of
AsyncCallback<T>, the possible sequences of interaction between an
asynchronous computation and its client are: successful termination after i
≥ 0 values; unsuccessful termination
after j values; or an infinite stream of
values that never completes, as shown
in Figure 3.
Another downside of passing callbacks directly as parameters to asynchronous methods is that revoking a
callback from being invoked is tricky
once the call has been made, leaving
you with just a void in your hands.
Suppose, for example, that the function getPeople streams back the
names of the people who have signed
up for a marketing promotion every
minute, but that you are not interested in receiving more than the first
thousand names. How do you achieve
this later if you did not anticipate this
pattern when you made the call and
received back void. Even if the asynchronous call delivers at most one
value, you may choose later to ignore
or cancel the call by timing out after
not receiving a result within a certain
time interval. Again, this is possible if
you anticipated this when passing the
callback into getPeople, but you cannot change your mind later.
These hitches are symptoms of the
fact that asynchronous computations
and streams are not treated as first-class values that can be returned from
methods, stored in variables, and
so on. The next section shows how
to make asynchronous data streams
into proper values by introducing an