tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Tapestry > Persistent Page Data
Date Wed, 16 Jun 2010 12:19:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1810/9/8/_/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/Persistent+Page+Data">Persistent
Page Data</a></h2>
    <h4>Page  <b>added</b> by             <a href="https://cwiki.apache.org/confluence/display/~uli">Ulrich
Stärk</a>
    </h4>
         <br/>
    <div class="notificationGreySide">
         <h1><a name="PersistentPageData-PersistentPageData"></a>Persistent
Page Data</h1>

<p>Most instance variables in Tapestry are automatically cleared at the end of each
request.</p>

<p>This is important, as it pertains to how Tapestry pages are pooled and shared, over
time, by many users.</p>

<p>However, you often want to store some persistent data on a <em>single</em>
page, and have access to it in later requests. Long term storage of data should go in a database
of some form, but server-side state for the duration of the as user's interaction with the
application should go in the HttpSession (though Tapestry provides a few other options as
well).</p>

<p><b>Note:</b> To store values that may be accessed across multiple pages,
uses a <a href="#PersistentPageData-appstate.html">session state object</a>.</p>

<p>Making a field persistent is accomplished with the <span class="error">&#91;Persist
annotation|../apidocs/org/apache/tapestry5/annotations/Persist.html&#93;</span>.
Again, this does <em>not</em> refer to database persistence, it refers to session
persistance.</p>

<p>This annotation is applied to private instance fields of components.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
  @Persist
  <span class="code-keyword">private</span> <span class="code-object">int</span>
value;
</pre>
</div></div>

<p>Annotated fields will store their state between requests. Generally, speaking, this
means that the value is stored into the session (but other approaches are possible).</p>

<p>Whenever you make a change to a persistent field, its value is stored.</p>

<p>On later requests, the value for such persistent fields is reloaded from storage.</p>

<h1><a name="PersistentPageData-PersistenceStrategies"></a>Persistence Strategies</h1>

<p>The value for each field is the <em>strategy</em> used to store the field
between requests.</p>

<h2><a name="PersistentPageData-sessionstrategy"></a>session strategy</h2>

<p>The session strategy stores field changes into the session; the session is created
as necessary.</p>

<p>A suitably long session attribute name is used; it incorporates the name of the page,
the nested component id, and the name of the field.</p>

<p>Session strategy is the default strategy used unless otherwise overridden.</p>

<h2><a name="PersistentPageData-flashstrategy"></a>flash strategy</h2>

<p>The flash strategy stores information in the session as well, just for not very long.
Values are stored into the session, but then deleted from the session as they are first used
to restore a page's state.</p>

<p>The flash is typically used to store temporary messages that should only be displayed
to the user once.</p>

<h2><a name="PersistentPageData-clientstrategy"></a>client strategy</h2>

<p>The field is persisted onto the client; you will see an additional query parameter
in each URL (or an extra hidden field in each form).</p>

<p>Client persistence is somewhat expensive. It can bloat the size of the rendered pages
by adding hundreds of characters to each link. There is extra processing on each request to
de-serialize the values encoded into the query parameter.</p>

<p>Client persistence does not scale very well; as more information is stored into the
query parameter, its length can become problematic. In many cases, web browsers, firewalls
or other servers may silently truncate the URL which will break the application.</p>

<p>Use client persistence with care, and store a minimal amount of data. Try to store
the identity (that is, primary key) of an object, rather than the object itself.</p>

<h1><a name="PersistentPageData-PersistenceSearch"></a>Persistence Search</h1>

<p>By default the value for the Persist annotation is the empty string. When this is
true, then the actual strategy to be used is determined by a search up the component hiearchy.</p>

<p>For each component, the meta-data property <tt>tapestry.persistence-strategy</tt>
is checked. This can be specified using the <span class="error">&#91;Meta|../apidocs/org/apache/tapestry5/annotations/Meta.html&#93;</span>
annotation.</p>

<p>If the value is non-blank, then that strategy is used. This allows a component to
control the persistence strategy used inside any sub-components (that don't explicitly use
a different strategy).</p>

<p>In any case, if no component provides the meta data, then the ultimate default, "session",
is used.</p>

<h1><a name="PersistentPageData-DefaultValues"></a>Default Values</h1>

<p>Fields marked with @Persist may not have default values (whether set inline, or inside
a constructor).</p>

<h1><a name="PersistentPageData-ClearingPersistentFields"></a>Clearing Persistent
Fields</h1>

<p>If you reach a point where you know that all data for a page can be discarded, you
can do exactly that.</p>

<p>The method <tt>discardPersistentFieldChanges()</tt> of ComponentResources
will discard all persistent fields for the page, regardless of which strategy is used to store
the property. This will not affect the page in memory, but takes effect for subsequent requests.</p>

<h1><a name="PersistentPageData-ClusteringIssues"></a>Clustering Issues</h1>

<p>The Servlet API was designed with the intention that there would be only a modest
amount of server-side state, and that the stored values would be individual numbers and strings,
and thus, immutable.</p>

<p>Many web frameworks do not use the HttpSession this way, and store large and mutable
objects in the session.</p>

<p>This is not an issue for single servers, but in a cluster, anything stored in the
session must be serialized to a bytestream and distributed to other servers within the cluster,
and restored there.</p>

<p>Most application servers perform the serialization and distribution as part of HttpSession.setAttribute().</p>

<p>This creates a problem for mutable objects, because if you read a mutable session
object, change its state, but <em>don't</em> invoke setAttribute(), the changes
will be isolated to just a single server in the cluster.</p>

<p>Tapestry attempts to solve this: any session persisted object that is read during
a request will be re-stored back into the HttpSession at the end of the request. This ensures
that changed internal state of those mutable objects is properly replicated around the cluster.</p>

<p>This can be a problem in a cluster as all those calls to setAttribute() may impact
performance, as often the internal state of the mutable object don't have changed.</p>

<p>Tapestry has solutions to this.</p>

<h2><a name="PersistentPageData-ImmutableObjects"></a>Immutable Objects</h2>

<p>Tapestry knows that Java's String, Number and Boolean classes are immutable. Immutable
objects do not require a re-store into the session.</p>

<p>You can mark your own session objects as immutable using the <span class="error">&#91;ImmutableSessionPersistedObject|../apidocs//org/apache/tapestry5/annotations/ImmutableSessionPersistedObject.html&#93;</span>
annotation.</p>

<h2><a name="PersistentPageData-OptimizedSessionPersistedObject"></a>OptimizedSessionPersistedObject</h2>

<p>The <span class="error">&#91;OptimizedSessionPersistedObject|../apidocs/org/apache/tapestry5/OptimizedSessionPersistedObject&#93;</span>
interface allows an object to control this behavior. An object with this interface can track
when its mutable state changes. Typically, you should extend from the <span class="error">&#91;BaseOptimizedSessionPersistedObject|../apidocs/org/apache/tapestry5/BaseOptimizedSessionPersistedObject.html&#93;</span>
base class.</p>

<h2><a name="PersistentPageData-SessionPersistedObjectAnalyzer"></a>SessionPersistedObjectAnalyzer</h2>

<p>The <span class="error">&#91;SessionPersistedObjectAnalyzer|../apidocs/org/apache/tapestry5/services/SessionPersistedObjectAnalyzer.html&#93;</span>
service is ultimately responsible for determining whether a session persisted object is dirty
or not (dirty meaning in need of a restore into the session). This is an extensible service
where new strategies, for new classes, can be introduced.</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/Persistent+Page+Data">View
Online</a>
           </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message