Modified: websites/production/tapestry/content/clustering-issues.html
==============================================================================
--- websites/production/tapestry/content/clustering-issues.html (original)
+++ websites/production/tapestry/content/clustering-issues.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 & 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">Clustering Issues</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 & 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">Clustering Issues</h1></div>
+
+</div>
<div class="clearer"></div>
</div>
@@ -54,33 +67,7 @@
</div>
<div id="content">
- <div id="ConfluenceContent"><h2
id="ClusteringIssues-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 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 replicated needlessly if the internal state of the
mutable object hasn't changed.</p>
-
-<p>Tapestry has solutions to this, too:</p>
-
-<h3
id="ClusteringIssues-@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="ClusteringIssues-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="ClusteringIssues-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>
+ <div id="ConfluenceContent"><h2
id="ClusteringIssues-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 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
replicated needlessly if the internal state of the mutable object hasn't
changed.</p><p>Tapestry has solutions to this, too:</p><h3
id="ClusteringIssues-@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="ClusteringIssues-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="ClusteringIssues-SessionPersistedObjectAnalyzerService">SessionPersistedObjectAnalyzer
Service</h3><p>The <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/or
g/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>
</div>
<div class="clearer"></div>
Modified: websites/production/tapestry/content/component-classes.html
==============================================================================
--- websites/production/tapestry/content/component-classes.html (original)
+++ websites/production/tapestry/content/component-classes.html Sat Feb 3
16:21:22 2018
@@ -145,7 +145,7 @@
</div>
-<p>In most cases, each component class will have a corresponding <a
href="component-templates.html">component template</a>. However, it is also
possible for a component class to emit all of its markup itself, without using
a template.</p><p><em>For Tapestry 4 Users: Component classes in Tapestry 5 are
much easier than in Tapestry 4. There are no base classes to extend from, the
classes are concrete (not abstract), and there's no XML file. There is still a
bit of configuration in the form of Java annotations, but those now go directly
onto fields of your class, rather than on abstract getters and
setters.</em></p><h2 id="ComponentClasses-CreatingaTrivialComponent">Creating a
Trivial Component</h2><p>Creating a page or component in Tapestry 5 is a
breeze. There are only a few constraints:</p><ul><li>There must be a public
Java class.</li><li>The class must be in the correct package (see
below).</li><li>The class must have a public, no-arguments constructor. (The
default one provided
by the compiler is fine.)</li></ul><p>Here's a minimal component that outputs
a fixed message, using a <a href="component-templates.html">template</a> with
a matching file name:</p><div class="sectionColumnWrapper"><div
class="sectionMacro"><div class="sectionMacroRow"><div class="columnMacro"><div
class="code panel pdl" style="border-width: 1px;"><div class="codeHeader
panelHeader pdl" style="border-bottom-width:
1px;"><b>HelloWorld.java</b></div><div class="codeContent panelContent pdl">
+<p>In most cases, each component class will have a corresponding <a
href="component-classes.html">component template</a>. However, it is also
possible for a component class to emit all of its markup itself, without using
a template.</p><p><em>For Tapestry 4 Users: Component classes in Tapestry 5 are
much easier than in Tapestry 4. There are no base classes to extend from, the
classes are concrete (not abstract), and there's no XML file. There is still a
bit of configuration in the form of Java annotations, but those now go directly
onto fields of your class, rather than on abstract getters and
setters.</em></p><h2 id="ComponentClasses-CreatingaTrivialComponent">Creating a
Trivial Component</h2><p>Creating a page or component in Tapestry 5 is a
breeze. There are only a few constraints:</p><ul><li>There must be a public
Java class.</li><li>The class must be in the correct package (see
below).</li><li>The class must have a public, no-arguments constructor. (The
default one provided by
the compiler is fine.)</li></ul><p>Here's a minimal component that outputs a
fixed message, using a <a href="component-classes.html">template</a> with a
matching file name:</p><div class="sectionColumnWrapper"><div
class="sectionMacro"><div class="sectionMacroRow"><div class="columnMacro"><div
class="code panel pdl" style="border-width: 1px;"><div class="codeHeader
panelHeader pdl" style="border-bottom-width:
1px;"><b>HelloWorld.java</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">package org.example.myapp.components;
public class HelloWorld
{
@@ -171,13 +171,13 @@ public class HelloWorld
}
}
</pre>
-</div></div><p>In this example, just like the first one, the component's only
job is to write out a fixed message. The @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/BeginRender.html">BeginRender</a>
annotation is a type of <em><a href="component-rendering.html">render phase
annotation</a></em>, a method annotation that instructs Tapestry when and under
what circumstances to invoke methods of your class.</p><p>These methods are not
necessarily public; they can have any access level you like (unlike in Tapestry
4). By convention they usually have package-private access level (the
default).</p><h2 id="ComponentClasses-ComponentPackages">Component
Packages</h2><p>Component classes must exist within an appropriate package
(this is necessary for runtime code transformation and class reloading to
operate).</p><p>These packages exist under the application's root package, as
follows:</p><ul><li>For pages, place classes in <em>ro
ot</em>.<strong>pages</strong>. Page names are mapped to classes within this
package.</li><li>For mixins, place classes in
<em>root</em>.<strong>mixins</strong>. Mixin types are mapped to classes within
this package.</li><li>For other components, place classes in
<em>root</em>.<strong>components</strong>. Component types are mapped to
classes within this package.</li></ul><p>In addition, it is common for an
application to have base classes, often <em>abstract</em> base classes, that
should not be directly referenced. These should <em>not</em> go in the
<strong>pages</strong>, <strong>components</strong> or <strong>mixins</strong>
packages, because they then look like valid pages, components or mixins.
Instead, use the <em>root</em>.<strong>base</strong> package to store such base
classes.</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="confl
uence-information-macro-body"><p>Only component classes should go in any of
these controlled packages; classes representing data, or interfaces, or
anything that isn't precisely a component class, must go elsewhere. Any
top-level class in any of the controlled packages will be transformed at
runtime. The only exception is inner classes (anonymous or not), which are
loaded by the same class loader as the component class loader, but not
transformed as components.</p></div></div><h2
id="ComponentClasses-Sub-Folders/Sub-Packages">Sub-Folders /
Sub-Packages</h2><p>Classes do not have to go directly inside the package
(pages, components, mixins, etc.). It is valid to create a sub-package to store
some of the classes. The sub-package name becomes part of the page name or
component type. Thus you might define a page component
<code>com.example.myapp.pages.admin.CreateUser</code> and the logical page name
(which often shows up inside URLs) will be
<strong>admin/CreateUser</strong>.</p><p>Tap
estry performs some simple optimizations of the logical page name (or
component type, or mixin type). It checks to see if the package name is either
a prefix or a suffix of the unqualified class name (case insensitively, of
course) and removes the prefix or suffix if so. The net result is that a class
name such as <code>com.example.myapp.pages.user.EditUser</code> will have a
page name of <code>user/Edit</code> (instead of user<code>/EditUser</code>).
The goal here is to provide shorter, more natural URLs.</p><h2
id="ComponentClasses-IndexPages">Index Pages</h2><p>One special simplification
exists for Index pages: if the logical page name is Index after removing the
package name from the unqualified class name, it will map to the root of that
folder. A class such as <code>com.example.myapp.pages.user.IndexUser</code> or
<code>com.example.myapp.pages.user.UserIndex</code> will have a page name of
<code>user/</code>.</p><p>In previous versions of Tapestry there was also the
concept of
a start page configured with the <code><a
href="configuration.html">tapestry.start-page-name</a></code> configuration
symbol (defaults to "start"). If a page with a name as configured with that
symbol exists at the root level, this page is used as the root URL. This has
precedence over an existing Index page. If for example you have a page class
<code>com.example.myapp.pages.Start</code> it will map to
<code>/</code>.</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>Use of start-pages is discouraged
and support for it will eventually be removed. Use an Index page
instead.</p></div></div><h2 id="ComponentClasses-Pagesvs.Components">Pages vs.
Components</h2><p>The distinction between pages and component is very, very
small. The primary difference is the package name:
<em>root</em>.<strong>pages</strong>.<
em>PageName</em> for pages, and
<em>root</em>.<strong>components</strong>.<em>ComponentType</em> for
components. Conceptually, page components are simply the <em>root
component</em> of a page's component tree.</p><p><em>For Tapestry 4 users:
there was a much greater distinction in Tapestry 4 between pages and
components, which showed up as separate interfaces and a hierarchy of abstract
implementations to extend your classes from.</em></p><h2
id="ComponentClasses-ClassTransformation">Class Transformation</h2><p>Tapestry
uses your class as a starting point. It <em>transforms</em> your class at
runtime. This is necessary for a number of reasons, including to address how
Tapestry shares pages between requests.</p><p>For the most part, these
transformations are both sensible and invisible. In a few limited cases, they
comprise a marginally <a class="external-link"
href="http://www.joelonsoftware.com/printerFriendly/articles/LeakyAbstractions.html"
rel="nofollow">leaky abstraction<
/a> – for instance, the scope restrictions on instance variables
described below – but the programming model in general supports a very
high level of developer productivity.</p><p>Because transformation doesn't
occur until <em>runtime</em>, the build stage of your application is not
affected by the fact that you are creating a Tapestry application. Further,
your classes are absolutely simple POJOs during unit testing.</p><h2
id="ComponentClasses-LiveClassReloading">Live Class Reloading</h2><p>Main
Article: <a href="class-reloading.html">Class Reloading</a></p><p>Component
classes are monitored for changes by the framework. <a
href="class-reloading.html">Classes are reloaded when changed</a>. This allows
you to build your application with a speed approaching that of a scripting
environment, without sacrificing any of the power of the Java
platform.</p><p>And it's fast! You won't even notice that this magic class
reloading has occurred.</p><p>The net result: super p
roductivity — change your class, see the change instantly. This is
designed to be a blend of the best of scripting environments (such as Python or
Ruby) with all the speed and power of Java backing it up.</p><p>However, class
reloading <em>only</em> applies to component classes (pages, components and
mixins) and, starting in 5.2, Tapestry IOC-based service implementations (with
some restrictions). Other classes, such as service interfaces, entity/model
classes, and other data objects, are loaded by the normal class loader and not
subject to live class reloading.</p><h2
id="ComponentClasses-InstanceVariables">Instance Variables</h2><p>Tapestry
components may have instance variables (unlike Tapestry 4, where you had to use
<em>abstract properties</em>).</p><p>Since release 5.3.2, instance variables
may be protected, or package private (that is, no access modifier). Under
specific circumstances they may even be public (public fields must either be
final, or have the @<a class="e
xternal-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Retain.html">Retain</a> annotation).</p><p><span
style="line-height: 1.4285715;">Be aware that you will need to either provide
getter and setter methods to access your classes' instance variables, or else
annotate the fields with</span><span style="line-height:
1.4285715;"> @</span><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Property.html"
style="line-height: 1.4285715;">Property</a>.</p><h2
id="ComponentClasses-TransientInstanceVariables">Transient Instance
Variables</h2><p>Unless an instance variable is decorated with an annotation,
it will be a <em>transient</em> instance variable. This means that its value
resets to its default value at the end of reach request (when the <a
href="page-life-cycle.html">page is detached from the request</a>).</p><div
class="confluence-information-macro confluence-information-macr
o-note"><p class="title">About initialization</p><span class="aui-icon
aui-icon-small aui-iconfont-warning
confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>Never initialize an instance field
to a <em>mutable</em> object at the point of declaration. If this is done, the
instance created from that initializer becomes the default value for that field
and is reused inside the component on every request. This could cause state to
inadvertently be shared between different sessions in an
application.</p></div></div>
+</div></div><p>In this example, just like the first one, the component's only
job is to write out a fixed message. The @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/BeginRender.html">BeginRender</a>
annotation is a type of <em><a href="component-classes.html">render phase
annotation</a></em>, a method annotation that instructs Tapestry when and under
what circumstances to invoke methods of your class.</p><p>These methods are not
necessarily public; they can have any access level you like (unlike in Tapestry
4). By convention they usually have package-private access level (the
default).</p><h2 id="ComponentClasses-ComponentPackages">Component
Packages</h2><p>Component classes must exist within an appropriate package
(this is necessary for runtime code transformation and class reloading to
operate).</p><p>These packages exist under the application's root package, as
follows:</p><ul><li>For pages, place classes in <em>root
</em>.<strong>pages</strong>. Page names are mapped to classes within this
package.</li><li>For mixins, place classes in
<em>root</em>.<strong>mixins</strong>. Mixin types are mapped to classes within
this package.</li><li>For other components, place classes in
<em>root</em>.<strong>components</strong>. Component types are mapped to
classes within this package.</li></ul><p>In addition, it is common for an
application to have base classes, often <em>abstract</em> base classes, that
should not be directly referenced. These should <em>not</em> go in the
<strong>pages</strong>, <strong>components</strong> or <strong>mixins</strong>
packages, because they then look like valid pages, components or mixins.
Instead, use the <em>root</em>.<strong>base</strong> package to store such base
classes.</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="conflue
nce-information-macro-body"><p>Only component classes should go in any of
these controlled packages; classes representing data, or interfaces, or
anything that isn't precisely a component class, must go elsewhere. Any
top-level class in any of the controlled packages will be transformed at
runtime. The only exception is inner classes (anonymous or not), which are
loaded by the same class loader as the component class loader, but not
transformed as components.</p></div></div><h2
id="ComponentClasses-Sub-Folders/Sub-Packages">Sub-Folders /
Sub-Packages</h2><p>Classes do not have to go directly inside the package
(pages, components, mixins, etc.). It is valid to create a sub-package to store
some of the classes. The sub-package name becomes part of the page name or
component type. Thus you might define a page component
<code>com.example.myapp.pages.admin.CreateUser</code> and the logical page name
(which often shows up inside URLs) will be
<strong>admin/CreateUser</strong>.</p><p>Tapes
try performs some simple optimizations of the logical page name (or component
type, or mixin type). It checks to see if the package name is either a prefix
or a suffix of the unqualified class name (case insensitively, of course) and
removes the prefix or suffix if so. The net result is that a class name such as
<code>com.example.myapp.pages.user.EditUser</code> will have a page name of
<code>user/Edit</code> (instead of user<code>/EditUser</code>). The goal here
is to provide shorter, more natural URLs.</p><h2
id="ComponentClasses-IndexPages">Index Pages</h2><p>One special simplification
exists for Index pages: if the logical page name is Index after removing the
package name from the unqualified class name, it will map to the root of that
folder. A class such as <code>com.example.myapp.pages.user.IndexUser</code> or
<code>com.example.myapp.pages.user.UserIndex</code> will have a page name of
<code>user/</code>.</p><p>In previous versions of Tapestry there was also the
concept of a
start page configured with the <code><a
href="component-classes.html">tapestry.start-page-name</a></code> configuration
symbol (defaults to "start"). If a page with a name as configured with that
symbol exists at the root level, this page is used as the root URL. This has
precedence over an existing Index page. If for example you have a page class
<code>com.example.myapp.pages.Start</code> it will map to
<code>/</code>.</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>Use of start-pages is discouraged
and support for it will eventually be removed. Use an Index page
instead.</p></div></div><h2 id="ComponentClasses-Pagesvs.Components">Pages vs.
Components</h2><p>The distinction between pages and component is very, very
small. The primary difference is the package name:
<em>root</em>.<strong>pages</strong>
.<em>PageName</em> for pages, and
<em>root</em>.<strong>components</strong>.<em>ComponentType</em> for
components. Conceptually, page components are simply the <em>root
component</em> of a page's component tree.</p><p><em>For Tapestry 4 users:
there was a much greater distinction in Tapestry 4 between pages and
components, which showed up as separate interfaces and a hierarchy of abstract
implementations to extend your classes from.</em></p><h2
id="ComponentClasses-ClassTransformation">Class Transformation</h2><p>Tapestry
uses your class as a starting point. It <em>transforms</em> your class at
runtime. This is necessary for a number of reasons, including to address how
Tapestry shares pages between requests.</p><p>For the most part, these
transformations are both sensible and invisible. In a few limited cases, they
comprise a marginally <a class="external-link"
href="http://www.joelonsoftware.com/printerFriendly/articles/LeakyAbstractions.html"
rel="nofollow">leaky abstractio
n</a> – for instance, the scope restrictions on instance variables
described below – but the programming model in general supports a very
high level of developer productivity.</p><p>Because transformation doesn't
occur until <em>runtime</em>, the build stage of your application is not
affected by the fact that you are creating a Tapestry application. Further,
your classes are absolutely simple POJOs during unit testing.</p><h2
id="ComponentClasses-LiveClassReloading">Live Class Reloading</h2><p>Main
Article: <a href="component-classes.html">Component
Classes</a></p><p>Component classes are monitored for changes by the framework.
<a href="component-classes.html">Classes are reloaded when changed</a>. This
allows you to build your application with a speed approaching that of a
scripting environment, without sacrificing any of the power of the Java
platform.</p><p>And it's fast! You won't even notice that this magic class
reloading has occurred.</p><p>The net result:
super productivity — change your class, see the change instantly. This
is designed to be a blend of the best of scripting environments (such as Python
or Ruby) with all the speed and power of Java backing it up.</p><p>However,
class reloading <em>only</em> applies to component classes (pages, components
and mixins) and, starting in 5.2, Tapestry IOC-based service implementations
(with some restrictions). Other classes, such as service interfaces,
entity/model classes, and other data objects, are loaded by the normal class
loader and not subject to live class reloading.</p><h2
id="ComponentClasses-InstanceVariables">Instance Variables</h2><p>Tapestry
components may have instance variables (unlike Tapestry 4, where you had to use
<em>abstract properties</em>).</p><p>Since release 5.3.2, instance variables
may be protected, or package private (that is, no access modifier). Under
specific circumstances they may even be public (public fields must either be
final, or have the @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Retain.html">Retain</a> annotation).</p><p><span>Be
aware that you will need to either provide getter and setter methods to access
your classes' instance variables, or else annotate the fields
with</span><span> @</span><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Property.html">Property</a>.</p><h2
id="ComponentClasses-TransientInstanceVariables">Transient Instance
Variables</h2><p>Unless an instance variable is decorated with an annotation,
it will be a <em>transient</em> instance variable. This means that its value
resets to its default value at the end of reach request (when the <a
href="component-classes.html">page is detached from the request</a>).</p><div
class="confluence-information-macro confluence-information-macro-note"><p
class="title">About initialization</p><span class="aui-icon aui-icon-small
aui-iconfont-warning confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>Never initialize an instance field
to a <em>mutable</em> object at the point of declaration. If this is done, the
instance created from that initializer becomes the default value for that field
and is reused inside the component on every request. This could cause state to
inadvertently be shared between different sessions in an
application.</p></div></div>
<div class="confluence-information-macro
confluence-information-macro-warning"><p class="title">Deprecated since
5.2</p><span class="aui-icon aui-icon-small aui-iconfont-error
confluence-information-macro-icon"></span><div
class="confluence-information-macro-body">
</div></div>
<div class="error"><span class="error">Unknown macro: {div}</span>
<p>For Tapestry 5.1 and earlier, in the rare event that you have a variable
that can keep its value between requests and you would like to defeat that
reset logic, then you can add a @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Retain.html">Retain</a>
annotation to the field. You should take care that no client-specific data is
stored into such a field, since on a later request the same page
<em>instance</em> may be used for a different user. Likewise, on a later
request for the <em>same</em> client, a <em>different</em> page instance may be
used.</p>
-</div><p>Use <a href="persistent-page-data.html">persistent fields</a> to
hold client-specific information from one request to the next.</p><p>Further,
final fields are (in fact) final, and will not be reset between
requests.</p><h2
id="ComponentClasses-Constructors">Constructors</h2><p>Tapestry will
instantiate your class using the default, no arguments constructor. Other
constructors will be ignored.</p><h2
id="ComponentClasses-Injection">Injection</h2><p>Main Article: <a
href="injection.html">Injection</a></p><p>Injection of dependencies occurs at
the field level, via additional annotations. At runtime, fields that contain
injections become read-only.</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div><p>Use <a href="component-classes.html">persistent fields</a> to hold
client-specific information from one request to the next.</p><p>Further, final
fields are (in fact) final, and will not be reset between requests.</p><h2
id="ComponentClasses-Constructors">Constructors</h2><p>Tapestry will
instantiate your class using the default, no arguments constructor. Other
constructors will be ignored.</p><h2
id="ComponentClasses-Injection">Injection</h2><p>Main Article: <a
href="component-classes.html">Component Classes</a></p><p>Injection of
dependencies occurs at the field level, via additional annotations. At runtime,
fields that contain injections become read-only.</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;">@Inject // inject a resource
private ComponentResources componentResources;
@@ -191,7 +191,7 @@ private Asset banner;
@Inject // inject a service
private AjaxResponseRenderer ajaxResponseRenderer;
</pre>
-</div></div><h2 id="ComponentClasses-Parameters">Parameters</h2><p>Main
Article: <a href="component-parameters.html">Component
Parameters</a></p><p>Component parameters are private fields of your component
class annotated with @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Parameter.html">Parameter</a>.
Component parameters represent a two-way binding of a field of your component
and a property or resource of its containing component or page.</p><h2
id="ComponentClasses-PersistentFields">Persistent Fields</h2><p>Main Article:
<a href="persistent-page-data.html">Persistent Page Data</a></p><p>Most fields
in component classes are automatically cleared at the end of each request.
However, fields may be annotated so that they retain their value across
requests, using the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Persist.html">Persist</a>
annotation.</p><h2 i
d="ComponentClasses-Embedded_ComponentsEmbeddedComponents"><span
class="confluence-anchor-link"
id="ComponentClasses-Embedded_Components"></span>Embedded
Components</h2><p>Components often contain other components. Components inside
another component's template are called <em>embedded components</em>. The
containing component's <a href="component-templates.html">template</a> will
contain special elements, in the Tapestry namespace, identifying where the the
embedded components go.</p><p>You can define the type of component inside
template, or you can create an instance variable for the component and use the
@<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Component.html">Component</a>
annotation to define the component type and parameters.</p><p>Example:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+</div></div><h2 id="ComponentClasses-Parameters">Parameters</h2><p>Main
Article: <a href="component-classes.html">Component
Classes</a></p><p>Component parameters are private fields of your component
class annotated with @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Parameter.html">Parameter</a>.
Component parameters represent a two-way binding of a field of your component
and a property or resource of its containing component or page.</p><h2
id="ComponentClasses-PersistentFields">Persistent Fields</h2><p>Main Article:
<a href="component-classes.html">Component Classes</a></p><p>Most fields in
component classes are automatically cleared at the end of each request.
However, fields may be annotated so that they retain their value across
requests, using the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Persist.html">Persist</a>
annotation.</p><h2 id="Component
Classes-Embedded_ComponentsEmbeddedComponents"><span
class="confluence-anchor-link"
id="ComponentClasses-Embedded_Components"></span>Embedded
Components</h2><p>Components often contain other components. Components inside
another component's template are called <em>embedded components</em>. The
containing component's <a href="component-classes.html">template</a> will
contain special elements, in the Tapestry namespace, identifying where the the
embedded components go.</p><p>You can define the type of component inside
template, or you can create an instance variable for the component and use the
@<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Component.html">Component</a>
annotation to define the component type and parameters.</p><p>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;">package org.example.app.pages;
import org.apache.tapestry5.annotations.Component;
Modified: websites/production/tapestry/content/component-events.html
==============================================================================
--- websites/production/tapestry/content/component-events.html (original)
+++ websites/production/tapestry/content/component-events.html Sat Feb 3
16:21:22 2018
@@ -154,7 +154,7 @@
</div>
</t:loop>
</pre>
-</div></div><p>Notice that Review.tml contains an ActionLink component in a
loop. For each rendering within the loop, the ActionLink component creates a
component event request URL, with the event type set to "action". In this case,
each URL might look like:</p><p><code><span
class="external-link">   
http://localhost:8080/review.edit/3</span></code></p><p>This URL identifies the
<strong>page</strong> that contains the component ("review"),
the <strong>Component id</strong> of the component within the page
("edit"), and the <strong>context</strong> value ("3", the "id" property of the
document). <em>Additional context values, if any, are appended to the
path.</em> (The URL may also contain the <strong>event name</strong>, unless,
as here, it is "action".)</p><p>There's no direct mapping from URL to a piece
of code. Instead, when the user clicks on the link, the ActionLink component
triggers events. And then Tapestry ensures that the correct bits of code (your
eve
nt handler method, see below) get invoked for those events.</p><p>This
demonstrates a critical difference between Tapestry and a more traditional,
action oriented framework. The URL doesn't say what happens when the link is
clicked, it identifies <em>which component is responsible</em> when the link is
clicked.</p><p>Often, a navigation request (originating with the user) will
spawn a number of flow-of-control requests. For example, a form component may
trigger an action event, which will then trigger notification events to
announce when the form submission is about to be processed, and whether it was
successful or not, and those event could be further handled by the page
component.</p><h1 id="ComponentEvents-EventHandlerMethods">Event Handler
Methods</h1><p>When a component event occurs, Tapestry invokes any event
handler methods that you have identified for that event. You can identify your
event handler methods via a naming convention (see Method Naming Convention
below), or via
the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/OnEvent.html">OnEvent</a>
annotation.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+</div></div><p>Notice that Review.tml contains an ActionLink component in a
loop. For each rendering within the loop, the ActionLink component creates a
component event request URL, with the event type set to "action". In this case,
each URL might look like:</p><p><code><span
class="external-link">    <a class="external-link"
href="http://localhost:8080/review.edit/3"
rel="nofollow">http://localhost:8080/review.edit/3</a></span></code></p><p>This
URL identifies the <strong>page</strong> that contains the component
("review"), the <strong>Component id</strong> of the component within the
page ("edit"), and the <strong>context</strong> value ("3", the "id" property
of the document). <em>Additional context values, if any, are appended to the
path.</em> (The URL may also contain the <strong>event name</strong>, unless,
as here, it is "action".)</p><p>There's no direct mapping from URL to a piece
of code. Instead, when the user clicks on the link, the ActionLink comp
onent triggers events. And then Tapestry ensures that the correct bits of code
(your event handler method, see below) get invoked for those events.</p><p>This
demonstrates a critical difference between Tapestry and a more traditional,
action oriented framework. The URL doesn't say what happens when the link is
clicked, it identifies <em>which component is responsible</em> when the link is
clicked.</p><p>Often, a navigation request (originating with the user) will
spawn a number of flow-of-control requests. For example, a form component may
trigger an action event, which will then trigger notification events to
announce when the form submission is about to be processed, and whether it was
successful or not, and those event could be further handled by the page
component.</p><h1 id="ComponentEvents-EventHandlerMethods">Event Handler
Methods</h1><p>When a component event occurs, Tapestry invokes any event
handler methods that you have identified for that event. You can identify your
eve
nt handler methods via a naming convention (see Method Naming Convention
below), or via the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/OnEvent.html">OnEvent</a>
annotation.</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;">@OnEvent(component="edit")
void editDocument(int docId)
{
@@ -187,7 +187,7 @@ void editDocument(int docId)
// do something with the document here
}
</pre>
-</div></div><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>Many people prefer the naming
convention approach, reserving the annotation just for situations that don't
otherwise fit.</p></div></div><h2
id="ComponentEvents-MethodReturnValues">Method Return Values</h2><p>Main
Article: <a href="page-navigation.html">Page Navigation</a></p><p>For page
navigation events (originating in components such as EventLink, ActionLink and
Form), the value returned from an event handler method determines how Tapestry
will render a response.</p><ul><li><strong>Null</strong>: For no value, or
null, the current page (the page containing the component) will render the
response.</li><li><strong>Page</strong>: For the name of a page, or a page
class or page instance, a render request URL will be constructed and sent to
the c
lient as a redirect to that page.</li><li><strong>URL</strong>: For a
java.net.URL, a redirect will be sent to the client. (In Tapestry 5.3.x and
earlier, this only works for non-Ajax requests.)</li><li><strong>Zone
body</strong>: In the case of an Ajax request to update a zone, the component
event handler will return the new zone body, typically via an injected
component or block.</li><li><strong>HttpError</strong>: For an <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html">HttpError</a>,
an error response is sent to the client.</li><li><strong>Link</strong>: For a
<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html">Link</a>,
a redirect is sent to the client.</li><li><strong>Stream</strong>: For a <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/StreamResponse.html">StreamResponse</a>,
a stream of data is sent to
the client</li><li><strong>boolean:</strong> <em>true</em> prevents the event
from bubbling up further; <em>false</em> lets it bubble up. See Event Bubbling,
below.</li></ul><p>See <a href="page-navigation.html">Page Navigation</a> for
more details.</p><h2 id="ComponentEvents-MultipleMethodMatches">Multiple Method
Matches</h2><p>In some cases, there may be multiple event handler methods
matching a single event. In that case, Tapestry invokes them in the following
order:</p><ul><li>Base class methods before sub-class methods.</li><li>Matching
methods within a class in alphabetical order.</li><li>For a single method name
with multiple overrides, by number of parameters, descending.</li></ul><p>Of
course, ordinarily would you <em>not</em> want to create more than one method
to handle an event.</p><p>When a sub-class overrides an event handler method of
a base class, the event handler method is only invoked once, along with any
other base class methods. The subclass can change the <em>
implementation</em> of the base class method via an override, but can't change
the <em>timing</em> of when that method is invoked. See <a
class="external-link"
href="https://issues.apache.org/jira/browse/TAP5-51">issue TAP5-51</a>.</p><h2
id="ComponentEvents-EventContext">Event Context</h2><p>The context values (the
context parameter to the EventLink or ActionLink component) can be any object.
However, only a simple conversion to string occurs. (This is in contrast to
Tapestry 4, which had an elaborate type mechanism with the odd name
"DataSqueezer".)</p><p>Again, whatever your value is (string, number, date), it
is converted into a plain string. This results in a more readable URL.</p><p>If
you have multiple context values (by binding a list or array of objects to the
<em>context</em> parameter of the EventLink or ActionLink), then each one, in
order, will be added to the URL.</p><p>When an event handler method is invoked,
the strings are converted back into values, or even object
s. A <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a>
is used to convert between client-side strings and server-side objects. The <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ValueEncoderSource.html">ValueEncoderSource</a>
service provides the necessary value encoders.</p><p>As shown in the example
above, most of the parameters passed to the event handler method are derived
from the values provided in the event context. Each successive method parameter
matches against a value provided in the event context (the context parameter of
the ActionLink component; though many components have a similar context
parameter).</p><p>In many cases it is helpful to have direct access to the
context (for example, to adapt to cases where there are a variable number of
context values). The context values may be passed to an event handler method as
parameter of
the following types:</p><ul><li><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/EventContext.html">EventContext</a></li><li>Object[]</li><li>List<Object></li></ul><p>The
latter two should be avoided, they may be removed in a future release. In all
of these cases, the context parameter acts as a freebie; it doesn't match
against a context value as it represents <em>all</em> context values.</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeContent
panelContent pdl">
+</div></div><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>Many people prefer the naming
convention approach, reserving the annotation just for situations that don't
otherwise fit.</p></div></div><h2
id="ComponentEvents-MethodReturnValues">Method Return Values</h2><p>Main
Article: <a href="component-events.html">Component Events</a></p><p>For page
navigation events (originating in components such as EventLink, ActionLink and
Form), the value returned from an event handler method determines how Tapestry
will render a response.</p><ul><li><strong>Null</strong>: For no value, or
null, the current page (the page containing the component) will render the
response.</li><li><strong>Page</strong>: For the name of a page, or a page
class or page instance, a render request URL will be constructed and sent to the
client as a redirect to that page.</li><li><strong>URL</strong>: For a <a
class="external-link" href="http://java.net" rel="nofollow">java.net</a>.URL, a
redirect will be sent to the client. (In Tapestry 5.3.x and earlier, this only
works for non-Ajax requests.)</li><li><strong>Zone body</strong>: In the case
of an Ajax request to update a zone, the component event handler will return
the new zone body, typically via an injected component or
block.</li><li><strong>HttpError</strong>: For an <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/HttpError.html">HttpError</a>,
an error response is sent to the client.</li><li><strong>Link</strong>: For a
<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/Link.html">Link</a>,
a redirect is sent to the client.</li><li><strong>Stream</strong>: For a <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5
/StreamResponse.html">StreamResponse</a>, a stream of data is sent to the
client</li><li><strong>boolean:</strong> <em>true</em> prevents the event from
bubbling up further; <em>false</em> lets it bubble up. See Event Bubbling,
below.</li></ul><p>See <a href="component-events.html">Component Events</a>
for more details.</p><h2 id="ComponentEvents-MultipleMethodMatches">Multiple
Method Matches</h2><p>In some cases, there may be multiple event handler
methods matching a single event. In that case, Tapestry invokes them in the
following order:</p><ul><li>Base class methods before sub-class
methods.</li><li>Matching methods within a class in alphabetical
order.</li><li>For a single method name with multiple overrides, by number of
parameters, descending.</li></ul><p>Of course, ordinarily would you
<em>not</em> want to create more than one method to handle an event.</p><p>When
a sub-class overrides an event handler method of a base class, the event
handler method is only invoked once, a
long with any other base class methods. The subclass can change the
<em>implementation</em> of the base class method via an override, but can't
change the <em>timing</em> of when that method is invoked. See <a
class="external-link"
href="https://issues.apache.org/jira/browse/TAP5-51">issue TAP5-51</a>.</p><h2
id="ComponentEvents-EventContext">Event Context</h2><p>The context values (the
context parameter to the EventLink or ActionLink component) can be any object.
However, only a simple conversion to string occurs. (This is in contrast to
Tapestry 4, which had an elaborate type mechanism with the odd name
"DataSqueezer".)</p><p>Again, whatever your value is (string, number, date), it
is converted into a plain string. This results in a more readable URL.</p><p>If
you have multiple context values (by binding a list or array of objects to the
<em>context</em> parameter of the EventLink or ActionLink), then each one, in
order, will be added to the URL.</p><p>When an event handler metho
d is invoked, the strings are converted back into values, or even objects. A
<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a>
is used to convert between client-side strings and server-side objects. The <a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ValueEncoderSource.html">ValueEncoderSource</a>
service provides the necessary value encoders.</p><p>As shown in the example
above, most of the parameters passed to the event handler method are derived
from the values provided in the event context. Each successive method parameter
matches against a value provided in the event context (the context parameter of
the ActionLink component; though many components have a similar context
parameter).</p><p>In many cases it is helpful to have direct access to the
context (for example, to adapt to cases where there are a variable number of
context values). The
context values may be passed to an event handler method as parameter of the
following types:</p><ul><li><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/EventContext.html">EventContext</a></li><li>Object[]</li><li>List<Object></li></ul><p>The
latter two should be avoided, they may be removed in a future release. In all
of these cases, the context parameter acts as a freebie; it doesn't match
against a context value as it represents <em>all</em> context values.</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;">Object onActionFromEdit(EventContext context)
{
if (context.getCount() > 0) {
@@ -198,7 +198,7 @@ void editDocument(int docId)
return null;
}
}</pre>
-</div></div><h2 id="ComponentEvents-AccessingRequestQueryParameters">Accessing
Request Query Parameters</h2><p>A parameter may be annotated with the
@RequestParameter annotation; this allows query parameters
(?name1=value1&name2=value2, etc) to be extracted from the request,
converted to the correct type, and passed to the method. Again, this doesn't
count against the event context values.</p><p>See the example in the <a
href="link-components-faq.html">Link Components FAQ</a>.</p><h2
id="ComponentEvents-MethodMatching">Method Matching</h2><p>An event handler
method will only be invoked <em>if the context contains at least as many values
as the method has parameters</em>. Methods with too many parameters will be
silently skipped.</p><p>Tapestry will silently skip over a method if there are
insufficient values in the context to satisfy the number of parameters
requested.</p><p>EventContext parameters, and parameters annotated with
@RequestParameter, do not count against this limi
t.</p><h2 id="ComponentEvents-MethodOrdering">Method Ordering</h2><p>When
multiple methods match within the same class, Tapestry will invoke them in
ascending alphabetical order. When there are multiple overrides of the same
method name, Tapestry invokes them in descending order by number of parameters.
In general, these situations don't happen ... in most cases, only a single
method is required to handle a specific event form a specific
component.</p><p>An event handler method may return the value <code>true</code>
to indicate that the event has been handled; this immediately stops the search
for additional methods in the same class (or in base classes) or in containing
components.</p><h1 id="ComponentEvents-EventBubbling">Event Bubbling</h1><p>The
event will bubble up the component hierarchy, first to the containing
component, then <em>that</em> component's containing component or page, and so
on, until it is <em>aborted</em> by an event handler method returning
<em>true</em> or a
non-null value.</p><p>Returning a boolean value from an event handler method
is special. Returning <em>true</em> will abort the event with no result; use
this when the event is fully handled without a return value and no further
event handlers (in the same component, or in containing components) should be
invoked.</p><p>Returning <em>false</em> is the same as returning null; event
processing will continue to look for more event handlers, in the same component
or its parent.</p><p>When an event bubbles up from a component to its
container, the origin of the event is changed to be the component. For example,
a Form component inside a BeanEditForm component may trigger a success event.
The page containing the BeanEditForm may listen for that event, but it will be
from the BeanEditForm component (which makes sense, because the id of the Form
inside the BeanEditForm is part of the BeanEditForm's implementation, not its
public interface).</p><p>If you want to handle events that have bubb
led up from nested component, you'll soon find that you don't have easy access
to the component ID of the firing component. In practical terms this means that
you'll want to trigger custom events for the events triggered by those nested
components (see Triggering Events, below), and use that custom event name in
your event handler method.</p><h1
id="ComponentEvents-EventMethodExceptions">Event Method Exceptions</h1><p>Event
methods are allowed to throw any exception (not just runtime exceptions). If an
event method does throw an exception, Tapestry will catch the thrown exception
and ultimately display the exception report page.</p><p>In other words, there's
no need to do this:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+</div></div><h2 id="ComponentEvents-AccessingRequestQueryParameters">Accessing
Request Query Parameters</h2><p>A parameter may be annotated with the
@RequestParameter annotation; this allows query parameters
(?name1=value1&name2=value2, etc) to be extracted from the request,
converted to the correct type, and passed to the method. Again, this doesn't
count against the event context values.</p><p>See the example in the <a
href="component-events.html">Component Events</a>.</p><h2
id="ComponentEvents-MethodMatching">Method Matching</h2><p>An event handler
method will only be invoked <em>if the context contains at least as many values
as the method has parameters</em>. Methods with too many parameters will be
silently skipped.</p><p>Tapestry will silently skip over a method if there are
insufficient values in the context to satisfy the number of parameters
requested.</p><p>EventContext parameters, and parameters annotated with
@RequestParameter, do not count against this limit.</p>
<h2 id="ComponentEvents-MethodOrdering">Method Ordering</h2><p>When multiple
methods match within the same class, Tapestry will invoke them in ascending
alphabetical order. When there are multiple overrides of the same method name,
Tapestry invokes them in descending order by number of parameters. In general,
these situations don't happen ... in most cases, only a single method is
required to handle a specific event form a specific component.</p><p>An event
handler method may return the value <code>true</code> to indicate that the
event has been handled; this immediately stops the search for additional
methods in the same class (or in base classes) or in containing
components.</p><h1 id="ComponentEvents-EventBubbling">Event Bubbling</h1><p>The
event will bubble up the component hierarchy, first to the containing
component, then <em>that</em> component's containing component or page, and so
on, until it is <em>aborted</em> by an event handler method returning
<em>true</em> or a non-n
ull value.</p><p>Returning a boolean value from an event handler method is
special. Returning <em>true</em> will abort the event with no result; use this
when the event is fully handled without a return value and no further event
handlers (in the same component, or in containing components) should be
invoked.</p><p>Returning <em>false</em> is the same as returning null; event
processing will continue to look for more event handlers, in the same component
or its parent.</p><p>When an event bubbles up from a component to its
container, the origin of the event is changed to be the component. For example,
a Form component inside a BeanEditForm component may trigger a success event.
The page containing the BeanEditForm may listen for that event, but it will be
from the BeanEditForm component (which makes sense, because the id of the Form
inside the BeanEditForm is part of the BeanEditForm's implementation, not its
public interface).</p><p>If you want to handle events that have bubbled up
from nested component, you'll soon find that you don't have easy access to
the component ID of the firing component. In practical terms this means that
you'll want to trigger custom events for the events triggered by those nested
components (see Triggering Events, below), and use that custom event name in
your event handler method.</p><h1
id="ComponentEvents-EventMethodExceptions">Event Method Exceptions</h1><p>Event
methods are allowed to throw any exception (not just runtime exceptions). If an
event method does throw an exception, Tapestry will catch the thrown exception
and ultimately display the exception report page.</p><p>In other words, there's
no need to do this:</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;"> void onActionFromRunQuery()
{
try
@@ -227,7 +227,7 @@ void editDocument(int docId)
return this;
}
</pre>
-</div></div><p>The return value of the exception event handler
<em>replaces</em> the return value of original event handler method. For the
typical case (an exception thrown by an "activate" or "action" event), this
will be a <a href="page-navigation.html">navigational response</a> such as a
page instance or page name.</p><p>This can be handy for handling cases where
the data in the URL is incorrectly formatted.</p><p>In the above example, the
navigational response is the page itself.</p><p>If there is no exception event
handler, or the exception event handler returns null (or is void), then the
exception will be passed to the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a>
service, which (in the default configuration) will render the exception
page.</p><h1 id="ComponentEvents-TriggeringEvents">Triggering
Events</h1><p></p><div class="navmenu" style="float:right; backg
round:#eee; margin:3px; padding:0 1em">
+</div></div><p>The return value of the exception event handler
<em>replaces</em> the return value of original event handler method. For the
typical case (an exception thrown by an "activate" or "action" event), this
will be a <a href="component-events.html">navigational response</a> such as a
page instance or page name.</p><p>This can be handy for handling cases where
the data in the URL is incorrectly formatted.</p><p>In the above example, the
navigational response is the page itself.</p><p>If there is no exception event
handler, or the exception event handler returns null (or is void), then the
exception will be passed to the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestExceptionHandler.html">RequestExceptionHandler</a>
service, which (in the default configuration) will render the exception
page.</p><h1 id="ComponentEvents-TriggeringEvents">Triggering
Events</h1><p></p><div class="navmenu" style="float:right; back
ground:#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/together/ajaxcomponentscrud/persons"
rel="nofollow">AJAX Components CRUD</a></p></div>If you want your own
component to trigger events, just call the <a rel="nofollow">triggerEvent</a>
method of <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ComponentResources.html">ComponentResources</a>
from within the component class.<p>For example, the following triggers an
"updateAll" event. A containing component can then respond to it, if desired,
with an "onUpdateAll()" method in its own component class.</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>Your component class
(partial)</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">@Inject
Modified: websites/production/tapestry/content/component-mixins.html
==============================================================================
--- websites/production/tapestry/content/component-mixins.html (original)
+++ websites/production/tapestry/content/component-mixins.html Sat Feb 3
16:21:22 2018
@@ -101,7 +101,7 @@
<span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
<div class="details">
- <a href="legacy-javascript.html">Legacy JavaScript</a>
+ <a href="component-templates.html">Component
Templates</a>
</div>
@@ -110,7 +110,7 @@
<span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
<div class="details">
- <a href="component-templates.html">Component
Templates</a>
+ <a href="legacy-javascript.html">Legacy JavaScript</a>
</div>
@@ -136,7 +136,7 @@
</div>
-<p>You can think of a mixin as a kind of mashup for a component; it combines
the new behavior of the mixin with the existing behavior of the component, and
bundles it all in one place. Mixins may be used to add specialized validation
to user input fields, dynamically modify the HTML output of a component, or to
add Ajax effects and behaviors of all sorts to components.</p><p>Tapestry comes
with several mixins, such as the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/mixins/Autocomplete.html">Autocomplete
mixin</a> which adds autocomplete behavior to an ordinary TextField Component.
In addition, you can easily create your own.</p><h2
id="ComponentMixins-MixinClasses">Mixin Classes</h2><p>Mixin classes are stored
in the <code>mixins</code> sub-package of your application, below the
application (or library) root package. This parallels where your component and
page classes are stored.</p><p>Other than that, mixin classes are th
e same as any other component class.</p><h2
id="ComponentMixins-MixinLimitations">Mixin Limitations</h2><p>Currently,
mixins are allowed to do anything a component can do, including having
parameters and render phase methods.</p><p>Mixins may not have a template. They
integrate with the component strictly in terms of invoking render phase
methods.</p><p>Mixins may have persistent fields, but currently, this is not
implemented perfectly (there is a potential for a name clash between a mixin
and the component or another mixin). Use persistent fields with mixins with
care ... or better yet, delegate persistence to the container using
parameters.</p><p>Mixins may not, themselves, have mixins.</p><h2
id="ComponentMixins-UsingMixins">Using Mixins</h2><p>Mixins are used in two
different scenarios: <em>Instance mixins</em> and <em>Implementation
mixins</em>.</p><h3 id="ComponentMixins-InstanceMixins">Instance
Mixins</h3><p>An instance mixin is a mixin applied to a specific
<em>instance</em>
of a component. This can be done in the <a
href="component-templates.html">component template</a> with the
<code>mixins</code> attribute of the component tag. This is a comma-separated
list of mixin names.</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+<p>You can think of a mixin as a kind of mashup for a component; it combines
the new behavior of the mixin with the existing behavior of the component, and
bundles it all in one place. Mixins may be used to add specialized validation
to user input fields, dynamically modify the HTML output of a component, or to
add Ajax effects and behaviors of all sorts to components.</p><p>Tapestry comes
with several mixins, such as the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/mixins/Autocomplete.html">Autocomplete
mixin</a> which adds autocomplete behavior to an ordinary TextField Component.
In addition, you can easily create your own.</p><h2
id="ComponentMixins-MixinClasses">Mixin Classes</h2><p>Mixin classes are stored
in the <code>mixins</code> sub-package of your application, below the
application (or library) root package. This parallels where your component and
page classes are stored.</p><p>Other than that, mixin classes are th
e same as any other component class.</p><h2
id="ComponentMixins-MixinLimitations">Mixin Limitations</h2><p>Currently,
mixins are allowed to do anything a component can do, including having
parameters and render phase methods.</p><p>Mixins may not have a template. They
integrate with the component strictly in terms of invoking render phase
methods.</p><p>Mixins may have persistent fields, but currently, this is not
implemented perfectly (there is a potential for a name clash between a mixin
and the component or another mixin). Use persistent fields with mixins with
care ... or better yet, delegate persistence to the container using
parameters.</p><p>Mixins may not, themselves, have mixins.</p><h2
id="ComponentMixins-UsingMixins">Using Mixins</h2><p>Mixins are used in two
different scenarios: <em>Instance mixins</em> and <em>Implementation
mixins</em>.</p><h3 id="ComponentMixins-InstanceMixins">Instance
Mixins</h3><p>An instance mixin is a mixin applied to a specific
<em>instance</em>
of a component. This can be done in the <a
href="component-mixins.html">component template</a> with the
<code>mixins</code> attribute of the component tag. This is a comma-separated
list of mixin names.</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
<pre class="brush: xml; gutter: false; theme: Default"
style="font-size:12px;"><t:textfield t:id="accountName"
t:mixins="Autocomplete,DefaultFromCookie" />
</pre>
</div></div><p>Alternately, when the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Component.html">Component</a>
annotation is used to define the component type, you may specify the mixins in
two ways:</p><ul><li>The @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/Mixins.html">Mixins</a>
annotation allows a list of mixin names to be specified.</li><li>The @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/MixinClasses.html">MixinClasses</a>
annotation allows a set of mixin classes to be specified
directly.</li></ul><p>The former is often less verbose, and allows core mixins
to be overridden with application-specific mixins. The later format is more
specific and more refactor-safe (renaming a mixin class will rename the entry
in the MixinClasses annotation as well).</p><p>Example:</p><div class="code pane
l pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
@@ -217,7 +217,7 @@ private TextField userId;
...
}
</pre>
-</div></div><p>"MyMixin" can be used on a textfield (principalObject is bound
to "value"), on BeanEditor or BeanDisplay (principalObject is bound to
"object"), or on Grid or Loop (principalObject is bound to "source").</p><h2
id="ComponentMixins-RenderPhaseOrdering">Render Phase Ordering</h2><p>All
mixins for a component execute their render phase methods <em>before</em> the
component's render phase methods for most phases. However, in the later phases
(AfterRender, CleanupRender) the order of executing is
reversed.</p><p>Exception: A mixins whose class is annotated with @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/MixinAfter.html">MixinAfter</a>
is ordered <em>after</em> the component, not before.</p><p>Withing a given
phase and class (@MixinAfter vs. mixin before), mixin ordering is determined by
the ordering constraints specified in the mixin definitions. The constraint
definitions follow the same conventions as <a
href="ordering-by-constraints.html">ordered service configurations</a>. How
you specify the constraints depends on how the mixin is specified.</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeHeader
panelHeader pdl" style="border-bottom-width: 1px;"><b>As an Implementation
Mixin</b></div><div class="codeContent panelContent pdl">
+</div></div><p>"MyMixin" can be used on a textfield (principalObject is bound
to "value"), on BeanEditor or BeanDisplay (principalObject is bound to
"object"), or on Grid or Loop (principalObject is bound to "source").</p><h2
id="ComponentMixins-RenderPhaseOrdering">Render Phase Ordering</h2><p>All
mixins for a component execute their render phase methods <em>before</em> the
component's render phase methods for most phases. However, in the later phases
(AfterRender, CleanupRender) the order of executing is
reversed.</p><p>Exception: A mixins whose class is annotated with @<a
class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/MixinAfter.html">MixinAfter</a>
is ordered <em>after</em> the component, not before.</p><p>Withing a given
phase and class (@MixinAfter vs. mixin before), mixin ordering is determined by
the ordering constraints specified in the mixin definitions. The constraint
definitions follow the same conventions as <a
href="component-mixins.html">ordered service configurations</a>. How you
specify the constraints depends on how the mixin is specified.</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeHeader
panelHeader pdl" style="border-bottom-width: 1px;"><b>As an Implementation
Mixin</b></div><div class="codeContent panelContent pdl">
<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">
@Mixin("Autocomplete",order={"before:DiscardBody","after:RenderDisabled"}
private TextField userId;
</pre>