You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2007/02/23 01:19:45 UTC

svn commit: r510729 - in /tapestry/tapestry5/tapestry-core/trunk/src/site: apt/guide/pagenav.apt apt/index.apt site.xml

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"/>



Re: svn commit: r510729 - in /tapestry/tapestry5/tapestry-core/trunk/src/site: apt/guide/pagenav.apt apt/index.apt site.xml

Posted by Howard Lewis Ship <hl...@gmail.com>.
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 <mi...@pekim.co.uk> 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 <mi...@pekim.co.uk> wrote:
> >> Very nice explanation.
> >>
> >> One small question. In the last scenario (Render Requests Only), why is
> >> the passivation method required?
> >>
> >>
> >> hlship@apache.org 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: dev-unsubscribe@tapestry.apache.org
> >> For additional commands, e-mail: dev-help@tapestry.apache.org
> >>
> >>
> >
> >
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: dev-help@tapestry.apache.org
>
>


-- 
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: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org


Re: svn commit: r510729 - in /tapestry/tapestry5/tapestry-core/trunk/src/site: apt/guide/pagenav.apt apt/index.apt site.xml

Posted by Mike D Pilsbury <mi...@pekim.co.uk>.
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 <mi...@pekim.co.uk> wrote:
>> Very nice explanation.
>>
>> One small question. In the last scenario (Render Requests Only), why is
>> the passivation method required?
>>
>>
>> hlship@apache.org 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: dev-unsubscribe@tapestry.apache.org
>> For additional commands, e-mail: dev-help@tapestry.apache.org
>>
>>
>
>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org


Re: svn commit: r510729 - in /tapestry/tapestry5/tapestry-core/trunk/src/site: apt/guide/pagenav.apt apt/index.apt site.xml

Posted by Howard Lewis Ship <hl...@gmail.com>.
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 <mi...@pekim.co.uk> wrote:
> Very nice explanation.
>
> One small question. In the last scenario (Render Requests Only), why is
> the passivation method required?
>
>
> hlship@apache.org 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: dev-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: dev-help@tapestry.apache.org
>
>


-- 
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: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org


Re: svn commit: r510729 - in /tapestry/tapestry5/tapestry-core/trunk/src/site: apt/guide/pagenav.apt apt/index.apt site.xml

Posted by Mike D Pilsbury <mi...@pekim.co.uk>.
Very nice explanation.

One small question. In the last scenario (Render Requests Only), why is 
the passivation method required?


hlship@apache.org 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: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org