You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2006/11/05 18:01:21 UTC

svn commit: r471463 [2/2] - in /tapestry/tapestry5/tapestry-core/trunk/src: main/java/org/apache/tapestry/ main/java/org/apache/tapestry/annotations/ main/java/org/apache/tapestry/corelib/components/ main/java/org/apache/tapestry/dom/ main/java/org/apa...

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.html Sun Nov  5 09:01:19 2006
@@ -5177,15 +5177,17 @@
 <div tiddler="InvisibleInstrumentation" modifier="HowardLewisShip" modified="200610201803" created="200610201802" tags="">A feature of Tapestry 4 where the component id, type and parameters were &quot;hidden&quot; inside ordinary HTML tags.\n\nThis will show up inside Tapestry 5 pretty soon, and look something like:\n{{{\n&lt;span t:type=&quot;If&quot; t:test=&quot;prop:showWarning&quot; class=&quot;warning&quot;&gt; \n  . . .\n&lt;/span&gt;\n}}}</div>
 <div tiddler="LogicalPageName" modifier="HowardLewisShip" modified="200610081330" created="200610081330" tags="">A logical page name is the name of a page as it is represented in a URI.\n\nInternally, 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.\n\nThe logical page name must be converted to a fully qualified class name.\n\nA 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.\n\nWhen 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.\n\nIf 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).\n\nFinally, 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.\n\n</div>
 <div tiddler="MainMenu" modifier="HowardLewisShip" modified="200609210701" created="200609210643" tags="">MasterIndex\n[[RSS feed|tap5devwiki.xml]]\n\n[[Tapestry 5 Home|http://tapestry.apache.org/tapestry5/]]\n[[Howard's Blog|http://howardlewisship.com/blog/]]\n\n[[Formatting Help|http://www.blogjones.com/TiddlyWikiTutorial.html#EasyToEdit%20Welcome%20NewFeatures%20WhereToFindHelp]]</div>
-<div tiddler="MasterIndex" modifier="HowardLewisShip" modified="200610281524" created="200609202214" tags="">Top level concepts within Tapestry 5.\n\nA //meta-note//: This is where new ideas are first explained, usually before being implemented. In many cases, the final implementation is\nnot 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.\n\n* PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix\n* TypeCoercion -- How Tapestry 5 extensibly addresses type conversion\n* FormProcessing\n* DynamicPageState -- tracking changes to page state during the render\n* EnvironmentalServices -- how components cooperate during page render\n* ComponentMixins -- A new fundamental way to build web functionality\n* RequestTypes -- Requests, request processing
 , URL formats\n* ComponentTemplates -- Issues about Component Templates\n* DeveloperProcedures -- Your a Tapestry committer ... how do you makes changes?</div>
+<div tiddler="MasterIndex" modifier="HowardLewisShip" modified="200611040038" created="200609202214" tags="">Top level concepts within Tapestry 5.\n\nA //meta-note//: This is where new ideas are first explained, usually before being implemented. In many cases, the final implementation is\nnot 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.\n\n* PropBinding -- Notes on the workhorse &quot;prop:&quot; binding prefix\n* TypeCoercion -- How Tapestry 5 extensibly addresses type conversion\n* FormProcessing\n* DynamicPageState -- tracking changes to page state during the render\n* EnvironmentalServices -- how components cooperate during page render\n* ComponentMixins -- A new fundamental way to build web functionality\n* RequestTypes -- Requests, request processing
 , URL formats\n* ComponentTemplates -- Issues about Component Templates\n* DeveloperProcedures -- Your a Tapestry committer ... how do you makes changes?\n* SmartDefaults -- do even more with event less\n* RandomIdeas -- stuff that doesn't fit elsewhere</div>
 <div tiddler="OGNL" modifier="HowardLewisShip" modified="200610071249" created="200609202254" tags="">The [[Object Graph Navigation Library|http://ognl.org]] was an essential part of Tapestry 4.\n\nOGNL is both exceptionally powerful (especially the higher order things it can do, such as list selections and projections). However, for the highest\nend 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.\n\nIt will be optional in Tapestry 5. I believe it will not be part of the tapestry-core, but may be packaged as tapestry-ognl.\n\nThe &quot;prop:&quot; binding prefix is an effective replacement for OGNL in Tapestry 5.   See PropBinding.\n</div>
 <div tiddler="PageRenderRequest" modifier="HowardLewisShip" modified="200610081333" created="200610071313" tags="">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.\n\nIn 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.\n\nIn 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.\n\n! URI Format\n\n{{{\n/page-name.html/id\n}}}\n\nHere &quot;page-name&quot; is the LogicalPageName for the page. \n\nThe &q
 uot;.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.\n\nThe 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\n\nNote 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.\n\nAny further information needed by Tapestry will be added to the URI as query parameters. This may include things like us
 er locale, persistent page properties, applicaition flow identifiers, or anything else we come up with.\n\n! Request Processing\n\nOnce the page and id parameters are identified, the corresponding page will be loaded.\n\nTapestry will fire two events before rendering the page.\n\nThe 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)\nand storing those objects into transient page properties, in expectaion of the render.\n\nThe @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\nthe context 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.\n\n{{{\n@SetupPageRender\nvoid setup(long id)\n{\n  . .
  .\n}\n}}}\n\n\n\nThe 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.</div>
 <div tiddler="PropBinding" modifier="HowardLewisShip" modified="200610201450" created="200609202203" tags="bindings">The &quot;prop:&quot; binding prefix is the default in a  lot of cases, i.e., in any Java code (annotations).\n\nThis binding prefix  supports several common idioms even though they are not, precisely, the names of properties.  In many cases, this will save developers the bother of using a &quot;literal:&quot; prefix.\n\nThe goal of the &quot;prop:&quot; prefix is to be highly efficient and useful in 90%+ of the cases. [[OGNL]], or synthetic properties in the component class, will pick up the remaining cases.\n\n!Numeric literals\n\nSimple numeric literals should be parsed into read-only, invariant bindings.\n{{{\nprop:5\n\nprop:-22.7\n}}}\n\nThe resulting objects will be of type Long or type Double. TypeCoercion will ensure that component parameters get values (say, int or float) of the correct type.\n\n!Range literals\n\nExpresses a range of integer values, 
 either ascending or descending.\n{{{\nprop:1..10\n\nprop:100..-100\n}}}\n\nThe value of such a binding is Iterable; it can be used by the Loop component.\n\n!Boolean literals\n\n&quot;true&quot; and &quot;false&quot; should also be converted to invariant bindings.\n{{{\nprop:true\n\nprop:false\n}}}\n\n!String literals\n\n//Simple// string literals, enclosed in single quotes.  Example:\n{{{\nprop:'Hello World'\n}}}\n\n//Remember that the binding expression will always be enclosed in double quotes.//\n\n!This literal\n\nIn some cases, it is useful to be able to identify the current component:\n{{{\nprop:this\n}}}\n\nEven though a component is not immutable, the value of //this// does not ever change,\nand this binding is also invariant.\n\n!Null literal\n\n{{{\nprop:null\n}}}\n\nThis value is always exactly null. This can be used to set a parameter who'se default value is non-null to the explicit value null.\n\n!Property paths\n\nMulti-step property paths are extremely importa
 nt.\n\n{{{\nprop:poll.title\n\nprop:identity.user.name\n}}}\n\nThe initial terms need to be readable, they are never updated. Only the final property name must be read/write, and in fact, it is valid to be read-only or write-only.\n\nThe prop: binding factory builds a Java expression to read and update properties. It does not use reflection at runtime. Therefore, the properties of the //declared// type are used. By contrast, [[OGNL]] uses the //actual// type, which is reflection-intensive. Also, unlike OGNL, errors (such as missing properties in the property path) are identified when the page is loaded, rather than when the expression is evaluated.\n</div>
+<div tiddler="RandomIdeas" modifier="HowardLewisShip" modified="200611041749" created="200611040039" tags="">!HTML / XHTML DTDs\n\nThe 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.\n\n!final should imply @Retain\n\nFinal fields should be treated as if they have the @Retain annotation\n\n! Exceptions from event handler / phase render methods\n\nTapestry 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.\n\n! SubForms\n\nPerhaps 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\nw
 ould 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.\n\n! Ajax Constraints\n\nThe 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.\n\nBasically ... never delete!  Deletions are a real pain to handle, unless I suddenly get much smarter.  Allow things to be hidden on the client side,\nand for the corresponding fields to do nothing on the server side, but don't allow them to full out delete. \n\nAllow new things to be added, preferable only at the &quot;tail end&quot; of the form. </div>
 <div tiddler="RequestTypes" modifier="HowardLewisShip" modified="200610081334" created="200610071243" tags="request">There are three broad categories of user requests (requests from the client web browser):\n\n* PageRenderRequest -- requests to render a specific page, possibly with some configuration\n* ComponentActionRequest -- requests that trigger behaivor within a specific component\n* ResourceRequest -- requests that access a resource file within the classpath\n\nEach of these requests has a specific URI format.</div>
 <div tiddler="SideBarTabs" modifier="HowardLewisShip" modified="200609210652" created="200609210651" tags="">&lt;&lt;tabs txtMainTab Timeline Timeline TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' TabMore&gt;&gt;\n</div>
 <div tiddler="SiteSubtitle" modifier="HowardLewisShip" modified="200609202249" created="200609202155" tags="">\nThe quick and dirty one-stop shopping of random ideas for Tapestry 5.</div>
 <div tiddler="SiteTitle" modifier="HowardLewisShip" modified="200609202249" created="200609202155" tags="">Tapestry 5 Brain Dump</div>
 <div tiddler="SiteUrl" modifier="HowardLewisShip" modified="200609210703" created="200609210641" tags="">http://tapestry.apache.org/tapestry5/tap5devwiki.html</div>
+<div tiddler="SmartDefaults" modifier="HowardLewisShip" modified="200611032359" created="200611032344" tags="">As great as the annotations are, allowing things to work without the annotations could be even better.\n\n!Event handler methods\n\nMethods 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):\n\n* onSubmit  --&gt; @~OnEvent(&quot;submit&quot;)\n* onSubmitFromForm --&gt; @~OnEvent(value=&quot;submit&quot;, component=&quot;form&quot;)\n* onUpdateFromSelect  --&gt; @~OnEvent(value=&quot;update&quot;, component=&quot;select&quot;)\n\n!Render phase methods\n\nNaming 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 present:\n\n* beforeRender
 () --&gt; @~BeforeRender\n* beforeRenderBody() --&gt; @~BeforeRenderBody\n\netc.  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.\n\nThere may be some minor implications w.r.t. render phase method ordering.\n\netc.\n\n!Other Ideas\n\nThis 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:\n\n{{{\n\n  @Inject\n  private ComponentResources _resources;\n\n  @Inject(&quot;infrastructure:bindingSource&quot;)\n  private BindingSource _source;\n\n  @Parameter\n  private Object _value;\n\n  B
 inding valueDefault()\n  {\n    ComponentResources containerResources = _resources.getContainer().getComponentResources();\n    return _source.newBinding(&quot;default value&quot;, containerResources, &quot;prop&quot;, _resources.getId(), null);  \n  }\n}}}\n\nSo 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.\n\nIf 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.\n</div>
 <div tiddler="TabAll" modifier="HowardLewisShip" modified="200609210650" created="200609210650" tags="">&lt;&lt;list all&gt;&gt;</div>
 <div tiddler="TypeCoercion" modifier="HowardLewisShip" modified="200610051240" created="200609202217" tags="parameters types">Automatic coercion of types is essential.  This primarily applies to component parameters.\n\nParameters are tied to the [[Binding|http://tapestry.apache.org/tapestry5/apidocs/org/apache/tapestry/Binding.html]] interface.\n\nTapestry 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().\n\n!Reading From Parameters\n\nReading a parameter value involves two steps:\n* Invoking Binding.get()\n* Converting the result to the type of the parameter (where different)\n\nWhen 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.\n\nThe parameter will be assigned to a variable that has a known type, possibly a primtive type (int, boolean) or an object type (Map, Date).\n\n!Writing To Parameters\n\nWriting to, or updating, a parameter is in two steps:\n* Converting the new value into a type appropriate for the binding\n* Invoking Binding.set()\n\nWe will be adding a getPropertyType() method to the Binding interface, that will identify the property type of the property bound to the parameter.\n\nThe component will be responsible for performing a coercion from the value provided to the proper type, before invoking Binding.set().\n\n!Coercion Tuples\n\nAt the core of this will be a service that performs type coercions.\n\nCoercions are based on //coercion tuples// that define:\n* A source type\n* A target type\n* An object to perform the coercion from source to target\n* A &quot;cost&quot; for the conversion (possibly, but usually with a standard default value) ''(not yet implemented)
 ''\n\nAs 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.\n\nThere should be a large number of these tuples available.  The most common tuples may be conversions between various types and String.\n\n!Coercion Algorithm\n* Determine the source type (treating null as void.class)\n* Determine the target type (converting primitive types to equivalent wrapper types)\n* If the source type is assignable to the target type, then the input value is valid and the process is complete\n* 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\n\nThat last part needs a bit of expansion.\n\nFirst off, there will often ''not'' be a tuple for coercing directly form the source type to the target type.\n\nIn 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.\n\nYou 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 super-class or super-interface of the source type) to some target type (or sub-class or sub-interface of the target type).\n\nMay 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.\n\nFor example, a coercion tuple from Number to Float may be represented as the tuple:\n(Number, Float, {{{ return new Float(input.floatValue()); }}})\n\n{{{\npublic interface Coercion&lt;S,T&gt;\n{\n  T coerce(S input);\n}\n}}}\n\nIf 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;climb&quot; the inheritance tree and look for coercions from Number (the super class of Integer); this will find the Number-&gt;Float tuple.\n\nAgain, 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.\n\n//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.//\n\nThe algorithm caches t
 he result of this search, with proper guards for concurrent access. The cache is cleared when an invalidation of the component class loader occurs.\n\n!Configuring the service\n\nThis has been implemented as service tapestry.TypeCoercer.\n\nThe configuration of this service is an unordered collection of CoercionTuple.</div>
 <div tiddler="WorkInYourOwnBranch" modifier="HowardLewisShip" modified="200610281536" created="200610281528" tags="">Working in the trunk can be a problem. ''The SVN trunk is where merges happen, not where development happens.''\n\nFor any bit of code change you make, you want to do the following:\n\n* Branch trunk to form your own sandbox\n* Work in the sandbox\n* Ensure high quality: high code coverage, unit and integration tests, up-to-date documentation\n* Announce (on the developer mailing list) that you are committing to trunk\n* Switch your workspace back to trunk\n* Tag trunk as premerge\n* Merge from your sandbox\n* Ensure a good merge (including documentation, tests, and code coverage)\n* Commit your merge to trunk\n* Tag trunk as postmerge\n\n!Branch names\n\nBranch names should consist of your user id, the current date as YYYYMMDD, and a short mneumonic, such as a bug id.  Example:  {{{hlship-20061027-removeaspectj}}}.\n\nThere's a branches folder for tapestry5/t
 apestry-core, i.e. [http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/]\n\n!Tag names\n\nPrefix the branch name with &quot;premerge&quot; or &quot;postmerge&quot;.  i.e. [http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/tags/]\n\nThese are really important when trying to back out a change, the pre and the post give a lot of context to see what actually changed.\n\n!Announcing\n\nMerging is hard enough, it's worse if two people are making possibly conflicting changes at the same time. A little coordination goes a long way.\n\n!Small increments are ''Good''\n\nThis looks like a lot of overhead, but thanks to Subversion, it really isn't. It's still better to do small increments of work. Don't go away for six months and expect an easy job of committing changes. You can do this style of work several times a day (Subversion was created specifically to make tagging, branching, and merging fast).</div>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/site/resources/tap5devwiki.xml Sun Nov  5 09:01:19 2006
@@ -6,27 +6,39 @@
 <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, 28 Oct 2006 15:36:05 GMT</pubDate>
-<lastBuildDate>Sat, 28 Oct 2006 15:36:05 GMT</lastBuildDate>
+<pubDate>Sat, 04 Nov 2006 17:49:18 GMT</pubDate>
+<lastBuildDate>Sat, 04 Nov 2006 17:49:18 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>
+</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>
+<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#MasterIndex</link>
+<pubDate>Sat, 04 Nov 2006 00:38: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>
+</item>
+<item>
 <title>WorkInYourOwnBranch</title>
 <description>Working in the trunk can be a problem. ''The SVN trunk is where merges happen, not where development happens.''&lt;br /&gt;&lt;br /&gt;For any bit of code change you make, you want to do the following:&lt;br /&gt;&lt;br /&gt;* Branch trunk to form your own sandbox&lt;br /&gt;* Work in the sandbox&lt;br /&gt;* Ensure high quality: high code coverage, unit and integration tests, up-to-date documentation&lt;br /&gt;* Announce (on the developer mailing list) that you are committing to trunk&lt;br /&gt;* Switch your workspace back to trunk&lt;br /&gt;* Tag trunk as premerge&lt;br /&gt;* Merge from your sandbox&lt;br /&gt;* Ensure a good merge (including documentation, tests, and code coverage)&lt;br /&gt;* Commit your merge to trunk&lt;br /&gt;* Tag trunk as postmerge&lt;br /&gt;&lt;br /&gt;!Branch names&lt;br /&gt;&lt;br /&gt;Branch names should consist of your user id, the current date as YYYYMMDD, and a short mneumonic, such as a bug id.  Example:  {{{hlship-20061
 027-removeaspectj}}}.&lt;br /&gt;&lt;br /&gt;There's a branches folder for tapestry5/tapestry-core, i.e. [http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/branches/]&lt;br /&gt;&lt;br /&gt;!Tag names&lt;br /&gt;&lt;br /&gt;Prefix the branch name with &quot;premerge&quot; or &quot;postmerge&quot;.  i.e. [http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/tags/]&lt;br /&gt;&lt;br /&gt;These are really important when trying to back out a change, the pre and the post give a lot of context to see what actually changed.&lt;br /&gt;&lt;br /&gt;!Announcing&lt;br /&gt;&lt;br /&gt;Merging is hard enough, it's worse if two people are making possibly conflicting changes at the same time. A little coordination goes a long way.&lt;br /&gt;&lt;br /&gt;!Small increments are ''Good''&lt;br /&gt;&lt;br /&gt;This looks like a lot of overhead, but thanks to Subversion, it really isn't. It's still better to do small increments of work. Don't go away for six months and exp
 ect an easy job of committing changes. You can do this style of work several times a day (Subversion was created specifically to make tagging, branching, and merging fast).</description>
 <link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#WorkInYourOwnBranch</link>
-<pubDate>Sat, 28 Oct 2006 15:36:05 GMT</pubDate>
+<pubDate>Sat, 28 Oct 2006 15:36:00 GMT</pubDate>
 </item>
 <item>
 <title>DeveloperProcedures</title>
 <description>Tapestry is a big chunk of code, growing every day. We need to not step on each other's toes.&lt;br /&gt;&lt;br /&gt;//At this time, Tapestry is pretty single threaded, with Howard setting up the main infrastructure.  Soon there's going to be a crowd of folks working on it, and we need to coordinate on this ahead of time.//&lt;br /&gt;&lt;br /&gt;Basic guidelines:&lt;br /&gt;&lt;br /&gt;* WorkInYourOwnBranch&lt;br /&gt;* WatchCodeCoverage&lt;br /&gt;* FocusOnTesting&lt;br /&gt;* DontTouchInternals&lt;br /&gt;</description>
 <link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#DeveloperProcedures</link>
-<pubDate>Sat, 28 Oct 2006 15:25:11 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?</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#MasterIndex</link>
-<pubDate>Sat, 28 Oct 2006 15:24:18 GMT</pubDate>
+<pubDate>Sat, 28 Oct 2006 15:25:00 GMT</pubDate>
 </item>
 <item>
 <title>ComponentTemplates</title>
@@ -125,18 +137,6 @@
 <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>
-<item>
-<title>MainMenu</title>
-<description>MasterIndex&lt;br /&gt;[[RSS feed|tap5devwiki.xml]]&lt;br /&gt;&lt;br /&gt;[[Tapestry 5 Home|http://tapestry.apache.org/tapestry5/]]&lt;br /&gt;[[Howard's Blog|http://howardlewisship.com/blog/]]&lt;br /&gt;&lt;br /&gt;[[Formatting Help|http://www.blogjones.com/TiddlyWikiTutorial.html#EasyToEdit%20Welcome%20NewFeatures%20WhereToFindHelp]]</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#MainMenu</link>
-<pubDate>Thu, 21 Sep 2006 07:01:00 GMT</pubDate>
-</item>
-<item>
-<title>SideBarTabs</title>
-<description>&lt;&lt;tabs txtMainTab Timeline Timeline TabTimeline All 'All tiddlers' TabAll Tags 'All tags' TabTags More 'More lists' TabMore&gt;&gt;&lt;br /&gt;</description>
-<link>http://tapestry.apache.org/tapestry5/tap5devwiki.html#SideBarTabs</link>
-<pubDate>Thu, 21 Sep 2006 06:52:00 GMT</pubDate>
 </item>
 </channel>
 </rss>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/app1/index.html Sun Nov  5 09:01:19 2006
@@ -33,17 +33,16 @@
                 <li>
                     <a href="BadTemplate.html">BadTemplate Page</a> -- More exception reporting </li>
                 <li>
-                    <a href="ActionPage.html">Action Page</a> -- tests fixture for ActionLink
-                    component </li>
+                    <a href="ActionPage.html">Action Page</a> -- tests fixture for ActionLink component </li>
                 <li>
-                    <a href="InstanceMixin.html">InstanceMixin</a> -- Mixin added to particular
-                    component instance </li>
+                    <a href="InstanceMixin.html">InstanceMixin</a> -- Mixin added to particular component instance </li>
                 <li>
-                    <a href="RenderPhaseOrder.html">RenderPhaseOrder</a> -- Order of operations when
-                    invoking render phase methods </li>
+                    <a href="RenderPhaseOrder.html">RenderPhaseOrder</a> -- Order of operations when invoking render
+                    phase methods </li>
+                <li>
+                    <a href="SimpleForm.html">SimpleForm</a> -- first pass at writing Form and TextField components
+                </li>
             </ul>
         </p>
-        <p> Feast your eyes: </p>
-        <img src="render-states1_1.png" alt="Component Render States"/>
     </body>
 </html>

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/dom/DOMTest.java Sun Nov  5 09:01:19 2006
@@ -27,8 +27,6 @@
 /**
  * Tests for a number of DOM node classes, including {@link org.apache.tapestry.dom.Element} and
  * {@link org.apache.tapestry.dom.Document}.
- * 
- * 
  */
 public class DOMTest extends Assert
 {
@@ -78,8 +76,8 @@
 
         Element e = d.newRootElement("has-attributes");
 
-        e.addAttribute("fred", "flintstone");
-        e.addAttribute("barney", "rubble");
+        e.attribute("fred", "flintstone");
+        e.attribute("barney", "rubble");
 
         assertEquals(d.toString(), readFile("document_with_root_element_and_attributes.txt"));
     }
@@ -92,14 +90,14 @@
         Element e = d.newRootElement("population");
 
         Element p = e.element("person");
-        p.addAttribute("first-name", "Fred");
-        p.addAttribute("last-name", "Flintstone");
+        p.attribute("first-name", "Fred");
+        p.attribute("last-name", "Flintstone");
 
         assertSame(p.getParent(), e);
 
         p = e.element("person");
-        p.addAttribute("first-name", "Barney");
-        p.addAttribute("last-name", "Rubble");
+        p.attribute("first-name", "Barney");
+        p.attribute("last-name", "Rubble");
 
         assertSame(p.getParent(), e);
 
@@ -121,7 +119,7 @@
 
         Element e = d.newRootElement("fred");
 
-        e.addAttribute("", "value");
+        e.attribute("", "value");
     }
 
     @Test
@@ -139,17 +137,17 @@
 
         Element e = d.newRootElement("root");
 
-        e.addAttribute("foo", "bar");
+        e.attribute("foo", "bar");
 
         final String expected = "<root foo=\"bar\"/>";
 
         assertEquals(d.toString(), expected);
 
-        e.addAttribute("foo", null);
+        e.attribute("foo", null);
 
         assertEquals(d.toString(), expected);
 
-        e.addAttribute("gnip", null);
+        e.attribute("gnip", null);
 
         assertEquals(d.toString(), expected);
     }
@@ -190,6 +188,18 @@
         e.text("<this> & <that>");
 
         assertEquals(d.toString(), "<root>&lt;this&gt; &amp; &lt;that&gt;</root>");
+    }
+
+    @Test
+    public void specify_attributes_with_new_element()
+    {
+        Document d = new Document();
+
+        Element e = d.newRootElement("root");
+
+        e.element("foo", "alpha", "legion");
+
+        assertEquals(d.toString(), "<root><foo alpha=\"legion\"/></root>");
     }
 
     @Test

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/SimpleForm.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/SimpleForm.java?view=auto&rev=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/SimpleForm.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/integration/app1/pages/SimpleForm.java Sun Nov  5 09:01:19 2006
@@ -0,0 +1,36 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.integration.app1.pages;
+
+import org.apache.tapestry.annotations.ComponentClass;
+import org.apache.tapestry.annotations.Persist;
+
+@ComponentClass
+public class SimpleForm
+{
+    @Persist
+    private String _email;
+
+    public String getEmail()
+    {
+        return _email;
+    }
+
+    public void setEmail(String email)
+    {
+        _email = email;
+    }
+
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/TypeCoercerImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/TypeCoercerImplTest.java?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/TypeCoercerImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/ioc/services/TypeCoercerImplTest.java Sun Nov  5 09:01:19 2006
@@ -117,41 +117,36 @@
 
         return new Object[][]
         {
-        { this, String.class, toString() }, // Object -> String
-                { 55l, Integer.class, 55 }, // Number (Long) --> Integer
-                { "", Boolean.class, false }, // String --> Boolean
+        // There's a lot of these!
+
+                { this, String.class, toString() }, 
+                { 55l, Integer.class, 55 }, 
+                { "", Boolean.class, false }, 
                 { "  ", Boolean.class, false },
                 { "x", Boolean.class, true },
                 { " z ", Boolean.class, true },
                 { "false", Boolean.class, false },
                 { "  False ", Boolean.class, false },
-                { null, Boolean.class, false }, // void --> Boolean
-                { new Double(256), Integer.class, new Integer(256) }, // Number --> Integer
+                { null, Boolean.class, false },
+                { new Double(256), Integer.class, new Integer(256) }, 
                 { new Double(22.7), Integer.class, new Integer(22) },
-                { new Integer(0), Boolean.class, false }, // Number --> Boolean
+                { new Integer(0), Boolean.class, false }, 
                 { new Long(32838), Boolean.class, true },
-                { new Integer(127), Byte.class, new Byte("127") }, // Number --> Byte
-                { new Double(58), Short.class, new Short("58") }, // Number --> Short
-                { new Integer(33), Long.class, new Long(33) }, // Number --> Long
-                { new Integer(22), Float.class, new Float(22) }, // Number --> Float
-                { new Integer(1234), Double.class, new Double(1234) }, // Number --> Float
-                { Collections.EMPTY_LIST, Boolean.class, false }, // Collection --> Boolean
+                { new Integer(127), Byte.class, new Byte("127") }, 
+                { new Double(58), Short.class, new Short("58") }, 
+                { new Integer(33), Long.class, new Long(33) }, 
+                { new Integer(22), Float.class, new Float(22) }, 
+                { new Integer(1234), Double.class, new Double(1234) }, 
+                { Collections.EMPTY_LIST, Boolean.class, false }, 
                 { Collections.singleton(this), Boolean.class, true },
-                { bigDecimalValue, BigDecimal.class, new BigDecimal(bigDecimalValue) }, // String
-                // -->
-                // BigDecimal
-                { new BigDecimal(bigDecimalValue), Double.class, 1.2345656748352436E49 }, // BigDecimal
-                // -->
-                // Double
-                { bigIntegerValue, BigInteger.class, new BigInteger(bigIntegerValue) }, // String
-                // -->
-                // BigInteger
+                { bigDecimalValue, BigDecimal.class, new BigDecimal(bigDecimalValue) }, 
+                { new BigDecimal(bigDecimalValue), Double.class, 1.2345656748352436E49 }, 
+                { bigIntegerValue, BigInteger.class, new BigInteger(bigIntegerValue) },
                 { new BigInteger("12345678"), Long.class, 12345678l },
                 { -12345678l, BigInteger.class, new BigInteger("-12345678") },
-                // Object --> List
                 { object, List.class, Collections.singletonList(object) },
+                { null, String.class, null },
 
         };
     }
-
 }

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentClassResolverImplTest.java Sun Nov  5 09:01:19 2006
@@ -447,8 +447,6 @@
 
         ComponentClassResolver resolver = create(source);
 
-        resolver.setApplicationPackage(APP_ROOT_PACKAGE);
-
         assertEquals(resolver.resolveMixinTypeToClassName("SimpleMixin"), expectedClassName);
 
         verify();
@@ -462,6 +460,9 @@
         train_for_packages(source, CORE_ROOT_PACKAGE);
         train_for_app_packages(source);
 
+        train_exists(source, APP_ROOT_PACKAGE + ".mixins.SimpleMixin", false);
+        train_exists(source, CORE_ROOT_PACKAGE + ".mixins.SimpleMixin", false);
+
         replay();
 
         ComponentClassResolver resolver = create(source, new LibraryMapping(CORE_PREFIX,
@@ -490,6 +491,9 @@
 
         train_for_packages(source, CORE_ROOT_PACKAGE);
         train_for_app_packages(source);
+
+        train_exists(source, APP_ROOT_PACKAGE + ".components.SimpleComponent", false);
+        train_exists(source, CORE_ROOT_PACKAGE + ".components.SimpleComponent", false);
 
         replay();
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentLifecycleMethodWorkerTest.java Sun Nov  5 09:01:19 2006
@@ -66,6 +66,8 @@
 
         train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
 
+        train_isRootClass(model, false);
+
         train_addMethod(
                 tf,
                 TransformConstants.SETUP_RENDER_SIGNATURE,
@@ -80,7 +82,7 @@
 
         verify();
     }
-    
+
     @Test
     public void multiple_methods_reverse_order()
     {
@@ -94,6 +96,8 @@
 
         train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
 
+        train_isRootClass(model, false);
+
         train_addMethod(
                 tf,
                 TransformConstants.SETUP_RENDER_SIGNATURE,
@@ -106,9 +110,9 @@
 
         worker.transform(tf, model);
 
-        verify();        
+        verify();
     }
-    
+
     @Test
     public void multiple_methods_parent_class_reverse_order()
     {
@@ -122,11 +126,8 @@
 
         train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
         train_isRootClass(model, true);
-        
-        train_addMethod(
-                tf,
-                TransformConstants.SETUP_RENDER_SIGNATURE,
-                "{ bMethod(); aMethod(); }");
+
+        train_addMethod(tf, TransformConstants.SETUP_RENDER_SIGNATURE, "{ bMethod(); aMethod(); }");
 
         replay();
 
@@ -136,9 +137,8 @@
         worker.transform(tf, model);
 
         verify();
-        
-    }
 
+    }
 
     @Test
     public void method_in_base_class()
@@ -154,10 +154,7 @@
 
         train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
 
-        train_addMethod(
-                tf,
-                TransformConstants.SETUP_RENDER_SIGNATURE,
-                "{ aMethod(); }");
+        train_addMethod(tf, TransformConstants.SETUP_RENDER_SIGNATURE, "{ aMethod(); }");
 
         replay();
 
@@ -189,6 +186,8 @@
 
         train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
 
+        train_isRootClass(model, false);
+
         train_addMethod(
                 tf,
                 TransformConstants.SETUP_RENDER_SIGNATURE,
@@ -219,6 +218,8 @@
 
         train_getClassName(tf, "biff.Baz");
 
+        train_isRootClass(model, false);
+
         train_addMethod(
                 tf,
                 TransformConstants.SETUP_RENDER_SIGNATURE,
@@ -251,6 +252,7 @@
         { MarkupWriter.class.getName() }, null));
 
         train_findMethodsWithAnnotation(tf, SetupRender.class, sigs);
+        train_isRootClass(model, false);
         train_getClassName(tf, "foo.Bar");
 
         train_addMethod(

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentSourceImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentSourceImplTest.java?view=auto&rev=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentSourceImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ComponentSourceImplTest.java Sun Nov  5 09:01:19 2006
@@ -0,0 +1,101 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import org.apache.tapestry.internal.structure.ComponentPageElement;
+import org.apache.tapestry.internal.structure.Page;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.runtime.ComponentLifecycle;
+import org.apache.tapestry.services.ComponentSource;
+import org.testng.annotations.Test;
+
+public class ComponentSourceImplTest extends InternalBaseTestCase
+{
+    private static final String PAGE_NAME = "foo.pages.Bar";
+
+    private static final String NESTED_ELEMENT_ID = "zip.zoom";
+
+    @Test
+    public void root_element_of_page()
+    {
+        RequestPageCache cache = newPageRequestCache();
+        Page page = newPage();
+        ComponentPageElement element = newComponentPageElement();
+        ComponentLifecycle component = newComponentLifecycle();
+
+        train_getByClassName(cache, PAGE_NAME, page);
+
+        train_getRootElement(page, element);
+
+        train_getComponent(element, component);
+
+        replay();
+
+        ComponentSource source = new ComponentSourceImpl(cache);
+
+        assertSame(source.getComponent(PAGE_NAME), component);
+
+        verify();
+    }
+
+    @Test
+    public void nested_element_within_page()
+    {
+        RequestPageCache cache = newPageRequestCache();
+        Page page = newPage();
+        ComponentPageElement element = newComponentPageElement();
+        ComponentLifecycle component = newComponentLifecycle();
+
+        train_getByClassName(cache, PAGE_NAME, page);
+
+        train_getComponentElementByNestedId(page, NESTED_ELEMENT_ID, element);
+
+        train_getComponent(element, component);
+
+        replay();
+
+        ComponentSource source = new ComponentSourceImpl(cache);
+
+        assertSame(source.getComponent(PAGE_NAME + ":" + NESTED_ELEMENT_ID), component);
+
+        verify();
+
+    }
+
+    protected final void train_getComponentElementByNestedId(Page page, String nestedId,
+            ComponentPageElement element)
+    {
+        page.getComponentElementByNestedId(nestedId);
+        setReturnValue(element);
+    }
+
+    protected final void train_getRootElement(Page page, ComponentPageElement element)
+    {
+        page.getRootElement();
+        setReturnValue(element);
+    }
+
+    protected final void train_getByClassName(RequestPageCache cache, String pageClassName,
+            Page page)
+    {
+        cache.getByClassName(pageClassName);
+        setReturnValue(page);
+    }
+
+    protected final RequestPageCache newPageRequestCache()
+    {
+        return newMock(RequestPageCache.class);
+    }
+}

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkImplTest.java?view=auto&rev=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkImplTest.java (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/LinkImplTest.java Sun Nov  5 09:01:19 2006
@@ -0,0 +1,144 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import java.util.Arrays;
+
+import org.apache.tapestry.Link;
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.services.WebResponse;
+import org.testng.annotations.Test;
+
+public class LinkImplTest extends InternalBaseTestCase
+{
+    private static final String ENCODED = "*encoded*";
+
+    @Test
+    public void url_with_parameters()
+    {
+        WebResponse response = newWebResponse();
+
+        train_encodeURL(response, "/foo/bar?barney=rubble&fred=flintstone", ENCODED);
+
+        replay();
+
+        Link link = new LinkImpl(response, "/foo/bar");
+
+        link.addParameter("fred", "flintstone");
+        link.addParameter("barney", "rubble");
+
+        assertEquals(link.toURI(), ENCODED);
+
+        verify();
+    }
+
+    @Test
+    public void retrieve_parameter_values()
+    {
+        WebResponse response = newWebResponse();
+
+        replay();
+
+        Link link = new LinkImpl(response, "/foo/bar");
+
+        link.addParameter("fred", "flintstone");
+        link.addParameter("barney", "rubble");
+
+        assertEquals(link.getParameterValue("fred"), "flintstone");
+        assertEquals(link.getParameterValue("barney"), "rubble");
+        assertNull(link.getParameterValue("wilma"));
+
+        verify();
+    }
+
+    @Test
+    public void ensure_parameter_values_are_encoded()
+    {
+        WebResponse response = newWebResponse();
+
+        train_encodeURL(response, "/foo/bar?fred=flint+stone%3F", ENCODED);
+
+        replay();
+
+        Link link = new LinkImpl(response, "/foo/bar");
+
+        link.addParameter("fred", "flint stone?");
+
+        assertEquals(link.toURI(), ENCODED);
+
+        verify();
+    }
+
+    @Test
+    public void parameter_names_are_returned_sorted()
+    {
+        WebResponse response = newWebResponse();
+
+        replay();
+
+        Link link = new LinkImpl(response, "/foo/bar");
+
+        link.addParameter("fred", "flintstone");
+        link.addParameter("barney", "rubble");
+
+        assertEquals(link.getParameterNames(), Arrays.asList("barney", "fred"));
+
+        verify();
+    }
+
+    @Test
+    public void parameter_names_must_be_unique()
+    {
+        WebResponse response = newWebResponse();
+
+        replay();
+
+        Link link = new LinkImpl(response, "/foo/bar");
+
+        link.addParameter("fred", "flintstone");
+        try
+        {
+            link.addParameter("fred", "flintstone");
+            unreachable();
+        }
+        catch (IllegalArgumentException ex)
+        {
+            assertEquals(
+                    ex.getMessage(),
+                    "Parameter names are required to be unique.  Parameter 'fred' already has the value 'flintstone'.");
+        }
+
+        verify();
+    }
+
+    @Test
+    public void to_form_URI_does_not_include_parameters()
+    {
+        WebResponse response = newWebResponse();
+
+        train_encodeURL(response, "/foo/bar", ENCODED);
+
+        replay();
+
+        Link link = new LinkImpl(response, "/foo/bar");
+
+        link.addParameter("fred", "flintstone");
+        link.addParameter("barney", "rubble");
+
+        assertEquals(link.toFormURI(), ENCODED);
+
+        verify();
+    }
+}

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MarkupWriterImplTest.java Sun Nov  5 09:01:19 2006
@@ -85,7 +85,7 @@
 
         w.write("after child");
 
-        root.addAttribute("gnip", "gnop");
+        root.attribute("gnip", "gnop");
 
         assertEquals(
                 w.toString(),

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/MixinWorkerTest.java Sun Nov  5 09:01:19 2006
@@ -65,6 +65,8 @@
                 TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
                 "fred = (foo.bar.Baz) rez.getMixinByClassName(\"foo.bar.BazMixin\");");
 
+        transformation.claimField("fred", annotation);
+
         replay();
 
         new MixinWorker(resolver).transform(transformation, model);
@@ -94,6 +96,8 @@
                 transformation,
                 TransformConstants.CONTAINING_PAGE_DID_LOAD_SIGNATURE,
                 "fred = (foo.bar.Baz) rez.getMixinByClassName(\"foo.bar.Baz\");");
+
+        transformation.claimField("fred", annotation);
 
         replay();
 

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/structure/ComponentPageElementImplTest.java Sun Nov  5 09:01:19 2006
@@ -136,6 +136,7 @@
         train_getLog(model, log);
 
         train_getNestedId(container, null);
+        train_getName(page, "foo.pages.MyPage");
 
         train_getParameterNames(model, "wilma", "barney", "fred");
         train_getParameterModel(model, "wilma", pmodel);

Modified: tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/Base64Tests.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/Base64Tests.java?view=diff&rev=471463&r1=471462&r2=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/Base64Tests.java (original)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/util/Base64Tests.java Sun Nov  5 09:01:19 2006
@@ -1,7 +1,22 @@
+// Copyright 2006 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 package org.apache.tapestry.internal.util;
 
 import static org.apache.tapestry.util.CollectionFactory.newMap;
 
+import java.io.EOFException;
 import java.io.InputStream;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -65,5 +80,41 @@
 
         assertEquals(output, input);
         assertNotSame(output, input);
+    }
+
+    @Test
+    public void checks_for_eof() throws Exception
+    {
+        String[] values =
+        { "fred", "barney", "wilma" };
+
+        Base64ObjectOutputStream os = new Base64ObjectOutputStream();
+
+        for (String value : values)
+            os.writeObject(value);
+
+        os.close();
+
+        String base64 = os.toBase64();
+
+        ObjectInputStream ois = new Base64ObjectInputStream(base64);
+
+        for (int i = 0; i < 3; i++)
+        {
+            String value = (String) ois.readObject();
+
+            assertEquals(value, values[i]);
+        }
+
+        try
+        {
+            ois.readObject();
+            fail("Unreachable.");
+        }
+        catch (EOFException ex)
+        {
+            // Expected.
+        }
+
     }
 }

Added: tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html?view=auto&rev=471463
==============================================================================
--- tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html (added)
+++ tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/integration/app1/pages/SimpleForm.html Sun Nov  5 09:01:19 2006
@@ -0,0 +1,20 @@
+<t:comp type="Border" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
+    <h1>Simple Form</h1>
+
+    <p> This is the <em>very early</em> start to Tapestry 5 form support. </p>
+
+    <t:comp type="Form">
+
+        <t:comp type="TextField" id="email" value="prop:email"/>
+
+        <br/>
+        
+        <input type="submit"/>
+        
+    </t:comp>
+
+    <t:comp type="If" test="prop:email">
+        <p> You entered: ${email} </p>
+    </t:comp>
+
+</t:comp>