tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Page Life Cycle
Date Sat, 02 Feb 2013 13:28:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/2042/9/12/_/styles/combined.css?spaceKey=TAPESTRY&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Page+Life+Cycle">Page
Life Cycle</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~bobharner">Bob
Harner</a>
    </h4>
        <div id="versionComment">
        <b>Comment:</b>
        Revised to reflect the migration from page pools to page singletons<br />
    </div>
        <br/>
                         <h4>Changes (23)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >In Tapestry, you are free to develop
your presentation objects, page and components classes, as ordinary objects, complete with
instance variables and so forth. <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >This is somewhat revolutionary
in terms of web development in Java. Using <span class="diff-added-words"style="background-color:
#dfd;">traditional</span> servlets, or Struts, your presentation objects (Servlets,
or Struts Actions, or the equivalent in other frameworks) are _stateless singletons_. That
is, a _single_ instance is created, and all incoming requests are threaded through that single
instance. <br></td></tr>
            <tr><td class="diff-unchanged" > <br>Because multiple requests
are handled by many different threads, this means that the single instance&#39;s variable
are useless ... any value written into an instance variable would immediately be overwritten
by a different thread. Thus, it is necessary to use the Servlet API&#39;s HttpServletRequest
object to store per-request data, and the HttpSession object to store data between requests.
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >Tapestry takes a very different approach.
<br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">In
Tapestry, you will have many different instances of any particular page, each either in use
for a single request (on a single thread), or waiting in a _page pool_ to be used. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">In
Tapestry, each page is a singleton, but with a _per thread_ map of field names &amp; values
that Tapestry invisibly manages for you. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">By
reserving page instances to particular threads,</span> <span class="diff-added-words"style="background-color:
#dfd;">With this approach,</span> all the difficult, ugly issues related to multi-threading
go by the wayside. Instead, familiar, simple coding practices (using ordinary methods and
fields) can be used. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">However,
there&#39;s a risk: it would be a disaster if data could &quot;bleed&quot; from
one request to another. Imagine the outcome in a banking application if the first user&#39;s
account number and password became the default for the second user to reach the application!
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">{info}
<br>Tapestry 5.0 and 5.1 used page pooling, rather than a singleton page with a per_thread
map, to achieve the same effect. <br>{info} <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Tapestry
takes special care to purge all instance variables back to their default value at the end
of each request. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">h2.
Page Life Cycle Methods <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">The
end result is that all pages in the pool are entirely equivalent to each other; it doesn&#39;t
matter which instance is used for processing any particular request. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">There
are a few situations where it is useful for a component to perform some operations, usually
some kind of initialization or caching, based on the life cycle of the page. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">Remember
that the page instance is just the tip of the iceberg: a page instance encompasses the page
component, its templates, all of its parameter bindings, tokens read from its template and
(recursively) the same thing for all components inside the page. It adds up. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">The
page life cycle is quite simple. When first needed, a page is loaded. Loading a page involves
instantiating the components of the page and connecting them together. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">A
page instance will be &quot;checked out&quot; of the pool for a short period of time:
a few milliseconds to service a typical request. Because of this, it is generally the case
that Tapestry can handle a large number of end users with a relatively small pool of page
instances. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">Once
a page is loaded, it is _attached_ to the current request. Remember that there will be many
threads, each handling its own request to the same page. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">h2.
Comparison to JavaServer Pages <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">At
the end of a request, after a response has been sent to the client, the page is _detached_
from the request. This is a chance to perform any cleanup needed for the page. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">JSPs
also use a caching mechanism; the JSP itself is compiled into a Java servlet class, and acts
as a singleton. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">As
with [component rendering|Component Rendering], you have the ability to make your components
&quot;aware&quot; of these events by identifying methods to be invoked. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">However,
the individual JSP tags are pooled. <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">Page
life cycle methods should take no parameters and return void. <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">You
have the choice of attaching an annotation to a method, or simply using the method naming
conventions: <br> <br>|| Annotation || Method Name || When Called || <br>|
@[PageLoaded|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageLoaded.html]|pageLoaded()|
After the page is fully loaded | <br>| @[PageAttached|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageAttached.html]
| pageAttached() | After the page is attached to the request. *Deprecated in Tapestry 5.3*
| <br>| @[PageDetached|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageDetached.html]
| pageDetached() | AFter the page is detached from the request. *Deprecated in Tapestry 5.3*
| <br> <br>h2. Comparison to JavaServer Pages <br> <br>JSPs also act
as singletons. However, the individual JSP tags are pooled. <br> <br></td></tr>
            <tr><td class="diff-unchanged" >This is one of the areas where Tapestry
can significantly outperform JSPs. Much of the code inside a compiled JSP class concerns getting
tags from a tag pool, configuring the properties of the tag instance, using the tag instance,
then cleaning up the tag instance and putting it back in the pool. <br> <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >{note}As of 5.2, Tapestry does _not_
employ page pooling by default{note} <br> <br></td></tr>
            <tr><td class="diff-changed-lines" ><span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">Tapestry&#39;s</span>
<span class="diff-added-words"style="background-color: #dfd;">In Tapestry 5.0 and 5.1,
a</span> page pool is used to store page instances. The pool is &quot;keyed&quot;
on the name of the page (such as &quot;start&quot;) and the _locale_ for the page
(such as &quot;en&quot; or &quot;fr&quot;). <br></td></tr>
            <tr><td class="diff-unchanged" > <br>Within each key, Tapestry
tracks the number of page instances that have been created, as well as the number that are
in use (currently attached to a request). <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" > <br>If performance is absolute
and you have lots of memory, then increase the soft and hard limit and reduce the soft wait.
This encourages Tapestry to create more page instances and not wait as long to re-use existing
instances. <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">
<br>h2. Page Life Cycle Methods <br> <br>There are a few situations where
it is useful for a component to perform some operations, usually some kind of initialization
or caching, based on the life cycle of the page. <br> <br>The page life cycle
is quite simple. When first needed, a page is loaded. Loading a page involves instantiating
the components of the page and connecting them together. <br> <br>Once a page
is loaded, it is _attached_ to the current request. Remember that there will be many threads,
each handling its own request. In many cases, there will be multiple copies of the same page
attached to different requests (and different threads). This is how Tapestry keeps you from
worrying about multi-threading issues ... the objects involved in any request are reserved
to _just_ that request (and _just_ that thread). <br> <br>At the end of a request,
after a response has been sent to the client, the page is _detached_ from the request. This
is a chance to perform a lot of cleanup of the page, discarding temporary objects (so that
they can be reclaimed by the garbage collector) and otherwise returning the page to its pristine
state. After detaching, a page is placed into the page pool, where it will await reuse for
some future request (likely by a completely different user). <br> <br>As with
[component rendering|Component Rendering], you have the ability to make your components &quot;aware&quot;
of these events by identifying methods to be invoked. <br> <br>You have the choice
of attaching an annotation to a method, or simply naming the method correctly. <br>
<br>Page life cycle methods should take no parameters and return void. <br> <br>The
annotations / method names are: <br> <br>* @[PageLoaded|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageLoaded.html]
annotation, or method name &quot;pageLoaded&quot; <br>* @[PageAttached|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageAttached.html]
annotation, or method name &quot;pageAttached&quot; <br>* @[PageDetached|http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageDetached.html]
annotation, or method name &quot;pageDetached&quot; <br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="PageLifeCycle-PageLifeCycle"></a>Page Life Cycle</h1>

<div class='navmenu' style='float:right; background:#eee; margin:3px; padding:3px'><table
class="tableview" width="100%">
            <tr><th style="padding: 3px 3px 3px 0px">Related Articles</th></tr>
                        <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Component+Events+FAQ">Component
Events FAQ</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Page+Life+Cycle">Page
Life Cycle</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Request+Processing">Request
Processing</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Component+Events">Component
Events</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Component+Rendering">Component
Rendering</a>
        
                                            </td>
        </tr>
                <tr>
            <td>
                                 <span class="icon icon-page" title=Page>Page:</span>
                         <a href="/confluence/display/TAPESTRY/Page+Navigation">Page
Navigation</a>
        
                                            </td>
        </tr>
            </table>
</div>

<p>In Tapestry, you are free to develop your presentation objects, page and components
classes, as ordinary objects, complete with instance variables and so forth.</p>

<p>This is somewhat revolutionary in terms of web development in Java. Using traditional
servlets, or Struts, your presentation objects (Servlets, or Struts Actions, or the equivalent
in other frameworks) are <em>stateless singletons</em>. That is, a <em>single</em>
instance is created, and all incoming requests are threaded through that single instance.</p>

<p>Because multiple requests are handled by many different threads, this means that
the single instance's variable are useless ... any value written into an instance variable
would immediately be overwritten by a different thread. Thus, it is necessary to use the Servlet
API's HttpServletRequest object to store per-request data, and the HttpSession object to store
data between requests.</p>

<p>Tapestry takes a very different approach.</p>

<p>In Tapestry, each page is a singleton, but with a <em>per thread</em>
map of field names &amp; values that Tapestry invisibly manages for you.</p>

<p>With this approach, all the difficult, ugly issues related to multi-threading go
by the wayside. Instead, familiar, simple coding practices (using ordinary methods and fields)
can be used.</p>

<div class='panelMacro'><table class='infoMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/information.gif" width="16"
height="16" align="absmiddle" alt="" border="0"></td><td>Tapestry 5.0 and 5.1
used page pooling, rather than a singleton page with a per_thread map, to achieve the same
effect.</td></tr></table></div>

<h2><a name="PageLifeCycle-PageLifeCycleMethods"></a>Page Life Cycle Methods</h2>

<p>There are a few situations where it is useful for a component to perform some operations,
usually some kind of initialization or caching, based on the life cycle of the page.</p>

<p>The page life cycle is quite simple. When first needed, a page is loaded. Loading
a page involves instantiating the components of the page and connecting them together.</p>

<p>Once a page is loaded, it is <em>attached</em> to the current request.
Remember that there will be many threads, each handling its own request to the same page.</p>

<p>At the end of a request, after a response has been sent to the client, the page is
<em>detached</em> from the request. This is a chance to perform any cleanup needed
for the page.</p>

<p>As with <a href="/confluence/display/TAPESTRY/Component+Rendering" title="Component
Rendering">component rendering</a>, you have the ability to make your components
"aware" of these events by identifying methods to be invoked.</p>

<p>Page life cycle methods should take no parameters and return void.</p>

<p>You have the choice of attaching an annotation to a method, or simply using the method
naming conventions:</p>

<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> Annotation </th>
<th class='confluenceTh'> Method Name </th>
<th class='confluenceTh'> When Called </th>
</tr>
<tr>
<td class='confluenceTd'> @<a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageLoaded.html"
class="external-link" rel="nofollow">PageLoaded</a></td>
<td class='confluenceTd'>pageLoaded()</td>
<td class='confluenceTd'> After the page is fully loaded </td>
</tr>
<tr>
<td class='confluenceTd'> @<a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageAttached.html"
class="external-link" rel="nofollow">PageAttached</a> </td>
<td class='confluenceTd'> pageAttached() </td>
<td class='confluenceTd'> After the page is attached to the request. <b>Deprecated
in Tapestry 5.3</b> </td>
</tr>
<tr>
<td class='confluenceTd'> @<a href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/PageDetached.html"
class="external-link" rel="nofollow">PageDetached</a> </td>
<td class='confluenceTd'> pageDetached() </td>
<td class='confluenceTd'> AFter the page is detached from the request. <b>Deprecated
in Tapestry 5.3</b> </td>
</tr>
</tbody></table>
</div>


<h2><a name="PageLifeCycle-ComparisontoJavaServerPages"></a>Comparison to
JavaServer Pages</h2>

<p>JSPs also act as singletons. However, the individual JSP tags are pooled.</p>

<p>This is one of the areas where Tapestry can significantly outperform JSPs. Much of
the code inside a compiled JSP class concerns getting tags from a tag pool, configuring the
properties of the tag instance, using the tag instance, then cleaning up the tag instance
and putting it back in the pool.</p>

<p>The operations Tapestry does once per request are instead executed dozens or potentially
hundreds of times (depending the complexity of the page, and if any nested loops occur).</p>

<p>Pooling JSP tags is simply the wrong granularity.</p>

<p>Tapestry can also take advantage of its more coarse grained caching to optimize how
data moves, via parameters, between components. This means that Tapestry pages will actually
speed up after they render the first time.</p>

<h2><a name="PageLifeCycle-PagePoolConfiguration"></a>Page Pool Configuration</h2>

<div class='panelMacro'><table class='noteMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/warning.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td>As of 5.2, Tapestry does <em>not</em>
employ page pooling by default</td></tr></table></div>

<p>In Tapestry 5.0 and 5.1, a page pool is used to store page instances. The pool is
"keyed" on the name of the page (such as "start") and the <em>locale</em> for
the page (such as "en" or "fr").</p>

<p>Within each key, Tapestry tracks the number of page instances that have been created,
as well as the number that are in use (currently attached to a request).</p>

<p>When a page is first accessed in a request, it is taken from the pool. Tapestry has
some <a href="/confluence/display/TAPESTRY/Configuration" title="Configuration">configuration
values</a> that control the details of how and when page instances are created.</p>

<ul>
	<li>If a free page instance is available, the page is marked in use and attached to
the request.</li>
	<li>If there are fewer page instances than the <em>soft limit</em>, then
a new page instance is simply created and attached to the request.</li>
	<li>If the soft limit has been reached, Tapestry will wait for a short period of time
for a page instance to become available before creating a new page instance.</li>
	<li>If the hard limit has been reached, Tapestry will throw an exception rather than
create a new page instance.</li>
	<li>Otherwise, Tapestry will create a new page instance.<br/>
Thus a busy application will initially create pages up-to the soft limit (which defaults to
five page instances). If the application continues to be pounded with requests, it will slow
its request processing, using the soft wait time in an attempt to reuse an existing page instance.</li>
</ul>


<p>A truly busy application will continue to create new page instances as needed until
the hard limit is reached.</p>

<p>Remember that all these configuration values are per key: the combination of page
name and locale. Thus even with a hard limit of 20, you may eventually find that Tapestry
has created 20 start page instances for locale "en" <em>and</em> 20 start page
instances for locale "fr" (if your application is configured to support both English and French).
Likewise, you may have 20 instances for the start page, and 20 instances for the newaccount
page.</p>

<p>Tapestry periodically checks its cache for page instances that have not been used
recently (within a configurable window). Unused page instances are release to the garbage
collector.</p>

<p>The end result is that you have quite a degree of tuning control over the process.
If memory is a limitation and throughput can be sacrificed, try lowering the soft and hard
limit and increasing the soft wait.</p>

<p>If performance is absolute and you have lots of memory, then increase the soft and
hard limit and reduce the soft wait. This encourages Tapestry to create more page instances
and not wait as long to re-use existing instances.</p>

    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Page+Life+Cycle">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=22872118&revisedVersion=5&originalVersion=4">View
Changes</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message