Modified: 
websites/production/tapestry/content/page-and-component-classes-faq.html
==============================================================================
--- websites/production/tapestry/content/page-and-component-classes-faq.html 
(original)
+++ websites/production/tapestry/content/page-and-component-classes-faq.html 
Mon May 21 05:20:56 2018
@@ -78,20 +78,20 @@
 
       <div id="content">
                 <div id="ConfluenceContent"><h1 
id="PageAndComponentClassesFAQ-PageAndComponentClasses">Page And Component 
Classes</h1><p>Main article: <a  href="component-classes.html">Component 
Classes</a></p><h2 
id="PageAndComponentClassesFAQ-Contents">Contents</h2><p><style 
type="text/css">/*<![CDATA[*/
-div.rbtoc1523334049720 {padding: 0px;}
-div.rbtoc1523334049720 ul {list-style: disc;margin-left: 0px;}
-div.rbtoc1523334049720 li {margin-left: 0px;padding-left: 0px;}
+div.rbtoc1526880010695 {padding: 0px;}
+div.rbtoc1526880010695 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1526880010695 li {margin-left: 0px;padding-left: 0px;}
 
-/*]]>*/</style></p><div class="toc-macro rbtoc1523334049720">
+/*]]>*/</style></p><div class="toc-macro rbtoc1526880010695">
 <ul class="toc-indentation"><li><a  
href="#PageAndComponentClassesFAQ-What'sthedifferencebetweenapageandacomponent?">What's
 the difference between a page and a component?</a></li><li><a  
href="#PageAndComponentClassesFAQ-HowdoIstoremypageclassesinadifferentpackage?">How
 do I store my page classes in a different package?</a></li><li><a  
href="#PageAndComponentClassesFAQ-Whydomyinstancevariableshavetobeprivate?">Why 
do my instance variables have to be private?</a></li><li><a  
href="#PageAndComponentClassesFAQ-Whydon'tmyinformalparametersshowupintherenderedmarkup?">Why
 don't my informal parameters show up in the rendered markup?</a></li><li><a  
href="#PageAndComponentClassesFAQ-WhydoIgetjava.lang.LinkageErrorwhenIinvokepublicmethodsofmypageclasses?">Why
 do I get java.lang.LinkageError when I invoke public methods of my page 
classes?</a></li><li><a  
href="#PageAndComponentClassesFAQ-Whichisbetter,usingmagicmethodnames(i.e.,beginRender())orannotations(i.e.BeginRender)?">Which
 is better, 
 using magic method names (i.e., beginRender()) or annotations (i.e. 
BeginRender)?</a></li><li><a  
href="#PageAndComponentClassesFAQ-WhydoIhavetoinjectapage?Whycan'tIjustcreateoneusingnew?">Why
 do I have to inject a page? Why can't I just create one using 
new?</a></li></ul>
 </div><h2 
id="PageAndComponentClassesFAQ-What'sthedifferencebetweenapageandacomponent?">What's
 the difference between a page and a component?</h2><p>There's very little 
difference between the two. Pages classes must be in the 
<em>root-package</em>.<code>pages</code> package; components must be in the 
<em>root-package</em>.<code>components</code>. Pages may provide event handlers 
for certain page-specific events (such as activate and passivate). Components 
may have parameters.</p><p>Other than that, they are more equal than they are 
different. They may have templates or may render themselves in code (pages 
usually have a template, components are more likely to render only in 
code).</p><p>The major difference is that Tapestry page templates may be stored 
in the web context directory, as if they were static files (they can't be 
accessed from the client however; a specific rule prevents access to files with 
the <code>.tml</code> extension).</p><div class="confluence-information-macro co
 nfluence-information-macro-warning"><span class="aui-icon aui-icon-small 
aui-iconfont-error confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body"><p>It is possible that this feature 
may be removed in a later release. It is preferred that page templates be 
stored on the classpath, like component templates.</p></div></div><h2 
id="PageAndComponentClassesFAQ-HowdoIstoremypageclassesinadifferentpackage?">How
 do I store my page classes in a different package?</h2><p>Tapestry is very 
rigid here; you can't. Page classes must go in 
<em>root-package</em>.<code>pages</code>, component classes in 
<em>root-package</em>.<code>components</code>, etc.</p><p>You are allowed to 
create sub-packages, to help organize your code better and more logically. For 
example, you might have 
<em>root-package</em>.<code>pages.account.ViewAccount</code>, which would have 
the page name "account/viewaccount". (<span>Tapestry would also create an alias 
"account/view", by stripping of
 f the redundant "account" suffix. Either name is equally valid in your code, 
and Tapestry will use the shorter name, "account/view" in 
URLs.)</span></p><p>In addition, it is possible to define additional root 
packages for the application:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: true; theme: Default" 
style="font-size:12px;">public static void 
contributeComponentClassResolver(Configuration&lt;LibraryMapping&gt; 
configuration) {
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: true; theme: Default" data-theme="Default">public static void 
contributeComponentClassResolver(Configuration&lt;LibraryMapping&gt; 
configuration) {
        configuration.add(new LibraryMapping("", "com.example.app.tasks"));
        configuration.add(new LibraryMapping("", "com.example.app.chat"));
 }
 </pre>
 </div></div><p>LibraryMappings are used to resolve a library prefix to one or 
more package names. The empty string represents the application itself; the 
above example adds two additional root packages; you might see additional pages 
under <code>com.example.app.tasks.pages</code>, for example.</p><div 
class="confluence-information-macro confluence-information-macro-warning"><span 
class="aui-icon aui-icon-small aui-iconfont-error 
confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body"><p>Tapestry doesn't check for name 
collisions, and the order the packages are searched for pages and components is 
not defined. In general, if you can get by with a single root package for your 
application, that is better.</p></div></div><h2 
id="PageAndComponentClassesFAQ-Whydomyinstancevariableshavetobeprivate?">Why do 
my instance variables have to be private?</h2><p><em>In Tapestry 5.3.1 and 
earlier all instance variables must be private. Starting in version 5.3.2 inst
 ance variables can also be protected or package private (that is, not public), 
or they can even be public if <code>final</code> or annotated with the 
deprecated @Retain.</em></p><p>Tapestry does a large amount of transformation 
to your simple POJO classes as it loads them into memory. In many cases, it 
must locate every read or write of an instance variable and change its 
behavior; for example, reading a field that is a component parameter will cause 
a property of the containing page or component to be read.</p><p>Restricting 
the scope of fields allows Tapestry to do the necessary processing one class at 
a time, as needed, at runtime. More complex Aspect Orient Programming systems 
such as AspectJ can perform similar transformations (and much more complex 
ones), but they require a dedicated build step (or the introduction of a JVM 
agent).</p><h2 
id="PageAndComponentClassesFAQ-Whydon'tmyinformalparametersshowupintherenderedmarkup?">Why
 don't my informal parameters show up in the rende
 red markup?</h2><p>Getting informal parameters to work is in two steps. First, 
you must make a call to the 
<code>ComponentResources.renderInformalParameters()</code> method, but just as 
importantly, you must tell Tapestry that you want the component to support 
informal parameters, using the <code>SupportsInformalParameters</code> 
annotation. Here's a hypothetical component that displays an image based on the 
value of a <code>Image</code> object (presumably, a database entity):</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: true; theme: Default" 
style="font-size:12px;">@SupportsInformalParameters
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: true; theme: Default" data-theme="Default">@SupportsInformalParameters
 public class DBImage
 {
   @Parameter(required=true)
@@ -117,18 +117,18 @@ public class DBImage
 
 
 
-<span class="gliffy-container" id="gliffy-container-23527573-3551" 
data-fullwidth="750" data-ceoid="23335008" 
data-edit="${diagramEditLink.getLinkUrl()}" 
data-full="${diagramZoomLink.getLinkUrl()}" data-filename="Class Loaders">
+<span class="gliffy-container" id="gliffy-container-23527573-8437" 
data-fullwidth="750" data-ceoid="23335008" 
data-edit="${diagramEditLink.getLinkUrl()}" 
data-full="${diagramZoomLink.getLinkUrl()}" data-filename="Class Loaders">
 
-    <map id="gliffy-map-23527573-1598" name="gliffy-map-23527573-1598"></map>
+    <map id="gliffy-map-23527573-1496" name="gliffy-map-23527573-1496"></map>
 
-    <img class="gliffy-image" id="gliffy-image-23527573-3551" width="750" 
height="425" data-full-width="750" data-full-height="425" 
src="https://cwiki.apache.org/confluence/download/attachments/23335008/Class%20Loaders.png?version=4&amp;modificationDate=1283534469000&amp;api=v2";
 alt="Class Loaders" usemap="#gliffy-map-23527573-1598">
+    <img class="gliffy-image" id="gliffy-image-23527573-8437" width="750" 
height="425" data-full-width="750" data-full-height="425" 
src="https://cwiki.apache.org/confluence/download/attachments/23335008/Class%20Loaders.png?version=4&amp;modificationDate=1283534469000&amp;api=v2";
 alt="Class Loaders" usemap="#gliffy-map-23527573-1496">
 
-    <map class="gliffy-dynamic" id="gliffy-dynamic-map-23527573-3551" 
name="gliffy-dynamic-map-23527573-3551"></map>
+    <map class="gliffy-dynamic" id="gliffy-dynamic-map-23527573-8437" 
name="gliffy-dynamic-map-23527573-8437"></map>
 </span>
 
 
 </p><p>In a Tapestry application, most application classes are loaded from the 
middle class loader. Additional class loaders are used<br clear="none"> to 
support live service reloading, and live component reloading (along with 
component class transformation).</p><p>When a page or component is passed as a 
parameter to a service, a failure occurs (how it is reported varies in 
different JDK releases) because of the class mismatch.</p><p>The solution is to 
define an interface with the methods that the service will invoke on the page 
or component instance. The service will expect an object implementing the 
interface (and doesn't care what class loader loaded the implementing 
class).</p><p>Just be sure to put the interface class in a non-controlled 
package, such as your application's <em>root-package</em> (and 
<strong>not</strong> <em>root-package</em>.<code>pages</code>).</p><h2 
id="PageAndComponentClassesFAQ-Whichisbetter,usingmagicmethodnames(i.e.,beginRender())orannotations(i.e.BeginR
 ender)?">Which is better, using magic method names (i.e., 
<code>beginRender()</code>) or annotations (i.e. 
<code>BeginRender</code>)?</h2><p>There is no single best way; this is where 
your taste may vary. Historically, the annotations came first, and the method 
naming conventions came later.</p><p>The advantage of using the method naming 
conventions is that the method names are more concise, which fewer characters 
to type, and fewer classes to import.</p><p>The main disadvantage of the method 
naming conventions is that the method names are not meaningful. 
<code>onSuccessFromLoginForm()</code> is a less meaningful name than 
<code>storeUserCredentialsAndReturnToProductsPage()</code>, for 
example.</p><p>The second disadvantage is you are more susceptible to 
off-by-a-character errors. For example, <code>onSucessFromLoginForm()</code> 
will <em>never</em> be called because the event name is misspelled; this would 
not happen using the annotation approach:</p><div class="code panel pdl" sty
 le="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: true; theme: Default" 
style="font-size:12px;">  @OnEvent(value=EventConstants.SUCCESS, 
component="loginForm")
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: true; theme: Default" data-theme="Default">  
@OnEvent(value=EventConstants.SUCCESS, component="loginForm")
   Object storeUserCredentialsAndReturnToProductsPage()
   {
     . . .

Modified: websites/production/tapestry/content/page-navigation.html
==============================================================================
--- websites/production/tapestry/content/page-navigation.html (original)
+++ websites/production/tapestry/content/page-navigation.html Mon May 21 
05:20:56 2018
@@ -86,11 +86,13 @@
 
 
 
+
+
 <h3>Related Articles</h3>
 
 <ul class="content-by-label"><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
                         <a  href="content-type-and-markup.html">Content Type 
and Markup</a>
@@ -99,55 +101,55 @@
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="page-navigation.html">Page Navigation</a>
+                        <a  href="page-life-cycle.html">Page Life Cycle</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="page-life-cycle.html">Page Life Cycle</a>
+                        <a  href="component-rendering.html">Component 
Rendering</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="component-rendering.html">Component 
Rendering</a>
+                        <a  href="component-events.html">Component Events</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="component-events.html">Component Events</a>
+                        <a  href="page-navigation.html">Page Navigation</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="component-events-faq.html">Component Events 
FAQ</a>
+                        <a  href="request-processing.html">Request 
Processing</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="request-processing.html">Request 
Processing</a>
+                        <a  href="component-events-faq.html">Component Events 
FAQ</a>
                 
                         
                     </div>
@@ -156,41 +158,41 @@
 
 
 <p>In essence, a Tapestry application is a number of related pages, working 
together. To some degree, each page is like an application unto 
itself.</p><p>Any individual request will be targeted at a single page. 
Requests come in two forms:&#160;</p><ul><li><em>component event</em> requests 
target a specific component on a specific page, triggering an event within that 
component</li><li><em>render</em> requests target a specific page, and stream 
the HTML markup for that page back to the client</li></ul><p>This dichotomy 
between component event requests and render 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.</p><h3 
id="PageNavigation-Contents">Contents</h3><h2 
id="PageNavigation-Contents|RelatedArticlesLogicalPageNameShortening"><style 
type="text/css">/*<![CDATA[*/
-div.rbtoc1523334030456 {padding: 0px;}
-div.rbtoc1523334030456 ul {list-style: disc;margin-left: 0px;}
-div.rbtoc1523334030456 li {margin-left: 0px;padding-left: 0px;}
+div.rbtoc1526880004612 {padding: 0px;}
+div.rbtoc1526880004612 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1526880004612 li {margin-left: 0px;padding-left: 0px;}
 
-/*]]>*/</style></h2><div class="toc-macro rbtoc1523334030456">
+/*]]>*/</style></h2><div class="toc-macro rbtoc1526880004612">
 <ul class="toc-indentation"><li><a  
href="#PageNavigation-Contents|RelatedArticlesLogicalPageNameShortening">Logical
 Page Name Shortening</a></li><li><a  
href="#PageNavigation-ComponentEventRequests&amp;Responses">Component Event 
Requests &amp; Responses</a>
 <ul class="toc-indentation"><li><a  href="#PageNavigation-1.Nullresponse">1. 
Null response</a></li><li><a  href="#PageNavigation-2.Stringresponse">2. String 
response</a></li><li><a  href="#PageNavigation-3.Classresponse">3. Class 
response</a></li><li><a  href="#PageNavigation-4.Pageresponse">4. Page 
response</a></li><li><a  href="#PageNavigation-5.HttpError">5. 
HttpError</a></li><li><a  href="#PageNavigation-6.Linkresponse">6. Link 
response</a></li><li><a  href="#PageNavigation-7.Streamresponse">7. Stream 
response</a></li><li><a  href="#PageNavigation-8.URLresponse">8. URL 
response</a></li><li><a  href="#PageNavigation-9.Objectresponse">9. Object 
response</a></li></ul>
 </li><li><a  href="#PageNavigation-PageRenderRequests">Page Render 
Requests</a></li><li><a  href="#PageNavigation-PageActivation">Page 
Activation</a></li><li><a  href="#PageNavigation-PageNavigationPatterns">Page 
Navigation Patterns</a>
 <ul class="toc-indentation"><li><a  
href="#PageNavigation-Pattern1:Componenteventrequests/PersistentData">Pattern 
1: Component event requests / Persistent Data</a></li><li><a  
href="#PageNavigation-Pattern2:ComponentEventRequests/NoPersistentData">Pattern 
2: Component Event Requests / No Persistent Data</a></li><li><a  
href="#PageNavigation-Pattern3:RenderRequestsOnly">Pattern 3: Render Requests 
Only</a></li><li><a  
href="#PageNavigation-Limitations">Limitations</a></li></ul>
 </li></ul>
 </div><br clear="none"><span style="color: rgb(83,145,38);">Logical Page Name 
Shortening</span><p>In certain cases, Tapestry will shorten the the logical 
name of a page. For example, the page class 
org.example.pages.address.CreateAddress will be given a logical name of 
"address/Create" (the redundant "Address" is removed as a suffix). However, 
this only affects how the page is referenced in URLs; the template file will 
still be CreateAddress.tml, whether on the classpath, or as 
address/CreateAddress.tml (in the web context).</p><p><span>Tapestry actually 
creates multiple names for the name page: "address/Create" and 
"address/CreateAddress" are both synonymous. You can user either in Java code 
that refers to a page by name, or as the page parameter of a 
PageLink.</span></p><h2 
id="PageNavigation-ComponentEventRequests&amp;Responses">Component Event 
Requests &amp; Responses</h2><p>Main Article:&#160; <a  
href="component-events.html">Component Events</a></p><p>Component event 
requests 
 may take the form of hyperlinks (<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/EventLink.html";>EventLink</a>
 or <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/ActionLink.html";>ActionLink</a>)
 or form submissions (<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Form.html";>Form</a>).</p><p>The
 value returned from an <a  href="component-events.html">event handler 
method</a> controls the response sent to the client web browser.</p><p>The URL 
for a component event request identifies the name of the page, the nested id of 
the component, and the name of the event to trigger on the component (specified 
by the "event" parameter of EventLink, or "action" for an ActionLink). Further, 
a component event request may contain additional context information, which 
will be provided to the event handl
 er method.</p><p>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 component event request URLs should not 
be bookmarked. Fortunately, users will rarely have the chance to do so (see 
below).</p><h3 id="PageNavigation-1.Nullresponse">1. Null response</h3><p>If 
the event handler method returns no value, or returns null, then the current 
page (the page containing the component) will render the response.</p><p>A page 
render URL 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.</p><p>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 type
 s). Render requests URLs are what your users will bookmark. The component 
event request URLs are transitory, meaningful only while the application is 
actively engaged, and not meant to be used in later sessions.</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public Object onAction(){
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">public Object onAction(){
   return null;
 }</pre>
 </div></div><h3 id="PageNavigation-2.Stringresponse">2. String 
response</h3><p>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.</p><p>Again, a render 
request URL will be constructed and sent to the client as a redirect.</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public String onAction(){
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">public String onAction(){
   return "Index";
 }</pre>
 </div></div><h3 id="PageNavigation-3.Classresponse">3. Class 
response</h3><p>When a class is returned, it is expected to be a page class. 
Returning a page class from an event handler is safer for refactoring than 
returning a page name.</p><p>As with other response types, a render request URL 
will be constructed and sent to the client as a redirect.</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public Object onAction(){
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">public Object onAction(){
   return Index.class
 }</pre>
 </div></div><h3 id="PageNavigation-4.Pageresponse">4. Page response</h3><p>You 
may also return an instance of a page, rather than the name or class of a 
page.</p><p>A page may be injected via the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/InjectPage.html";>InjectPage</a>
 annotation.</p><p>Often, you will configure the page in some way before 
returning the page (examples below).</p><p>You can also return a component 
within the page, but this will generate a runtime warning (unless you are doing 
a partial-page update via <a  href="ajax-and-zones.html">Ajax</a>).</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">@InjectPage
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">@InjectPage
 private Index index;
 
 public Object onAction(){
   return index;
 }</pre>
 </div></div><h3 id="PageNavigation-5.HttpError">5. HttpError</h3><p>An event 
handler method may return an instance of <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html";>HttpError</a>
 to send an error response to the client.</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public Object onAction(){
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">public Object onAction(){
   return new HttpError(302, "The Error message);
 }</pre>
 </div></div><h3 id="PageNavigation-6.Linkresponse">6. Link response</h3><p>An 
event handler method may return a <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html";>Link</a>
 instance directly. The Link is converted into a URL and a client redirect to 
that URL is sent to the client.</p><p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ComponentResources.html";>ComponentResources</a>
 object that is injected into your pages (and components) has methods for 
creating component links.</p><p>The&#160;<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/PageRenderLinkSource.html";>PageRenderLinkSource</a>
 service can be injected to allow links to other pages to be created (though 
that is rarely necessary, given the other options listed above).</p><h3 
id="PageNavigation-7.Streamresponse">7. Stream response</h3><p>An event handler 
can als
 o return a <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html";>StreamResponse</a>
 object, which encapsulates a stream to be sent directly to the client browser. 
This is useful for components that want to, say, generate an image or PDF and 
provide it to the client:</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public Object onAction(){
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">public Object onAction(){
     return new StreamResponse() {
         @Override
         public String getContentType() {
@@ -207,7 +209,7 @@ public Object onAction(){
     };
 }</pre>
 </div></div><p>&#160;</p><h3 id="PageNavigation-8.URLresponse">8. URL 
response</h3><p>A java.net.URL response is handled as a client redirect to an 
external URL. (In Tapestry 5.3.x and earlier this only works for non-Ajax 
requests.)</p><h3 id="PageNavigation-9.Objectresponse">9. Object 
response</h3><p>Any other type of object returned from an event handler method 
is an error.</p><h2 id="PageNavigation-PageRenderRequests">Page Render 
Requests</h2><p>Render requests are simpler in structure and behavior than 
component event requests. In the simplest case, the URL is simply the logical 
name of the page.</p><p>Pages may have an <em>activation context</em>. 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.</p><p>When a page has an activation context, the 
values of the context are appended to the URL path. For example, 
in&#160;<code><span class="nolink">http
 ://www.example.com/myapp/foo/bar</span></code> the "myapp" part is the servlet 
context (usually the name of your app), and the "foo/bar" part is the 
activation context, with "foo" being the first activation parameter and "bar" 
being the second.</p><p>It is common for most pages to not have any activation 
context.</p><p>The activation context may be explicitly set when the render 
request link is created (the PageLink component has a context parameter for 
this purpose).</p><p>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:</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">public class ProductDetail
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">public class ProductDetail
 {
   private Product product;
   . . .
@@ -218,7 +220,7 @@ public Object onAction(){
 <p>    <strong>JumpStart Demos:</strong><br clear="none">
     <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/navigation/onactivateandonpassivate/3";
 rel="nofollow">onActivate and onPassivate</a><br clear="none">
     <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/infrastructure/handlingabadcontext/1";
 rel="nofollow">Handling A Bad Context</a></p></div>Activation serves two 
purposes:<ul><li>It allows the page to restore its internal state from data 
encoded into the URL (the activation context discussed above).</li><li>It 
provides coarse approach to validating access to the page.</li></ul><p>The 
later case &#8211; validation&#160;&#8211; 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 for verifying that 
access.</p><p>Page activation uses Tapestry's <em>Component Event</em> 
mechanism. See&#160;<a  href="component-events.html">Component Events</a> for 
details.</p><p>A page's activate event handler mirrors its passivate 
handler:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  private Product product;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  private Product product;
   . . .
   void onActivate(long productId)
   {
@@ -227,7 +229,7 @@ public Object onAction(){
   . . .
 </pre>
 </div></div><p>Here's the relevant part: when the page renders, it is likely 
to include more component event request URLs (links and forms). The component 
event requests for those links and forms will <em>also</em> start by activating 
the page, before performing other work. This forms an unbroken chain of 
requests that include the same activation context.</p><p>To some degree, this 
same effect could be accomplished using a <a  
href="persistent-page-data.html">persistent page value</a>, but that requires 
an active servlet session, and the result is not bookmarkable.</p><p>Your 
activate event handler, like any event handler, may also return a value, which 
is treated identically to a return value of a component event method. This 
technique is commonly used as a simple access validation mechanism.</p><p>You 
sometimes need to handle multiple page activation scenarios in one page class. 
You could create multiple activate event handler methods with different 
arguments (see the "Multiple Me
 thod Matches" section at&#160;<a  href="component-events.html">Component 
Events</a> for details), but if you do so, you should generally 
return&#160;<code>true</code> from each to avoid having more than one 
activation event handler method from being called for each page request. 
However, a better approach is to create one method with an EventContext 
argument. Tapestry will populate the EventContext argument with all of the 
activation parameters, and the EventContext's&#160;<code>get</code> method will 
retrieve and coerce each parameter to the desired type. For example:</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  . . .
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  . . .
 
   void onActivate(EventContext eventContext) {
 
@@ -248,12 +250,12 @@ public Object onAction(){
   . . .
 </pre>
 </div></div><h2 id="PageNavigation-PageNavigationPatterns">Page Navigation 
Patterns</h2><p>This combination of action links and context and page context 
can be put together in any number of ways.</p><p>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.</p><h3 
id="PageNavigation-Pattern1:Componenteventrequests/PersistentData">Pattern 1: 
Component event requests / Persistent Data</h3><p>In this pattern, the 
ProductListing page uses action events and a persistent field on the 
ProductDetails page.</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ProductListing.html</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  &lt;t:loop source="products" value="product"&gt;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  &lt;t:loop 
source="products" value="product"&gt;
     &lt;a t:type="actionlink" t:id="select" 
context="product.id"&gt;${product.name}&lt;/a&gt;
   &lt;/t:loop&gt;
 </pre>
 </div></div><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ProductListing.java</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @InjectPage
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  @InjectPage
   private ProductDetails details;
 
   Object onActionFromSelect(long productId)
@@ -264,7 +266,7 @@ public Object onAction(){
   }
 </pre>
 </div></div><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ProductDetails.java</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Inject
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  @Inject
   private ProductDAO dao;
 
   private Product product;
@@ -280,7 +282,7 @@ public Object onAction(){
   }
 </pre>
 </div></div><p>This is a minimal approach, perhaps good enough for a 
prototype.</p><p>When the user clicks a link, the component event request URL 
will initially be something like "http://.../productlisting.select/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.</p><p>This pattern has the following drawbacks:</p><ul><li>It requires a 
session (to store the productId field between requests).</li><li>It may fail if 
the ProductDetails page is accessed before a valid product id is 
set.</li><li>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).</li></ul><p><span class="confluence-anchor-link" 
id="PageNavigation-activationpattern"></span></p><h3 
id="PageNavigation-Pattern2:ComponentEventRequests/NoPersistentData">Pattern 2: 
Component Event Requests / No Persiste
 nt Data</h3><p>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.</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>ProductDetails.java</b></div><div 
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Inject
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  @Inject
   private ProductDAO dao;
 
   private Product product;
@@ -299,15 +301,15 @@ public Object onAction(){
   long onPassivate() { return productId; }
 </pre>
 </div></div><p>This change ensures that the render request URL will include 
the product id, i.e., "http://.../productdetails/99";.</p><p>It has the 
advantage that the connection from page to page occurs in type-safe Java code, 
inside the onActionFromSelect method of ProductListing. It has the disadvantage 
that clicking a link requires two round trips to the server.</p><h3 
id="PageNavigation-Pattern3:RenderRequestsOnly">Pattern 3: Render Requests 
Only</h3><p>This is the most common version of this master/detail 
relationship.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ProductListing.html</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  &lt;t:loop source="products" value="product"&gt;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  &lt;t:loop 
source="products" value="product"&gt;
     &lt;a t:type="pagelink" page="productdetails" 
context="product.id"&gt;${product.name}&lt;/a&gt;
   &lt;/t:loop&gt;
 </pre>
 </div></div><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ProductListing.java</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">No code is needed to support the link.
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">No code is needed to 
support the link.
 </pre>
 </div></div><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ProductDetails.java</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Inject
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  @Inject
   private ProductDAO dao;
 
   private Product product;

Modified: websites/production/tapestry/content/persistent-page-data.html
==============================================================================
--- websites/production/tapestry/content/persistent-page-data.html (original)
+++ websites/production/tapestry/content/persistent-page-data.html Mon May 21 
05:20:56 2018
@@ -86,11 +86,13 @@
 
 
 
+
+
 <h3>Related Articles</h3>
 
 <ul class="content-by-label"><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
                         <a  href="performance-and-clustering.html">Performance 
and Clustering</a>
@@ -99,19 +101,19 @@
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="session-storage.html">Session Storage</a>
+                        <a  href="persistent-page-data.html">Persistent Page 
Data</a>
                 
                         
                     </div>
     </li><li>
         <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
+                <span class="icon aui-icon content-type-page" 
title="Page">Page:</span>        </div>
 
         <div class="details">
-                        <a  href="persistent-page-data.html">Persistent Page 
Data</a>
+                        <a  href="session-storage.html">Session Storage</a>
                 
                         
                     </div>
@@ -120,35 +122,35 @@
 
 
 <p>However, you often want to store some data on a <em>single</em> page, and 
have access to it in later requests to that same page, without having to store 
it in a database between requests. (To store values across multiple pages, see 
<a  href="session-storage.html">Session Storage</a>.)</p><p>Making page data 
persist across requests to a single page is accomplished with the @<a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Persist.html";>Persist</a>
 annotation. This annotation is applied to private instance fields of 
components:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Persist
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  @Persist
   private int value;
 </pre>
 </div></div><p>Such annotated fields will retain 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 saved. On later requests to the same page, the 
value for the field is restored.</p><h2 
id="PersistentPageData-PersistenceStrategies">Persistence Strategies</h2><p>The 
value for each field is the <em>strategy</em> used to store the field between 
requests.</p><h3 id="PersistentPageData-SessionStrategy">Session 
Strategy</h3><p></p><div class="navmenu" style="float:right; background:#eee; 
margin:3px; padding:0 1em">
 <p>    <strong>JumpStart Demo:</strong><br clear="none">
     <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/state/storingdatainapage";
 rel="nofollow">Storing Data in a Page</a><br clear="none">
     <a  class="external-link" 
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/state/passingdatabetweenpages";
 rel="nofollow">Passing Data Between Pages</a></p></div>The session strategy 
stores field changes into the session; the session is created as necessary. 
Session strategy is the default strategy used unless otherwise overridden.<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><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>Example: Session Strategy</b></div><div 
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Persist
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  @Persist
   private int value;
 </pre>
 </div></div><h3 id="PersistentPageData-FlashStrategy">Flash 
Strategy</h3><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><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>Example: Flash Strategy</b></div><div class="codeContent panelContent 
pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Persist(PersistenceConstants.FLASH)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
@Persist(PersistenceConstants.FLASH)
   private int value;
 </pre>
 </div></div><h3 id="PersistentPageData-ClientStrategy">Client 
Strategy</h3><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><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="bord
 er-bottom-width: 1px;"><b>Example: Client Strategy</b></div><div 
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Persist(PersistenceConstants.CLIENT)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
@Persist(PersistenceConstants.CLIENT)
   private int value;
 </pre>
 </div></div><h3 id="PersistentPageData-HibernateEntityStrategy">Hibernate 
Entity Strategy</h3><p><span>Entity persistence is provided by the 
tapestry-hibernate module (which extends Tapestry with new 
features).</span></p><p>In Entity persistence, the field should store a 
Hibernate entity instance.</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>"Hibernate Entity Strategy"</b></div><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Persist(HibernatePersistenceConstants.ENTITY)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
@Persist(HibernatePersistenceConstants.ENTITY)
   private User user;</pre>
 </div></div><p>&#160;</p><p>The value stored in the HttpSession is 
a&#160;<em>token</em> for the entity: its Java class name and primary key. When 
the field is restored in a later request, the entity is re-instantiated using 
that data.</p><p>What is&#160;<em>not</em> stored is any changes to the 
persistent entity that are not committed to the external datastore (the 
database).</p><p>Starting in Tapestry 5.4, it is possible to store a 
non-persistent entity (a transient entity). A transient entity is stored 
directly into the HttpSession, and should be Serializable if the application is 
clustered.</p><h3 id="PersistentPageData-JPAEntityStrategy">JPA Entity 
Strategy</h3><p>The tapestry-jpa module uses a similar strategy. However, at 
the current time it can only store a persisted entity (one that has been saved 
to the database and has a primary key).</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>"Exa
 mple: JPA Entity Strategy"</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Persist(JpaPersistenceConstants.ENTITY)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
@Persist(JpaPersistenceConstants.ENTITY)
   private Account account;</pre>
 </div></div><h3 id="PersistentPageData-PersistenceStrategyInheritance"><span 
style="color: rgb(83,145,38);">Persistence Strategy 
Inheritance</span></h3><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 hierarchy.</p><p>For each component, 
the meta-data property <code>tapestry.persistence-strategy</code> is checked. 
This can be specified using the @<a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Meta.html";>Meta</a>
 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><h2 id="PersistentPageData-DefaultValues">Default 
Values</h2><p>Fields marke
 d with @Persist may not have default values (whether set inline, or inside a 
constructor).</p><h2 id="PersistentPageData-ClearingPersistentFields">Clearing 
Persistent Fields</h2><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 
<code>discardPersistentFieldChanges()</code> 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><p></p><h2 
id="PersistentPageData-ClusteringIssues">Clustering Issues</h2><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>However, many web applications do not use 
the HttpSession this way, instead storing large, mutable objects in the 
session. This is not a problem for s
 ingle 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 that serialization 
and distribution whenever HttpSession.setAttribute() is called. This creates a 
data consistency 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>But while this solution solves the data 
consistency problem, it does so at the expense of performance, since all of 
those calls to setAttribute() result in extra session data being re
 plicated needlessly if the internal state of the mutable object hasn't 
changed.</p><p>Tapestry has solutions to this, too:</p><h3 
id="PersistentPageData-@ImmutableSessionPersistedObjectAnnotation">@ImmutableSessionPersistedObject
 Annotation</h3><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 (and thus not 
requiring session replication) using the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/ImmutableSessionPersistedObject.html";>ImmutableSessionPersistedObject</a>
 annotation.</p><h3 
id="PersistentPageData-OptimizedSessionPersistedObjectInterface">OptimizedSessionPersistedObject
 Interface</h3><p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptimizedSessionPersistedObject";>OptimizedSessionPersistedObject</a>
 interface allo
 ws an object to control this behavior. An object with this interface can track 
when its mutable state changes. Typically, you should extend from the <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/BaseOptimizedSessionPersistedObject.html";>BaseOptimizedSessionPersistedObject</a>
 base class.</p><h3 
id="PersistentPageData-SessionPersistedObjectAnalyzerService">SessionPersistedObjectAnalyzer
 Service</h3><p>The <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SessionPersistedObjectAnalyzer.html";>SessionPersistedObjectAnalyzer</a>
 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 class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom
 -width: 1px;"><b>Example: Entity Session Strategy</b></div><div 
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Persist(HibernatePersistenceConstants.ENTITY)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
@Persist(HibernatePersistenceConstants.ENTITY)
   private User user;</pre>
 </div></div><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>"Example:JAP Session Strategy"</b></div><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Persist(JpaPersistenceConstants.ENTITY)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java; 
gutter: false; theme: Default" data-theme="Default">  
@Persist(JpaPersistenceConstants.ENTITY)
   private Account account;</pre>
 </div></div></div>
       </div>

Modified: websites/production/tapestry/content/release-notes-50.html
==============================================================================
--- websites/production/tapestry/content/release-notes-50.html (original)
+++ websites/production/tapestry/content/release-notes-50.html Mon May 21 
05:20:56 2018
@@ -78,11 +78,11 @@
 
       <div id="content">
                 <div id="ConfluenceContent"><p>This is the consolidated list 
of changes between Tapestry versions 5.0.3 and 5.0.19. Before upgrading, be 
sure to review the&#160;<a  href="how-to-upgrade.html">How to Upgrade</a> 
instructions.</p><p><strong>Contents</strong></p><p><style 
type="text/css">/*<![CDATA[*/
-div.rbtoc1523334078972 {padding: 0px;}
-div.rbtoc1523334078972 ul {list-style: disc;margin-left: 0px;padding-left: 
5px;}
-div.rbtoc1523334078972 li {margin-left: 0px;padding-left: 0px;}
+div.rbtoc1526880023417 {padding: 0px;}
+div.rbtoc1526880023417 ul {list-style: disc;margin-left: 0px;padding-left: 
5px;}
+div.rbtoc1526880023417 li {margin-left: 0px;padding-left: 0px;}
 
-/*]]>*/</style></p><div class="toc-macro rbtoc1523334078972">
+/*]]>*/</style></p><div class="toc-macro rbtoc1526880023417">
 <ul class="toc-indentation"><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.19">Tapestry Version 
5.0.19</a></li><li><a  href="#ReleaseNotes5.0-TapestryVersion5.0.18">Tapestry 
Version 5.0.18</a></li><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.17">Tapestry Version 
5.0.17</a></li><li><a  href="#ReleaseNotes5.0-TapestryVersion5.0.16">Tapestry 
Version 5.0.16</a></li><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.15">Tapestry Version 
5.0.15</a></li><li><a  href="#ReleaseNotes5.0-TapestryVersion5.0.14">Tapestry 
Version 5.0.14</a></li><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.13">Tapestry Version 
5.0.13</a></li><li><a  href="#ReleaseNotes5.0-TapestryVersion5.0.12">Tapestry 
Version 5.0.12</a></li><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.11">Tapestry Version 
5.0.11</a></li><li><a  href="#ReleaseNotes5.0-TapestryVersion5.0.10">Tapestry 
Version 5.0.10</a></li><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.9">Tapestry Version 
5.0.9</a></li><li><a  href="#ReleaseNot
 es5.0-TapestryVersion5.0.8">Tapestry Version 5.0.8</a></li><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.7">Tapestry Version 
5.0.7</a></li><li><a  href="#ReleaseNotes5.0-TapestryVersion5.0.6">Tapestry 
Version 5.0.6</a></li><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.5">Tapestry Version 
5.0.5</a></li><li><a  href="#ReleaseNotes5.0-TapestryVersion5.0.4">Tapestry 
Version 5.0.4</a></li><li><a  
href="#ReleaseNotes5.0-TapestryVersion5.0.3">Tapestry Version 
5.0.3</a></li></ul>

[... 3 lines stripped ...]

Reply via email to