It's saturday and I'm working on the tutorial. So your appreciation is appreciated.
The main thing holding Tapestry 3 and 4 back a couple of years ago, when they were clearly superior technologically, was documentation. The reference documentation is a bit of a brain dump, but will be good for those in-depth questions. The tutorial is very important for people getting started. It's important to hook people in their first hour using Tapestry. On 2/24/07, Mike D Pilsbury <[EMAIL PROTECTED]> wrote:
Of course. It should have been obvious. Thanks again for the great T5 docs. They're much appreciated. Howard Lewis Ship wrote: > If there's a form or a link on the page, back to the same page, the > context will be maintained. > > On 2/23/07, Mike D Pilsbury <[EMAIL PROTECTED]> wrote: >> Very nice explanation. >> >> One small question. In the last scenario (Render Requests Only), why is >> the passivation method required? >> >> >> [EMAIL PROTECTED] wrote: >> > Author: hlship >> > Date: Thu Feb 22 16:19:45 2007 >> > New Revision: 510729 >> > >> > URL: http://svn.apache.org/viewvc?view=rev&rev=510729 >> > Log: >> > Add some detailed documentation concerning page navigation, >> including component request context and page activation context. >> > >> > Added: >> > >> tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt >> > Modified: >> > tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt >> > tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml >> > >> > Added: >> tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt >> > URL: >> http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt?view=auto&rev=510729 >> >> > >> ============================================================================== >> >> > --- >> tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt >> (added) >> > +++ >> tapestry/tapestry5/tapestry-core/trunk/src/site/apt/guide/pagenav.apt >> Thu Feb 22 16:19:45 2007 >> > @@ -0,0 +1,293 @@ >> > + ---- >> > + Page Navigation >> > + ---- >> > + >> > +Page Navigation >> > + >> > + In essense, a Tapestry application is a number of related pages, >> working together. To some degree, each page is like an application >> unto itself. >> > + >> > + Any individual request will be targetted at a single page. >> Requests come in two forms: >> > + >> > + * <action> requests target a specific component on a specific >> page, triggering an event within that component >> > + >> > + * <render> requests target a specific page, and stream the HTML >> markup for that page back to the client >> > + >> > + [] >> > + >> > + This dictomy between action requests >> > + and render requests is new in Tapestry 5. It is in some ways >> based on ideas from the Portlet specification and differentiating >> > + the two types of requests alleviates a number of problems in >> traditional web applications related to the browser back button, or >> to the user hitting the >> > + refresh button in their browser. >> > + >> > +Action Requests >> > + >> > + Action requests may take the form of hyperlinks >> > + >> ({{{../component-parameters.html#org.apache.tapestry.corelib.components.actionlink}ActionLink}}) >> or form submissions >> > + >> ({{{../component-parameters.html#org.apache.tapestry.corelib.components.form}Form}}). >> >> > + >> > + In both cases, the value returned from an {{{event.html}event >> handler method}} controls the response sent to the client web browser. >> > + >> > + The URL for an action request identifies the name of the page, >> the nested id of the component, and the name of the event to trigger >> on the component (this is usually "action"). >> > + Further, an action request may contain additional context >> information, which will be provided to the event handler method. >> > + >> > + These URLs expose a bit of the internal structure of the >> application. Over time, as an application grows and is maintained, >> the ids of components may change. This means that >> > + action request URLs should not be bookmarked. Fortunately, >> users will rarely have the chance to do so (see below). >> > + >> > +* Null response >> > + >> > + If the event handler method returns no value, or returns null, >> then the current page (the page containing the component) will render >> the response. >> > + >> > + A page render link for the current page is created and sent to >> the client as a client side redirect. The client browser will >> automatically submit a new request >> > + to generate the page. >> > + >> > + The user will see the newly generated content in their browser. >> In addition, the URL in the browser's address bar will be a render >> request URL. Render request URLs are >> > + shorter and contain less application structure (for instance, >> they don't include component ids or event types). Render requests >> URLs are what your users will bookmark. The action request URLs >> > + are transitory, meaningful only while the application is >> actively engaged, and not meant to be used in later sessions. >> > + >> > +* String response >> > + >> > + When a string is returned, it is expected to be the logical name >> of a page (as opposed to the page's >> > + fully qualified class name). As elsewhere, the name of the page >> is case insensitive. >> > + >> > + Again, a render request URL will be constructed and sent to the >> client as a redirect. >> > + >> > +* Page response >> > + >> > + You may also return an instance of a page, rather than the name >> of a page. >> > + >> > + A page may be injected via the >> {{{../apidocs/org/apache/tapestry/annotations/InjectPage.html}InjectPage}} >> annotation. >> > + >> > + Often, you will configure the page in some way before returning >> the page (examples below). >> > + >> > + You can also return a component within the page, but this will >> generate a runtime warning. >> > + >> > +* Link response >> > + >> > + An event handler method may return a >> > + {{{../apidocs/org/apache/tapestry/Link.html}Link}} instance >> directly. The Link is converted into a URL and a client redirect to >> that URL is sent to the client. >> > + >> > + The >> {{{../apidocs/org/apache/tapestry/ComponentResources.html}ComponentResources}} >> object that is injected into your pages (and components) has methods >> > + for creating action and page links (they are actually defined in >> > + >> {{{../apidocs/org/apache/tapestry/ComponentResourcesCommon.html}ComponentResourcesCommon}}). >> >> > + >> > +* Stream response >> > + >> > + An event handler can also return a >> {{{../apidocs/org/apache/tapestry/StreamResponse.html}StreamResponse}} >> object, which encapsulates a stream to >> > + be sent directly to the client browser. This is useful for >> compnents that want to, say, generate an image or PDF and provide it >> to the client. >> > + >> > +* Object response >> > + >> > + Any other type of object returned from an event handler method >> is an error. >> > + >> > +Page Render Requests >> > + >> > + Render requests are simpler in structure and behavior than >> action requests. In the simplest case, the URL is simply the >> > + logical name of the page. >> > + >> > + Pages may have an <activation context>. The activation context >> represents persistent information about the state of the page. In >> practical terms, >> > + the activation context is usually the id of some >> database-persistent object. >> > + >> > + When a page has an activation context, the values of the context >> are appended to the URL path. >> > + >> > + Not all pages have an activation context. >> > + >> > + The activation context may be explicitly set when the render >> request link is created (the PageLink component has a context >> parameter for this purpose). >> > + When no explicit activation context is provided, the page itself >> is queried for its activation context. >> > + >> > + This querying takes the form of an event trigger. The event name >> is "passivate" (as we'll see shortly, there's a corresponding >> "activate"). The >> > + return value of the method is used as the context. For example: >> > + >> > ++---+ >> > +public class ProductDetail >> > +{ >> > + private Product _product; >> > + >> > + . . . >> > + >> > + long onPassivate() { return _product.getId(); } >> > +} >> > ++----+ >> > + >> > + The activation context may consist of a series of values, in >> which case the return value of the method should be an array or a List. >> > + >> > +* Page activation >> > + >> > + When a page render request arrives, the page is activated before >> it is rendered. >> > + >> > + Activation serves two purposes: >> > + >> > + * It allows the page to restore its internal state from data >> encoded into the URL (the activation context discussed above). >> > + >> > + * It provides coarse approach to validating access to the page. >> > + >> > + [] >> > + >> > + The later case, validation, is generally concerned with user >> identity and access; if you have pages that may only be accessed by >> certain users, >> > + you may use the page's activate event handler responsible for >> verifying that access. >> > + >> > + A page's activate event handler mirrors its passivate handler: >> > + >> > ++----+ >> > + . . . >> > + >> > + void onActivate(long productId) >> > + { >> > + _product = _productDAO.getById(productId); >> > + } >> > + >> > + . . . >> > ++-----+ >> > + >> > + Here's the relevant part: when the page renders, it is likely to >> include more action request URLs (links and forms). The action requests >> > + for those links and forms will <also> start by activating the >> page, before performing other work. This forms an unbroken chain of >> requests >> > + that include the same activation context. >> > + >> > + To some degree, this same effect could be accomplished using a >> {{{persist.html}persistent page value}}, but that requires an active >> session, >> > + and the result is not bookmarkable. >> > + >> > + The activate event handler may also return a value, which is >> treated identically to a return value of an action request event >> trigger. This will typically >> > + be used in an access validation scenario. >> > + >> > +Page Navigation Patterns >> > + >> > + This combination of action links and context and page context >> can be put together in any number of ways. >> > + >> > + Let's take a typical master/detail relationship using the >> concept of a product catalog page. In this example, the >> > + ProductListing page is a list of products, and the >> ProductDetails page must display the details for a specific product. >> > + >> > +* Action Requests / Persistent Data >> > + >> > + In this pattern, the ProductListing page uses action events and >> a persistent field on the ProductDetails page. >> > + >> > + ProductListing.html: >> > + >> > ++---+ >> > + <t:comp id="loop" source="products" value="product"> >> > + <a t:type="actionlink" t:id="select" >> context="product.id">${product.name}</a> >> > + </t:comp> >> > ++---+ >> > + >> > + ProductListing.java: >> > + >> > ++---+ >> > + @InjectPage >> > + private ProductDetails _details; >> > + >> > + Object onActionFromSelect(long productId) >> > + { >> > + _details.setProductId(productId); >> > + >> > + return _details; >> > + } >> > ++---+ >> > + >> > + ProductDetails.java: >> > + >> > ++----+ >> > + @Inject >> > + private ProductDAO _dao; >> > + >> > + private Product _product; >> > + >> > + @Persist >> > + private long _productId; >> > + >> > + public void setProductId(long productId) { _productId = >> productId; } >> > + >> > + void onActivate() >> > + { >> > + _product = _dao.getById(_productId); >> > + } >> > ++----+ >> > + >> > + This is a minimal approach, perhaps good enough for a prototype. >> > + >> > + When the user clicks a link, the action request URL will >> initially be something like >> "http://.../productlisting/select.action/99" and the final >> > + render request URL will be something like >> "http://.../productdetails". Notice that the product id ("99") does >> not appear in the render request URL. >> > + >> > + It has some minor flaws: >> > + >> > + * It requires a session (to store the _productId field between >> requests). >> > + >> > + * It may fail if the ProductDetails page is accessed before a >> valid product id is set. >> > + >> > + * The URL does not indicate the identity of the product; if the >> user bookmarks the URL and comes back later, they will trigger the >> previous case (no valid product id). >> > + >> > +* Action Requests / Persistent Data >> > + >> > + We can improve the previous example without changing the >> ProductListing page, using a passivation and activation context >> > + to avoid the session and make the links more bookmarkable. >> > + >> > + ProductDetails.java: >> > + >> > ++----+ >> > + @Inject >> > + private ProductDAO _dao; >> > + >> > + private Product _product; >> > + >> > + private long _productId; >> > + >> > + public void setProductId(long productId) { _productId = >> productId; } >> > + >> > + void onActivate(long productId) >> > + { >> > + _productId = productId; >> > + >> > + _product = _dao.getById(_productId); >> > + } >> > + >> > + long onPassivate() { return _productId; } >> > ++----+ >> > + >> > + This change ensures that the render request URL will include the >> product id, i.e., "http://.../productdetails/99". >> > + >> > + It has the advantage that the connection from page to page >> occurs in typesafe Java code, inside the onActionFromSelect method of >> ProductListing. >> > + It has the disadvantage that clicking a link requires two round >> trips to the server. >> > + >> > +* Render Requests Only >> > + >> > + This is the most common version of this master/detail relationship. >> > + >> > + ProductListing.html: >> > + >> > ++---+ >> > + <t:comp id="loop" source="products" value="product"> >> > + <a t:type="pagelink" page="productdetails" >> context="product.id">${product.name}</a> >> > + </t:comp> >> > ++---+ >> > + >> > + ProductListing.java: >> > + >> > + No code is needed to support the link. >> > + >> > + ProductDetails.java: >> > + >> > ++----+ >> > + @Inject >> > + private ProductDAO _dao; >> > + >> > + private Product _product; >> > + >> > + private long _productId; >> > + >> > + void onActivate(long productId) >> > + { >> > + _productId = productId; >> > + >> > + _product = _dao.getById(_productId); >> > + } >> > + >> > + long onPassivate() { return _productId; } >> > ++----+ >> > + >> > + The setProductId() method is no longer needed. >> > + >> > +* Limitations >> > + >> > + As your application's workflow expands, you may find that there >> is not a reasonable way to avoid storing some data persistently >> between requests, outside >> > + of the page activation context. For example, if from the >> ProductDetails page, the user is allowed to navigate to related pages >> and then back to ProductDetails, it >> > + starts to become necessary to keep passing that product id >> around from page to page to page. >> > + >> > + At some point, persistent values make more sense. In the near >> future, there will be a client-side persistence strategy that will >> encode persistent data, such as >> > + the product id field, into query parameters (and hidden form >> fields) automatically. >> > \ No newline at end of file >> > >> > Modified: >> tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt >> > URL: >> http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt?view=diff&rev=510729&r1=510728&r2=510729 >> >> > >> ============================================================================== >> >> > --- tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt >> (original) >> > +++ tapestry/tapestry5/tapestry-core/trunk/src/site/apt/index.apt >> Thu Feb 22 16:19:45 2007 >> > @@ -80,6 +80,8 @@ >> > >> > * Component parameters may have default values. >> > >> > + * The @ComponentClass anntotation, seen in the earlier >> {{{../screencast.html}screencasts}} has been removed. >> > + >> > Adaptive API >> > >> > A key feature of Tapestry 5 is <adaptive API>. >> > >> > Modified: tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml >> > URL: >> http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml?view=diff&rev=510729&r1=510728&r2=510729 >> >> > >> ============================================================================== >> >> > --- tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml >> (original) >> > +++ tapestry/tapestry5/tapestry-core/trunk/src/site/site.xml Thu >> Feb 22 16:19:45 2007 >> > @@ -61,6 +61,7 @@ >> > <item name="Component Classes" >> href="guide/component-classes.html"/> >> > <item name="Component Templates" >> href="guide/templates.html"/> >> > <item name="Component Parameters" >> href="guide/parameters.html"/> >> > + <item name="Page Navigation" href="guide/pagenav.html"/> >> > <item name="Input Validation" >> href="guide/validation.html"/> >> > <item name="Component Events" href="guide/event.html"/> >> > <item name="Page Lifecycle" href="guide/lifecycle.html"/> >> > >> > >> > >> >> >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: [EMAIL PROTECTED] >> For additional commands, e-mail: [EMAIL PROTECTED] >> >> > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
-- Howard M. Lewis Ship TWD Consulting, Inc. Independent J2EE / Open-Source Java Consultant Creator and PMC Chair, Apache Tapestry Creator, Apache HiveMind Professional Tapestry training, mentoring, support and project work. http://howardlewisship.com --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
