Ajax Push and ICEfaces for enterprise collaboration
The web has evolved from a document repository into a multi-user collaboration medium, shaped and created by its users. Ajax Push gives the server the ability to update any part of any page at any time, transforming every application into a new communication tool, connecting users to each other through web server mediated channels.
In this session, recorded at the recent JSFOne conference, Ted Goddard provides an overview of Ajax Push and its range of uses in multi-user web applications. By stepping through the development of a multi-user slideshow and chat system, he shows you how easily sophisticated Ajax applications can be created.
The complete transcript of the presentation has been provided below:
Hi. I'm Ted Goddard. Welcome to "Using ICEfaces for Ajax Push: Enterprise
Collaboration."
We're going to talk about a few things here, introduce Web 2.0. What does it
mean? Is it an O'Reilly trademark, or is it a useful word that we can make use
of in understanding how to build applications? We'll talk about how to use Push
for enterprise collaboration. Then we'll see some demos, two demos, showing
multi-user Ajax capabilities.
Then, we'll look at how Ajax Push works on the wire. How does asynchronous HTTP
work with browsers? What's the impact on the server? We'll take a look at that
- it affects scalability. Then, we'll look at a bit of scopes and flows for
Ajax. When you want to build a sophisticated Ajax Push application, you need to
use more advanced scopes and flows than are available with the standard JSF
Faces-config. Then, we'll drill a little deeper into how we developed some of
those demos that I showed you.
Well, we'll pitch this as a revolution. This is a revolutionary change for the
web. But, what kind of revolution am I signing you up for? Is it like the
American Revolution, where you have to dump your favorite beverage into the
bay, or maybe the French Revolution, where you have some great obstacle to
overcome? Well, really, we'd like to keep our favorite beverage, Java, and we
don't want some big learning curve.
Wouldn't it be better if this is like the Scientific Revolution, where a small
change in perspective lets us do a lot more, see further, and use the tools and
the knowledge that we have in a way that dramatically changes the kinds of
applications that we can build.
Why, yes it is. But first, let's understand Web 2.0. In order to understand
this beyond some marketing term, let's look at what we consider to be Web 2.0
applications and gather the common characteristics from them.
A good example is eBay. Is eBay interesting because eBay has a bunch of things
to sell us, or is eBay interesting because the users of eBay are posting items
for auction and other users are bidding on them? Really, the eBay application
is built collaboratively by its users. So, it's a multi-user collaboration
system, where the users are participating to create the eBay application. The
eBay application is really a container for what the users are doing in it.
Jonathan Schwartz had a nice quote at JavaOne a few years back, where he said,
"We're moving out of the Information Age into the Participation Age."
No longer is the web just about somebody having some documents, putting them on
a file server, and letting other people retrieve them. Now, the web is all
about users building the applications together, by their contributions. We're
posting auctions. We're posting Wikipedia articles. We're making entries on
blogs, contributing photos and movies. All of these things contributed by users
are what are building the web. In other words, the web as a whole is turning
into a collaborative environment.
But now, let's drill down into an individual eBay page, where you're looking at
an item that you want to bid on. At that moment, it's almost like a print-out
on your screen. You can't see what the other users are doing at that time. They
could be bidding on the item, but you have no knowledge of that until you press
"refresh." So, really, that page is still just a single-user page.
It's not collaborative or multi-user.
Ajax helps a little bit to improve the user experience in this regard, but it
doesn't really allow us to see what the other users are doing at that time. To
do this, we need the full realization of Ajax, or Ajax Push. You may see this
referred to as Comet, or Reverse Ajax, where we have an asynchronous channel,
from the server to the browser, that allows us to update the page at any time.
Let's look at this basic idea in terms of enterprise collaboration. How can we
use the server as a communication channel to mediate between users, in
combination with push, to build a more interesting application?
So, imagine that we have two users. Maybe, they're in different countries. And
they're using a slide-show application. Perhaps they're viewing this set of
slides. One user is the moderator. Mika is the moderator, and he advances the
slide. This sends a user event to the server. Then, the server processes that
user event and, using its push capability, can push that slide change out to me
on another computer.
So, by having this push capability as part of our framework, we're able to turn
the server into a new type of communication channel. In this case, the
communication that we're performing is a multi-user slide-show.
Well, perhaps our source of events into the server is not coming from users. It
could be coming from a sensor network or an external application - some other
software or hardware system. Those events can be propagated in, and pushed out
to users as well.
So, there are two fundamental sources. And this is the key idea behind Ajax
Push, that, by using the ability to send messages from the server to the
browser, we can create new applications that are new forms of communication. As
well, we can inform users, in a timely fashion, of events that are occurring in
their enterprise or their environment.
If you take a step back and think about the application that you're working on
today, there are probably some very interesting ways that you could add a push
capability to that application.
Here are just some examples, on this slide, to give you some ideas of the
categories. For instance, distance learning. You're trying to teach someone
about a new concept. If you were able to build a web application that allowed
you to push that information to them, you could do that more effectively.
Some of the interesting things that we're going to see in a demo today revolve
around enterprise-shared locking and negotiation.
Then, of course, games are another interesting way to use push. As one user
makes a move in the game, that game move can be pushed to the other users.
In the future, we'll see chat, forums, blogging, all of these things merge into
a single application, a hybrid application. If you imagine that your blog, with
its responses to your post, was updated as the various users in the system made
posts as responses to your blog, you would be able to respond to them in a more
timely fashion. And that would turn the blogging system, with comments, into a
chat system.
Well, you may be wondering how you would actually implement applications like
this. And the fact is that, using the ICEfaces framework, it's relatively easy,
because it's based on the JavaServer Faces framework. And it allows you to build
your application without violating any of the basic principles that JSF is
based on.
For instance, one of the great successes of JSF is the clean separation between
model and view. The model is implemented as JavaBeans, and the view is
implemented declaratively through a markup language with expression language
binding back to the beans.
If you consider what you should have to create in order to produce an Ajax
application, really, we've already given a sufficient description to the system
in order for it to build this application. We have told the system what the
contents of the model are, and we've told the system what user-interface
components to put into the page and how those components are related to the
model. It should be the job of the framework to translate that for us into an
Ajax user interface. After all, we're application developers, not Ajax
developers.
ICEfaces does exactly that. It takes this description of the application, with
no Ajax concerns in the page or in the model, and translates it into an Ajax
user interface for us. It does so by providing a number of AJAX-based
components.
What I would like to discuss here is, one of these components is not like the
others. In fact, most of these components can be used in a purely synchronous
fashion; they're based on user events. When I click on one of the components,
an event is sent to the server, the page is updated, and the response is
returned.
But one of these components really requires Push to function in any sensible
way, and that's Progress Bar. Progress Bar is familiar to us on the desktop,
but on the web, progress bars are somewhat difficult to implement because in
order to show the accurate state of the progress on the server, we need some
way to push those updates into the browser. Well, having Ajax Push mechanism is
just what we need to implement that.
Now, let's move into some demos. First of all, we'll show a multi-user
slideshow system that we discussed in that Ajax Push slide.
This is the WebMC application. As a moderator, I'll sign in and create a
presentation named JSFOne. Then, I can upload my slides to make them available in
the system, where they'll be unpacked and be ready for use in the presentation.
Now, they're uploaded.
And now, as another user, I can sign into the JSFOne presentation and those
slides are available to me there. When the moderator advances the slide to the
next one, you can see that it's automatically updated in the other user's
browser.
If you combine this with an audio channel, for instance, just a telephone or
perhaps Skype, this will allow you to conduct a conference over the web. Ajax
Push allows the moderator to move the slide presentation to the desired slide.
It turns the web presentation application into a communication application.
There are other features in this application such as chat. We'll demonstrate
that here.
In this case, the chat text is sent from the moderator to the server. The
server pushes the update to the page to the other user's browser.
This application, WebMC, is completely open-source, freely available, you can
download it from ICEfaces.org. You can also
use the webMC.ICEfaces.org server to
try it out or for any presentations that you want to share.
Now, back to the slides. Let's look at another demo. This is an interactive
locking demo. This demo is developed jointly with our partner in Switzerland,
mimacom.
Close these windows. Here, I'll log in as Mika. And here, I'll log in as Ted.
And now, let's allow the two users to edit various records. For instance, I can
select this record and click on "Edit". Perhaps I am changing one of
the entries.
Both users are looking at the same dataset, and when I save it, it's pushed to
the other users viewing that same page. So, both of these users are seeing a
consistent, timely view of the same data model.
Well, perhaps I realize that there's something wrong with what I've done, and I
want to edit that record again. And at the same time, the other user realizes
that the record should be edited. If you go back to this one, we have acquired
the lock on the left, on the right, we would like to edit that same record, but
that record is locked. So, we can request it.
Our chat messages are pushed to the other user. So, the two users can discuss
the state of this item that's locked. This allows them to negotiate, in human
terms, what should be done with the record.
I can ask the other user to fix the record, I'll remove the window so that we
can see the chat message as it appears. "Please fix it." All right,
so that means that I'll cancel my edit and allow the other user to edit it. As
now, the lock is released, they can change it and save. And we can see that the
update is pushed to the other user. So, in this way, the users are working
through a shared locking mechanism to edit a shared dataset.
Very common type of application, but now we've translated, or transformed, what
was a problem of contention which perhaps we could've solved purely by some
software means, but it would've meant a policy where only the last user record
would be saved or something like that. In this case, by allowing the users to
interact with each other, we can deal with contention in a more sophisticated
way and actually allow people to resolve the problem and come to the correct
answer.
What does this mean on the wire? How do we actually implement this Push
technology in terms of a protocol? Well, there are really three options.
Pulling is not a good option, because either you choose your pulling interval
to be short, in which case you swamp the server with so many requests that the
application seems slow, or you choose your pulling interval to be long, in
which case, the time between one pull request and the next is so long that you don't
receive timely updates.
What we use with ICEfaces is something called a long pull or blocking HTTP,
where we make a request to the server and it responds precisely when it has an
update available.
Another option for Ajax Push would be HTTP streaming, where the server just
continually writes to a stream. In terms of the efficiency on the network,
streaming might be the best choice.
The difficulty is implementing it in today's web, and there are two problems:
One problem is that there's no read API available in JavaScript, so to read
from a stream, we have to really build up the entire stream as a buffer in
memory. That's essentially like a memory leak in the browser, not the most
efficient.
The other problem is that an intermediate proxy may choose to buffer the HTTP
response until it is complete. Well, in our case, the HTTP response wouldn't be
complete until the application exited, and that's not the desired case at all.
So, we use the blocking HTTP technique. The way that it works is when the browser
loads the page from the server, it executes the ICEfaces JavaScript. The first
operation is to request any page updates. If there are no page updates at that
time, the server simply waits. When a page update appears, for instance, a user
has typed in a chat message, that's when the server responds. Then, the browser
asks again, and the cycle completes. This allows us to invert the message flow
of HTTP and push updates to the browser.
But there are some complications. For instance, does this scale well?
If you consider that, with the Servlet API asking us to wait in the service
method, before we issue a response, means that there will be a thread sitting
there blocked in the service method. In other words, we would consume a thread
on the server for every single user. That's not good for scalability.
So, what we would prefer to do is handle multiple requests and responses with a
small thread pool. While not possible with the Servlet API currently, it is
possible with additional APIs available on a variety of web servers. For
instance, Jetty provides a continuation mechanism for this. Tomcat provides an
event-based API that gives you suspend and resume. And GlassFish, as well,
provides the Grizzly APIs for performing asynchronous reading, writing, suspend,
and resume.
In addition, GlassFish provides quality of service that you can apply. The
quality of service allows you to make it so that the system can degrade
gracefully under load, so that, if you have more updates than the server can
efficiently deliver at a particular time, you're able to prioritize those
updates and deliver just the most important ones, meaning that the system
behaves well even though it has exceeded its loaded capacity.
And Resin and WebLogic also provide similar APIs that allow us to suspend and
resume requests and responses beyond what the Servlet API provides for us.
Well, now, work is ongoing in Servlet 3.0 to define a standard API so that we
don't need to use these application-specific APIs. This will give us a standard
API for asynchronous IO, potentially, and for suspending and resuming requests
and responses. Since not that many people write Servlets nowadays, it may not
affect your day-to-day code as writing an application, but it will affect the
portability of various Ajax frameworks, such as ICEfaces, DWR, and Cometd.
For JSF 2.0, we would like to add this idea of push into JSF itself. And the
idea here is to split the push concept into notification and refresh.
Notification could be delivered in a variety of ways. Perhaps it's just from a
timer, or perhaps it's from a push mechanism as I described the protocol just
now.
Refresh is simple to implement in ICEfaces. ICEfaces can render the DOM on the
server at any time and determine just the updates and send them down to the
browser. Other Ajax frameworks tend to be based on update regions, so they
can't do this.
But, the notification could specify a target for the refresh. So, those targets
could be reserved in the page, and this would allow just the desired target to
be refreshed, which should be compatible with a variety of Ajax frameworks.
Now, another technical problem that we encounter when trying to implement push
is the fact that the browser generally has a two-connection limit to the
server. So, for a given host, the browser can only make two connections to that
host. Well, you could imagine that if you open up two browser windows, each
browser window having a push connection maintained to the server, you've now
used up both of the TCP connections that are permitted.
What that means is that any user events that you attempt to generate - click on
a button or a link - will not be sent to the server because there isn't an
available TCP connection to deliver it over. So, what we need to do is to share
a single TCP connection across the multiple windows in the browser.
Now, imagine that you have multiple web applications on the server, all of them
using push. They're all in the same host, so there's only a single TCP
connection allowed for the push updates from that single web application.
Well, to solve this, we've created the ICEfaces Ajax Push Server. And what that
does is it uses JMS to coordinate all of the push updates over a single
channel. And then, in the browser, we use a JavaScript cookie-pooling technique
to share those updates across the browser. This allows you to put multiple web
applications on the server, open up multiple browser tabs, multiple browser
windows, and have the push updates reliably delivered to all of them.
In the case of GlassFish, we've made an update-center module that allows you to
easily add the Ajax Push Server and install it, automatically configure the JMS
topics for you and the applications together, making it simple to deploy Ajax
Push applications in this manner.
Let's move on to scopes and flows, because we're interested in building a
sophisticated application with Ajax Push, but it turns out that request,
session, and application scope are not sufficient for this.
Let's go back to the multi-window problem. Request scope lasts for each user
event. So, it's a short-lived scope. Application scope is a much longer-lasting
scope. It spends all of the user activity, all of the different user's
activity, within the application. It's a very broad scope, and not easily used
for storing user-specific data. In fact, you shouldn't store user-specific data
in the application scope. Session scope lies in between these.
But now, we should observe that the multiple browser windows all share a common
session scope. They're all in the same HTTP session. So, we don't have a
formally defined scope, according to the Servlet specification, that allows us
to distinguish multiple windows. We need something that lies between request
and session.
Well, with ICEfaces, we've defined an extended request scope. What that does is
it modifies request scope so that it lasts from one full-page refresh to the
next. You could consider, when you open up multiple browser windows, each of
these browser windows initiates a single full-page refresh, and then Ajax requests
take place within each of those windows. That means that each of these distinct
windows has a distinct extended request scope. It's actually a very effective
way to distinguish your windows.
The downside of this is that it subverts request scope so that standard,
short-lived request scope is then not available to your application. In most
cases, that is an acceptable compromise because request scope is really rarely
used.
But, there are cases where it is used. In fact, some of the cases where it's
used most are when we integrate with third-party libraries, such as Seam or
Spring Web Flow. But, the good thing about that is that Seam and Spring Web
Flow both add new scopes of their own that go beyond request, session, and
application, such as event, page, conversation, and business process in Seam
and flash, flow, and conversation in Spring Web Flow.
We'll talk about each of these scopes in turn. So, the ICEfaces extended
request scope is very useful for Ajax. It allows you to distinguish multiple
windows. But really, we may be better off using one of the extended scopes in
Seam or Spring Web Flow.
Seam has a request scope. It's actually called "event scope" in Seam.
It's just the standard request scope.
Flash scope, in Spring Web Flow, allows you to carry objects from one request
to the next. It's useful for propagating objects out of a user dialog.
Seam page scope is not the same as JSP page scope. It's actually backed by the
ViewRoot. Now, this is a very useful scope for Ajax, because you'll have distinct
ViewRoots for each of these distinct windows. This means that if you put things
in Seam page scope, they'll be well-separated between the different windows.
This is a good alternative from the ICEfaces' extended request scope.
Spring Web Flow flow scope is defined by the flow. And the flow is defined in
your flow definition. But, multiple browser windows will have distinct flows.
So, you can also use this as a replacement for ICEfaces' extended request
scope.
Seam conversation scope is a sophisticated scope. It allows you to define a
task. So, the task has a beginning and an ending; objects last for the duration
of the task. It's a little more work to deal with than something like the view
scope or the page scope, but as an application developer, you have more control
over it, and it can actually span multiple window navigations. So, that's a
good scope to use. You can use it with AJAX and Ajax Push.
The conversation scope in Spring Web Flow is a larger scope than the flow
scope. It spans all of the flows within the conversation and is terminated when
the flow reaches an end state. This is really like a super-flow state. You can
use this as well, and replace the ICEfaces extended request scope. What you
want to keep in mind is that it's defined by your web flow config.
Now, business process scope is available in Seam. This could be a very
long-running scope indeed, and it's controlled by the business process manager.
Session scope, of course, you're familiar with this. The session is defined by
the HTTP session. What you have to keep in mind is that objects in session
scope are shared by all browser windows. So, if you put something like your
selected index in the session scope, don't be surprised when that same record
is selected in multiple windows. But still, session scope can be very useful
even in AJAX applications because often you do want to share data between the
different user windows.
Application scope is such a broad scope that in many ways it's difficult to use
in applications for application-specific data. Often, people simply put
configuration into application scope. One disadvantage is that application
scope data is typically not propagated in clustering systems.
One scope that is particularly interesting is a new scope that'll be found in
JSF 2.0, and this is explicitly called the view scope. So, in addition to
requests, session, and application, in your faces-config, you can simply
declare that an object should be stored with the view root. Well, that's very
much like the Seam page scope and the ICEfaces extended request scope. It
allows you to associate objects for a specific window that the user has open,
effectively solving that problem.
If you don't need the added sophistication of defining objects that last for
the duration of a task, but are simply available within a window, this is the
scope that you need. And it will be very easy to use, you simply declare that
the object is attached to the view.
Now, let's look in a little more detail at developing an asynchronous
application. You've seen the WebMC demo. Now, let's look at how it's
implemented.
We need an API to perform Ajax Push. The easiest API to use is the session
renderer. With the session renderer, we have the idea of adding the current
session to a group. This decision has to be made in an application-dependent
manner.
For instance, when the user visits the chat area of the application, then you
should add that user, that current session, to the chat group. Then later,
pushing updates to all of those chat users is as simple as calling
SessionRenderer.render("chat").
So, the way that you develop your application is you accept user input, you
update the model to be the desired state, and then you call a render on the
group that is relevant to that update. ICEfaces will render all of the pages in
all of the sessions in that group, determine the changes to the page for you,
and push those changes out to the browser. So really, developing a Push-based
application is only two lines of code beyond a standard JSF application.
Just look at the typical code that we would find in WebMC application. It's a
JSF application, so we import some namespaces. You can have markup. Organize
your page into groups with layout components. Perhaps you have output text with
static or dynamic values. And then, the key part of this application is the
slide. Well, we don't need any AJAX concerns here, we simply need to say that
the page has a graphic image with it whose value is derived from the current
slide URL.
In our Bean, we have a getter for get slide URL. It's just recording the
current state of the model. The moderator will change the value of the slide
URL to the current slide.
We also have some methods for the chat log. Our input can be received and added
to the log.
But now, let's look at the Ajax Push aspect. Import the session renderer. In
the case of the WebMC application, we want to organize our users into groups of
presentations. We created the JSFOne presentation, let's add the sessions of
those users who are viewing the JSFOne presentation into the group associated
with that presentation. So, we call add current session with the presentation
name.
Then, when the moderator advances a slide, we simply call
SessionRenderer.render("presentation name"). That will push out the
changes to all of those users in that common presentation.
Now, we have an additional API that provides more fine-grained control. When I
talked about the session renderer, I said that all the windows in all of the
sessions in a given group will be rendered. But, what if you wanted to render
just specific windows that the user had open? For scalability reasons, you
might want to concern yourself with that, even thought it is a bit more
bookkeeping in your application. In that case, you should use the persistent
faces state object associated with that view.
Here, we call request render on the render manager. In this example, we're
using an interval renderer, where we configure it with an interval. We add this
renderable object to the render manager so that it can be rendered when the
interval has elapsed.
In addition, we're able to observe exceptions and perform cleanup with these
APIs. For instance, we might see exceptions if a user has closed their browser
window and we attempt to push an update to it. That exception could be
transient or fatal, depending on the conditions, either simply delayed
heartbeat messages or an actual socket close that has taken place. Using the
dispose bean interface, we can perform cleanup and we should remove ourselves
from the clock render manager.
In order to configure this, you make use of the faces-config. Instantiate the
render manager through the dependency injection mechanism in the faces-config
and inject that render manager into the clock bean so that you can add yourself
as a renderable to it.
In conclusion, I hope we've demonstrated that the asynchronous web is a
revolutionary change in the type of web applications that we can make. And Ajax
Push is the key for building collaborative enterprise applications. As you've
seen, it can scale, as long as we use the right application servers and the
right APIs, on those servers. And ICEfaces is what you need in order to add
these features to your application, because ICEfaces provides the high-level
application framework capabilities in order to develop Ajax Push.
Thank you and please contact us with any questions or comments that you might
have.
About Ted Goddard
Ted Goddard is a Senior Software Architect at ICEsoft Technologies and
is the technical lead for the JavaServer Faces Ajax framework,
ICEfaces. Following a PhD in Mathematics from Emory University that
answered open problems in complexity theory and infinite colorings for
ordered sets, he proceeded with post-doctoral research in component and
web-based collaborative technologies. He has held positions at Sun
Microsystems, AudeSi Technologies, and Wind River Systems, and
currently particpates in the Servlet and JavaServer Faces expert
groups.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





Comments
Clemens Eisserer replied on Fri, 2008/10/03 - 3:15pm
Ted Goddard replied on Mon, 2008/10/06 - 11:58am
in response to:
Clemens Eisserer
Ajax really only refers to a way of using the web that decouples the user interface from the network protocol (no more full page refresh when submitting forms) so there are a great variety of ways of writing applications that apply this basic principle.
ICEfaces is an extension of JavaServer Faces, so the application developer can apply all that server-side Java development has to offer. Application logic is implemented in Java Beans and the pages are defined declaratively and dynamically bound via expression language to the model beans. This is highly structured and modern IDEs can substantially assist the developer through tag-level syntax completion and expression language completion. Since JavaServer Faces is a component technology, some environments also offer visual design capabilities. With ICEfaces, the Java developer need never be exposed to the underlying JavaScript techniques that are used to implement the Ajax capabilities; this is orders of magnitude more pleasant and more powerful than editing VB files in Word.
However, another interpretation is that writing applications for the web is like writing applications in VB that run in Word. The web is clearly pervasive and here to stay, but it's always good to step back and look at whether our society is on the right track (because the prevalence of the web makes it more a part of society than just a software technology). An important point is that the agnostic nature of the web allows any language to be used; we are not restricted to the VB runtime available in Word. Secondly, web clients are freely available to all users; the variety of browsers are (substantially) based on standards and available for practically all operating systems. Finally, the web is based on the idea of a "document", an idea that has been tremendously powerful for thousands of years. Web applications are simply the realization of "dynamic" documents that are accessible from anywhere in the world. Maybe humanity is on the right track after all.
In any case, ICEfaces applications are easily developed when the right tools are applied (you can even edit the source code with Word, but it's not recommended) and the framework complexity required to target different browser environments is vastly simpler than the complexity of supporting AWT on X11, Win32, and MacOS 9.