dev@jsf-extensions.java.net

Avatar Status (Jacob, Dan and Craig, please read)

From: Ed Burns <ed.burns_at_sun.com>
Date: Sat, 17 Jun 2006 11:49:59 -0700

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