You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by bu...@apache.org on 2018/02/03 16:21:23 UTC

svn commit: r1024781 [10/11] - in /websites/production/tapestry/content: ./ cache/

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 Sat Feb  3 16:21:22 2018
@@ -27,6 +27,16 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
+          <link href='/resources/highlighter/styles/shCoreCXF.css' rel='stylesheet' type='text/css' />
+    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' type='text/css' />
+    <script src='/resources/highlighter/scripts/shCore.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushJava.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushXml.js' type='text/javascript'></script>
+          <script src='/resources/highlighter/scripts/shBrushPlain.js' type='text/javascript'></script>
+        <script>
+      SyntaxHighlighter.defaults['toolbar'] = false;
+      SyntaxHighlighter.all();
+    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -67,23 +77,80 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><rich-text-body><p>The use of the term "persistence" here refers to <em>page-level</em> persistence, NOT database persistence.</p></rich-text-body><p>Most instance variables in Tapestry are automatically cleared at the end of each request. This is important, as it pertains to how Tapestry pages are shared, over time, by many users.</p><parameter ac:name="style">float:right</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="class">aui-label</parameter><rich-text-body><parameter ac:name="showLabels">false</parameter><parameter ac:name="showSpace">false</parameter><parameter ac:name="title">Related Articles</parameter><parameter ac:name="cql">label = "persistence" and space = currentSpace()</parameter></rich-text-body><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. (T
 o 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><parameter ac:name="">java</parameter><plain-text-body>  @Persist
+                <div id="ConfluenceContent"><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>The use of the term "persistence" here refers to <em>page-level</em> persistence, NOT database persistence.</p></div></div><p>Most instance variables in Tapestry are automatically cleared at the end of each request. This is important, as it pertains to how Tapestry pages are shared, over time, by many users.</p><div class="aui-label" style="float:right" title="Related Articles">
+
+
+
+
+
+
+
+
+<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>
+
+        <div class="details">
+                        <a  href="performance-and-clustering.html">Performance and Clustering</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  href="session-storage.html">Session Storage</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  href="persistent-page-data.html">Persistent Page Data</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<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="persistent-page-data.html">Persistent Page Data</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
   private int value;
-</plain-text-body><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><plain-text-body>{float:right|background=#eee|padding=0 1em}
-    *JumpStart Demo:*
-    [Storing Data in a Page|http://jumpstart.doublenegative.com.au/jumpstart/examples/state/storingdatainapage]
-    [Passing Data Between Pages|http://jumpstart.doublenegative.com.au/jumpstart/examples/state/passingdatabetweenpages]
-{float}</plain-text-body>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><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><parameter ac:name="title">Example: Session Strategy</parameter><plain-text-body>  @Persist
+</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
   private int value;
-</plain-text-body><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><parameter ac:name="title">Example: Flash Strategy</parameter><plain-text-body>  @Persist(PersistenceConstants.FLASH)
+</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)
   private int value;
-</plain-text-body><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><parameter ac:name="title">Example: Client Strategy</parameter><plain-text-body>  @Persist(Persisten
 ceConstants.CLIENT)
+</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)
   private int value;
-</plain-text-body><h3 id="PersistentPageData-HibernateEntityStrategy">Hibernate Entity Strategy</h3><p><span style="line-height: 1.4285715;">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><parameter ac:name="title">"Hibernate Entity Strategy"</parameter><plain-text-body>  @Persist(HibernatePersistenceConstants.ENTITY)
-  private User user;</plain-text-body><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><parameter ac:name="title">"Example: JPA Entity Strategy"</parameter><plain-text-body>  @Persist(JpaPersistenc
 eConstants.ENTITY)
-  private Account account;</plain-text-body><p><span style="color: rgb(83,145,38);font-size: 20.0px;line-height: 1.5;">Persistence Strategy Inheritance</span></p><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>Fie
 lds marked 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><parameter ac:name=""><a  href="clustering-issues.html">Clustering Issues</a></parameter></p><parameter ac:name="title">Example: Entity Session Strategy</parameter><plain-text-body>  @Persist(HibernatePersistenceConstants.ENTITY)
-  private User user;</plain-text-body><parameter ac:name="title">"Example:JAP Session Strategy"</parameter><plain-text-body>  @Persist(JpaPersistenceConstants.ENTITY)
-  private Account account;</plain-text-body></div>
+</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)
+  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)
+  private Account account;</pre>
+</div></div><p><span style="color: rgb(83,145,38);">Persistence Strategy Inheritance</span></p><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 marked with @Persist may not have default values (whether set i
 nline, 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 single servers, but in a cluster, anything stored in the se
 ssion 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 replicated needlessly if the internal state of the mutable o
 bject 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 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 <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)
+  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)
+  private Account account;</pre>
+</div></div></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/property-expressions.html
==============================================================================
--- websites/production/tapestry/content/property-expressions.html (original)
+++ websites/production/tapestry/content/property-expressions.html Sat Feb  3 16:21:22 2018
@@ -67,7 +67,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>Tapestry uses <strong>property expressions</strong> to move data between components. Property expressions are the basis of the <a  href="component-parameters.html">component parameters</a> and <a  href="component-templates.html">template expansions</a>.</p><div class="aui-label" style="float:right" title="Related Articles">
+                <div id="ConfluenceContent"><p>Tapestry uses <strong>property expressions</strong> to move data between components. Property expressions are the basis of the <a  href="property-expressions.html">component parameters</a> and <a  href="property-expressions.html">template expansions</a>.</p><div class="aui-label" style="float:right" title="Related Articles">
 
 
 
@@ -100,7 +100,7 @@
 </div>
 
 
-<p>A property expression is a string that explains to Tapestry how to navigate from a root object (the containing component) through some number of properties, to a final property that can be read or updated. In fact, that's a simplification, as the properties may actually be public fields, or even method invocations.</p><p>As elsewhere in Tapestry, the names of fields, properties, and methods are recognized in a case-insensitive manner.</p><p>The most basic form of a property expression is a simple property name, such as "userName".</p><p>A series of property names may be specified, separated by periods: "user.name", which is equivalent to either <code>getUser().getName()</code> or <code>getUser().setName()</code>, depending on context (whether the expression is being read or updated).</p><p>The "." is called the "dereference operator". A second operator is "?." or the "safe dereference operator". This works the same as "." except that it allows any of the properties to be null. Wh
 en reading, a null short-circuits the expression (which returns null). When writing to a property, an intermediate null value will cause the value to be discarded without error.</p><p>In other words, "user?.name" works, even when the <code>user</code> property may be null.</p><p>Property expressions can also reference public methods. Methods may take parameters (or not), but must not return void. When the final term in a property expression is a method, then the property expression is read-only.</p><p>Being able to invoke methods was originally added so that it was possible to access methods such as <code>java.util.Map.size()</code> (which is not named like a property getter method). In Tapestry 5.1, property expressions were extended so that parameters could be passed into methods.</p><p>Parameters to methods are, themselves, property expressions. This means that you can write a property expression that reads a property and passes it as a parameter to a method, and then access a pr
 operty of the object returned from the method.</p><h2 id="PropertyExpressions-Compilation">Compilation</h2><p>Property expressions are compiled to Java classes at runtime; there is no runtime reflection (unlike the OGNL expression language used in prior releases of Tapestry).</p><h2 id="PropertyExpressions-Grammar">Grammar</h2><p>Expressed in simplified <a  class="external-link" href="http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form" rel="nofollow">Backus&#8211;Naur Form</a>, the grammar of property expressions is as follows:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
+<p>A property expression is a string that explains to Tapestry how to navigate from a root object (the containing component) through some number of properties, to a final property that can be read or updated. In fact, that's a simplification, as the properties may actually be public fields, or even method invocations.</p><p>As elsewhere in Tapestry, the names of fields, properties, and methods are recognized in a case-insensitive manner.</p><p>The most basic form of a property expression is a simple property name, such as "userName".</p><p>A series of property names may be specified, separated by periods: "user.name", which is equivalent to either <code>getUser().getName()</code> or <code>getUser().setName()</code>, depending on context (whether the expression is being read or updated).</p><p>The "<span style="color: rgb(255,0,0);"><strong>.</strong></span>" is called the "dereference operator". In addition, there is a a "safe dereference operator", "<span style="color: rgb(255,0,0)
 ;">?.</span>", which&#160; works the same as "<span style="color: rgb(255,0,0);">.</span>" except that it allows any of the properties to be null. When reading, a null short-circuits the expression (which returns null). When writing to a property, an intermediate null value will cause the value to be discarded without error.</p><p>In other words, "user<span style="color: rgb(255,0,0);">?.</span>name" works, even when the <code>user</code> property may be null.</p><p>Property expressions can also reference public methods. Methods may take parameters (or not), but must not return void. When the final term in a property expression is a method, then the property expression is read-only.</p><p>Being able to invoke methods was originally added so that it was possible to access methods such as <code>java.util.Map.size()</code> (which is not named like a property getter method). In Tapestry 5.1, property expressions were extended so that parameters could be passed into methods.</p><p>Parame
 ters to methods are, themselves, property expressions. This means that you can write a property expression that reads a property and passes it as a parameter to a method, and then access a property of the object returned from the method.</p><h2 id="PropertyExpressions-Compilation">Compilation</h2><p>Property expressions are compiled to Java classes at runtime; there is no runtime reflection (unlike the OGNL expression language used in prior releases of Tapestry).</p><h2 id="PropertyExpressions-Grammar">Grammar</h2><p>Expressed in simplified <a  class="external-link" href="http://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form" rel="nofollow">Backus&#8211;Naur Form</a>, the grammar of property expressions is as follows:</p><div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
 <pre>expression : keyword | rangeOp | constant | propertyChain | list | notOp | map;
 
 keyword : 'null' | 'this';
@@ -139,7 +139,7 @@ mapKey : keyword | constant | propertyCh
 </div></div>
 <div class="error"><span class="error">Unknown macro: {div}</span> 
 <p>Support for map literals was added in Tapestry 5.3.</p>
-</div>Notes:<ul><li>Whitespace is ignored.</li><li>Integers and decimals may have a leading sign ('+' or '-').</li><li>Constants are in base 10 (octal and hex notation is not yet supported). Decimals may contain a decimal point (exponent notation not yet supported).</li><li>Literal strings are enclosed in single quotes.</li><li>The <code>rangeOp</code> creates a range object that will iterate between the two values. The upper and lower bounds may be literal integers, or property expressions.</li><li>An identifier by itself is a property name. An identifier with parenthesis is a method invocation.</li><li>Property names, method names, and keywords are case-insensitive.</li><li>'this' is the root object (i.e., the containing component).</li><li>The <code>not</code> operator coerces the expression to a <code>boolean</code> (so it can be used on strings, numbers, etc.).</li><li>Method matching is based on method name and number of parameters, but not parameter types. The <a  href="type-
 coercion.html">TypeCoercer</a> service is used to convert parameters to the correct type to be passed into the method.</li></ul><h2 id="PropertyExpressions-Examples">Examples</h2><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>&#160;</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Example</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Notes</p></th></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Keyword</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>this</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&#160;</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Keyword</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>null</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&#160;</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Property Name</p></th><td colspan="1" rowspan="1" class="confluenceTd"><
 p>userName</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Calls getUserName() or setUserName, depending on context</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Property Chain</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>user.address.city</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Calls getUser().getAddress().getCity() or getUser().getAddress().setCity(), depending on context</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Property Chain</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>user?.name</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Calls getUser() and, if the result is not null, calls getName() on the result</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Method Invocation</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>groupList.size()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>calls getGroupList().size()</p></
 td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Method Invocation</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>members.findById(user.id)?.name</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Calls getMembers().findById(getUser().getId())?.getName() (unless findById returns null)</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Range</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>1..10</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Iterates between integers 1 and 10</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Range</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>1..groupList.size()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Iterates between 1 and the result of getGroupList().size()</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Literal String</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>'Beer is proof that 
 God loves us and wants us to be happy.'</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Use single quotes</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>List</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>[user.name, user.email, user.phone]</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&#160;</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Not Operator</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>! user.deleted</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>the boolean negation of getUser().getDeleted()</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Not, Coerced</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>! user.middleName</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>true only if getUser.getMiddleName() returns null or an empty string</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Map</p></th><td cols
 pan="1" rowspan="1" class="confluenceTd"><p>{ 'framework' : 'Tapestry', 'version' : version }</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Keys are string literals (in single quotes), but could be properties as well</p></td></tr></tbody></table></div></div>
+</div>Notes:<ul><li>Whitespace is ignored.</li><li>Integers and decimals may have a leading sign ('+' or '-').</li><li>Constants are in base 10 (octal and hex notation is not yet supported). Decimals may contain a decimal point (exponent notation not yet supported).</li><li>Literal strings are enclosed in single quotes.</li><li>The <code>rangeOp</code> creates a range object that will iterate between the two values. The upper and lower bounds may be literal integers, or property expressions.</li><li>An identifier by itself is a property name. An identifier with parenthesis is a method invocation.</li><li>Property names, method names, and keywords are case-insensitive.</li><li>'this' is the root object (i.e., the containing component).</li><li>The <code>not</code> operator coerces the expression to a <code>boolean</code> (so it can be used on strings, numbers, etc.).</li><li>Method matching is based on method name and number of parameters, but not parameter types. The <a  href="prope
 rty-expressions.html">TypeCoercer</a> service is used to convert parameters to the correct type to be passed into the method.</li></ul><h2 id="PropertyExpressions-Examples">Examples</h2><div class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>&#160;</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Example</p></th><th colspan="1" rowspan="1" class="confluenceTh"><p>Notes</p></th></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Keyword</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>this</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&#160;</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Keyword</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>null</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&#160;</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Property Name</p></th><td colspan="1" rowspan="1" class="confluen
 ceTd"><p>userName</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Calls getUserName() or setUserName, depending on context</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Property Chain</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>user.address.city</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Calls getUser().getAddress().getCity() or getUser().getAddress().setCity(), depending on context</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Property Chain</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>user?.name</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Calls getUser() and, if the result is not null, calls getName() on the result</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Method Invocation</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>groupList.size()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>calls getGroupList().size(
 )</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Method Invocation</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>members.findById(<a  class="external-link" href="http://user.id" rel="nofollow">user.id</a>)?.name</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Calls getMembers().findById(getUser().getId())?.getName() (unless findById returns null)</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Range</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>1..10</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Iterates between integers 1 and 10</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Range</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>1..groupList.size()</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Iterates between 1 and the result of getGroupList().size()</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Literal String</p></t
 h><td colspan="1" rowspan="1" class="confluenceTd"><p>'Beer is proof that God loves us and wants us to be happy.'</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Use single quotes</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>List</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>[<a  class="external-link" href="http://user.name" rel="nofollow">user.name</a>, user.email, user.phone]</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>&#160;</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Not Operator</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>! user.deleted</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>the boolean negation of getUser().getDeleted()</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Not, Coerced</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>! user.middleName</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>true only if ge
 tUser.getMiddleName() returns null or an empty string</p></td></tr><tr><th colspan="1" rowspan="1" class="confluenceTh"><p>Map</p></th><td colspan="1" rowspan="1" class="confluenceTd"><p>{ 'framework' : 'Tapestry', 'version' : version }</p></td><td colspan="1" rowspan="1" class="confluenceTd"><p>Keys are string literals (in single quotes), but could be properties as well</p></td></tr></tbody></table></div></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/request-processing.html
==============================================================================
--- websites/production/tapestry/content/request-processing.html (original)
+++ websites/production/tapestry/content/request-processing.html Sat Feb  3 16:21:22 2018
@@ -36,13 +36,26 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
+
+</div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html"> 
- <input type="text" name="q"> 
- <input type="submit" value="Search"> 
-</form></div><div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Request Processing</h1></div></div>
+            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
+<form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html">
+  <input type="text" name="q">
+  <input type="submit" value="Search">
+</form>
+
+</div>
+
+
+<div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
+
+
+<div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Request Processing</h1></div>
+
+</div>
       <div class="clearer"></div>
       </div>
 
@@ -54,43 +67,76 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><div class="aui-label" style="float:right" title="Related Articles"><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> 
-  <div class="details"> 
-   <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> 
-  <div class="details"> 
-   <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> 
-  <div class="details"> 
-   <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> 
-  <div class="details"> 
-   <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> 
-  <div class="details"> 
-   <a  href="component-events-faq.html">Component Events FAQ</a> 
-  </div> </li><li> 
-  <div> 
-   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
-  </div> 
-  <div class="details"> 
-   <a  href="request-processing.html">Request Processing</a> 
-  </div> </li></ul></div><p><strong>Request Processing</strong> involves a sequence of steps that Tapestry performs when every HTTP request comes in. You <em>don't need</em> to know these steps to use Tapestry productively, but understanding the request processing pipeline is helpful if you want to understand Tapestry deeply.</p><p>Much of the early stages of processing are in the form of extensible <a  href="pipelinebuilder-service.html">pipelines</a>.</p><h2 id="RequestProcessing-TapestryFilter">Tapestry Filter</h2><p>All incoming requests originate with the TapestryFilter, which is a servlet filter configured inside your application's <a  href="configuration.html">web.xml</a>.</p><p>The TapestryFilter is responsible for a number of startup and initialization functions.</p><p>When it receives a request, the TapestryFilter obtains the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpServletRequestHandler.html">HttpServletR
 equestHandler</a> service, and invokes its service() method.</p><h2 id="RequestProcessing-HttpServletRequestHandlerPipeline">HttpServletRequestHandler Pipeline</h2><p>This pipeline performs initial processing of the request. It can be extended by contributing a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpServletRequestFilter.html">HttpServletRequestFilter</a> into the HttpServletRequestHandler service's configuration.</p><p>Tapestry does not contribute any filters into this pipeline of its own.</p><p>The terminator for the pipeline does two things:</p><ul><li>It stores the request and response into the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestGlobals.html">RequestGlobals</a> service. This is a per-thread scoped service that stores per-thread/per-request information.</li><li>It wraps the request and response as a <a  class="external-link" href="http:
 //tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/Request.html">Request</a> and <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/Response.html">Response</a>, and passes them into the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestHandler.html">RequestHandler</a> pipeline.</li></ul><h2 id="RequestProcessing-RequestHandlerPipeline">RequestHandler Pipeline</h2><p>This pipeline is where most extensions related to requests take place. Request represents an abstraction on top of HttpServletRequest. (Primarily, this exists to bridge from the Servlet API objects to the corresponding Tapestry objects. This is to allow for a possible portlet integration for Tapestry.) Where other code and services within Tapestry require access to information in the request, such as query parameters, that information is obtained from the Request (or Response) objects.</p><
 p>The RequestHandler pipeline includes a number of built-in filters:</p><ul><li>CheckForUpdates is responsible for <a  href="class-reloading.html">class and template reloading</a>.</li><li>Localization identifies the <a  href="localization.html">locale for the user</a>.</li><li>StaticFiles checks for URLs that are for static files (files that exist inside the web context) and aborts the request, so that the servlet container can handle the request normally.</li><li>ErrorFilter catches uncaught exceptions from the lower levels of Tapestry and presents the exception report page. This involves the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a> service, which is responsible for initializing and rendering the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/pages/ExceptionReport.html">core/ExceptionReport</a> page.</li>
 </ul><p>The terminator for this pipeline stores the Request and the Response into RequestGlobals, then requests that the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/Dispatcher.html">MasterDispatcher</a> service figure out how to handle the request (if it is, indeed, a Tapestry request).</p><h2 id="RequestProcessing-MasterDispatcherService">Master Dispatcher Service</h2><p>The MasterDispatcher service is a chain-of-command, aggregating together (in a specific order), several Dispatcher objects. Each Dispatcher is built to recognize and process a particular kind of URL.</p><h3 id="RequestProcessing-RootPathDispatcher">RootPath Dispatcher</h3><p>The RootPath Dispatcher recognizes a request for the application root (i.e., "/") and handles this the same as a render request for the "Start" page. Support for the Start page is kept for legacy purposes. Index pages are the correct approach.</p><h3 id="RequestProcessing-AssetDispatc
 her">Asset Dispatcher</h3><p>Requests that begin with "/assets/" are references to <a  href="assets.html">asset resources</a> that are stored on the classpath, inside the Tapestry JARs (or perhaps inside the JAR for a component library). The contents of the file will be delivered to the client browser as a byte stream. This dispatcher also handles requests that are simply polling for a change to the file.</p><h3 id="RequestProcessing-PageRenderDispatcher">PageRender Dispatcher</h3><p>Page render requests are requests to render a particular page. Such requests may include additional elements on the path, which will be treated as activation context (see ComponentEvent Dispatcher below). Generally speaking, the activation context is the primary key of some related entity object. This allows the page to reconstruct the state it will need to successfully render itself.</p><p>The event handler method for the activate event may return a value; this is treated the same as the return value f
 rom a component action request; typically this will result in a redirect to another page. In this way, the activate event can perform simple validation at the page level ("can the user see this page?").</p><p>Page render URLs consist of the logical name of the page plus additional path elements for the activation context. The dispatcher here strips terms off of the path until it finds a known page name. Thus, "/mypage/27" would look first for a page whose name was "mypage/27", then look for a page name "mypage". Assuming the second search was successful, the page would be activated with the context "27". If no logical page name can be identified, control passes to the next dispatcher.</p><h3 id="RequestProcessing-ComponentEventDispatcher">ComponentEvent Dispatcher</h3><p>The ComponentEvent dispatcher is used to trigger events in components.</p><p>The URL identifies the name of the page, then a series of component ids (the path from the page down to the specific component), then the 
 name of the event to be triggered on the component. The remaining path elements are used as the context for the <em>event</em> (not for the page activation, which does not currently apply). For example, "/griddemo.FOO.BAR/3" would locate page "griddemo", then component "FOO.BAR", and trigger an event named "action" (the default event type, which is omitted from the URL), with the context "3".</p><p>If the page in question has an activation context, it is supplied as an additional query parameter on the link.</p><p>In cases where the event type is not the default, "action", it will appear between the nested component id and the event context, preceded by a colon. Example: "/example/foo.bar:magic/99" would trigger an event of type "magic". This is not common in the vanilla Tapestry framework, but will likely be more common as Ajax features (which would not use the normal request logic) are implemented.</p><p>The response from a component action request is typically, but not universall
 y, used to send a redirect to the client; the redirect URL is a page render URL to display the response to the event. This is detailed under <a  href="page-navigation.html">Page Navigation</a>.</p><h2 id="RequestProcessing-RequestGlobalsService">RequestGlobals Service</h2><p>The RequestGlobals service has a life cycle of per-thread; this means that a separate instance exists for every thread, and therefore, for every request. The terminators of the two handler pipelines store the request/response pairs into the RequestGlobals service.</p><h2 id="RequestProcessing-RequestService">Request Service</h2><p>The Request service is a <a  href="shadowbuilder-service.html">shadow</a> of the RequestGlobals services' request property. That is, any methods invoked on this service are delegated to the request object stored inside the RequestGlobals.</p><h2 id="RequestProcessing-Overview">Overview</h2><p>The following diagram provides an overview of how the different pipelines, filters and dispatc
 hers interact when processing an incoming request.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-content-image-border" src="request-processing.data/tapestry_request_processing_800.png"></span></p></div>
+                <div id="ConfluenceContent"><div class="aui-label" style="float:right" title="Related Articles">
+
+
+
+
+
+
+
+
+<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>
+
+        <div class="details">
+                        <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>
+
+        <div class="details">
+                        <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>
+
+        <div class="details">
+                        <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>
+
+        <div class="details">
+                        <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>
+
+        <div class="details">
+                        <a  href="component-events-faq.html">Component Events FAQ</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  href="request-processing.html">Request Processing</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<p><strong>Request Processing</strong> involves a sequence of steps that Tapestry performs when every HTTP request comes in. You <em>don't need</em> to know these steps to use Tapestry productively, but understanding the request processing pipeline is helpful if you want to understand Tapestry deeply.</p><p>Much of the early stages of processing are in the form of extensible <a  href="request-processing.html">pipelines</a>.</p><h2 id="RequestProcessing-TapestryFilter">Tapestry Filter</h2><p>All incoming requests originate with the TapestryFilter, which is a servlet filter configured inside your application's <a  href="request-processing.html">web.xml</a>.</p><p>The TapestryFilter is responsible for a number of startup and initialization functions.</p><p>When it receives a request, the TapestryFilter obtains the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpServletRequestHandler.html">HttpServletRequestHandler</a> service
 , and invokes its service() method.</p><h2 id="RequestProcessing-HttpServletRequestHandlerPipeline">HttpServletRequestHandler Pipeline</h2><p>This pipeline performs initial processing of the request. It can be extended by contributing a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpServletRequestFilter.html">HttpServletRequestFilter</a> into the HttpServletRequestHandler service's configuration.</p><p>Tapestry does not contribute any filters into this pipeline of its own.</p><p>The terminator for the pipeline does two things:</p><ul><li>It stores the request and response into the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestGlobals.html">RequestGlobals</a> service. This is a per-thread scoped service that stores per-thread/per-request information.</li><li>It wraps the request and response as a <a  class="external-link" href="http://tapestry.apache.org/cur
 rent/apidocs/org/apache/tapestry5/services/Request.html">Request</a> and <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/Response.html">Response</a>, and passes them into the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestHandler.html">RequestHandler</a> pipeline.</li></ul><h2 id="RequestProcessing-RequestHandlerPipeline">RequestHandler Pipeline</h2><p>This pipeline is where most extensions related to requests take place. Request represents an abstraction on top of HttpServletRequest. (Primarily, this exists to bridge from the Servlet API objects to the corresponding Tapestry objects. This is to allow for a possible portlet integration for Tapestry.) Where other code and services within Tapestry require access to information in the request, such as query parameters, that information is obtained from the Request (or Response) objects.</p><p>The RequestHandler pipe
 line includes a number of built-in filters:</p><ul><li>CheckForUpdates is responsible for <a  href="request-processing.html">class and template reloading</a>.</li><li>Localization identifies the <a  href="request-processing.html">locale for the user</a>.</li><li>StaticFiles checks for URLs that are for static files (files that exist inside the web context) and aborts the request, so that the servlet container can handle the request normally.</li><li>ErrorFilter catches uncaught exceptions from the lower levels of Tapestry and presents the exception report page. This involves the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a> service, which is responsible for initializing and rendering the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/pages/ExceptionReport.html">core/ExceptionReport</a> page.</li></ul><p>The term
 inator for this pipeline stores the Request and the Response into RequestGlobals, then requests that the <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/Dispatcher.html">MasterDispatcher</a> service figure out how to handle the request (if it is, indeed, a Tapestry request).</p><h2 id="RequestProcessing-MasterDispatcherService">Master Dispatcher Service</h2><p>The MasterDispatcher service is a chain-of-command, aggregating together (in a specific order), several Dispatcher objects. Each Dispatcher is built to recognize and process a particular kind of URL.</p><h3 id="RequestProcessing-RootPathDispatcher">RootPath Dispatcher</h3><p>The RootPath Dispatcher recognizes a request for the application root (i.e., "/") and handles this the same as a render request for the "Start" page. Support for the Start page is kept for legacy purposes. Index pages are the correct approach.</p><h3 id="RequestProcessing-AssetDispatcher">Asset Dispa
 tcher</h3><p>Requests that begin with "/assets/" are references to <a  href="request-processing.html">asset resources</a> that are stored on the classpath, inside the Tapestry JARs (or perhaps inside the JAR for a component library). The contents of the file will be delivered to the client browser as a byte stream. This dispatcher also handles requests that are simply polling for a change to the file.</p><h3 id="RequestProcessing-PageRenderDispatcher">PageRender Dispatcher</h3><p>Page render requests are requests to render a particular page. Such requests may include additional elements on the path, which will be treated as activation context (see ComponentEvent Dispatcher below). Generally speaking, the activation context is the primary key of some related entity object. This allows the page to reconstruct the state it will need to successfully render itself.</p><p>The event handler method for the activate event may return a value; this is treated the same as the return value from 
 a component action request; typically this will result in a redirect to another page. In this way, the activate event can perform simple validation at the page level ("can the user see this page?").</p><p>Page render URLs consist of the logical name of the page plus additional path elements for the activation context. The dispatcher here strips terms off of the path until it finds a known page name. Thus, "/mypage/27" would look first for a page whose name was "mypage/27", then look for a page name "mypage". Assuming the second search was successful, the page would be activated with the context "27". If no logical page name can be identified, control passes to the next dispatcher.</p><h3 id="RequestProcessing-ComponentEventDispatcher">ComponentEvent Dispatcher</h3><p>The ComponentEvent dispatcher is used to trigger events in components.</p><p>The URL identifies the name of the page, then a series of component ids (the path from the page down to the specific component), then the name
  of the event to be triggered on the component. The remaining path elements are used as the context for the <em>event</em> (not for the page activation, which does not currently apply). For example, "/griddemo.FOO.BAR/3" would locate page "griddemo", then component "FOO.BAR", and trigger an event named "action" (the default event type, which is omitted from the URL), with the context "3".</p><p>If the page in question has an activation context, it is supplied as an additional query parameter on the link.</p><p>In cases where the event type is not the default, "action", it will appear between the nested component id and the event context, preceded by a colon. Example: "/example/foo.bar:magic/99" would trigger an event of type "magic". This is not common in the vanilla Tapestry framework, but will likely be more common as Ajax features (which would not use the normal request logic) are implemented.</p><p>The response from a component action request is typically, but not universally, u
 sed to send a redirect to the client; the redirect URL is a page render URL to display the response to the event. This is detailed under <a  href="request-processing.html">Request Processing</a>.</p><h2 id="RequestProcessing-RequestGlobalsService">RequestGlobals Service</h2><p>The RequestGlobals service has a life cycle of per-thread; this means that a separate instance exists for every thread, and therefore, for every request. The terminators of the two handler pipelines store the request/response pairs into the RequestGlobals service.</p><h2 id="RequestProcessing-RequestService">Request Service</h2><p>The Request service is a <a  href="request-processing.html">shadow</a> of the RequestGlobals services' request property. That is, any methods invoked on this service are delegated to the request object stored inside the RequestGlobals.</p><h2 id="RequestProcessing-Overview">Overview</h2><p>The following diagram provides an overview of how the different pipelines, filters and dispatch
 ers interact when processing an incoming request.</p><p><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource confluence-content-image-border" src="https://cwiki-test.apache.org/confluence/download/attachments/22872133/tapestry_request_processing_800.png?version=1&amp;modificationDate=1299128361000&amp;api=v2" data-image-src="https://cwiki-test.apache.org/confluence/download/attachments/22872133/tapestry_request_processing_800.png?version=1&amp;modificationDate=1299128361000&amp;api=v2"></span></p></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/response-compression.html
==============================================================================
--- websites/production/tapestry/content/response-compression.html (original)
+++ websites/production/tapestry/content/response-compression.html Sat Feb  3 16:21:22 2018
@@ -36,13 +36,26 @@
 
   <div class="wrapper bs">
 
-        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div></div>
+        <div id="navigation"><div class="nav"><ul class="alternate"><li><a  href="index.html">Home</a></li><li><a  href="getting-started.html">Getting Started</a></li><li><a  href="documentation.html">Documentation</a></li><li><a  href="download.html">Download</a></li><li><a  href="about.html">About</a></li><li><a  class="external-link" href="http://www.apache.org/licenses/LICENSE-2.0">License</a></li><li><a  href="community.html">Community</a></li><li><a  class="external-link" href="http://www.apache.org/security/">Security</a></li><li><a  class="external-link" href="http://www.apache.org/">Apache</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li><li><a  class="external-link" href="http://www.apache.org/foundation/thanks.html">Thanks</a></li></ul></div>
+
+</div>
 
           <div id="top">
-            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span><form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html"> 
- <input type="text" name="q"> 
- <input type="submit" value="Search"> 
-</form></div><div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div><div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Response Compression</h1></div></div>
+            <div id="smallbanner"><div class="searchbox" style="float:right;margin: .3em 1em .1em 1em"><span style="color: #999; font-size: 90%">Tapestry docs, issues, wikis &amp; blogs:</span>
+<form enctype="application/x-www-form-urlencoded" method="get" action="http://tapestry.apache.org/search.html">
+  <input type="text" name="q">
+  <input type="submit" value="Search">
+</form>
+
+</div>
+
+
+<div class="emblem" style="float:left"><p><a  href="index.html"><span class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image confluence-external-resource" src="http://tapestry.apache.org/images/tapestry_small.png" data-image-src="http://tapestry.apache.org/images/tapestry_small.png"></span></a></p></div>
+
+
+<div class="title" style="float:left; margin: 0 0 0 3em"><h1 id="SmallBanner-PageTitle">Response Compression</h1></div>
+
+</div>
       <div class="clearer"></div>
       </div>
 
@@ -54,25 +67,49 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><p>Starting in Tapestry 5.1, the framework automatically GZIP <strong>compresses</strong> content streamed to the client. This can significantly reduce the amount of network traffic for a Tapestry application, at the cost of extra processing time on the server to compress the response stream.</p><div class="aui-label" style="float:right" title="Related Articles"><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> 
-  <div class="details"> 
-   <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> 
-  <div class="details"> 
-   <a  href="configuration.html">Configuration</a> 
-  </div> </li><li> 
-  <div> 
-   <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span> 
-  </div> 
-  <div class="details"> 
-   <a  href="assets.html">Assets</a> 
-  </div> </li></ul></div><p>This directly applies to both rendered pages and streamed assets from the classpath.</p><p>Context assets will also be compressed ... but this requires referencing such assets using the "context:" binding prefix, so that generated URL is handled by Tapestry and not the servlet container.</p><h1 id="ResponseCompression-CompressionConfiguration">Compression Configuration</h1><p>Main Article: <a  href="configuration.html">Configuration</a></p><p>Small streams generally do not benefit from being compressed; there is overhead when using compression, not just the CPU time to compress the bytes, but a lot of overhead. For small responses, Tapestry does not attempt to compress the output stream.</p><p>The configuration symbol <code>tapestry.min-gzip-size</code> allows the cutoff to be set; it defaults to 100 bytes.</p><p>In addition, some file types are already compressed and should not be recompressed (they actually get larger, not smaller!). The service <a  cla
 ss="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ResponseCompressionAnalyzer.html">ResponseCompressionAnalyzer</a>'s configuration is an unordered collection of content type strings that should <em>not</em> be compressed. The default content types are "image/jpeg".</p><h1 id="ResponseCompression-StreamResponse">StreamResponse</h1><p>When returning a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html">StreamResponse</a> from a <a  href="page-navigation.html">component event method</a>, the stream is totally under your control; it will not be compressed. You should use the ResponseCompressionAnalyzer service to determine if the client supports compression, and add a java.util.zip.GZIPOutputStream to your stream stack if compression is desired.</p></div>
+                <div id="ConfluenceContent"><p>Starting in Tapestry 5.1, the framework automatically GZIP <strong>compresses</strong> content streamed to the client. This can significantly reduce the amount of network traffic for a Tapestry application, at the cost of extra processing time on the server to compress the response stream.</p><div class="aui-label" style="float:right" title="Related Articles">
+
+
+
+
+
+
+
+
+<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>
+
+        <div class="details">
+                        <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>
+
+        <div class="details">
+                        <a  href="configuration.html">Configuration</a>
+                
+                        
+                    </div>
+    </li><li>
+        <div>
+                <span class="icon aui-icon aui-icon-small aui-iconfont-page-default" title="Page">Page:</span>        </div>
+
+        <div class="details">
+                        <a  href="assets.html">Assets</a>
+                
+                        
+                    </div>
+    </li></ul>
+</div>
+
+
+<p>This directly applies to both rendered pages and streamed assets from the classpath.</p><p>Context assets will also be compressed ... but this requires referencing such assets using the "context:" binding prefix, so that generated URL is handled by Tapestry and not the servlet container.</p><h1 id="ResponseCompression-CompressionConfiguration">Compression Configuration</h1><p>Main Article: <a  href="response-compression.html">Response Compression</a></p><p>Small streams generally do not benefit from being compressed; there is overhead when using compression, not just the CPU time to compress the bytes, but a lot of overhead. For small responses, Tapestry does not attempt to compress the output stream.</p><p>The configuration symbol <code>tapestry.min-gzip-size</code> allows the cutoff to be set; it defaults to 100 bytes.</p><p>In addition, some file types are already compressed and should not be recompressed (they actually get larger, not smaller!). The service <a  class="externa
 l-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ResponseCompressionAnalyzer.html">ResponseCompressionAnalyzer</a>'s configuration is an unordered collection of content type strings that should <em>not</em> be compressed. The default content types are "image/jpeg".</p><h1 id="ResponseCompression-StreamResponse">StreamResponse</h1><p>When returning a <a  class="external-link" href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html">StreamResponse</a> from a <a  href="response-compression.html">component event method</a>, the stream is totally under your control; it will not be compressed. You should use the ResponseCompressionAnalyzer service to determine if the client supports compression, and add a java.util.zip.GZIPOutputStream to your stream stack if compression is desired.</p></div>
       </div>
 
       <div class="clearer"></div>