Modified: 
tapestry/tapestry5/tapestry-project/trunk/src/site/resources/tap5devwiki.xml
URL: 
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-project/trunk/src/site/resources/tap5devwiki.xml?view=diff&rev=478972&r1=478971&r2=478972
==============================================================================
--- 
tapestry/tapestry5/tapestry-project/trunk/src/site/resources/tap5devwiki.xml 
(original)
+++ 
tapestry/tapestry5/tapestry-project/trunk/src/site/resources/tap5devwiki.xml 
Fri Nov 24 12:03:47 2006
@@ -6,27 +6,76 @@
 <description>The quick and dirty one-stop shopping of random ideas for 
Tapestry 5.</description>
 <language>en-us</language>
 <copyright>Copyright 2006 HowardLewisShip</copyright>
-<pubDate>Sat, 04 Nov 2006 17:49:18 GMT</pubDate>
-<lastBuildDate>Sat, 04 Nov 2006 17:49:18 GMT</lastBuildDate>
+<pubDate>Fri, 24 Nov 2006 19:57:26 GMT</pubDate>
+<lastBuildDate>Fri, 24 Nov 2006 19:57:26 GMT</lastBuildDate>
 <docs>http://blogs.law.harvard.edu/tech/rss</docs>
 <generator>TiddlyWiki 2.0.11</generator>
 <item>
-<title>RandomIdeas</title>
-<description>!HTML / XHTML DTDs&lt;br /&gt;&lt;br /&gt;The template parser 
should include local (in JAR) copies of the HTML and XHTML DTDs and redirect 
the parser to use the local copies. This can be a huge performance boost when 
parsing a template.&lt;br /&gt;&lt;br /&gt;!final should imply @Retain&lt;br 
/&gt;&lt;br /&gt;Final fields should be treated as if they have the @Retain 
annotation&lt;br /&gt;&lt;br /&gt;! Exceptions from event handler / phase 
render methods&lt;br /&gt;&lt;br /&gt;Tapestry should wrap non-runtime 
exceptions from these methods. I think today, if you declare that such a method 
throws an exception, you'll get a runtime exception out of Javassist.&lt;br 
/&gt;&lt;br /&gt;! SubForms&lt;br /&gt;&lt;br /&gt;Perhaps one way to approach 
highly dynamic, Ajax pages with forms is to have a logical &quot;sub form&quot; 
concept. A sub form would work inside an existing form, and organize a group of 
fields within that form. Processing of the fields would occur only
  if the sub form was active, which itself&lt;br /&gt;would be tracked based on 
visibility of the sub form (a sub form in an invisible panel would not be 
processed on the server side).  This idea needs a lot of fleshing out, even to 
see if it is viable.&lt;br /&gt;&lt;br /&gt;! Ajax Constraints&lt;br 
/&gt;&lt;br /&gt;The best way to tackle Ajax features, especially w.r.t. forms, 
is to put some sensible constraints on what the user can do, then make it easy 
to implement those things.&lt;br /&gt;&lt;br /&gt;Basically ... never delete!  
Deletions are a real pain to handle, unless I suddenly get much smarter.  Allow 
things to be hidden on the client side,&lt;br /&gt;and for the corresponding 
fields to do nothing on the server side, but don't allow them to full out 
delete. &lt;br /&gt;&lt;br /&gt;Allow new things to be added, preferable only 
at the &quot;tail end&quot; of the form. </description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#RandomIdeas</link>
-<pubDate>Sat, 04 Nov 2006 17:49:18 GMT</pubDate>
+<title>WatchCodeCoverage</title>
+<description>The code coverage tools built into ''mvn site'' are quite useful. 
Right now, overall coverage is at 93%. Keep an eye on code coverage, including 
branch coverage (do you test both outcomes of an if statement?).  Use 
unexecuted code to target your efforts.&lt;br /&gt;&lt;br /&gt;I often do a 
cursory unit test for &quot;normal behavior&quot;, plus more exaustive unit 
tests for error conditions.  I then &quot;back the test up&quot; using an 
integration test (build with [[Selenium]]) to prove that the normal behavior 
case really works.</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#WatchCodeCoverage</link>
+<pubDate>Fri, 24 Nov 2006 19:57:26 GMT</pubDate>
+</item>
+<item>
+<title>FocusOnTesting</title>
+<description>I'm still not at the stage of test first, but with every line of 
code I write, I am thiking about how I will test that line of code.  Tapestry 
uses EasyMock extensively, and there's lots of existing code examples to work 
with.&lt;br /&gt;&lt;br /&gt;!Dont Despair&lt;br /&gt;&lt;br /&gt;I 
occasionally get exhausted by the amount of test code I write for simple chunks 
of code.  And I inevitably find a broken line of code that would be a major 
pain to locate inside a running application, but easy inside a unit test. Keep 
your eyes on the big picture.</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#FocusOnTesting</link>
+<pubDate>Fri, 24 Nov 2006 19:54:49 GMT</pubDate>
+</item>
+<item>
+<title>DontTouchInternals</title>
+<description>Very few of the Tapestry committers will need to touch anything 
inside the internals package.  When this occurs, some online discussion may be 
mandated.  The goal of Tapestry is to ensure that most work for commiters and 
for developers is in the domain of creating components, not tinkering with 
internals.</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#DontTouchInternals</link>
+<pubDate>Fri, 24 Nov 2006 19:53:07 GMT</pubDate>
+</item>
+<item>
+<title>Assets</title>
+<description>The concept of Assets is unchanged from Tapestry 4.&lt;br 
/&gt;&lt;br /&gt;There will be an &quot;exclusion list&quot; of file name 
extensions. Files with that extension will require an md5sum as part of the 
URI.  The default exclusion list with be &quot;.class&quot;. For other file 
types (particularily .js, .css, etc.) the file will be the file, and relative 
file names will work.&lt;br /&gt;&lt;br /&gt;Some kind of hook will be 
necessary to support schemes like Akamai, where assets are stored externally. 
This should also take into account localization.&lt;br /&gt;&lt;br /&gt;Some 
kind of folder aliasing will be necessary.  I may want 
&quot;/assets/dojo/&quot; to map on the classpath to 
&quot;/org/apache/tapestry/dojo/dojo_0_0_4/&quot;.  When handling updates to 
big packages such as Dojo, I don't want to have to sort through some ungodly 
number of changes between 0.0.4 and 0.0.5, I want to create a new dojo_0_0_5 
folder, drop the contents in, delete the dojo_0_0
 _4 folder, and update the mapping of &quot;/assets/dojo/&quot;.</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#Assets</link>
+<pubDate>Fri, 24 Nov 2006 19:51:07 GMT</pubDate>
 </item>
 <item>
 <title>MasterIndex</title>
-<description>Top level concepts within Tapestry 5.&lt;br /&gt;&lt;br /&gt;A 
//meta-note//: This is where new ideas are first explained, usually before 
being implemented. In many cases, the final implementation is&lt;br /&gt;not a 
perfect match for the notes. That's OK ... as long as the official Maven 
documentation does a good job. It's not reasonable to expect developers to jump 
back in here and dot every i and cross every t if they're already expected to 
generate good Maven documentation.&lt;br /&gt;&lt;br /&gt;* PropBinding -- 
Notes on the workhorse &quot;prop:&quot; binding prefix&lt;br /&gt;* 
TypeCoercion -- How Tapestry 5 extensibly addresses type conversion&lt;br 
/&gt;* FormProcessing&lt;br /&gt;* DynamicPageState -- tracking changes to page 
state during the render&lt;br /&gt;* EnvironmentalServices -- how components 
cooperate during page render&lt;br /&gt;* ComponentMixins -- A new fundamental 
way to build web functionality&lt;br /&gt;* RequestTypes -- Requests, requ
 est processing, URL formats&lt;br /&gt;* ComponentTemplates -- Issues about 
Component Templates&lt;br /&gt;* DeveloperProcedures -- Your a Tapestry 
committer ... how do you makes changes?&lt;br /&gt;* SmartDefaults -- do even 
more with event less&lt;br /&gt;* RandomIdeas -- stuff that doesn't fit 
elsewhere</description>
+<description>Top level concepts within Tapestry 5.&lt;br /&gt;&lt;br /&gt;A 
//meta-note//: This is where new ideas are first explained, usually before 
being implemented. In many cases, the final implementation is&lt;br /&gt;not a 
perfect match for the notes. That's OK ... as long as the official Maven 
documentation does a good job. It's not reasonable to expect developers to jump 
back in here and dot every i and cross every t if they're already expected to 
generate good Maven documentation.&lt;br /&gt;&lt;br /&gt;* PropBinding -- 
Notes on the workhorse &quot;prop:&quot; binding prefix&lt;br /&gt;* 
TypeCoercion -- How Tapestry 5 extensibly addresses type conversion&lt;br 
/&gt;* FormProcessing&lt;br /&gt;* DynamicPageState -- tracking changes to page 
state during the render&lt;br /&gt;* EnvironmentalServices -- how components 
cooperate during page render&lt;br /&gt;* ComponentMixins -- A new fundamental 
way to build web functionality&lt;br /&gt;* RequestTypes -- Requests, requ
 est processing, URL formats&lt;br /&gt;* ComponentTemplates -- Issues about 
Component Templates&lt;br /&gt;* DeveloperProcedures -- Your a Tapestry 
committer ... how do you makes changes?&lt;br /&gt;* SmartDefaults -- do even 
more with event less&lt;br /&gt;* RandomIdeas -- stuff that doesn't fit 
elsewhere&lt;br /&gt;* ProblemsNeedingSolutions&lt;br /&gt;* 
ComponentDocumentation -- Generating Documentation about Components&lt;br 
/&gt;* TapestryLookAndFeel -- Default CSS&lt;br /&gt;* [[Assets]]&lt;br 
/&gt;&lt;br /&gt;</description>
 <link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#MasterIndex</link>
-<pubDate>Sat, 04 Nov 2006 00:38:00 GMT</pubDate>
+<pubDate>Fri, 24 Nov 2006 19:44:49 GMT</pubDate>
+</item>
+<item>
+<title>TapestryLookAndFeel</title>
+<description>I think it would be very compelling to create a reasonably sharp 
default CSS for Tapestry applications. Something pretty, standards based, 
Web-2.0-ish, that would make even the simplest apps stand out.&lt;br 
/&gt;&lt;br /&gt;Of course, the Tapestry default CSS would be the first 
stylesheet, and could be overridden by additional stylesheets or inline 
styles.</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#TapestryLookAndFeel</link>
+<pubDate>Fri, 24 Nov 2006 19:43:24 GMT</pubDate>
+</item>
+<item>
+<title>DynamicPageState</title>
+<description>Tapestry 4 has left tracking of dynamic page state as an exercise 
to the developer.  Mostly, this is done using the ''parameters'' parameter of 
the ~DirectLink component.&lt;br /&gt;&lt;br /&gt;''Update: As I've thought 
this one through, I don't think it is viable outside of Forms. It will end up 
with long URLs and a constant ambiguity about whether each link should include 
or exclude the page state.  So this one is unlikely to get implemented.''&lt;br 
/&gt;&lt;br /&gt;Dynamic page state is anything that isn't inside a persistent 
page property. For the most part, this includes page properties updated by a 
For component&lt;br /&gt;&lt;br /&gt;It seems likely that this information 
could be automatically encoded into ~URLs.  &lt;br /&gt;&lt;br /&gt;I'm 
envisioning a service that accumulates a series of //commands//. Each command 
is used to store a bit of page state. The commands are serializable.  The 
commands are ultimately serialized into a MIME string and attach
 ed as a query parameter to each URL.&lt;br /&gt;&lt;br /&gt;When such a link 
is triggered, the commands are de-serialized and each executed in turn. Only 
when that is finished is any further event processing executed, including 
calling into to user code.&lt;br /&gt;&lt;br /&gt;My outline for this is to 
store a series of tuples; each tuple is a component id plus the command to 
execute.&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;public interface 
ComponentCommand&lt;T&gt;&lt;br /&gt;{&lt;br /&gt;  void execute(T 
component);&lt;br /&gt;}&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;These commands 
should be immutable.&lt;br /&gt;&lt;br /&gt;So a component, such as a For loop 
component, could provide itself and a ComponentCommand instance (probably a 
static inner class) to some kind of PageStateTracker service.&lt;br /&gt;&lt;br 
/&gt;{{{&lt;br /&gt;public interface PageStateTracker&lt;br /&gt;{&lt;br /&gt;  
void &lt;T&gt; addCommand(T component, ComponentCommand&lt;T&gt; 
command);&lt;br /&gt;
 }&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;The commands are kept in the order 
that they are added, except that new commands for the same component 
//replace// previous commands for that component.&lt;br /&gt;&lt;br /&gt;As 
with the Tapestry 4 For component, some mechanism will be needed to store 
object ids inside the URLs (that is, inside the commands serialized into URL 
query parameters) and translate back to //equivalent// objects when the link is 
triggered.&lt;br /&gt;&lt;br /&gt;Dynamic page state outside of a Form will 
overlap with some of the FormProcessing inside the form.</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#DynamicPageState</link>
+<pubDate>Fri, 24 Nov 2006 18:32:00 GMT</pubDate>
 </item>
 <item>
 <title>SmartDefaults</title>
 <description>As great as the annotations are, allowing things to work without 
the annotations could be even better.&lt;br /&gt;&lt;br /&gt;!Event handler 
methods&lt;br /&gt;&lt;br /&gt;Methods with the prefix &quot;on&quot; could 
automatically be considered event handler methods.  The string after the 
prefix, converted to lower case, would be the event type.  We could even add 
&quot;from//~ComponentId//&quot; to the end.  Examples (with annotation 
equivalents):&lt;br /&gt;&lt;br /&gt;* onSubmit  --&gt; 
@~OnEvent(&quot;submit&quot;)&lt;br /&gt;* onSubmitFromForm --&gt; 
@~OnEvent(value=&quot;submit&quot;, component=&quot;form&quot;)&lt;br /&gt;* 
onUpdateFromSelect  --&gt; @~OnEvent(value=&quot;update&quot;, 
component=&quot;select&quot;)&lt;br /&gt;&lt;br /&gt;!Render phase 
methods&lt;br /&gt;&lt;br /&gt;Naming a method the same as the render phase 
(with the first character lower case).  Again, Tapestry could deduce the phase 
from the method name, as if the annotation were pres
 ent:&lt;br /&gt;&lt;br /&gt;* beforeRender() --&gt; @~BeforeRender&lt;br 
/&gt;* beforeRenderBody() --&gt; @~BeforeRenderBody&lt;br /&gt;&lt;br /&gt;etc. 
 Again, the methods don't have to be public, they just have to have the correct 
name. In every other way they are the same as annotated render phase methods 
except that they don't have the annotation.&lt;br /&gt;&lt;br /&gt;There may be 
some minor implications w.r.t. render phase method ordering.&lt;br /&gt;&lt;br 
/&gt;etc.&lt;br /&gt;&lt;br /&gt;!Other Ideas&lt;br /&gt;&lt;br /&gt;This gets 
more component specific. I had the idea that a ~TextField whose id was 
&quot;userId&quot; might want to edit a property named &quot;userId&quot; as 
the default for when its value parameter is unbound. I think to accomplish 
this, we need the concept of computed bindings for unbound parameters ... 
perhaps in the form of methods that return a Binding with a name and/or 
annotation, for example:&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;&lt;br /&
 gt;  @Inject&lt;br /&gt;  private ComponentResources _resources;&lt;br 
/&gt;&lt;br /&gt;  @Inject(&quot;infrastructure:bindingSource&quot;)&lt;br 
/&gt;  private BindingSource _source;&lt;br /&gt;&lt;br /&gt;  @Parameter&lt;br 
/&gt;  private Object _value;&lt;br /&gt;&lt;br /&gt;  Binding 
valueDefault()&lt;br /&gt;  {&lt;br /&gt;    ComponentResources 
containerResources = _resources.getContainer().getComponentResources();&lt;br 
/&gt;    return _source.newBinding(&quot;default value&quot;, 
containerResources, &quot;prop&quot;, _resources.getId(), null);  &lt;br /&gt;  
}&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;So valueDefault() is invoked if the 
value parameter is not bound.  The component uses its own immediate id 
(&quot;userId&quot;) as the name of a property of its container (typically, the 
page).  ~ComponentResources does not yet implement getContainer(), but the rest 
would work.&lt;br /&gt;&lt;br /&gt;If this was widespread, there could be even 
better optimizations for it.  
 Perhaps container resources could just be passed into the method as a 
parameter, to save the code to find it.  Ditto with BindingSource.  Once again, 
rather than come up with complex XML-ese to come up with defaults, we're trying 
to work //with// Java code.&lt;br /&gt;</description>
 
<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#SmartDefaults</link>
-<pubDate>Fri, 03 Nov 2006 23:59:00 GMT</pubDate>
+<pubDate>Thu, 23 Nov 2006 15:35:00 GMT</pubDate>
+</item>
+<item>
+<title>ComponentDocumentation</title>
+<description>Tapestry needs a JavaDoc-like, or JavaDoc-based tool to extract 
documentation about component parameters (and mixins) and present it in a 
useable format.  In Tapestry 4, you could document the public getters and 
setters, but in Tapestry 5, the annotations are on the private instance 
variables, which are generally not documented.</description>
+<category>parameters</category>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#ComponentDocumentation</link>
+<pubDate>Thu, 23 Nov 2006 15:34:00 GMT</pubDate>
+</item>
+<item>
+<title>RandomIdeas</title>
+<description>!HTML / XHTML DTDs&lt;br /&gt;&lt;br /&gt;The template parser 
should include local (in JAR) copies of the HTML and XHTML DTDs and redirect 
the parser to use the local copies. This can be a huge performance boost when 
parsing a template.&lt;br /&gt;&lt;br /&gt;!final should imply @Retain&lt;br 
/&gt;&lt;br /&gt;Final fields should be treated as if they have the @Retain 
annotation&lt;br /&gt;&lt;br /&gt;! Exceptions from event handler / phase 
render methods&lt;br /&gt;&lt;br /&gt;Tapestry should wrap non-runtime 
exceptions from these methods. I think today, if you declare that such a method 
throws an exception, you'll get a runtime exception out of Javassist.&lt;br 
/&gt;&lt;br /&gt;! SubForms&lt;br /&gt;&lt;br /&gt;Perhaps one way to approach 
highly dynamic, Ajax pages with forms is to have a logical &quot;sub form&quot; 
concept. A sub form would work inside an existing form, and organize a group of 
fields within that form. Processing of the fields would occur only
  if the sub form was active, which itself&lt;br /&gt;would be tracked based on 
visibility of the sub form (a sub form in an invisible panel would not be 
processed on the server side).  This idea needs a lot of fleshing out, even to 
see if it is viable.&lt;br /&gt;&lt;br /&gt;! Ajax Constraints&lt;br 
/&gt;&lt;br /&gt;The best way to tackle Ajax features, especially w.r.t. forms, 
is to put some sensible constraints on what the user can do, then make it easy 
to implement those things.&lt;br /&gt;&lt;br /&gt;Basically ... never delete!  
Deletions are a real pain to handle, unless I suddenly get much smarter.  Allow 
things to be hidden on the client side,&lt;br /&gt;and for the corresponding 
fields to do nothing on the server side, but don't allow them to full out 
delete. &lt;br /&gt;&lt;br /&gt;Allow new things to be added, preferable only 
at the &quot;tail end&quot; of the form. &lt;br /&gt;&lt;br /&gt;! SPI 
Package&lt;br /&gt;&lt;br /&gt;A number of interfaces, such as Binding
 , probably belong in a SPI (Service Provider Interface) package, since they 
will generally only be used by authors of Tapestry extensions.  Perhaps we 
should just use the oat.services package as the SPI package?</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#RandomIdeas</link>
+<pubDate>Thu, 23 Nov 2006 05:01:00 GMT</pubDate>
+</item>
+<item>
+<title>ProblemsNeedingSolutions</title>
+<description>There are a few things that I'm concerned about.&lt;br 
/&gt;&lt;br /&gt;!Render Complexity&lt;br /&gt;&lt;br /&gt;All those states in 
the render component state machine may be a little much, especially 
~PreBeginRender, ~BeginRender and ~PostBeginRender.  In addition, it doesn't 
work for a case I'm interested in ... for link components, I'd like to use the 
RenderInformals mixin, but also support a disable parameter that turns off the 
&lt;a&gt; tag (but still renders the body).  The state machine currently is set 
up so that returning false in any of the ~BeginRender states skips all the way 
to ~AfterRender, bypassing the template and/or body.</description>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#ProblemsNeedingSolutions</link>
+<pubDate>Thu, 23 Nov 2006 04:01:00 GMT</pubDate>
 </item>
 <item>
 <title>WorkInYourOwnBranch</title>
@@ -85,58 +134,6 @@
 <description>Page render requests are requests used to render a specific page. 
 //render// is the term meaning to compose the HTML response to be sent to the 
client. Note: HTML is used here only as the most common case, other markups are 
entirely possible.&lt;br /&gt;&lt;br /&gt;In many cases, pages are stand-alone. 
 No extra information in the URL is necesarry to render them.  
PersistentProperties of the page will factor in to the rendering of the 
page.&lt;br /&gt;&lt;br /&gt;In specific cases, a page needs to render within a 
particular context. The most common example of this is a page that is used to 
present a specific instance of a database persistent entity. In such a case, 
the page must be combined with additional data, in the URL, to identify the 
specific entity to access and render.&lt;br /&gt;&lt;br /&gt;! URI Format&lt;br 
/&gt;&lt;br /&gt;{{{&lt;br /&gt;/page-name.html/id&lt;br /&gt;}}}&lt;br 
/&gt;&lt;br /&gt;Here &quot;page-name&quot; is the LogicalPageName for th
 e page. &lt;br /&gt;&lt;br /&gt;The &quot;.html&quot; file extension is used 
as a delimiter between the page name portion of the URI, and the context 
portion of the URI. This is necessary because it is not possible (given the 
plethora of libraries and folders) to determine how many slashes will appear in 
the URI.&lt;br /&gt;&lt;br /&gt;The context consists of one ore more ids 
(though a single id is the normal case). The id is used to identify the 
specific data to be displayed. Further, a page may require multiple ids, which 
will separated with slashes. Example: 
/admin/DisplayDetail.html/loginfailures/2006&lt;br /&gt;&lt;br /&gt;Note that 
these context values, the ids, are simply //strings//. Tapestry 4 had a 
mechanism, the DataSqueezer, that would encode the type of object with its 
value, as a single string, and convert it back. While seemingly desirable, this 
facility was easy to abuse, resulting in long and extremely ugly URIs.&lt;br 
/&gt;&lt;br /&gt;Any further informatio
 n needed by Tapestry will be added to the URI as query parameters. This may 
include things like user locale, persistent page properties, applicaition flow 
identifiers, or anything else we come up with.&lt;br /&gt;&lt;br /&gt;! Request 
Processing&lt;br /&gt;&lt;br /&gt;Once the page and id parameters are 
identified, the corresponding page will be loaded.&lt;br /&gt;&lt;br 
/&gt;Tapestry will fire two events before rendering the page.&lt;br /&gt;&lt;br 
/&gt;The first event is of type &quot;setupPageRender&quot;.  This allows the 
page to process the context (the set of ids). This typically involves reading 
objects from an external persistent store (a database)&lt;br /&gt;and storing 
those objects into transient page properties, in expectaion of the 
render.&lt;br /&gt;&lt;br /&gt;The @SetupPageRender annotation marks a method 
to be invoked when this event is triggered.  The method may take one or more 
strings, or an array of strings, as parameters; these will be&lt;br /&gt;the co
 ntext values.  The method will normally return void.  Other values are 
''TBD''. It may also take other simple types, which will be coerced from the 
string values.&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;@SetupPageRender&lt;br 
/&gt;void setup(long id)&lt;br /&gt;{&lt;br /&gt;  . . .&lt;br /&gt;}&lt;br 
/&gt;}}}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The second event is of 
type &quot;pageValidate&quot;.  It allows the page to decide whether the page 
is valid for rendering at this time. This most often involves a check to see if 
the user is logged into the application, and has the necessary privileges to 
display the contents of the page.  User identity and privileges are //not// 
concepts built into Tapestry, but are fundamental to the majority of Tapestry 
applications.</description>
 
<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#PageRenderRequest</link>
 <pubDate>Sun, 08 Oct 2006 13:33:00 GMT</pubDate>
-</item>
-<item>
-<title>LogicalPageName</title>
-<description>A logical page name is the name of a page as it is represented in 
a URI.&lt;br /&gt;&lt;br /&gt;Internally, Tapestry operates on pages using full 
qualified class names. Technically, the FQCN is the class of the page's root 
element, but from an end developer point of view, the root element is the 
page.&lt;br /&gt;&lt;br /&gt;The logical page name must be converted to a fully 
qualified class name.&lt;br /&gt;&lt;br /&gt;A set of LibraryMappings are used. 
 Each library mapping is used to express a folder name, such as 
&quot;core&quot;, with a Java package name, such as 
org.apache.tapestry.corelib.  For pages, the page name is searched for in the 
pages sub-package (i.e., org.apache.tapestry.corelib.pages).  Component 
libraries have unique folder names mapped to root packages that contain the 
pages (and components, and mixins) of that library.&lt;br /&gt;&lt;br /&gt;When 
there is no folder name, the page is expected to be part of the application, 
under the pages sub-
 package of the application's root package.&lt;br /&gt;&lt;br /&gt;If not found 
there, as a special case, the name is treated as if it were prefixed with 
&quot;core/&quot;.  This allows access to the core pages (and more importantly, 
components -- the search algorithm is the same).&lt;br /&gt;&lt;br 
/&gt;Finally, pages may be organized into folders.  These folders become 
further sub-packages. Thus as page name of &quot;admin/EditUsers&quot; may be 
resolved to class org.example.myapp.pages.admin.EditUsers.&lt;br /&gt;&lt;br 
/&gt;</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#LogicalPageName</link>
-<pubDate>Sun, 08 Oct 2006 13:30:00 GMT</pubDate>
-</item>
-<item>
-<title>OGNL</title>
-<description>The [[Object Graph Navigation Library|http://ognl.org]] was an 
essential part of Tapestry 4.&lt;br /&gt;&lt;br /&gt;OGNL is both exceptionally 
powerful (especially the higher order things it can do, such as list selections 
and projections). However, for the highest&lt;br /&gt;end sites, it is also a 
performance problem, both because of its heavy use of reflection, and because 
it uses a lot of code inside synchronized blocks.&lt;br /&gt;&lt;br /&gt;It 
will be optional in Tapestry 5. I believe it will not be part of the 
tapestry-core, but may be packaged as tapestry-ognl.&lt;br /&gt;&lt;br /&gt;The 
&quot;prop:&quot; binding prefix is an effective replacement for OGNL in 
Tapestry 5.   See PropBinding.&lt;br /&gt;</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#OGNL</link>
-<pubDate>Sat, 07 Oct 2006 12:49:00 GMT</pubDate>
-</item>
-<item>
-<title>ComponentMixins</title>
-<description>One of the more exciting ideas in Tapestry 5 is //mixins//; the 
ability to add behavior to a component without writing code. &lt;br /&gt;&lt;br 
/&gt;It is expected that much common behavior, especially for form control 
components, will be provided by mixins. Further, many Ajax techniques will take 
the form of mixins applied to otherwise ordinary components.&lt;br /&gt;&lt;br 
/&gt;A mixin is an additional component class that operates //with// the main 
component. For a component element within the page, the functionality is 
provided by the main component class and by&lt;br /&gt;the mixin.  &lt;br 
/&gt;&lt;br /&gt;Mixins are primarily about rendering. Mixin render methods are 
//mixed in// to the components' render methods. In effect, the different 
rendering phases of a component are different AOP-like //joinpoints//, and the 
mixins can provide //before advice//.&lt;br /&gt;&lt;br /&gt;Mixins can be 
specified for an //instance// of a component, or can be specified 
 as part of the //implementation// of a component.&lt;br /&gt;&lt;br /&gt;In 
the former case, the @Component annotation will be supplemented with a @Mixin 
annotation. The @Mixin is a list of one or more mixin classes for that 
component.&lt;br /&gt;&lt;br /&gt;''Todo: Template syntax for mixins?''&lt;br 
/&gt;&lt;br /&gt;In the latter case, the @ComponentClass annotation will be 
supplemented with a @Mixin annotation.&lt;br /&gt;&lt;br /&gt;Mixins can be 
configured.  They can have parameters, just like ordinary components. When a 
formal parameter name is ambiguous, it will be prefixed with the unqualified 
class name. Thus, you might have to say, 
&quot;MyMixin.parameterName=someProperty&quot; if &quot;parameterName&quot; is 
ambiguous (by ambiguous, we mean, a parameter of more than one mixin or of the 
component itself).  &lt;br /&gt;&lt;br /&gt;This disambiguation is //simple//. 
It is assumed that the unqualified class name will be sufficient to uniquely 
identify a mixin. That is
 , it is expected that you will not have the same class name even in different 
packages (as mixins, on a single component). In a //degenerate case// where 
this is not so, it will be necessary to disambiguate the mixin name by create a 
subclass of the mixin with a new name.&lt;br /&gt;&lt;br /&gt;''Todo: how are 
mixins on a component implementation configured?''&lt;br /&gt;&lt;br 
/&gt;Mixins may have persistent state, just as with ordinary components.&lt;br 
/&gt;&lt;br /&gt;</description>
-<category>mixins</category>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#ComponentMixins</link>
-<pubDate>Thu, 05 Oct 2006 12:43:00 GMT</pubDate>
-</item>
-<item>
-<title>TypeCoercion</title>
-<description>Automatic coercion of types is essential.  This primarily applies 
to component parameters.&lt;br /&gt;&lt;br /&gt;Parameters are tied to the 
[[Binding|http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry/Binding.html]]
 interface.&lt;br /&gt;&lt;br /&gt;Tapestry component parameters look like 
simple instance variables, but Tapestry's RuntimeTransformation of component 
classes means that reading the value of a parameter instance variable //may// 
invoke Binding.get(), and changing the value of a parameter instance variable 
will invoke Binding.set().&lt;br /&gt;&lt;br /&gt;!Reading From 
Parameters&lt;br /&gt;&lt;br /&gt;Reading a parameter value involves two 
steps:&lt;br /&gt;* Invoking Binding.get()&lt;br /&gt;* Converting the result 
to the type of the parameter (where different)&lt;br /&gt;&lt;br /&gt;When 
reading parameters, the binding will provide an object of the type of the bound 
property.  Various kinds of invariant bindings will returned a fixed
  type, typically a String.&lt;br /&gt;&lt;br /&gt;The parameter will be 
assigned to a variable that has a known type, possibly a primtive type (int, 
boolean) or an object type (Map, Date).&lt;br /&gt;&lt;br /&gt;!Writing To 
Parameters&lt;br /&gt;&lt;br /&gt;Writing to, or updating, a parameter is in 
two steps:&lt;br /&gt;* Converting the new value into a type appropriate for 
the binding&lt;br /&gt;* Invoking Binding.set()&lt;br /&gt;&lt;br /&gt;We will 
be adding a getPropertyType() method to the Binding interface, that will 
identify the property type of the property bound to the parameter.&lt;br 
/&gt;&lt;br /&gt;The component will be responsible for performing a coercion 
from the value provided to the proper type, before invoking 
Binding.set().&lt;br /&gt;&lt;br /&gt;!Coercion Tuples&lt;br /&gt;&lt;br 
/&gt;At the core of this will be a service that performs type coercions.&lt;br 
/&gt;&lt;br /&gt;Coercions are based on //coercion tuples// that define:&lt;br 
/&gt;* A source ty
 pe&lt;br /&gt;* A target type&lt;br /&gt;* An object to perform the coercion 
from source to target&lt;br /&gt;* A &quot;cost&quot; for the conversion 
(possibly, but usually with a standard default value) ''(not yet 
implemented)''&lt;br /&gt;&lt;br /&gt;As a special case, the type of null will 
be treated as type void (i.e., void.class).  Thus we can use the same mechanism 
to identify how to convert from null to other types, such as Boolean or 
Integer.&lt;br /&gt;&lt;br /&gt;There should be a large number of these tuples 
available.  The most common tuples may be conversions between various types and 
String.&lt;br /&gt;&lt;br /&gt;!Coercion Algorithm&lt;br /&gt;* Determine the 
source type (treating null as void.class)&lt;br /&gt;* Determine the target 
type (converting primitive types to equivalent wrapper types)&lt;br /&gt;* If 
the source type is assignable to the target type, then the input value is valid 
and the process is complete&lt;br /&gt;* Find a converter that converts 
 between the source type and the target type, pass the source value through the 
converter to get a target value&lt;br /&gt;&lt;br /&gt;That last part needs a 
bit of expansion.&lt;br /&gt;&lt;br /&gt;First off, there will often ''not'' be 
a tuple for coercing directly form the source type to the target type.&lt;br 
/&gt;&lt;br /&gt;In that scenario, the conversion will involve a search  to 
find a sequence of tuples that will perform the coercion.  This will take the 
form a breadth-first search where we look for tuples that coerce from the 
source type to an intermediate type, then search for tuples from the 
intermediate type to the target type.  This may involve more than two 
coercions.&lt;br /&gt;&lt;br /&gt;You can think of the set of tuples as a kind 
of directed graph.  Each type is a node on the graph, and each tuple represents 
a connection between one type and another type (say, from String to Double).  
What we're trying to do is find a path form a source type (or some supe
 r-class or super-interface of the source type) to some target type (or 
sub-class or sub-interface of the target type).&lt;br /&gt;&lt;br /&gt;May need 
to express a &quot;cost&quot; of the coercion from start type to target type; 
this might be useful if there are multiple paths for the conversion. Cost may 
factor in both the computing expense, and any loss of detail.  Basic cost is 
established in terms of the number of steps and enforced by the order in which 
tuples are considered and combined.&lt;br /&gt;&lt;br /&gt;For example, a 
coercion tuple from Number to Float may be represented as the tuple:&lt;br 
/&gt;(Number, Float, {{{ return new Float(input.floatValue()); }}})&lt;br 
/&gt;&lt;br /&gt;{{{&lt;br /&gt;public interface Coercion&lt;S,T&gt;&lt;br 
/&gt;{&lt;br /&gt;  T coerce(S input);&lt;br /&gt;}&lt;br /&gt;}}}&lt;br 
/&gt;&lt;br /&gt;If the input type is an Integer, then a search for 
Integer-&gt;Float will find no entries. At that point, it will be necessary to 
&quot;cl
 imb&quot; the inheritance tree and look for coercions from Number (the super 
class of Integer); this will find the Number-&gt;Float tuple.&lt;br /&gt;&lt;br 
/&gt;Again, in terms of cost, we might also find a pair of tuples:  
Object-&gt;String and String-&gt;Float.  This will have a higher cost than the 
Number-&gt;Float tuple and should be rejected in favor of the lower cost 
coercion.&lt;br /&gt;&lt;br /&gt;//Note: cost hasn't been implemented, and 
likely won't be, unless and until the algorithm as it stands is shown to 
provide less than optimal results.//&lt;br /&gt;&lt;br /&gt;The algorithm 
caches the result of this search, with proper guards for concurrent access. The 
cache is cleared when an invalidation of the component class loader 
occurs.&lt;br /&gt;&lt;br /&gt;!Configuring the service&lt;br /&gt;&lt;br 
/&gt;This has been implemented as service tapestry.TypeCoercer.&lt;br 
/&gt;&lt;br /&gt;The configuration of this service is an unordered collection 
of CoercionTuple.</d
 escription>
-<category>parameters</category>
-<category>types</category>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#TypeCoercion</link>
-<pubDate>Thu, 05 Oct 2006 12:40:00 GMT</pubDate>
-</item>
-<item>
-<title>EnvironmentalServices</title>
-<description>Frequently, different components need to //cooperate// during the 
rendering process.&lt;br /&gt;&lt;br /&gt;This is an established pattern from 
Tapestry 4, which an enclosing component provides services to the components it 
encloses. By //encloses// we mean, any components that are rendered as part of 
the Form's body; give the use of the Block/~RenderBlock components, this can 
not be determined statically, but is instead determined dynamically, as part of 
the rendering process.&lt;br /&gt;&lt;br /&gt;The canoncial example of this 
pattern is Form component, and the complex relationship it has with each form 
element component it encloses.&lt;br /&gt;&lt;br /&gt;In Tapestry 4, this 
mechanism was based on the ~IRequestCycle which could store named attributes. 
The service providing component would store itself into the cycle using a well 
known name, and service consuming components would retrieve the service using 
the same well known name.&lt;br /&gt;&lt;br /&gt;For 
 Tapestry 5, this will be formalized. A new service will be used to manage this 
information:&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;public interface 
Enviroment&lt;br /&gt;{&lt;br /&gt;  &lt;T&gt; T push(Class&lt;T&gt; type, T 
instance);&lt;br /&gt;&lt;br /&gt;  &lt;T&gt; peek(Class&lt;T&gt; type);&lt;br 
/&gt;&lt;br /&gt;  &lt;T&gt; T pop(Class&lt;T&gt; type);&lt;br /&gt;}&lt;br 
/&gt;}}}&lt;br /&gt;&lt;br /&gt;The Environment is unique to a 
request.</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#EnvironmentalServices</link>
-<pubDate>Tue, 26 Sep 2006 01:45:00 GMT</pubDate>
-</item>
-<item>
-<title>DynamicPageState</title>
-<description>Tapestry 4 has left tracking of dynamic page state as an exercise 
to the developer.  Mostly, this is done using the ''parameters'' parameter of 
the ~DirectLink component.&lt;br /&gt;&lt;br /&gt;Dynamic page state is 
anything that isn't inside a persistent page property. For the most part, this 
includes page properties updated by a For component&lt;br /&gt;&lt;br /&gt;It 
seems likely that this information could be automatically encoded into ~URLs.  
&lt;br /&gt;&lt;br /&gt;I'm envisioning a service that accumulates a series of 
//commands//. Each command is used to store a bit of page state. The commands 
are serializable.  The commands are ultimately serialized into a MIME string 
and attached as a query parameter to each URL.&lt;br /&gt;&lt;br /&gt;When such 
a link is triggered, the commands are de-serialized and each executed in turn. 
Only when that is finished is any further event processing executed, including 
calling into to user code.&lt;br /&gt;&lt;br /&gt;My
  outline for this is to store a series of tuples; each tuple is a component id 
plus the command to execute.&lt;br /&gt;&lt;br /&gt;{{{&lt;br /&gt;public 
interface ComponentCommand&lt;T&gt;&lt;br /&gt;{&lt;br /&gt;  void execute(T 
component);&lt;br /&gt;}&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;These commands 
should be immutable.&lt;br /&gt;&lt;br /&gt;So a component, such as a For loop 
component, could provide itself and a ComponentCommand instance (probably a 
static inner class) to some kind of PageStateTracker service.&lt;br /&gt;&lt;br 
/&gt;{{{&lt;br /&gt;public interface PageStateTracker&lt;br /&gt;{&lt;br /&gt;  
void &lt;T&gt; addCommand(T component, ComponentCommand&lt;T&gt; 
command);&lt;br /&gt;}&lt;br /&gt;}}}&lt;br /&gt;&lt;br /&gt;The commands are 
kept in the order that they are added, except that new commands for the same 
component //replace// previous commands for that component.&lt;br /&gt;&lt;br 
/&gt;As with the Tapestry 4 For component, some mechanism will be ne
 eded to store object ids inside the URLs (that is, inside the commands 
serialized into URL query parameters) and translate back to //equivalent// 
objects when the link is triggered.&lt;br /&gt;&lt;br /&gt;Dynamic page state 
outside of a Form will overlap with some of the FormProcessing inside the 
form.</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#DynamicPageState</link>
-<pubDate>Thu, 21 Sep 2006 16:35:00 GMT</pubDate>
-</item>
-<item>
-<title>FormProcessing</title>
-<description>Form processing in Tapestry 4 had certain strengths and 
limitations.&lt;br /&gt;&lt;br /&gt;Basically, any action framework that can do 
a simple mapping from query parameters to bean property names has advantages in 
terms of simple forms, and Tapestry 4's approach has huge advantages on more 
complex forms (with some considerable developer and framework overhead).&lt;br 
/&gt;&lt;br /&gt;With a direct mapping of query parameter names to bean names, 
each query parameter becomes self describing. You map query parameters to 
property of some well known bean. You do simple conversions from strings to 
other types (typically, ints and dates and the like). You drop query parameters 
that don't match up. You leave a lot of validation and other plumbing (such as 
getting those values into your DataTransferObjects) to the developer.&lt;br 
/&gt;&lt;br /&gt;But you never see a ~StaleLinkException.&lt;br /&gt;&lt;br 
/&gt;You also have some unwanted loopholes in your application i
 n that //any// property can be updated through the URL. This is //one step// 
towards a security hole.&lt;br /&gt;&lt;br /&gt;!Tapestry 4 Approach&lt;br 
/&gt;&lt;br /&gt;Every form component, as it renders, asks the Form that 
encloses it to provide a client id.  The terminology is a little messed; client 
id is the unique (within the form) name for //one rendering// of the component. 
If the component renders multiple times, because of loops, each rendering gets 
a unique name.  This becomes the &lt;input&gt;'s name attribute, and 
ultimately, the query parameter name.&lt;br /&gt;&lt;br /&gt;Tapestry attempts 
to make the client id match the (user provided) component id. This is not 
always possible, especially in a loop, in which case a numeric suffix may be 
appended to the id to (help) ensure uniqueness.&lt;br /&gt;&lt;br /&gt;On 
render, a sequence of //component activations// occur, guided by the normal 
render sequence. The exact sequence of activations guides&lt;br /&gt;the pro
 duction of client ids.&lt;br /&gt;&lt;br /&gt;Using more advanced Tapestry 
techniques, including loops, conditionals and the Block/RenderBlock combo, the 
exact set of components and&lt;br /&gt;component activations that will occur 
for a given rendering of a given form can not be predicted statically. Tapestry 
must actually render out the form&lt;br /&gt;to discover all of these.&lt;br 
/&gt;&lt;br /&gt;In fact, while the Form component is producing this series of 
client ids, it builds up the list and stores it into the rendered page as a 
hidden form field. It will need it later, when the client-side form is 
submitted back to the server.&lt;br /&gt;&lt;br /&gt;An advantage of this 
approach is the disconnect between the query parameter names (the client ids) 
and the objects and properties being editted. Often the client ids will be 
//mneumonic// for the properties, but aren't directly mapped to them. Only the 
components responsible for each query parameter know how to validate 
 the submitted value, and what property of which object will need to be 
updated.&lt;br /&gt;&lt;br /&gt;When a form submission occurs, we want to 
ensure that each query parameter value read out of the request is applied to 
the correct property of the correct object. There's a limit to how much 
Tapestry can help here (because it has only a casual knowledge of this aspect 
of the application structure).&lt;br /&gt;&lt;br /&gt;During this submission 
process, which endded up with the curious name, //rewind phase//, Tapestry must 
do two things:&lt;br /&gt;* Activate each component, such that the component 
may re-determine its client id, read its parameter, and update its page 
property&lt;br /&gt;* Validate that the process has not been comprimised by a 
change of server side state&lt;br /&gt;&lt;br /&gt;That second element is a 
tricky one; things can go wonky if a race condition occurs between two users. 
For example, lets take a simple invoice and line item model. If users A and B b
 oth read the same invoice, user A adds a line item, and user B changes a line 
item ... we can have a problem when user B submits the form. Now that there are 
three line items (not two) in the form, there will be extra component 
activations to process query parameters that don't exist in the request. &lt;br 
/&gt;&lt;br /&gt;This scenario can occur whenever the processing of the form 
submission is driven by server-side data that can change between request.&lt;br 
/&gt;&lt;br /&gt;Tapestry detects this as a difference in the sequence of 
client ids allocated, and throws a ~StaleLinkException, which is very 
frustrating for developers to comprehend and fix.&lt;br /&gt;&lt;br /&gt;There 
are also other edge cases for different race conditions where data is applied 
to the wrong server-side objects.&lt;br /&gt;&lt;br /&gt;The Tapestry 3 
~ListEdit component, which evolved into the  Tapestry 4 For component, attempts 
to address this by serializing a series of //object ids// into the form
  (as a series of hidden fields). This requires a bit of work on the part of 
the developer to provide an ~IPrimaryKeyConverter that can help convert objects 
to ids (when rendering) and ids back to objects (during form submission).&lt;br 
/&gt;&lt;br /&gt;Generally speaking, the Tapestry 4 approach represents layers 
of kludge on layers of kludge. It works, it gets the job done, it can handle 
some very complex situations, but it is less than ideal.&lt;br /&gt;&lt;br 
/&gt;!Tapestry 5&lt;br /&gt;&lt;br /&gt;The goal here is to capture the series 
of //component activations//, along with any significant page state changes, 
during the render.&lt;br /&gt;&lt;br /&gt;These activations will be a series of 
//commands//.  For each component activation there will be two commands:  the 
first command will be used to inform the component of its client id (this 
command executes during render and during form submission). The second command 
will request that the client handle the form submission
  (this command executes only during form submission).&lt;br /&gt;&lt;br 
/&gt;The serialized series of commands is stored as a hidden form field.&lt;br 
/&gt;&lt;br /&gt;There's a lot of API to be figured out, especially the 
relationship between the form components and the form itself.&lt;br /&gt;&lt;br 
/&gt;Further, a lot of what the Tapestry 4 For component does, in terms of 
serializing dynamic page state, will need to fold into this as well.&lt;br 
/&gt;&lt;br /&gt;The end result will be a single hidden field with a big MIME 
string inside it ... but compared to the Tapestry 4 Form component (which has 
to write out many hidden fields) the whole will be less than the sum of the 
parts ... due to the overhead of serialization and gzip compression.&lt;br 
/&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br 
/&gt;</description>
-<category>forms</category>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#FormProcessing</link>
-<pubDate>Thu, 21 Sep 2006 15:40:00 GMT</pubDate>
-</item>
-<item>
-<title>SiteUrl</title>
-<description>http://tapestry.apache.org/tapestry5/tap5devwiki.html</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#SiteUrl</link>
-<pubDate>Thu, 21 Sep 2006 07:03:00 GMT</pubDate>
 </item>
 </channel>
 </rss>


Reply via email to