Modified: websites/production/tapestry/content/security.html
==============================================================================
--- websites/production/tapestry/content/security.html (original)
+++ websites/production/tapestry/content/security.html Mon May 21 05:20:56 2018
@@ -86,11 +86,13 @@
+
+
<h3>Related Articles</h3>
<ul class="content-by-label"><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
<a href="security.html">Security</a>
@@ -99,7 +101,7 @@
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
<a
href="integrating-with-spring-framework.html">Integrating with Spring
Framework</a>
@@ -108,19 +110,19 @@
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a href="security-faq.html">Security FAQ</a>
+ <a href="https.html">HTTPS</a>
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a href="https.html">HTTPS</a>
+ <a href="security-faq.html">Security FAQ</a>
</div>
@@ -131,7 +133,7 @@
<p> </p><h2 id="Security-HTTPS-onlyPages">HTTPS-only Pages</h2><p>Main
Article: <a href="https.html">HTTPS</a></p><p>Tapestry provides several
annotations and configuration settings that you can use to <span>ensure
that all access to certain pages (or all pages) occurs only via the encrypted
HTTPS protocol</span><span>. See <a href="https.html">HTTPS</a> for
details.</span></p><h2 id="Security-ControllingPageAccess"><span>Controlling
Page Access</span></h2><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/infrastructure/protectingpages"
rel="nofollow">Protecting Pages</a></p></div><span>For simple access control
needs, you can contribute a <span><a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ComponentRequestFilter.html">ComponentRequestFilter</a>
with your custom logic that decides which pages should be accessed by which
users. The <a class="external-link"
href="https://tapestry-app.apache.org/hotels/">Tapestry Hotel Booking </a>app
demonstrates this approach with an <code>@AnonymousAccess</code> annotation
along with a ComponentRequestFilter
named <code>AuthenticationFilter.java</code>. The filter enforces security
by intercepting all requests to pages that don't have that annotation, and it
redirects those requests to the login page. <a class="external-link"
href="http://jumpstart.doublenegative.com.au/jumpstart/examples
/infrastructure/protectingpages" rel="nofollow">JumpStart</a> has a similar
demo.<br clear="none"></span></span><p><span>For more advanced needs see the
Security Framework Integration section below.</span></p><h2
id="Security-White-listedPages">White-listed Pages</h2><p>Pages whose component
classes are annotated with @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/WhitelistAccessOnly.html">WhitelistAccessOnly</a> will
only be displayed to users (clients) that are on the <em>whitelist</em>.
By default the whitelist consists only of clients whose fully-qualified domain
name is "localhost" (or the IP address equivalent, 127.0.0.1 or
0:0:0:0:0:0:0:1), but you can customize this by contributing to the
ClientWhitelist service in your application's module class (usually
AppModule.java):</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-
width: 1px;"><b>AppModule.java (partial) – simple inline
example</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> @Contribute(ClientWhitelist.class)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">
@Contribute(ClientWhitelist.class)
public static void
provideWhitelistAnalyzer(OrderedConfiguration<WhitelistAnalyzer>
configuration)
{
configuration.add("MyCustomAnalyzer", new WhitelistAnalyzer()
Modified: websites/production/tapestry/content/session-storage.html
==============================================================================
--- websites/production/tapestry/content/session-storage.html (original)
+++ websites/production/tapestry/content/session-storage.html Mon May 21
05:20:56 2018
@@ -86,11 +86,13 @@
+
+
<h3>Related Articles</h3>
<ul class="content-by-label"><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
<a href="performance-and-clustering.html">Performance
and Clustering</a>
@@ -99,19 +101,19 @@
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a href="session-storage.html">Session Storage</a>
+ <a href="persistent-page-data.html">Persistent Page
Data</a>
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a href="persistent-page-data.html">Persistent Page
Data</a>
+ <a href="session-storage.html">Session Storage</a>
</div>
@@ -122,11 +124,11 @@
<p>Ordinary <a href="persistent-page-data.html">page-persistent
fields</a></p><p>won't work for this, since persistent fields are available
only to a specific page, not shared across multiple pages.</p><p>Tapestry
provides two mechanisms for storing such data: Session State Objects and
Session Attributes. When deciding between the two, it's best to use Session
State Objects for complex objects, and Session Attributes for simple
types.</p><h2 id="SessionStorage-SessionStateObjects">Session State
Objects</h2><p>With a Session State Object (SSO), the value is automatically
stored outside the page; with the default storage strategy, it is stored in the
session. Such a value is global to all pages <em>for the same user</em>, but is
stored separately for different users.</p><p>A field holding an SSO is marked
with the @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SessionState.html">SessionState</a>
annotation.</p><div class="
navmenu" style="float:right; background:white; margin:3px; padding:3px">
<div class="panel" style="border-width: 1px;"><div class="panelHeader"
style="border-bottom-width: 1px;"><b>Contents</b></div><div
class="panelContent">
<style type="text/css">/*<![CDATA[*/
-div.rbtoc1523334086243 {padding: 0px;}
-div.rbtoc1523334086243 ul {list-style: disc;margin-left: 0px;}
-div.rbtoc1523334086243 li {margin-left: 0px;padding-left: 0px;}
+div.rbtoc1526880007280 {padding: 0px;}
+div.rbtoc1526880007280 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1526880007280 li {margin-left: 0px;padding-left: 0px;}
-/*]]>*/</style><div class="toc-macro rbtoc1523334086243">
+/*]]>*/</style><div class="toc-macro rbtoc1526880007280">
<ul class="toc-indentation"><li>Related Articles</li></ul>
<ul><li><a href="#SessionStorage-SessionStateObjects">Session State
Objects</a>
<ul class="toc-indentation"><li><a
href="#SessionStorage-Pitfalls">Pitfalls</a></li><li><a
href="#SessionStorage-CheckforCreation">Check for Creation</a></li><li><a
href="#SessionStorage-PersistenceStrategies">Persistence
Strategies</a></li><li><a href="#SessionStorage-ConfiguringSSOs">Configuring
SSOs</a></li></ul>
@@ -137,7 +139,7 @@ div.rbtoc1523334086243 li {margin-left:
</li><li><a href="#SessionStorage-SessionLocking">Session
Locking</a></li></ul>
</div>
</div></div></div>Example:<div class="code panel pdl" style="border-width:
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>MyPage.java (partial)</b></div><div class="codeContent panelContent
pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">public class MyPage
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">public class MyPage
{
@SessionState
private ShoppingCart shoppingCart;
@@ -146,7 +148,7 @@ div.rbtoc1523334086243 li {margin-left:
}
</pre>
</div></div><p>Any other component or page that declares a field <strong>of
the same type</strong>, regardless of name, and marks it with the SessionState
annotation will share the same value. It's that simple. However, using
@SessionState <em>safely</em> requires care:</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>DO NOT USE @SessionState FOR
SIMPLE TYPES! Only use it on variables that are of a custom-built class
designed expressly for this purpose! <strong>See the Pitfalls section
below</strong>.</p></div></div><p>The first time you access an SSO, it is
created automatically. Typically, the SSO will have a public no-args
constructor ... but you may inject dependencies into the SSO via its
constructor, as you can with a Tapestry IoC service
implementation.</p><p><em>For Tapestry 4 Users:</em> a big ch
ange here is that you don't need to provide any configuration for the SSO
before using it, nor do you provide a logical name. Tapestry 5 uses the class
name to identify the SSO, so there's no need for a logical
name.</p><p>Assigning a value to an SSO field will store that value. Assigning
null to an SSO field will remove the SSO (reading the field subsequently will
force a new SSO instance to be created).</p><h3
id="SessionStorage-Pitfalls">Pitfalls</h3><p>With @SessionState, you are
creating a session-wide data storage area that is tied to the <em>type</em>
(class) of the variable you annotate. It is not specifically tied to the
variable itself, or even to the class in which that variable was annotated. As
with all session data, there is the serious possibility of collisions, not just
within your application but with other modules/libraries:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>Example
of Data Collision – Don't Do This!</b></div><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> @SessionState
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> @SessionState
private String userName; // Unsafe -- String is not a custom type
... then, later in this class or any other:
@@ -155,14 +157,14 @@ div.rbtoc1523334086243 li {margin-left:
private String userCity; // This overwrites value in userName, because
it's also a String!
</pre>
</div></div><p>The simple rule is, NEVER use @SessionState for simple-type
variables. It is ALWAYS worth taking the time to build a special class to hold
your session state information. Doing so will force you to consolidate that
information into a single, logical unit that can't be accidentally accessed by
other classes. (Alternatively, see the Session Attribute section below.)</p><h3
id="SessionStorage-CheckforCreation">Check for Creation</h3><p>Scalable web
applications do not create the server-side session needlessly. If you can avoid
creating the session, especially on first access to your web application, you
will be able to handle an order of magnitude more users. So, if you can avoid
creating the SSO, you should do so.</p><p>But how to avoid creating it? Simply
checking ("shoppingCart!= null") will force the creation of the SSO and the
session to store it in.</p><p>Instead, create a second field with a matching
name but with "Exists" appended:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> private boolean shoppingCartExists;
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> private boolean
shoppingCartExists;
</pre>
</div></div><p>It is not annotated; it is located by naming convention
("Exists" appended). It must be type boolean and must be a private instance
variable. Tapestry will automatically set this variable to <code>true</code>
when the SSO is created, so you can check it to see if the SSO already
exists.</p><p>Alternately, you may allow for the state being null:</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;"> @SessionState(create=false)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">
@SessionState(create=false)
private ShoppingCart shoppingCart;
</pre>
</div></div><p>In this case, the shoppingCart field will be null if the
ShoppingCart SSO does not exist, but will be non-null if it has been created
(either by assigning a value to the field, or by a different SSO field where
create is true).</p><h3 id="SessionStorage-PersistenceStrategies">Persistence
Strategies</h3><p>Main Article: <a
href="persistent-page-data.html">PersistentPage</a></p><p>Each SSO is managed
according to a persistence strategy. The default persistence strategy,
"session", stores the SSOs inside the session. The session is created as
needed.</p><h3 id="SessionStorage-ConfiguringSSOs">Configuring
SSOs</h3><p>Generally, you will need to configure your Session State Object if
you want to change the persistence strategy to other than the default. (Right
now there's only one built in strategy, but more will be coming in the
future.)</p><p>Alternately, you can configure a Session State Object in order
to control how it is instantiated. You may need to inject some val
ues into the SSO when it is first created, or otherwise initialize it. In this
case, you may provide an <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/ApplicationStateCreator.html">ApplicationStateCreator</a>
object, which will be called upon to create the SSO as necessary. This is also
the technique to use when you want your SSO to be represented by an
<em>interface</em> rather than a <em>class</em>: you need to provide a creator
that knows about the class that implements the interface.</p><p>A Session State
Object is configured using contributions to the ApplicationStateManager
service. From your application's module:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public void
contributeApplicationStateManager(MappedConfiguration<Class,
ApplicationStateContribution> configuration)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> public void
contributeApplicationStateManager(MappedConfiguration<Class,
ApplicationStateContribution> configuration)
{
ApplicationStateCreator<MyState> creator = new
ApplicationStateCreator<ShoppingCart>()
{
@@ -182,7 +184,7 @@ div.rbtoc1523334086243 li {margin-left:
</div><p>As an alternative to SSOs, Tapestry provides a <strong>Session
Attribute</strong> mechanism, which lets you store data in the session by name
(rather than type). It is particularly useful when integrating Tapestry with
legacy applications that directly manipulate the HttpSession.</p><div
class="code panel pdl" style="border-width: 1px;"><div class="codeHeader
panelHeader pdl" style="border-bottom-width: 1px;"><b>MyPage.java - The Old
Way</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">public class MyPage {
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">public class MyPage {
@Inject
private Request request;
@@ -192,19 +194,19 @@ div.rbtoc1523334086243 li {margin-left:
}
</pre>
</div></div><p>Starting with Tapestry 5.2, this can be accomplished just by
annotating a page or component property with @<a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/annotations/SessionAttribute.html">SessionAttribute</a>.
This annotation is used to map a property of a page or component to value
stored in session. Unlike Session State Objects, the name (not the type) of the
annotated property is used as the name of the session attribute to look
for.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>MyPage.java - The New Way</b></div><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">public class MyPage {
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">public class MyPage {
@SessionAttribute
private User loggedInUserName;
}
</pre>
</div></div><p>You can also provide a name using the annotation's
<code>value</code> parameter:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>MyPage.java</b></div><div
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">public class MyPage {
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">public class MyPage {
@SessionAttribute("loggedInUserName")
private User userName;
}
</pre>
</div></div><h3 id="SessionStorage-Pitfalls.1">Pitfalls</h3><p>As with SSOs,
when using Session Attributes you are creating a session-wide data storage area
that has the serious possibility of data collisions, not just within your
application but with other modules/libraries. To avoid problems, you should
qualify the session attribute name with a package-like naming convention. For
example, use something like "com.mycompany.myapp.username" instead of just
"username".</p><p>It's best to define the session attribute name as constant,
and use that in the annotation's value parameter, rather then defaulting to the
instance variable name. This will help prevent subtle runtime errors due to
misspellings. For example:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>MyPage.java - The Safer Way</b></div><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">public static final String USER_NAME_SESSION_ATTRIBUTE
= "com.example.shoppingapp.username";
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">public static final String
USER_NAME_SESSION_ATTRIBUTE = "com.example.shoppingapp.username";
...
@@ -214,7 +216,7 @@ public class MyPage {
}
</pre>
</div></div><p></p><h2 id="SessionStorage-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="SessionStorage-@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/cu
rrent/apidocs/org/apache/tapestry5/annotations/ImmutableSessionPersistedObject.html">ImmutableSessionPersistedObject</a>
annotation.</p><h3
id="SessionStorage-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="SessionStorage-SessionPersistedObjectAnalyzerService">SessionPersistedObjectAnalyzer
Service</h3><p>The <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/Sessi
onPersistedObjectAnalyzer.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><h2 id="SessionStorage-SessionLocking">Session
Locking</h2><p>Starting with version 5.4, by default Tapestry will apply
locking semantics around access to the HttpSession. Reading attribute names
occurs with a shared read lock, and getting or setting an attribute upgrades
the lock to an exclusive write lock. This can tend to serialize threads when a
number of simultaneous (Ajax) requests from the client arrive. However, many
implementations of HttpSession are not thread safe, and often mutable
objects<br clear="none"> are stored in the session and shared between
threads.</p><p>The <a
href="configuration.html"><code>tapestry.session-locking-enabled</code></a>
<span class="co
nfluence-link">configuration symbol</span> can control this behavior. Setting
this to true (the default) will yield a more robust application; setting it to
false may speed up processing for more Ajax intensive applications (but care
should then be given to ensuring that objects shared inside the session are
themeselves immutable or thread-safe).</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public static void
contributeApplicationDefaults(MappedConfiguration<String,String>
configuration)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> public static void
contributeApplicationDefaults(MappedConfiguration<String,String>
configuration)
{
configuration.add(SymbolConstants.SESSION_LOCKING_ENABLED, true);
...
Modified: websites/production/tapestry/content/specific-errors-faq.html
==============================================================================
--- websites/production/tapestry/content/specific-errors-faq.html (original)
+++ websites/production/tapestry/content/specific-errors-faq.html Mon May 21
05:20:56 2018
@@ -78,11 +78,11 @@
<div id="content">
<div id="ConfluenceContent"><h1
id="SpecificErrorsFAQ-SpecificErrors">Specific Errors</h1><h2
id="SpecificErrorsFAQ-Contents">Contents</h2><p><style
type="text/css">/*<![CDATA[*/
-div.rbtoc1523334076705 {padding: 0px;}
-div.rbtoc1523334076705 ul {list-style: disc;margin-left: 0px;}
-div.rbtoc1523334076705 li {margin-left: 0px;padding-left: 0px;}
+div.rbtoc1526880009323 {padding: 0px;}
+div.rbtoc1526880009323 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1526880009323 li {margin-left: 0px;padding-left: 0px;}
-/*]]>*/</style></p><div class="toc-macro rbtoc1523334076705">
+/*]]>*/</style></p><div class="toc-macro rbtoc1526880009323">
<ul class="toc-indentation"><li><a
href="#SpecificErrorsFAQ-WhydoIgettheexception"Noserviceimplementstheinterfaceorg.apache.tapestry5.internal.InternalComponentResources"whentryingtousetheBeanEditFormcomponent?">Why
do I get the exception "No service implements the interface
org.apache.tapestry5.internal.InternalComponentResources" when trying to use
the BeanEditForm component?</a></li><li><a
href="#SpecificErrorsFAQ-Igetanerrorabout"Pagedidnotgenerateanymarkupwhenrendered."butIhaveatemplate,whathappened?">I
get an error about "Page did not generate any markup when rendered." but I
have a template, what happened?</a></li><li><a
href="#SpecificErrorsFAQ-MyapplicationfailswiththeerrorPermGen,howdoIfixthis?">My
application fails with the error PermGen, how do I fix this?</a></li><li><a
href="#SpecificErrorsFAQ-WhydoIsometimesgetajava.lang.NoSuchMethodErrorexceptionafterreloadingmypage?">Why
do I sometimes get a java.lang.NoSuchMethodError exception after reloadi
ng my page?</a></li><li><a
href="#SpecificErrorsFAQ-Whydomylogscontain"java.lang.RuntimeException:FormsrequirethattherequestmethodbePOSTandthatthet:formdataqueryparameterhavevalues"?">Why
do my logs contain "java.lang.RuntimeException: Forms require that the request
method be POST and that the t:formdata query parameter have
values"?</a></li></ul>
</div><div class="aui-label" style="float:right" title="Related Articles">
@@ -93,20 +93,31 @@ div.rbtoc1523334076705 li {margin-left:
+
+
<h3>Related Articles</h3>
<ul class="content-by-label"><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a href="error-page-recipe.html">Error Page Recipe</a>
+ <a href="runtime-exceptions.html">Runtime
Exceptions</a>
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
+
+ <div class="details">
+ <a
href="overriding-exception-reporting.html">Overriding Exception Reporting</a>
+
+
+ </div>
+ </li><li>
+ <div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
<a href="specific-errors-faq.html">Specific Errors
FAQ</a>
@@ -115,10 +126,10 @@ div.rbtoc1523334076705 li {margin-left:
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a
href="overriding-exception-reporting.html">Overriding Exception Reporting</a>
+ <a href="error-page-recipe.html">Error Page Recipe</a>
</div>
@@ -127,7 +138,7 @@ div.rbtoc1523334076705 li {margin-left:
<h2
id="SpecificErrorsFAQ-WhydoIgettheexception"Noserviceimplementstheinterfaceorg.apache.tapestry5.internal.InternalComponentResources"whentryingtousetheBeanEditFormcomponent?">Why
do I get the exception "No service implements the interface
org.apache.tapestry5.internal.InternalComponentResources" when trying to use
the BeanEditForm component?</h2><p>This can occur when you choose the wrong
package for your data object, the object edited by the BeanEditForm component.
If you place it in the same package as your pages, Tapestry will treat it like
a page, and perform a number of transformation on it, including adding a new
constructor.</p><p>Only component classes should go in the Tapestry-controlled
packages (<code>pages</code>, <code>components</code>, <code>mixins</code> and
<code>base</code> under your application's root package). By convention, simple
data objects should go in a <code>data</code> package, and Hibernate entities
should go in an <code>entities</code> pac
kage.</p><div class="confluence-information-macro
confluence-information-macro-note"><span class="aui-icon aui-icon-small
aui-iconfont-warning confluence-information-macro-icon"></span><div
class="confluence-information-macro-body"><p>This is likely a bit different in
5.3 than in 5.2 (because 5.3 builds a very different constructor into the
component) and needs to be tested in 5.3 to see what exact exception will
occur.</p></div></div><h2
id="SpecificErrorsFAQ-Igetanerrorabout"Pagedidnotgenerateanymarkupwhenrendered."butIhaveatemplate,whathappened?">I
get an error about "Page did not generate any markup when rendered." but I
have a template, what happened?</h2><p>The most common error here is that the
case of the page class did not match the case of the template. For example, you
might name your class ViewOrders, but name the template vieworders.tml. The
correct name for the template is ViewOrders.tml, matching the case of the Java
class name.</p><p>Worse, you may find tha
t your application works during development (under Windows, which is case
insensitive) but does not work when deployed on a Linux or Unix server, which
may be case sensitive.</p><p>The other cause of this may be that your template
files simply are not being packaged up correctly with the rest of your
application. When in doubt, use the Java <code>jar</code> command to see
exactly whats inside your WAR file. Your page templates should either be in the
root folder of the WAR, or package with the corresponding .class file.</p><h2
id="SpecificErrorsFAQ-MyapplicationfailswiththeerrorPermGen,howdoIfixthis?">My
application fails with the error <strong>PermGen</strong>, how do I fix
this?</h2><p>In Java versions <em>prior to</em> JDK 1.8, PermGen refers to the
part of the Java memory space devoted to permanent objects, which are mostly
loaded classes. When developing under Tapestry, many more classes and class
loaders are created than normal; this is part of live class reloading. Because
of
this, you will want to increase the amount of memory Java devotes to
this.</p><p>In JDK 1.7 and earlier, the solution is to add
<code>-XX:MaxPermSize=512m</code> to your command line. You may also want to
increase the regular amount of heap space with <code>-Xmx600M</code>. Of
course, you may need to adjust the amount of memory in each category to match
your actual application, but these are good starting values.</p><p>Java Virtual
Machine arguments can be specified inside an Eclipse launch
configuration:</p><p> </p><p><span
class="confluence-embedded-file-wrapper"><img class="confluence-embedded-image
confluence-thumbnail"
src="specific-errors-faq.data/eclipse-permgen.png"></span></p><h2
id="SpecificErrorsFAQ-WhydoIsometimesgetajava.lang.NoSuchMethodErrorexceptionafterreloadingmypage?">Why
do I sometimes get a <code>java.lang.NoSuchMethodError</code> exception after
reloading my page?</h2><p>Tapestry's live class reloading is not
perfect. <span>It tends to use a lot of J
ava ClassLoaders on top of the normal ClassLoaders used by the Java Virtual
Machine and the servlet container. When you change non-component classes and
interfaces that are referenced by components and pages, such as to add or
change a method, only the component classes are reloaded. The non-component
classes are frozen as they were when they were </span><em>first</em><span>
loaded.</span></p><p>Unfortunately, this is one of the areas where you must
restart your application entirely in order to force the new versions of the
non-component classes to be loaded into memory.</p><h2
id="SpecificErrorsFAQ-Whydomylogscontain"java.lang.RuntimeException:FormsrequirethattherequestmethodbePOSTandthatthet:formdataqueryparameterhavevalues"?">Why
do my logs contain "java.lang.RuntimeException: Forms require that the request
method be POST and that the t:formdata query parameter have
values"?</h2><p>This is caused by someone (or something) submitting the URL of
your form using an HTTP GE
T instead of POST. Tapestry forms must always use POST actions.</p><p>Some
known scenarios that cause this error:</p><ul><li>Bots crawling your
site</li><li>Web browser auto-complete functions trying to be
helpful</li><li>Users with browser developer tools manually modifying the form
from a POST to a GET to see what will happen.</li><li>Users getting a
validation error on a form, then re-submitting the form by clicking in the URL
address field and hitting Enter.</li><li>In Tapestry versions before 5.4,
(rarely) the use of property names for form fields where the property name
matches a JavaScript property (see <a class="external-link"
href="https://issues.apache.org/jira/browse/TAP5-2066">TAP5-2066</a>).</li></ul><p>In
every known scenario except the last, these errors are harmless and you
probably want to redirect the user to the page the form is on – and avoid
logging an error. That's not too hard to do. Just add code like the following
to your module class (usually AppModu
le.java):</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent
pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> /**
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> /**
* Redirect the user to the intended page when browsing through
* tapestry forms through browser history or over-eager autocomplete
*/
Modified:
websites/production/tapestry/content/tapestry-inversion-of-control-faq.html
==============================================================================
--- websites/production/tapestry/content/tapestry-inversion-of-control-faq.html
(original)
+++ websites/production/tapestry/content/tapestry-inversion-of-control-faq.html
Mon May 21 05:20:56 2018
@@ -78,11 +78,11 @@
<div id="content">
<div id="ConfluenceContent"><h1
id="TapestryInversionofControlFAQ-TapestryInversionofControlContainer">Tapestry
Inversion of Control Container</h1><p>Main article: <a
href="tapestry-inversion-of-control-faq.html">Tapestry IoC</a></p><h2
id="TapestryInversionofControlFAQ-Contents">Contents</h2><p><style
type="text/css">/*<![CDATA[*/
-div.rbtoc1523334017365 {padding: 0px;}
-div.rbtoc1523334017365 ul {list-style: disc;margin-left: 0px;}
-div.rbtoc1523334017365 li {margin-left: 0px;padding-left: 0px;}
+div.rbtoc1526880012595 {padding: 0px;}
+div.rbtoc1526880012595 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1526880012595 li {margin-left: 0px;padding-left: 0px;}
-/*]]>*/</style></p><div class="toc-macro rbtoc1523334017365">
+/*]]>*/</style></p><div class="toc-macro rbtoc1526880012595">
<ul class="toc-indentation"><li><a
href="#TapestryInversionofControlFAQ-WhydoIneedtodefineaninterfaceformyservices?Whycan'tIjustusetheclassitself?">Why
do I need to define an interface for my services? Why can't I just use the
class itself?</a></li><li><a
href="#TapestryInversionofControlFAQ-Myservicestartsathread;howdoIknowwhentheapplicationisshuttingdown,tostopthatthread?">My
service starts a thread; how do I know when the application is shutting down,
to stop that thread?</a></li><li><a
href="#TapestryInversionofControlFAQ-HowdoImakemyservicestartupwiththerestoftheapplication,ratherthanlazily?">How
do I make my service startup with the rest of the application, rather than
lazily?</a></li></ul>
</div><p> </p><div class="aui-label" style="float:right" title="Related
Articles">
@@ -93,41 +93,43 @@ div.rbtoc1523334017365 li {margin-left:
+
+
<h3>Related Articles</h3>
<ul class="content-by-label"><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a href="ioc.html">IOC</a>
+ <a href="tapestry-ioc-overview.html">Tapestry IoC
Overview</a>
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a href="ioc-cookbook.html">IoC cookbook</a>
+ <a href="ioc.html">IOC</a>
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a href="tapestry-ioc-overview.html">Tapestry IoC
Overview</a>
+ <a
href="tapestry-inversion-of-control-faq.html">Tapestry Inversion of Control
FAQ</a>
</div>
</li><li>
<div>
- <span class="icon aui-icon aui-icon-small
aui-iconfont-page-default" title="Page">Page:</span> </div>
+ <span class="icon aui-icon content-type-page"
title="Page">Page:</span> </div>
<div class="details">
- <a
href="tapestry-inversion-of-control-faq.html">Tapestry Inversion of Control
FAQ</a>
+ <a href="ioc-cookbook.html">IoC cookbook</a>
</div>
@@ -136,7 +138,7 @@ div.rbtoc1523334017365 li {margin-left:
<h3
id="TapestryInversionofControlFAQ-WhydoIneedtodefineaninterfaceformyservices?Whycan'tIjustusetheclassitself?">Why
do I need to define an interface for my services? Why can't I just use the
class itself?</h3><p>First of all: you can do exactly this, but you lose some
of the functionality that Tapestry's IoC container provides.</p><p>The reason
for the split is so that Tapestry can provide functionality for your service
around the core service implementation. It does this by creating
<em>proxies</em>: Java classes that implement the service interface. The
methods of the proxy will ultimately invoke the methods of your service
implementation.</p><p>One of the primary purposes for proxies is to encapsulate
the service's life cycle: most services are singletons that are created
<em>just in time</em>. Just in time means only as soon as you invoke a method.
What's going on is that the life cycle proxy (the object that gets injected
into pages, components or other service implementation
s) checks on each method invocation to see if the actual service exists yet.
If not, it instantiates and configures it (using proper locking to ensure
thread safety), then delegates the method invocation to the service.</p><p>If
you bind a service class (not a service interface and class), then the service
is fully instantiated the first time it is injected, rather than at that first
method invocation. Further, you can't use decorations or method advice on such
a service.</p><p>The final reason for the service interface / implementation
split is to nudge you towards always coding to an interface, which has manifest
benefits for code structure, robustness, and testability.</p><h3
id="TapestryInversionofControlFAQ-Myservicestartsathread;howdoIknowwhentheapplicationisshuttingdown,tostopthatthread?">My
service starts a thread; how do I know when the application is shutting down,
to stop that thread?</h3><p>This same concern applies to any long-lived
resource (a thread, a database connec
tion, a JMS queue connection) that a service may hold onto. Your code needs to
know when the application has been undeployed and shutdown. This is actually
quite easy, by adding some post-injection logic to your implementation
class.</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>MyServiceImpl.java</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: true; theme: Default"
style="font-size:12px;">public class MyServiceImpl implements MyService
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: true; theme: Default" data-theme="Default">public class MyServiceImpl
implements MyService
{
private boolean shuttingDown;
Modified: websites/production/tapestry/content/templating-and-markup-faq.html
==============================================================================
--- websites/production/tapestry/content/templating-and-markup-faq.html
(original)
+++ websites/production/tapestry/content/templating-and-markup-faq.html Mon May
21 05:20:56 2018
@@ -78,21 +78,21 @@
<div id="content">
<div id="ConfluenceContent"><h1
id="TemplatingandMarkupFAQ-TemplatingandMarkup">Templating and
Markup</h1><p>Main Article: <a href="component-templates.html">Component
Templates</a></p><h2
id="TemplatingandMarkupFAQ-Contents">Contents</h2><p><style
type="text/css">/*<![CDATA[*/
-div.rbtoc1523334077760 {padding: 0px;}
-div.rbtoc1523334077760 ul {list-style: disc;margin-left: 0px;}
-div.rbtoc1523334077760 li {margin-left: 0px;padding-left: 0px;}
+div.rbtoc1526880009769 {padding: 0px;}
+div.rbtoc1526880009769 ul {list-style: disc;margin-left: 0px;}
+div.rbtoc1526880009769 li {margin-left: 0px;padding-left: 0px;}
-/*]]>*/</style></p><div class="toc-macro rbtoc1523334077760">
+/*]]>*/</style></p><div class="toc-macro rbtoc1526880009769">
<ul class="toc-indentation"><li><a
href="#TemplatingandMarkupFAQ-WhydoIgetaSAXParseExceptionwhenIuseanHTMLentity,suchas&nbsp;inmytemplate?">Why
do I get a SAXParseException when I use an HTML entity, such as &nbsp; in
my template?</a></li><li><a
href="#TemplatingandMarkupFAQ-Whydosomeimagesinmypageshowupasbrokenlinks?">Why
do some images in my page show up as broken links?</a></li><li><a
href="#TemplatingandMarkupFAQ-What'sthedifferencebetweenidandt:id?">What's the
difference between id and t:id?</a></li><li><a
href="#TemplatingandMarkupFAQ-WhydomyimagesandstylesheetsendupwithaweirdURLslike/assets/meta/zeea17aee26bc0cae/layout/layout.css?">Why
do my images and stylesheets end up with a weird URLs like
/assets/meta/zeea17aee26bc0cae/layout/layout.css?</a></li><li><a
href="#TemplatingandMarkupFAQ-HowdoIaddaCSSclasstoaTapestrycomponent?">How do I
add a CSS class to a Tapestry component?</a></li></ul>
</div><h2
id="TemplatingandMarkupFAQ-WhydoIgetaSAXParseExceptionwhenIuseanHTMLentity,suchas&nbsp;inmytemplate?">Why
do I get a SAXParseException when I use an HTML entity, such as
<code>&nbsp;</code> in my template?</h2><p>Tapestry uses a standard SAX
parser to read your templates. This means that your templates must be <em>well
formed</em>: open and close tags must balance, attribute values must be quoted,
and entities must be declared. The easiest way to accomplish this is to add a
DOCTYPE to your the top of your template:</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;"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
Strict//EN"
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: xml;
gutter: false; theme: Default" data-theme="Default"><!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
</pre>
</div></div><p>Part of the DOCTYPE is the declaration of entities such as
<code>&nbsp;</code>.</p><p>Alternately, you can simply use the numeric
version: <code>&#160</code>; This is the exact same character and will
render identically in the browser.</p><p>Starting in release 5.3, Tapestry
introduces an XHTML doctype when no doctype is present; this means that common
HTML entities will work correctly.</p><h2
id="TemplatingandMarkupFAQ-Whydosomeimagesinmypageshowupasbrokenlinks?">Why do
some images in my page show up as broken links?</h2><p>You have to be careful
when using relative URLs inside page templates; the base URL may not always be
what you expect. For example, inside your <code>ViewUser.tml</code> file, you
may have:</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;"> <img class="icon"
src="icons/admin.png"/>${user.name} has Administrative access
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: xml;
gutter: false; theme: Default" data-theme="Default"> <img class="icon"
src="icons/admin.png"/>${user.name} has Administrative access
</pre>
</div></div><p>This makes sense; ViewUser.tml is in the web context, as is the
icons folder. The default URL for this page will be /viewuser (assuming that
ViewUser class is in the  <em>root-package</em>.pages
package).</p><p>However, the ViewUser page might use a page activation context
to identify which user is to be displayed:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">public class ViewUser
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">public class ViewUser
@Property
@PageActivationContext
@@ -101,29 +101,29 @@ div.rbtoc1523334077760 li {margin-left:
. . .
</pre>
</div></div><p>With a page activation context, the URL for the page will
incorporate the ID of the User object, something like
<code>/viewuser/37371</code>. This is why the relative URL to the
<code>admin.png</code> image is broken: the base path is relative to the page's
URL, not to the page template. (In fact, the page template may not even be in
the web context, it may be stored on the classpath, as component templates
are.)</p><p>One solution would be to predict what the page URL will be, and
adjust the path for that:</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;"> <img class="icon"
src="../icons/admin.png"/>${user.name} has Administrative access
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: xml;
gutter: false; theme: Default" data-theme="Default"> <img class="icon"
src="../icons/admin.png"/>${user.name} has Administrative access
</pre>
</div></div><p>But this has its own problems; the page activation context may
vary in length at different times, or the template in question may be a
component used across many different pages, making it difficult to predict what
the correct relative URL would be.</p><p>The <em>best</em> solution for this
situation, one that will be sure to work in all pages and all components, is to
make use of the <code>context:</code> binding prefix:</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;"> <img class="icon"
src="${context:icons/admin.png}"/>${user.name} has Administrative access
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: xml;
gutter: false; theme: Default" data-theme="Default"> <img class="icon"
src="${context:icons/admin.png}"/>${user.name} has Administrative access
</pre>
</div></div><p>The src attribute of the <img> tag will now be bound to a
dynamically computed value: the location of the image file relative to the web
application context. This is especially important for components that may be
used on different pages.</p><h2
id="TemplatingandMarkupFAQ-What'sthedifferencebetweenidandt:id?">What's the
difference between <code>id</code> and <code>t:id</code>?</h2><p>You might
occasionally see something like the following in a template:</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:zone id="status" t:id="statusZone">
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: xml;
gutter: false; theme: Default" data-theme="Default"><t:zone id="status"
t:id="statusZone">
</pre>
</div></div><p>Why two ids? Why are they different?</p><p>The
<code>t:id</code> attribute is the Tapestry component id. This id is unique
within its immediate container. This is the id you might use to inject the
component into your page class:</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;"> @InjectComponent
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> @InjectComponent
private Zone statusZone;
</pre>
</div></div><p>The other id is the client id, a unique id for the rendered
element within the client-side DOM. JavaScript that needs to access the element
uses this id. For example:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: text; gutter: false; theme: Default"
style="font-size:12px;"> $('status').hide();
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: text;
gutter: false; theme: Default" data-theme="Default"> $('status').hide();
</pre>
</div></div><p>In many components, the <code>id</code> attribute is an
informal parameter; a value from the template that is blindly echoed into the
output document. In other cases, the component itself has an <code>id</code>
attribute. Often, in the latter case, the Tapestry component id is the
<em>default</em> value for the client id.</p><h2
id="TemplatingandMarkupFAQ-WhydomyimagesandstylesheetsendupwithaweirdURLslike/assets/meta/zeea17aee26bc0cae/layout/layout.css?">Why
do my images and stylesheets end up with a weird URLs like
<code>/assets/meta/zeea17aee26bc0cae/layout/layout.css</code>?</h2><p>Tapestry
doesn't rely on the servlet container to serve up your static assets (images,
stylesheets, flash movies, etc.). Instead, Tapestry processes the requests
itself, streaming assets to the browser.</p><p>Asset content will be GZIP
compressed (if the client supports compression, and the content is
compressible). In addition, Tapestry will set a far-future expires header on
the conten
t. This means that the browser will not ask for the file again, greatly
reducing network traffic.</p><p>The weird hex string is
a <em>fingerprint</em>; it is a hash code computed from the actual content
of the asset. If the asset ever changes, it will have a new fingerprint, and so
will be a new path and a new (immutable) resource. This approach, combined with
a far-future expires header also provided by Tapestry, ensures that clients
aggressively cache assets as they navigate your site, or even between
visits.</p><h2
id="TemplatingandMarkupFAQ-HowdoIaddaCSSclasstoaTapestrycomponent?"><span
style="color: rgb(83,145,38);">How do I add a CSS class to a Tapestry
component?</span></h2><p>As they say, "just do it". The majority of Tapestry
components support <em>informal parameters</em>, meaning that any extra
attributes in the element (in the template) will be rendered out as additional
attributes. So, you can apply a CSS class or style quite easily:</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="username" class="big-green"/>
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: xml;
gutter: false; theme: Default" data-theme="Default"> <t:textfield
t:id="username" class="big-green"/>
</pre>
</div></div><p>You can even use template expansions inside the attribute
value:</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="username"
class="${usernameClass}"/>
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: xml;
gutter: false; theme: Default" data-theme="Default"> <t:textfield
t:id="username" class="${usernameClass}"/>
</pre>
</div></div><p>and</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public String getUsernameClass()
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> public String
getUsernameClass()
{
return isUrgent() ? "urgent" : null;
}
Modified: websites/production/tapestry/content/uploading-files.html
==============================================================================
--- websites/production/tapestry/content/uploading-files.html (original)
+++ websites/production/tapestry/content/uploading-files.html Mon May 21
05:20:56 2018
@@ -78,7 +78,7 @@
<div id="content">
<div id="ConfluenceContent"><p>Tapestry provides a file upload
component based on <a class="external-link"
href="http://commons.apache.org/fileupload/">Apache Commons FileUpload</a> to
make it easier to handle files uploaded through web forms (via the standard
<input type="file"> HTML element).</p><h1
id="UploadingFiles-Downloading">Downloading</h1><p><strong>tapestry-upload</strong>
is not automatically included in Tapestry applications because of the
additional dependencies it requires. To include it, just add the
<code>tapestry-upload</code> dependency to the pom of your application,
something like this:</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;"><dependency>
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: xml;
gutter: false; theme: Default" data-theme="Default"><dependency>
<groupId>org.apache.tapestry</groupId>
<artifactId>tapestry-upload</artifactId>
<version>${tapestry-release-version}</version>
@@ -87,14 +87,14 @@
</div></div><p>If you aren't using Maven, you'll have to download the jar and
its dependencies yourself.</p><h1 id="UploadingFiles-Usage">Usage</h1><p>The
upload component supports default value binding (based on id) and
validation.</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/javascript/fileupload"
rel="nofollow">File Upload</a></p></div><h2
id="UploadingFiles-ComponentTemplate">Component Template</h2><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;"> <t:form>
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> <t:form>
<t:errors/>
<input t:type="upload" t:id="file" t:value="file"
validate="required"/>
<br/>
<input type="submit" value="Upload"/>
</t:form></pre>
</div></div><p>Here, because the value parameter was not bound, the component
used the file property of its container (because the component's id is 'file').
If you want to upload as a different property, either bind the value parameter
or change the component's id.</p><h2 id="UploadingFiles-Pageclass">Page
class</h2><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> public class UploadExample
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> public class
UploadExample
{
@Property
private UploadedFile file;
@@ -107,7 +107,7 @@
}
}</pre>
</div></div><h1 id="UploadingFiles-UploadExceptions">Upload
Exceptions</h1><p>In some cases, file uploads may fail. This can be because of
a simple communication exception, or more likely, because the configured
maximum upload size was exceeded.</p><p>When a file upload exception occurs,
Tapestry will trigger a "uploadException" event on the page to notify it of the
error. All other normal processing is skipped (no "activate" event, no form
submission, etc.).</p><p>The event handler should return a non-null object,
which will be handled as a navigational result. 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;"> @Persist(PersistenceConstants.FLASH)
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">
@Persist(PersistenceConstants.FLASH)
@Property
private String message;
Modified: websites/production/tapestry/content/using-select-with-a-list.html
==============================================================================
--- websites/production/tapestry/content/using-select-with-a-list.html
(original)
+++ websites/production/tapestry/content/using-select-with-a-list.html Mon May
21 05:20:56 2018
@@ -78,14 +78,14 @@
<div id="content">
<div id="ConfluenceContent"><h1
id="UsingSelectWithaList-UsingSelectWithaList">Using Select With a
List</h1><p>The documentation for the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Select.html">Select
Component</a> and the <a href="tapestry-tutorial.html">Tapestry Tutorial</a>
provide simplistic examples of populating a drop-down menu (as the (X)HTML
<em>Select</em> element) using comma-delimited strings and enums. However, most
real-world Tapestry applications need to populate such menus using values from
a database, commonly in the form of java.util.List objects. Doing so generally
requires a <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/SelectModel.html">SelectModel</a>
and a <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ValueEncoder.html">ValueEncoder</a>
bound to the Select component with its
"model" and "encoder" parameters:</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;"><t:select t:id="colorMenu" value="selectedColor"
model="ColorSelectModel" encoder="colorEncoder" />
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"><t:select
t:id="colorMenu" value="selectedColor" model="ColorSelectModel"
encoder="colorEncoder" />
</pre>
</div></div><p>In the above example, ColorSelectModel must be of type
SelectModel, or anything that Tapestry knows how to <a
href="parameter-type-coercion.html">coerce</a> into a SelectModel, such as a
List or a Map or a "value=label,value=label,..." delimited string, or anything
Tapestry knows how to coerce into a List or Map, such as an Array or a
comma-delimited String.</p><h2
id="UsingSelectWithaList-SelectModel">SelectModel</h2><p></p><div
class="navmenu" style="float:right; background:#eee; margin:3px; padding:0 1em">
<p> <strong>JumpStart Demos:</strong><br clear="none">
<a class="external-link"
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/totalcontrolobject"
rel="nofollow">Total Control Object Select</a><br clear="none">
<a class="external-link"
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/id"
rel="nofollow">ID Select</a><br clear="none">
<a class="external-link"
href="http://jumpstart.doublenegative.com.au/jumpstart/examples/select/easyid"
rel="nofollow">Easy ID Select</a></p></div>A SelectModel is a collection of
options (specifically <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/OptionModel.html">OptionModel</a>
objects) for a drop-down menu. Basically, each option is a value (an object)
and a label (presented to the user).<p>If you provide a property of type List
for the "model" parameter, Tapestry automatically builds a SelectModel that
uses each object's toString() for both the select option value and the select
option label. For database-derrived lists this is rarely useful, however, since
after form submission you would then have to look up the selected object using
that label.</p><p>If you provide a Map, Tapestry builds a SelectModel that uses
each item's key as the encoded value and its value as the user-visible label.
This is more useful, but if you ar
e going to build a copy of the list as a map just for this purpose, you may as
well let Tapestry do it for you, using SelectModelFactory.</p><h2
id="UsingSelectWithaList-SelectModelFactory">SelectModelFactory</h2><p>To have
Tapestry create a SelectModel for you, use the <a class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/SelectModelFactory.html">SelectModelFactory</a>
service. SelectModelFactory creates a SelectModel from a List of objects (of
whatever type) and a label property name that you choose:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a page
class)</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">@Property
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">@Property
private SelectModel colorSelectModel;
@Inject
SelectModelFactory selectModelFactory;
@@ -99,7 +99,7 @@ void setupRender() {
}
</pre>
</div></div><p>The resulting SelectModel has a selectable option
(specifically, an OptionModel) for every object in the original List. The label
property name (the "name" property, in this example) determines the
user-visible text of each menu option, and your ValueEncoder's toClient()
method provides the encoded value (most commonly a simple number). If you don't
provide a ValueEncoder, the result of the objects' toString() method
(Color#toString() in this example) is used. Although not a recommended
practice, you <em>could</em> set your toString() to return the object's ID for
this purpose:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>Color.java (partial)</b></div><div class="codeContent panelContent
pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">...
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">...
@Override
public String toString() {
return String.valueOf(this.getId());
@@ -108,7 +108,7 @@ public String toString() {
</div></div><p>But that is contorting the purpose of the toString() method,
and if you go to that much trouble you're already half way to the recommended
practice: creating a ValueEncoder.</p><h2
id="UsingSelectWithaList-ValueEncoder">ValueEncoder</h2><p>In addition to a
SelectModel, your Select menu is likely to need a ValueEncoder. While a
SelectModel is concerned only with how to construct a Select menu, a
ValueEncoder is used when constructing the Select menu <em>and</em> when
interpreting the encoded value that is submitted back to the server. A
ValueEncoder is a converter between the type of objects you want to represent
as options in the menu and the client-side encoded values that uniquely
identify them, and vice-versa.</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/select/easyobject"
rel="nofollow">Easy Object Select</a></p></div>Most commonly, your
ValueEncoder's toClient() method will return a unique ID (e.g. a database
primary key, or perhaps a UUID) of the given object, and its toValue() method
will return the <em>object</em> matching the given ID by doing a database
lookup (ideally using a service or DAO method).<p>If you're using one of the
ORM integration modules (<a href="hibernate.html">Tapestry-Hibernate</a>, <a
href="integrating-with-jpa.html">Tapestry-JPA</a>, or <a class="external-link"
href="http://code.google.com/p/tapestry5-cayenne/wiki/ValueEncoder"
rel="nofollow">Tapestry-Cayenne</a>), the ValueEncoder is automatically
provided for each of your mapped entity classes. The Hibernate module's
implementation is typical: the primary key field of the object (converted to a
String) is used as the client-side value, and that same primary
key is used to look up the selected object.</p><p>That's exactly what you
should do in your own ValueEncoders too:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>ColorEncoder.java (perhaps in your
com.example.myappname.encoders package)</b></div><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">public class ColorEncoder implements
ValueEncoder<Color>, ValueEncoderFactory<Color> {
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">public class ColorEncoder
implements ValueEncoder<Color>, ValueEncoderFactory<Color> {
@Inject
private ColorService colorService;
@@ -133,7 +133,7 @@ public String toString() {
}
</pre>
</div></div><p>Alternatively, if you don't expect to need a particular
ValueEncoder more than once in your app, you might want to just create it on
demand, using an anonymous inner class, from the getter method in the component
class where it is needed. For example:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>SelectWithListDemo.java (a page class,
partial)</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"> . . .
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"> . . .
public ValueEncoder<Color> getColorEncoder() {
@@ -154,14 +154,14 @@ public String toString() {
}
</pre>
</div></div><p>Notice that the body of this anonymous inner class is the same
as the body of the ColorEncoder top level class, except that we don't need a
<code>create</code> method.</p><h2
id="UsingSelectWithaList-ApplyingyourValueEncoderAutomatically">Applying your
ValueEncoder Automatically</h2><p>If your ValueEncoder <em>implements
ValueEncoderFactory</em> (as the ColorEncoder top level class does, above), you
can associate your custom ValueEncoder with your entity class so that Tapestry
will automatically use it every time a ValueEncoder is needed for items of that
type (such as with the Select, RadioGroup, Grid, Hidden and AjaxFormLoop
components). Just add lines like the following to your module class (usually
AppModule.java):</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>AppModule.java (partial)</b></div><div class="codeContent panelContent
pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">...
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">...
public static void
contributeValueEncoderSource(MappedConfiguration<Class<Color>,
ValueEncoderFactory<Color>> configuration) {
configuration.addInstance(Color.class, ColorEncoder.class);
}
</pre>
</div></div><p>If you are contributing more than one ValueEncoder, you'll have
to use raw types, like this:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
style="border-bottom-width: 1px;"><b>AppModule.java (partial)</b></div><div
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">...
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">...
public static void
contributeValueEncoderSource(MappedConfiguration<Class,
ValueEncoderFactory> configuration)
{
@@ -170,10 +170,10 @@ public String toString() {
}
</pre>
</div></div><h2 id="UsingSelectWithaList-WhatifIomittheValueEncoder?">What if
I omit the ValueEncoder?</h2><p>The Select component's "encoder" parameter is
optional, but if the "value" parameter is bound to a complex object (not a
simple String, Integer, etc.) and you don't provide a ValueEncoder with the
"encoder" parameter (and one isn't provided automatically by, for example, the
Tapestry Hibernate integration), you'll receive a "Could not find a coercion"
exception (when you submit the form) as Tapestry tries to convert the selected
option's encoded value back to the <em>object</em> in your Select's "value"
parameter. To fix this, you'll either have to 1) provide a ValueEncoder, 2)
provide a <a href="type-coercion.html">Coercion</a>, or 3) use a simple value
(String, Integer, etc.) for your Select's "value" parameter, and then you'll
have to add logic in the corresponding onSuccess event listener method:</p><div
class="code panel pdl" style="border-width: 1px;"><div class="code
Header panelHeader pdl" style="border-bottom-width:
1px;"><b>SelectWithListDemo.tml (partial)</b></div><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;"><t:select t:id="colorMenu" value="selectedColorId"
model="ColorSelectModel" />
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default"><t:select
t:id="colorMenu" value="selectedColorId" model="ColorSelectModel" />
</pre>
</div></div><div class="code panel pdl" style="border-width: 1px;"><div
class="codeHeader panelHeader pdl" style="border-bottom-width:
1px;"><b>SelectWithListDemo.java (partial)</b></div><div class="codeContent
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default"
style="font-size:12px;">...
+<pre class="syntaxhighlighter-pre" data-syntaxhighlighter-params="brush: java;
gutter: false; theme: Default" data-theme="Default">...
public void onSuccessFromMyForm() {
// look up the color object from the ID selected
selectedColor = colorService.findById(selectedColorId);