<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-20632077</id><updated>2012-02-01T04:05:43.239-08:00</updated><title type='text'>JSF in SF</title><subtitle type='html'>A blog about JavaServer Faces - or anything else in the Java world that needs saying.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-20632077.post-7900297827137956510</id><published>2007-07-31T15:12:00.000-07:00</published><updated>2007-07-31T16:21:16.624-07:00</updated><title type='text'>AJAX and the Refresh Button</title><content type='html'>JSF relies heavily on &lt;code&gt;&amp;lt;input type="hidden" name="javax.faces.ViewState"&amp;gt;&lt;/code&gt; for its lifecycle.  This hidden field carries all UI state for the page.  Whether that's client-side state (with the entire page Base64-encoded) or server-side state (with a simple token), it's important that the right field be delivered with any JSF postback for the page to function correctly.&lt;br /&gt;&lt;br /&gt;As a result, AJAX implementations in JSF typically need not only to submit this value to the server when posting an AJAX request, but also to update it as necessary when a request completes.  While looking at an &lt;a href="http://www.oracle.com/technology/products/adf/adffaces/11/doc/demo/adf_faces_rc_demo.html"&gt;ADF Rich Client&lt;/a&gt; bug recently, I was rudely reminded that the Refresh/Reload button doesn't always behave as you might imagine, and thought it was worth delving into the details.  (I'll be talking about JSF, but the behavior is generic to DHTML and applies outside of JSF, and the code samples are just raw HTML.)&lt;br /&gt;&lt;br /&gt;Take the following page:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&amp;lt;form name="foo"&amp;gt;&lt;br /&gt;&amp;lt;div id="valCtr"&amp;gt;&lt;br /&gt;&amp;lt;input name="val" type="hidden" svalue="1"&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;document.forms.foo.val.value=1;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;a href="#" onclick="forms.foo.val.value =&lt;br /&gt;  parseInt(forms.foo.val.value) + 1; return false;"&amp;gt;&lt;br /&gt;    Increment&amp;lt;/a&amp;gt;&lt;br /&gt;&amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Now, in your favorite browser, try the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Click Display (you'll see 1)&lt;/li&gt;&lt;li&gt;Click Increment a couple of times&lt;/li&gt;&lt;li&gt;Click Display again (you'll see 3)&lt;/li&gt;&lt;li&gt;Click or select Refresh/Reload (but not Shift-Refresh)&lt;/li&gt;&lt;li&gt;And Display once more.  You'll still see 3 (unless you're using Safari)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Now, Shift-Refresh, and Display.  Now we're back at 1.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;What have we seen?  Refresh has re-queried the HTML for the page, but instead of resetting the value of our hidden input field back to 1, it's stored the updated value of 3!  This isn't a bug - so says &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=46845"&gt;this Bugzilla bug&lt;/a&gt; (and all &lt;span style="font-weight: bold;"&gt;61 duplicates&lt;/span&gt;!)  Microsoft would agree with Mozilla here.  Of the big 3, only Safari doesn't overwrite form fields on reload.  (The caching behavior is in fact very handy for Back/Forward, and is exploited by the &lt;a href="http://codinginparadise.org/projects/dhtml_history/README.html"&gt;Really Simple History&lt;/a&gt; framework.)  Shift-refresh fully reloads the page, and drops the form element cache.&lt;br /&gt;&lt;br /&gt;This can lead to big problems in a JSF application.  Take the following scenario:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A page initially renders with state token 1 in a hidden field&lt;br /&gt;&lt;/li&gt;&lt;li&gt;An  AJAX request updates the state token to 2&lt;/li&gt;&lt;li&gt;The user hits Reload, and the new HTML contains state token 3&lt;/li&gt;&lt;li&gt;But the browser ignores it, and overwrites it with state token 2!&lt;/li&gt;&lt;/ul&gt;Now we've got a page in state "3", but a token claiming it's really in state "2".  This is &lt;span style="font-weight: bold;"&gt;bad&lt;/span&gt;.  As always, let's see what alternatives we've got, and whether they suffer from the same problem.&lt;br /&gt;&lt;br /&gt;First, how about creating the DOM on the fly?&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;function incrementViaDOM()&lt;br /&gt;{&lt;br /&gt;  var value = parseInt(document.forms.foo.val.value) + 1;&lt;br /&gt;  var newField = document.createElement("input");&lt;br /&gt;  newField.name = "val";&lt;br /&gt;  newField.type = "hidden";&lt;br /&gt;  newField.value = "" + value;&lt;br /&gt;  var oldField = document.forms.foo.val;&lt;br /&gt;  var parent = oldField.parentNode;&lt;br /&gt;  parent.replaceChild(newField, oldField);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;a href="#" onclick="incrementViaDOM(); return false;"&amp;gt;&lt;br /&gt;  Increment with replaceChild&amp;lt;/a&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;In Firefox, this still doesn't help.  The hidden field value is still cached.  (And this example doesn't work at all in IE... see &lt;a href="http://www.thunderguy.com/semicolon/2005/05/23/setting-the-name-attribute-in-internet-explorer/"&gt;this entry&lt;/a&gt; for why and how to fix it.)&lt;br /&gt;&lt;br /&gt;OK, how about innerHTML?&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;var value = parseInt(document.forms.foo.val.value) + 1;&lt;br /&gt;var valCtr = document.getElementById("valCtr");&lt;br /&gt;valCtr.innerHTML = "&amp;lt;input name=\"val\" " +&lt;br /&gt;  "type=\"hidden\" value=\"" + value + "\"&amp;gt;";&lt;br /&gt;&lt;br /&gt;&amp;lt;a href="#" onclick="increment(); return false;"&amp;gt;&lt;br /&gt;  Increment with innerHTML&amp;lt;/a&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Now this works...  changes made by innerHTML are not remembered by Firefox or Internet Explorer (or Safari).  So, if you don't want a hidden field cached, update with innerHTML and browsers won't hassle you.&lt;br /&gt;&lt;br /&gt;Alternatively, you could look at tackling this issue during the refresh, by forcibly resetting the value from Javascript:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;input name="val" type="hidden"&amp;gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;document.forms.foo.val.value=1;&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;This works in Firefox, but does not in IE.  Whatever code overwrites the value of the hidden field runs after this inline script, but before the page's onload handler.  So, if you want to tackle this problem while refreshing, you'll have to do it in onload.&lt;br /&gt;&lt;br /&gt;To (finally) come back to JSF, there's a better way to solve this problem, at least for the state token.  Use a &lt;span style="font-family: courier new;"&gt;StateManager&lt;/span&gt; that automatically doesn't generate new tokens for AJAX requests, but instead reuses the old token.  New tokens are important when you're rendering a new page, but are a waste of space when you're just working on a single page.  And, as a nice side-effect, this makes this issue moot.  (MyFaces Trinidad 1.0.2 will include this token-reuse optimization, though it's always used innerHTML for updating the state token, so it hasn't been hit by this bug.)&lt;br /&gt;&lt;br /&gt;So, to summarize, if you have a programatically-modified, hidden input field that needs to be Reload-proof, two techniques look good:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Use innerHTML to update the field&lt;/li&gt;&lt;li&gt;Use onload to set the hidden input field value&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If you've got any other tricks, I'd be happy to know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-7900297827137956510?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/7900297827137956510/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=7900297827137956510' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/7900297827137956510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/7900297827137956510'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2007/07/ajax-and-refresh-button.html' title='AJAX and the Refresh Button'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-1095223483790782937</id><published>2007-05-23T14:20:00.000-07:00</published><updated>2007-05-23T15:03:24.960-07:00</updated><title type='text'>A year already? So long incubator!</title><content type='html'>How time flies... A year ago, we checked ADF Faces into the Apache incubator.  Now, we're out of the incubator, we're named Trinidad, and we're officially part of the &lt;a href="http://myfaces.apache.org"&gt;Apache MyFaces &lt;/a&gt;project. You can visit &lt;a href="http://myfaces.apache.org/trinidad/"&gt;our site&lt;/a&gt;, and &lt;a href="http://people.apache.org/repo/m2-snapshot-repository/org/apache/myfaces/trinidad/"&gt;download nightly builds &lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A lot has happened in this past year - a few highlights:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A bunch of new committers were added from inside Oracle and, most importantly, from outside Oracle&lt;/li&gt;&lt;li&gt;All the ins-and-outs of running an Apache project were ably handled by Matthias Wessendorf&lt;/li&gt;&lt;li&gt;Skinning functionality has gotten a lot better, mostly courtesy of Jeanne Waldman&lt;/li&gt;&lt;li&gt;Portlet support from Scott O'Bryan&lt;/li&gt;&lt;li&gt;Client-side validation now looks much better (no more JS alerts), from Danny Robinson&lt;/li&gt;&lt;li&gt;Lots and lots of bugs (300+) were put to ground&lt;/li&gt;&lt;li&gt;New components - a spinbox and an outputDocument&lt;/li&gt;&lt;li&gt;JSF 1.2 support was implemented (on a branch); the MyFaces implementation of the 1.2 JSF API uses a Trinidad plugin to generate components and tags.&lt;/li&gt;&lt;li&gt;And, I got engaged! (The future Mrs. even lets me get away with working on Trinidad at home.)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;It all took awhile, and a lot of work, but we're all glad to have reached this point.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-1095223483790782937?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/1095223483790782937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=1095223483790782937' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/1095223483790782937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/1095223483790782937'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2007/05/year-already-so-long-incubator.html' title='A year already? So long incubator!'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-114703013270311198</id><published>2006-05-07T12:23:00.000-07:00</published><updated>2006-05-07T14:23:59.530-07:00</updated><title type='text'>ADF Faces checked in to open source !</title><content type='html'>&lt;pre style="font-size:x-small;word-wrap:break-word;text-wrap:unrestricted"&gt;&lt;br /&gt;Transmitting file data .........................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;................................................................................&lt;br /&gt;...........................................&lt;br /&gt;Committed revision 404824.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;... and it's done.  ADF Faces has been checked into an Apache incubator at &lt;a href="http://svn.apache.org/repos/asf/incubator/adffaces/trunk/"&gt;http://svn.apache.org/repos/asf/incubator/adffaces/trunk/&lt;/a&gt;.  Now the real work begins!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-114703013270311198?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/114703013270311198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=114703013270311198' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114703013270311198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114703013270311198'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/05/adf-faces-checked-in-to-open-source.html' title='ADF Faces checked in to open source !'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-114374050426870076</id><published>2006-03-30T09:31:00.000-08:00</published><updated>2006-03-30T09:41:44.286-08:00</updated><title type='text'>Facelets 1.1.2 is out!</title><content type='html'>As &lt;a href="http://weblogs.java.net/blog/jhook/archive/2006/03/facelets_milest.html"&gt;Jacob Hookom just announced&lt;/a&gt;, Facelets 1.1.2 is now available.  This is a major milestone for Facelets:  the big issues have been nailed, templating's solidified, and excellent features like &amp;lt;ui:repeat&amp;gt; are in there too.  Give it a whirl!&lt;br /&gt;&lt;br /&gt;(And, for this blog, that "build before restore" feature that's part of saving JSF state saving has its first public appearance here too.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-114374050426870076?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/114374050426870076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=114374050426870076' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114374050426870076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114374050426870076'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/03/facelets-112-is-out.html' title='Facelets 1.1.2 is out!'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-114307478668896208</id><published>2006-03-22T16:24:00.000-08:00</published><updated>2006-03-22T16:46:38.926-08:00</updated><title type='text'>Usings Sets with UIData</title><content type='html'>One of the more personally surprising usability complaints I've heard was that the JSF UIData component does not support Sets.  I hadn't anticipated that one.  The underlying reason is that UIData is built around indexed data.  For example, you can ask it to show rows 10,000 through 10,099.  Such an operation would be nightmarishly expensive in a Set:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  Iterator iter = collection.iterator();&lt;br /&gt;  for (int i = 0; i &lt; 10000; i++) { iter.next(); }&lt;br /&gt;  // Hey, now we can start reading our data!&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;But, hey, we still got it wrong:  we should have supported it.  Yeah, it'd be slow - O(N) where N is the size of the set, not the amount of data actually displayed at one time - but the ease of use argument is compelling.&lt;br /&gt;&lt;br /&gt;That said, there's nothing stopping you from using Sets with UIData right now...  if you use the following class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import java.util.AbstractMap;&lt;br /&gt;import java.util.AbstractList;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Collection;&lt;br /&gt;import java.util.Collections;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.Map;&lt;br /&gt;import java.util.RandomAccess;&lt;br /&gt;import java.util.Set;&lt;br /&gt;&lt;br /&gt;public class ListFromCollection&lt;br /&gt;{&lt;br /&gt;  public ListFromCollection()&lt;br /&gt;  {&lt;br /&gt;    _map = new MakeList();&lt;br /&gt;    _size = _DEFAULT_SIZE;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public Map&amp;lt;Collection, List&amp;gt; getList()&lt;br /&gt;  {&lt;br /&gt;    return _map;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public int getSize()&lt;br /&gt;  {&lt;br /&gt;    return _size;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public void setSize(int size)&lt;br /&gt;  {&lt;br /&gt;    _size = size;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private class MakeList extends AbstractMap&amp;lt;Collection, List&amp;gt;&lt;br /&gt;  {&lt;br /&gt;    public List get(Object o)&lt;br /&gt;    {&lt;br /&gt;      if (!(o instanceof Collection))&lt;br /&gt;        return null;&lt;br /&gt;      &lt;br /&gt;      // Just send RandomAccess lists out;  wrap any other Collection&lt;br /&gt;      // into a List&lt;br /&gt;      if ((o instanceof List) &amp;&amp;&lt;br /&gt;          (o instanceof RandomAccess))&lt;br /&gt;        return (List) o;&lt;br /&gt;&lt;br /&gt;      Collection c = (Collection) o;&lt;br /&gt;      if (c.isEmpty())&lt;br /&gt;        return Collections.EMPTY_LIST;&lt;br /&gt;&lt;br /&gt;      return new ListImpl(c, getSize());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Set&amp;lt;Map.Entry&amp;lt;Collection, List&amp;gt;&amp;gt; entrySet()&lt;br /&gt;    {&lt;br /&gt;      // Not worth implementing at the moment;  this Map is only&lt;br /&gt;      // accessed from &lt;br /&gt;      return Collections.emptySet();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  static private class ListImpl extends AbstractList&lt;br /&gt;  {&lt;br /&gt;    public ListImpl(Collection c, int size)&lt;br /&gt;    {&lt;br /&gt;      _c = c;&lt;br /&gt;      _cSize = c.size();&lt;br /&gt;      if (size == 0)&lt;br /&gt;        _bufferSize = _cSize;&lt;br /&gt;      else&lt;br /&gt;        _bufferSize = Math.min(size, _cSize);&lt;br /&gt;&lt;br /&gt;      _buffer = new ArrayList(_bufferSize);&lt;br /&gt;      _offset = -1;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int size()&lt;br /&gt;    {&lt;br /&gt;      return _cSize;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public Object get(int index)&lt;br /&gt;    {&lt;br /&gt;      if ((index &lt; 0) || (index &gt;= _cSize))&lt;br /&gt;        throw new IndexOutOfBoundsException();&lt;br /&gt;&lt;br /&gt;      int offset = (index / _bufferSize) * _bufferSize;&lt;br /&gt;      if (offset != _offset)&lt;br /&gt;      {&lt;br /&gt;        _loadBuffer(offset);&lt;br /&gt;        _offset = offset;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      return _buffer.get(index - _offset);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void _loadBuffer(int offset)&lt;br /&gt;    {&lt;br /&gt;      Iterator iter = _c.iterator();&lt;br /&gt;      int i = 0;&lt;br /&gt;&lt;br /&gt;      while (i &lt; offset)&lt;br /&gt;      {&lt;br /&gt;        assert iter.hasNext();&lt;br /&gt;        iter.next();&lt;br /&gt;        i++;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      _buffer.clear();&lt;br /&gt;&lt;br /&gt;      int count = 0;&lt;br /&gt;      while ((count &lt; _bufferSize) &amp;&amp; (i &lt; _cSize))&lt;br /&gt;      {&lt;br /&gt;        assert iter.hasNext();&lt;br /&gt;        _buffer.add(iter.next());&lt;br /&gt;        i++;&lt;br /&gt;        count++;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private final Collection _c;&lt;br /&gt;    private final int        _bufferSize;&lt;br /&gt;    private final int        _cSize;&lt;br /&gt;    private int       _offset;&lt;br /&gt;    private ArrayList _buffer;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private Map&amp;lt;Collection, List&amp;gt; _map;&lt;br /&gt;  private int                   _size;&lt;br /&gt;&lt;br /&gt;  static private int _DEFAULT_SIZE = 50;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So, what's this all mean?  Well, say you want to write:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;h:dataTable value="#{mySet}"&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;... but that doesn't work.  Just add one managed-bean entry to your faces-config.xml:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt; &amp;lt;managed-bean&amp;gt;&lt;br /&gt;    &amp;lt;managed-bean-name&amp;gt;makeList&amp;lt;/managed-bean-name&amp;gt;&lt;br /&gt;    &amp;lt;managed-bean-class&amp;gt;&lt;br /&gt;       yourPackageHere.ListFromCollection&lt;br /&gt;    &amp;lt;/managed-bean-class&amp;gt;&lt;br /&gt;    &amp;lt;managed-bean-scope&amp;gt;&lt;br /&gt;       request&lt;br /&gt;    &amp;lt;/managed-bean-scope&amp;gt;&lt;br /&gt; &amp;lt;/managed-bean&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;... and now, you can use sets on dataTable via:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;  &amp;lt;h:dataTable value="#{makeList.list[mySet]}"&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-114307478668896208?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/114307478668896208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=114307478668896208' title='45 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114307478668896208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114307478668896208'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/03/usings-sets-with-uidata.html' title='Usings Sets with UIData'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>45</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-114257689737703543</id><published>2006-03-16T22:17:00.000-08:00</published><updated>2006-03-16T22:28:17.403-08:00</updated><title type='text'>Fixing JSF state saving: Save vs. Restore</title><content type='html'>(A bit of esoterica, but probably of interest here to those deeply focused on JSF performance...)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;An update&lt;/b&gt;:  I got a chance to take some timings.  As expected, saving state is now much faster:  85-90% faster, roughly equivalent to the improvements in the size of the saved state.  But I was very surprised to discover that restoring the view isn't any faster, perhaps even marginally slower - until I realized that was the only possible result.&lt;br /&gt;&lt;br /&gt;Restore View has to create a full tree, starting from zero.  What could possibly be faster than creating that tree from an object tree that specifies every attribute that needs to be set, every class name that needs to be instantiated?  Put another way, the old restoreVIew() approach, for all of its memory inefficiencies, is essentially an equivalent workload to building the tree in the first place, and might be even faster.  This new approach starts with the overhead of building the tree from scratch, &lt;em&gt;plus&lt;/em&gt; the overhead of setting some additional state.  (That additional overhead is fairly negligible, but the point remains: fixing JSF state saving doesn't make Restore View fast.)&lt;br /&gt;&lt;br /&gt;A slight clarification, BTW:  I'm not using client-side state saving a la the RI or MyFaces, which serializes the entire tree to the client.  Instead, we use ADF Faces's tokenized client-side state saving - run &lt;code&gt;saveSerializedView&lt;/code&gt;, but then stash the result on the session, and only send a token to the client.  If we were using fully serialized trees, then you would get a performance boost even in Restore View, because you'd only have to unserialize a small block, instead of the whole thing.&lt;br /&gt;&lt;br /&gt;So, does that mean that restoreView() is necessarily slow?  Well, no.  There are approaches to optimizing restoreView().  The most direct is optimizing building the component tree - which will help both with initial component tree creation and with restoreView().  How to do that in another post.  (Hint: FacesBean and Facelets are a huge help here, too!)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-114257689737703543?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/114257689737703543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=114257689737703543' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114257689737703543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114257689737703543'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/03/fixing-jsf-state-saving-save-vs.html' title='Fixing JSF state saving: Save vs. Restore'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-114247200153778615</id><published>2006-03-15T17:08:00.000-08:00</published><updated>2006-03-16T09:18:35.523-08:00</updated><title type='text'>Fixing JSF state saving:  a progress report</title><content type='html'>I've implemented the first version of an improved JSF state saving architecture, essentially what I talked about in my last post.&lt;br /&gt;&lt;br /&gt;The very latest and greatest Facelets source code has a &lt;code&gt;facelets.BUILD_BEFORE_RESTORE&lt;/code&gt; initialization parameter.  When turned on, it changes &lt;code&gt;ViewHandler.restoreView()&lt;/code&gt; to build the view before asking the StateManager for help.&lt;br /&gt;&lt;br /&gt;And the latest ADF Faces code adds a new &lt;code&gt;markInitialState()&lt;/code&gt; method to our components - which calls through to &lt;code&gt;FacesBean.markInitialState()&lt;/code&gt;.  When our MyFaces svn repository is set up, you'll be able to see this code too...&lt;br /&gt;&lt;br /&gt;And the results?  Well, one test case with a fairly large page dropped from nearly 10K of client-side state to only 600 bytes.  That's more than a 90% reduction in saved state!  (Presumably, CPU usage is way down, but I haven't measured that yet.)&lt;br /&gt;&lt;br /&gt;There's still potential improvements:  I could get that 600 bytes down further by overriding the state saving in UIViewRoot.  Also, Jacob's suggestion to use a flat Map instead of a hierarchy would also help - currently, if one component deep in the hierarchy needs to store state, we build up a large hierarchy of mostly null Object arrays.  This isn't especially expensive, but it is avoidable.&lt;br /&gt;&lt;br /&gt;A footnote: Mike Youngstrom cogently noted in a comment to my last post that a delta approach to state saving would let us make UIData both simpler and more generic - instead of handcoding a specific set of properties to save on certain types of child components, just run state saving.  Absolutely, Mike!  I haven't prototyped this on our UIXTable component (which doesn't extend UIData, FWIW), but that's a great thing to try.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-114247200153778615?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/114247200153778615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=114247200153778615' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114247200153778615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114247200153778615'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/03/fixing-jsf-state-saving-progress.html' title='Fixing JSF state saving:  a progress report'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-114132059410916321</id><published>2006-03-02T09:16:00.000-08:00</published><updated>2006-03-02T09:30:19.373-08:00</updated><title type='text'>How we're going to fix JSF state saving</title><content type='html'>State is not bad.  Statelesness is not good. State is your friend.  But like a bad friend, State can sometimes hang around the house, eating your &lt;a href="http://www.mitchellsicecream.com/"&gt;Mitchell's ice cream&lt;/a&gt; and drinking your &lt;a href="http://www.amarula.co.za/"&gt;Amarula&lt;/a&gt; 'til he gets fat and lazy, turns your house into a pig sty, and makes you wonder why you ever were friends with him in the first place.&lt;br /&gt;&lt;br /&gt;JSF state is kind of like that.  As I've said in a previous post, JSF state saving is way too hefty and saves far too much that doesn't need to be saved in the first place.  So, here's my 5 step plan for fixing that.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;br /&gt;1. Use Facelets.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;br /&gt;2. Enhance the ADF Faces &lt;code&gt;FacesBean&lt;/code&gt; API to support a "delta" mode - call a new &lt;code&gt;markInitialState()&lt;/code&gt; method on it, and its &lt;code&gt;saveState()&lt;/code&gt; implementation only saves all the changes made since &lt;code&gt;markInitialState()&lt;/code&gt;.  And if there's no changes, just return null.  (You can't easily do this without FacesBean;  see my earlier post on the subject.) &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;br /&gt;3. Update the ADF Faces Facelets TagHandlers to call &lt;code&gt;markInitialState()&lt;/code&gt; after creating the components.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Step 4&lt;/h3&gt;&lt;br /&gt;4. Implement Jacob Hookom's idea to save the tree of component state in a Map, not a gigantic Object array hierarchy.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Step 5&lt;/h3&gt;&lt;br /&gt;5. Rewrite the Facelets restoreView() implementation to recreate the tree from scratch in its original state, then call restoreState() on each component from the Map we built up in step 4.&lt;br /&gt;&lt;br /&gt;And done.   You don't need to save the tree structure anymore - Facelets is handling that by recreating the tree from its cached TagHandlers.  And since most components don't actually change - unless you explicitly set properties on them - most components don't have to save any state.&lt;br /&gt;&lt;br /&gt;(P.S.: there's some trickiness here that I'm ignoring:  if you add components dynamically to the hierarchy, you do have to save their state and structure, since it's not present in the page.  That's one reason why I strongly recommend making all dynamically created components transient if you have any choice in the matter, but that's a subject for another post.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-114132059410916321?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/114132059410916321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=114132059410916321' title='25 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114132059410916321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114132059410916321'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/03/how-were-going-to-fix-jsf-state-saving.html' title='How we&apos;re going to fix JSF state saving'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>25</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-114055420138285579</id><published>2006-02-21T12:10:00.000-08:00</published><updated>2006-02-22T14:58:04.046-08:00</updated><title type='text'>Usability problems in JSF</title><content type='html'>JSF is not perfect, nor the greatest thing since sliced bread.  There, I said it!&lt;br /&gt;&lt;br /&gt;What bugs me most (and remember, I'm still a big fan) is that JSF was supposed to be really easy-to-use.  In many ways, it is very easy.  But the reality isn't always quite so sweet.  There's shortfalls that make the learning curve longer than it should be, and they are fixable.&lt;br /&gt;&lt;br /&gt;The most annoying problem is that errors simply result in big stack traces.  There's nothing wrong with stack traces per se, but by themselves they're totally insufficient for error diagnosis.  Real diagnosis requires at a minimum:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Line and column numbers, as well as file name.  And even better, the snippet of content from that document that matches up.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If an EL expression fails, information on what part of the EL expression failed.  (When a complicated expression like &lt;code&gt;#{foo.bar.baz == my.other.expression}&lt;/code&gt; fails, it's very hard to figure out what went wrong.)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In general, all exceptions thrown anywhere in JSF or JSPs should be vetted to ensure that they:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Contain a meaningful, useful error message&lt;/li&gt;&lt;li&gt;Contain enough context to point out what bit of user content failed&lt;/li&gt;&lt;li&gt;Never, ever drop the base error, if one is being wrapped&lt;/li&gt;&lt;/ul&gt;A second category of annoyances in JSF consist of "nothing happened" problems.   For example, if a validation error stops you from going on to Invoke Application, but you've forgotten to add an &lt;h:messages&gt; tag or something similar to your page, all that you see is - nothing.&lt;br /&gt;&lt;br /&gt;Finally, when you do figure out what you've done wrong, quite often you need to bounce the server to pick up the changes.  Any changes to WEB-INF/faces-config.xml require this.   That's a huge productivity hit.&lt;br /&gt;&lt;br /&gt;So, that's my hit list for JSF usability problems.  What are your biggest JSF usability concerns?&lt;br /&gt;&lt;br /&gt;[PS: Yes, I edited the wording a bit.  It was coming across as an angry rant that JSF isn't useable, which isn't where I'm coming from.]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-114055420138285579?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/114055420138285579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=114055420138285579' title='185 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114055420138285579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/114055420138285579'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/02/usability-problems-in-jsf.html' title='Usability problems in JSF'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>185</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-113938245845822253</id><published>2006-02-07T22:55:00.000-08:00</published><updated>2006-02-07T23:07:38.480-08:00</updated><title type='text'>ADF Faces and JSF 1.2</title><content type='html'>JSF 1.2 is &lt;a href="http://weblogs.java.net/blog/edburns/archive/2006/01/jsf_12_jars_now.html"&gt;right around the corner&lt;/a&gt;, and, of course, &lt;a href="http://www.oracle.com/technology/products/jdev/htdocs/partners/addins/exchange/jsf/index.html"&gt;ADF Faces&lt;/a&gt; is going to be right there too, right?  Well, not so fast...&lt;br /&gt;&lt;br /&gt;ADF Faces took one fairly unusual approach in designing its components.  Instead of extending the standard &lt;a href="http://java.sun.com/j2ee/javaserverfaces/1.1_01/docs/api/javax/faces/component/UIComponentBase.html"&gt;UIComponentBase&lt;/a&gt; class like almost everyone else does, we directly extended UIComponent with &lt;a href="http://72.14.207.104/search?q=cache:uP_kYk85x8AJ:www.oracle.com/technology/products/jdev/htdocs/partners/addins/exchange/jsf/doc/apidocs/oracle/adf/view/faces/component/UIXComponentBase.html++site:www.oracle.com+UIXComponentBase&amp;hl=en&amp;gl=us&amp;ct=clnk&amp;cd=2&amp;client=safari"&gt;UIXComponentBase&lt;/a&gt;.  I chose this path for good reasons - like the FacesBean state saving approach I blogged about a few posts down - but it does carry a penalty.  When UIComponent changes, ADF Faces breaks.  And UIComponent does change in JSF 1.2.  In particular, the move from the JSF EL to the new Unified EL means new getValueExpression() and setValueExpression() methods.&lt;br /&gt;&lt;br /&gt;C'est la vie.&lt;br /&gt;&lt;br /&gt;So, here's the good news:  I'm promising, right here and now, to get a version of ADF Faces out soon that will be based on JSF 1.2.  There's one big question to resolve:  should it be based on the code in JDev 10.1.3, or on the post-10.1.3 code we're donating to &lt;a href="http://myfaces.apache.org"&gt;MyFaces&lt;/a&gt;?  I'm leaning towards the latter, but let me know if you feel differently.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-113938245845822253?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/113938245845822253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=113938245845822253' title='31 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/113938245845822253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/113938245845822253'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/02/adf-faces-and-jsf-12.html' title='ADF Faces and JSF 1.2'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>31</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-113926644535836646</id><published>2006-02-06T13:29:00.000-08:00</published><updated>2006-02-06T17:01:25.016-08:00</updated><title type='text'>What belongs in the JSF standard?</title><content type='html'>As the Expert Group starts working on JSF 2.0, we're faced with a very fundamental question:  how do we pick and choose what belongs in the standard?  And what, by contrast, does &lt;b&gt;not&lt;/b&gt; belong in the standard?&lt;br /&gt;&lt;br /&gt;There are several reasons why something should go in the standard:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Feature ABC cannot be implemented outside of the standard.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Feature DEF is not directly needed by the standard, but promotes interoperability.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Standards receive better tool support, and tool support is essential for feature XYZ.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Some examples of each:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://weblogs.java.net/blog/jhook/archive/2005/09/jsf_avatar_vs_m_1.html"&gt;JSF Avatar&lt;/a&gt; requires support from UIComponent, and therefore has to go into the standard.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The &lt;a href="http://java.sun.com/j2ee/javaserverfaces/1.1_01/docs/api/javax/faces/model/DataModel.html"&gt;DataModel&lt;/a&gt; API allows interoperability between different model providers and component providers.  It would be helpful if JSF had a TreeModel for the same reason - instead of everyone inventing their own TreeModel, we can have one abstract interface that lets model experts provide the best implementations possible and component developers design the best tree UIs around.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href='https://facelets.dev.java.net/'&gt;Facelets&lt;/a&gt; would benefit from tool support (Creator, JDeveloper, etc.)&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;But if you don't meet these standards, why not still add the feature to JSF?  Why not add a calendar component?   How about a declarative framework that makes it easy to create renderers?  Or support for XSLT post-processing of content?  These all seem like handy features, but I feel strongly that none belong in the JSF standard yet.  A J2EE standard has very difficult constraints placed on it.  The long development cycle means we only get to add features occasionally.  But we're also required to maintain backwards compatibility, so fixing mistakes is difficult-to-impossible.  So, here's a list of some reasons why &lt;b&gt;not&lt;/b&gt; to add something to the JSF spec:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Feature ABC can be implemented just as easily outside of the spec as inside of it.  That is, the current public API is entirely sufficient to implement the feature.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Feature DEF is not yet well understood - there are multiple possible directions to head.  The JCP process works best when it standardizes existing best practices.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Feature XYZ is of only limited use - not everyone needs it.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;These are not at all mutually exclusive lists.  For example, the Avatar API is not the last word in handling AJAX requests for JSF.  A declarative framework for renderers can be implemented outside the spec, but it would benefit from more tool support.  And so forth.&lt;br /&gt;&lt;br /&gt;Perhaps the most difficult task of any framework developer is learning how to say "No".  As in, "No, we don't want that feature." But that is absolutely our responsibility as architects of JSF.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;It's down there somewhere, let me take another look...&lt;br /&gt;-- &lt;em&gt;The Big Lebowski&lt;/em&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-113926644535836646?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/113926644535836646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=113926644535836646' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/113926644535836646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/113926644535836646'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/02/what-belongs-in-jsf-standard.html' title='What belongs in the JSF standard?'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-113797016546321229</id><published>2006-01-31T14:12:00.000-08:00</published><updated>2006-01-31T14:30:42.583-08:00</updated><title type='text'>Should JSF go stateless?</title><content type='html'>Jacob Hookom's written an interesting blog entry about whether JSF could &lt;a href="http://weblogs.java.net/blog/jhook/archive/2006/01/experiment_goin_1.html"&gt;go stateless.&lt;/a&gt;  The two of us have gone back and forth on this on e-mail a bunch of times, and I guess you could say that I fall in the "UI state is a good thing" camp.  In large part, that comes from all the time I've spent working on component frameworks.&lt;br /&gt;&lt;br /&gt;I absolutely agree with Jacob on one of his points - "Statesaving in JSF is [really] bad in implementation".  It's a massive and heavyweight "save everything on the page" approach that is, at least conceptually, horrible overkill.  For example, it's ridiculous that we have to save the UI component hierarchy, attributes, EL expressions, etc., when we have a JSP or Facelets document containing &lt;span style="font-weight: bold;"&gt;exactly&lt;/span&gt; that information just sitting there on the server.  Even though I know why this happened - JSF had to support JSPs, etc., etc. - it's a very frustrating state of affairs.&lt;br /&gt;&lt;br /&gt;Nevertheless, I think throwing out state saving altogether in response would be going too far.  It'd be like saying that you should never bother sorting because Bubble Sort is a really slow algorithm.  Unfortunately, JSF, as designed today, makes it very difficult to even attempt to optimize state saving.  Until there's a really sane, solid implementation of state saving, any big policy decisions are premature.&lt;br /&gt;&lt;br /&gt;The real problem with optimizing JSF state saving is the way that UIComponent.saveState() (and restoreState()) is typically implemented.  Each class is responsible for saving all of its own per-instance state, up and down the hierarchy.  So UIComponentBase stores its properties in an array, then UIOutput stores a few more properties (plus the UIComponentBase state) in an array of its own, then UIInput aggregates its own state, and finally HtmlInputText adds its own.  For example, here's the start of HtmlInputText.saveState():&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;  public Object saveState(FacesContext _context) {&lt;br /&gt;    Object _values[] = new Object[31];&lt;br /&gt;    _values[0] = super.saveState(_context);&lt;br /&gt;    _values[1] = accesskey;&lt;br /&gt;    _values[2] = alt;&lt;br /&gt;    _values[3] = dir;&lt;br /&gt;    _values[4] = this.disabled ? Boolean.TRUE : Boolean.FALSE;&lt;br /&gt;    _values[5] = this.disabled_set ? Boolean.TRUE : Boolean.FALSE;&lt;br /&gt;    .... and on and on and on for another 26 lines ....&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Nasty!  If a container wanted to optimize state saving, it'd somehow have to mix that in not just into one class, but into every component class up and down the hierarchy. &lt;br /&gt;&lt;br /&gt;ADF Faces took a different approach.  We store all of our component state in an &lt;a href="http://www.oracle.com/technology/products/jdev/htdocs/partners/addins/exchange/jsf/doc/apidocs/oracle/adf/view/faces/bean/FacesBean.html"&gt;FacesBean&lt;/a&gt; instance.  It takes care of storing simple properties, ValueBindings, lists (like listeners and validators), and knows how to save and restore state.  Here's the full code for UIXComponentBase.saveState();&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;  public Object saveState(FacesContext context)&lt;br /&gt;  {&lt;br /&gt;    return getFacesBean().saveState(context);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;And subclasses don't neeed any code at all.  Aaahhhh.....  Now that's better.  More on FacesBean in a later post (there's a lot of other advantages), but what's relevant is the general principle:  all state saving is implemented up in the base class, so now there's a hook to implement real cross-cutting optimizations like:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Cache reusable FacesBean instances on a Facelet tag handler (with copy-on-write), especially for panels and output components that rarely if ever mutate&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Implement saveState() that only saves deltas from the original state of the bean (and rely on Facelets to recreate the tree in its original state)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Secondarily, we'd do very well to follow &lt;a href="https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=176"&gt;Jacob's advice&lt;/a&gt; and re-think how processSaveState() and processRestoreState() function - instead of creating a deep heirarchy, create a flattened Map or array structure.&lt;br /&gt;&lt;br /&gt;Implement all of this, and then we're in a place to judge whether fully stateless UIs are necessary.  I think they will be, for some limited types of applications, but JSF can be pushed a lot further than it's going now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-113797016546321229?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/113797016546321229/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=113797016546321229' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/113797016546321229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/113797016546321229'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/01/should-jsf-go-stateless.html' title='Should JSF go stateless?'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20632077.post-113658254832145400</id><published>2006-01-06T13:21:00.000-08:00</published><updated>2006-01-06T13:30:18.736-08:00</updated><title type='text'>Blogging at last...</title><content type='html'>It seems about time that I &lt;a href="http://www.phrases.org.uk/bulletin_board/13/messages/347.html"&gt;throw my hat into the ring&lt;/a&gt; and give blogging a whirl.  There should be plenty to say, what with &lt;a href="http://technology.amis.nl/blog/?p=947"&gt;ADF Faces joining MyFaces&lt;/a&gt; (though the name's not going to be Cherokee), and &lt;a href="http://hookom.blogspot.com/"&gt;anyone who's met me&lt;/a&gt; knows I'm never at a loss for opinions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20632077-113658254832145400?l=sfjsf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://sfjsf.blogspot.com/feeds/113658254832145400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20632077&amp;postID=113658254832145400' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/113658254832145400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20632077/posts/default/113658254832145400'/><link rel='alternate' type='text/html' href='http://sfjsf.blogspot.com/2006/01/blogging-at-last.html' title='Blogging at last...'/><author><name>Adam Winer</name><uri>http://www.blogger.com/profile/13723363818490025216</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
