Friday Oct 26, 2007
Friday Oct 26, 2007
By Roger Kitain
The world of dynamic web applications offers various ways for a client and server to interact. Two approaches are particularly well suited for situations when information on the server changes frequently. These approaches are:
In HTTP streaming, the client/server connection is left open for an extended period of time so that data is streamed from the server to the client. This approach is also known as server-side push, reverse Ajax, or comet. As information changes on the server, updates are pushed to the client.
With client polling, the browser periodically issues an
XMLHttpRequest call to obtain new information from the server.
For example, a client can send an XMLHttpRequest to the server
every five seconds to get new information. This approach is also
known as periodic refresh.
The Dynamic Faces framework brings the power of Ajax to traditional JavaServer Faces Technology (often abbreviated as JSF) applications. Ajax function calls are typically made in JavaScript, which can be unfamiliar to Java developers. With Dynamic Faces, you can add Ajax functionality to a JSF application with little or no JavaScript. Dynamic Faces provides a small "out of the box" JavaScript library that you can use with a JSF application.
This tip will show you how you can use Dynamic Faces to build a real-time, stock query application that does client-side polling. You'll see that you don't have to do much JavaScript coding. A package that contains the code for the sample application accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package).
The Stock Query Application
This tip uses a stock query application to demonstrate client-side polling with Dynamic Faces.
First, let's take a look at the user interface (UI) for the application.
User Interface
Stock Query
|
The UI is pretty basic. You enter one or more space-delimited stock symbols in the Symbol text field and click the Search button. In response, the application displays a table of data pertinent to the stocks represented by the symbols you entered.
You enter proxy information in the Proxy Host and Proxy Port fields if you are behind a firewall.
The most interesting feature of the UI is the Streaming field. The choices are On or Off. If Streaming is set to On, the client polls the server, firing Ajax transactions every 10 seconds (or a specified time interval).
The Remote/Local field allows you to choose either Local or Remote. If you select Local, the application uses local data. This is the choice to make if a network connection is not available. If you select Remote, the application calls the Yahoo Stock Quoting service to get the stock data.
The size of the result table dynamically changes depending on the number of symbols that you enter.
Now let's take a look at the artifacts used in the application.
Artifacts
There are only three artifacts used in the application:
JSP Page
Here's a snippet of the JSP page for the application, home.jsp, showing the relevant parts:
<f:view> <html> <head> ... ... <jsfExt:scripts/> <script type="text/javascript"> ... ... include_js('javascripts/stock-faces.js'); </script> </head> <body> <h:form id="form" prependId="false"> ... <h:panelGrid border="1" columns="1" styleClass="panel-input-border"> <h:panelGrid border="1" columns="7"> <h:outputText value="Symbol:"/> <h:inputText id="symbol"/> <h:commandButton id="search" value="Search" onclick="DynaFaces.fireAjaxTransaction( this, {});return false;" actionListener="#{bean.getStockInfo}" /> ... <h:selectOneMenu id="streaming" value="Off" onchange="toggleStreaming()"> ... </h:panelGrid> </h:panelGrid> <h:panelGrid id="stockdata" border="1" columns="8" styleClass="panel-data-border" rendered="false"> ... </body> </html> </f:view> Here are some things to notice in the code snippet:
<jsfExt:scripts/> is the standard tag to include for Dynamic
Faces applications. It includes the Dynamic Faces JavaScript
library.
include_js('javascripts/stock-faces.js'); line is a
utility function that loads the application's JavaScript file,
stock-faces.js.
h:commandButton tag has an onclick JavaScript event
handler attached to it. The event handler,
DynaFaces.fireAjaxTransaction, sends an Ajax request to the
server when the button is clicked. The actionListener
specified by #{bean.getStockInfo} is then executed on the
server. What's significant here is that any view or JSF
component manipulation done on the server happens using Ajax.
h:selectOneMenu component that has
an onchange JavaScript event handler.
h:panelGrid tag with an id of "stockdata" is a placeholder
the dynamic table of stock data. The attribute rendered is set
to "false", meaning that the table is not initially rendered.
However, the application code sets the attribute to true
when there is stock data to return.
JavaScript File
Here is the JavaScript file, stockfaces.js, for the application:
var pollId; /** Delay between requests to the server when polling. */ var pollDelay = 10000; /** Start polling the server */ function start() { pollId = setInterval(poll, pollDelay); } /** Stop polling the server */ function stop() { clearInterval(pollId); } function poll() { queueEvent(); DynaFaces.fireAjaxTransaction(null, {}); } function queueEvent() { var actionEvent = new DynaFaces.ActionEvent("search", DynaFaces.PhaseId.INVOKE_APPLICATION); DynaFaces.queueFacesEvent(actionEvent); return false; } function toggleStreaming() { var menu = document.getElementById("streaming"); var idx = menu.selectedIndex; var streaming = menu[idx].value; if (streaming == "Off") { stop(); } else if (streaming == "On") { start(); } }Here's what the JavaScript code in the file does:
start() function initiates the server polling.stop() function stops server polling.poll() function queues up a server-side JSF action event.
It then fires an Ajax request to the server using the Dynamic
Faces library.
queueEvent() function queues up a server-side JSF action
event using the Dynamic Faces library. The action event is
processed during the standard JSF lifecycle processing as the
Ajax request flows to the server.
toggleStreaming() function toggles the value of the "streaming" menu control.JSF Managed Bean
Here's a snippet of the JSF managed bean, Bean.java, showing the relevant parts:
/** * This bean has methods to retrieve stock information from * the Yahoo quote service. */ public class Bean { private static final String SERVICE_URL = "http://quote.yahoo.com/d/quotes.csv"; /** * Action method that is used to retrieve stock * information. This method uses two helper methods - one * to get the stock information, and the other to * dynamically build the "data" components for the UI. */ public void getStockInfo(ActionEvent ae) { ... ... stockData = getStockData(symbols); buildUI(stockData); ... } /** * Helper method to get the stock data (remotely). */ private String[] getStockData(String[] symbols) throws IOException, MalformedURLException { String[] data = new String[symbols.length]; for (int i=0; i<symbols.length; i++) { StringBuffer sb = new StringBuffer(SERVICE_URL); ... ... } return data; } /** * Helper method to dynamically add JSF components to * display the data. */ private void buildUI(String[] stockData) { FacesContext context = FacesContext.getCurrentInstance(); UIForm form = (UIForm)context.getViewRoot().findComponent("form"); UIPanel dataPanel = (UIPanel)form.findComponent("stockdata"); ... ... // Create and add components with data values // Symbol ... dataPanel.getChildren().add(outputComponent); // Name ... dataPanel.getChildren().add(outputComponent); // Open Price (if any) ... dataPanel.getChildren().add(outputComponent); ... ... } dataPanel.setRendered(true); }This JSF Managed Bean has an action method, getStockInfo, that
does two things:
getStockData, to contact the Yahoo
Stock Quote service (as defined by SERVICE_URL) to retrieve
stock data for all the symbols.
buildUI, to build JSF components
(from the stock data) and it adds the JSF components to the
JSF component view. After all the components have been created
and added, the action method sets the rendered attribute to
true on the stockdata JSF component.
The action method, getStockInfo, is called when the Search
button is pressed. It is also called as the result of an Ajax
poll request. This is because each client poll queues an
action event tied to this event handler. Refer to the
queueEvent method in the stock-faces.js JavaScript file.
Running the Sample Code
A sample package accompanies this tip that demonstrates the techniques covered in the tip. You can deploy the sample package on any web container that supports the Servlet 2.5 API, JavaServer Pages (JSP) Technology 2.1, and JavaServer Faces Technology 1.2. These instructions assume that you are using GlassFish.
To install and run the sample:
<sample_install_dir>/client-poll-dfaces, where
<sample_install_dir> is the directory where you installed the
sample application. For example, if you extracted the
contents to C:\ on a Windows machine, then your newly created
directory should be at C:\client-poll-dfaces.
<GF_HOME>/bin/asadmin start-domain domain1<GF_HOME> is the directory where you installed GlassFish.
<sample_install_dir>/client-poll-dfaces/stock-faces.war to <GF_HOME>/domains/domain1/autodeploy
URL: http://localhost:8080/stock-faces/.
You should see the Stock Query Application UI.
Stock Query
|
Stock Query
|
Summary
This tip demonstrated how you can combine JSF with Ajax to produce dynamic applications. This application illustrated two features of Dynamic Faces:
fireAjaxTransactionYou can find out more about Dynamic Faces in the jsf-extensions project. Also see Ed Burns's blog Introducing Project Dynamic Faces.
>About the Author
Roger Kitain is the JavaServer Faces technology co-specification lead. He has been extensively involved with server-side web technologies and products since 1997. Roger started working on JSF in 2001 as a member of the reference implementation team. He has experience with Java Servlet technology, JSP, and most recently has been involved with different rendering technologies for JSF.
Hi,
First of All Thanks a lot for publishing this artical and it is also informative.
Posted by Nihar Bhatt on December 19, 2007 at 10:49 AM PST #
Hi....
Thanks a lot .... i run your sample successfully ... and it is really helpful to me...
Posted by Nihar Bhatt on December 19, 2007 at 10:55 AM PST #
Thanks for the positive feedback.
Posted by Ed Ort on December 20, 2007 at 08:45 AM PST #