Here is a status report on Avatar. It's coming along. I hope to have
the first milestone release on the 30th.
https://jsf-extensions.dev.java.net/files/documents/4613/36314/20060617-avatar-plan.html
Attached for your convenience and discussion.
I have just checked in a major change to the avatar code in
jsf-extensions. I'm using some ideas from Jacob's JavaOne demo as a
starting point. Here's what I have.
1.
AjaxLifecycle
Description of new Avatar Implementation
The AjaxLifecycle is now the main lifecycle for Avatar enabled
apps. This replaces the custom UIViewRoot approach and decorates
the default Lifecycle. All one need change in their web.xml is to
add an init-param to their Faces Servlet mapping.
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<init-param>
<param-name>javax.faces.LIFECYCLE_ID</param-name>
<param-value>com.sun.faces.lifecycle.AJAX</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
This approach has the benefit of not requiring mounting any
additional FacesServlet instances, nor filters or phaseListeners,
not to mention it frees up the UIViewRoot for others to sub-class
and replace if necessary.
2.
Use request headers to convey ajax metadata.
The following headers are currenty supported in the AjaxLifecycle
com.sun.faces.Async
If this header is present, the AjaxLifecycle treats this
request as an AJAX request.
com.sun.faces.Subtrees
This is a comma separated list of clientIds against which the
lifecycle should be run. Each lifecycle phase is run on each
clientId using invokeOnComponent() to ensure proper context.
com.sun.faces.lifecycle.RunThru
This header gives the name of the request processing lifecycle
phase through which the lifecycle should be run. For example, the
replacement for Jacob's javax.faces.Update parameter is to define
the RunThru header with the value of UPDATE_MODEL_VALUES. The
response generated when running a partial lifecycle will be
described below.
I have the following header also in-mind, but not yet implemented:
com.sun.faces.lifecycle.<LIFECYCLE_PHASE>
If defined, this is a comma separated list of client ids to be
used for that specific lifecycle phase. This value overrides the
value of com.sun.faces.Subtrees for that specific phase.
3.
New XML application for AJAX responses from avatar server.
If the request has the com.sun.faces.Async and
com.sun.faces.Subtrees headers, with valid values, but no
com.sun.faces.lifecycle.RunThru header, request will look
something like this:
POST
http://localhost:8080/jsf-extensions/faces/result-set.jsp HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Proxy-Connection: keep-alive
X-Requested-With: XMLHttpRequest
X-Prototype-Version: 1.5.0_rc0
Content-Type: application/x-www-form-urlencoded
Connection: close
com.sun.faces.Async: true
com.sun.faces.Subtrees: form:table,form:subview2
Content-Length: 277
Cookie: com.sun.faces.extensions.flashPostbackRequest=8.0; JSESSIONID=33ab516de8b10090a6e8c9f604f4
Pragma: no-cache
Cache-Control: no-cache
options=%5Bobject%20Object%5D&form%3Ascroller_action=10&form%3Ascroller_curPage=1&javax.faces.ViewState=j_id3%3Aj_id4&form=form&http%3A%2F%2Flocalhost%3A8080%2Fjsf-extensions%2Ffaces%2Fresult-set.jsp%23=http%3A%2F%2Flocalhost%3A8080%2Fjsf-extensions%2Ffaces%2Fresult-set.jsp%23
And the response like this:
HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Cache-Control: no-cache
Content-Type: text/xml;charset=ISO-8859-1
Date: Sat, 17 Jun 2006 18:23:28 GMT
Server: Sun Java System Application Server Platform Edition 9.1
Connection: close
<async-response>
<render id="form:table">
<![CDATA[<table id="form:table" class="list-background">
<thead>
<tr>
<th class="list-header" scope="col">Account Id</th>
<th class="list-header" scope="col">Customer Name</th>
<th class="list-header" scope="col">Symbol</th>
<th class="list-header" scope="col">Total Sales</th>
</tr>
</thead>
<tbody>
<tr class="list-row-even">
<td class="list-column-center"><span id="form:table:180:accountId">180</span></td>
<td class="list-column-center"><script type="text/javascript" src="
http://localhost:8080/jsf-extensions/jmaki.js"></script>
<script type="text/javascript">jmaki.webRoot='
http://localhost:8080/jsf-extensions';</script>
<script type="text/javascript" src="
http://localhost:8080/jsf-extensions/resources/scriptaculous/prototype.js"></script>
<script type="text/javascript" src="
http://localhost:8080/jsf-extensions/resources/scriptaculous/scriptaculous.js"></script>
<link rel="stylesheet" type="text/css" href="
http://localhost:8080/jsf-extensions/inplace/component.css"></link>
<a id="form:table:180:j_id_id52" href="#">name_180</a>
<script type="text/javascript">
jmaki.addWidget({service:'
http://localhost:8080/jsf-extensions/faces/result-set.jsp',script:'
http://localhost:8080/jsf-extensions//inplace/component.js',uuid:'form:table:180:j_id_id52',name:'inplace',id:'form:table:180:j_id_id52'});</script>
</td>
<td class="list-column-center"><span id="form:table:180:symbol">symbol_180</span></td>
<td class="list-column-center"><span id="form:table:180:totalSales">180.0</span></td>
</tr>
<-- additional rows omitted -->]]></render>
<render id="form:subview2">
<![CDATA[<div id="form:subview2"><table border="0" cellpadding="0" align="center"><tr align="center" valign="top"><td><font size="-1">Result Page: </font></td><td>
<a href="#" onmousedown="document.forms[0]['form:scroller_action'].value='-2'; document.forms[0]['form:scroller_curPage'].value='10'; document.forms[0].submit()">Previous<img src="/jsf-extensions/images/arrow-left.gif" alt="" /><br /></a></td><td>
<a href="#" onmousedown="document.forms[0]['form:scroller_action'].value='1'; document.forms[0]['form:scroller_curPage'].value='10'; document.forms[0].submit()">1</a></td>
<!-- additional cells omitted -->
</tr><input type="hidden" name="form:scroller_action"/>
<input type="hidden" name="form:scroller_curPage"/></table>
<script type='text/javascript'>
document.forms[0].submit = function() {};
var a = $('form:subview2').getElementsByTagName('a');
$A(a).each(function(e) {
new Faces.Command(e, 'mousedown', { subtrees: 'form:table,form:subview2' });
});
</script>
</div>]]></render>
<state>
<![CDATA[j_id3:j_id4]]>
</state>
</async-response>
To support simple updating (with validation and conversion properly handled) of one or more values in the component tree, use the RunThru header with a value of UPDATE_MODEL_VALUES. A request with this header looks like this:
POST
http://localhost:8080/jsf-extensions/faces/result-set.jsp HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4
Accept: text/javascript, text/html, application/xml, text/xml, */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Proxy-Connection: keep-alive
X-Requested-With: XMLHttpRequest
X-Prototype-Version: 1.5.0_rc0
Content-Type: application/x-www-form-urlencoded
Connection: close
com.sun.faces.Async: true
com.sun.faces.Subtrees: form:table:181:j_id_id52
com.sun.faces.lifecycle.RunThru: UPDATE_MODEL_VALUES
Content-Length: 163
Cookie: com.sun.faces.extensions.flashPostbackRequest=8.0; JSESSIONID=33ab516de8b10090a6e8c9f604f4
Pragma: no-cache
Cache-Control: no-cache
form%3Atable%3A181%3Aj_id_id52=181&form%3Atable%3A181%3Aj_id_id52-inplaceeditor=form%3Atable%3A181%3Aj_id_id52-inplaceeditor&javax.faces.ViewState=j_id3%3Aj_id4&_=
And the response will look like this:
HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Cache-Control: no-cache
Content-Type: text/xml;charset=ISO-8859-1
Content-Length: 133
Date: Sat, 17 Jun 2006 18:29:42 GMT
Server: Sun Java System Application Server Platform Edition 9.1
Connection: close
<async-response><update id="form:table:181:j_id_id52"><![CDATA[181]]></update><state><![CDATA[j_id3:j_id4]]></state></async-response>
The values returned is subject to conversion and validation with
any converters or validators that are attached to the component.
This implementation also supports updating multiple components in
the tree with a single transaction.
Next Steps - Concrete Tasks
Currently, the result-set.jsp example, in the run-time-test
module, is the only one that works. My next step is to take
Jacob's JavaOne demo and move it into our repo and make it work
with the avatar impl. This will require support for Jacob's
javax.faces.Event header, which I don't think will be too hard to
add, but we'll see.
After that, I want to get the ajaxZones implementation updated to
use the new framework, and remove as much of my old procedural
JavaScript code from com_sun_faces_ajax.js as possible. In concert
with this task, I will make the jsf-ajax-carstore example work
again. This will prove out the fully functional ajaxZone concept.
Next Steps - Concepts
You can see where I'm going with this lifecycle idea. I'd like to
expose the JSF lifecycle easily to AJAX. One interesting idea is
to pass up a chunk of JavaScript in the AJAX request, along with
processing instructions about it, that will cause the JavaScript
to be executed on the server to help serv up the response. We'd
need Phobos to do this, but I think having the ability for the
client to send up JavaScript to the server to be executed in the
context of the JSF lifecycle is a powerful feature.
Another idea is to make the rendering of the response pluggable so
that one could send the response back in JSON instead of hard
coded XML. Perhaps Dan Labreque can help with this.
--
| ed.burns_at_sun.com | {home: 407 869 9587, office: 408 884 9519 OR x31640}
| homepage: | http://purl.oclc.org/NET/edburns/
| aim: edburns0sunw | iim: ed.burns_at_sun.com