Modified: websites/production/tapestry/content/localization.html
==============================================================================
--- websites/production/tapestry/content/localization.html (original)
+++ websites/production/tapestry/content/localization.html Tue Sep 26 19:20:27 
2017
@@ -27,16 +27,6 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
-          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
-    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
-    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushXml.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushPlain.js' 
type='text/javascript'></script>
-        <script>
-      SyntaxHighlighter.defaults['toolbar'] = false;
-      SyntaxHighlighter.all();
-    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -77,94 +67,32 @@
       </div>
 
       <div id="content">
-                <div 
id="ConfluenceContent"><p>&#160;</p><p><strong>Localization</strong> (aka L10n) 
is all about getting the right text to the user, in the right language.</p><div 
class="aui-label" style="float:right" title="Related Articles">
-
-
-
-
-
-
-
-
-<h3>Related Articles</h3>
-
-<ul class="content-by-label"><li>
-        <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
-
-        <div class="details">
-                        <a  href="templating-and-markup-faq.html">Templating 
and Markup FAQ</a>
-                
-                        
-                    </div>
-    </li><li>
-        <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
-
-        <div class="details">
-                        <a  href="component-classes.html">Component Classes</a>
-                
-                        
-                    </div>
-    </li><li>
-        <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
-
-        <div class="details">
-                        <a  href="localization.html">Localization</a>
-                
-                        
-                    </div>
-    </li><li>
-        <div>
-                <span class="icon aui-icon aui-icon-small 
aui-iconfont-page-default" title="Page">Page:</span>        </div>
-
-        <div class="details">
-                        <a  href="component-parameters.html">Component 
Parameters</a>
-                
-                        
-                    </div>
-    </li></ul>
-</div>
-
-
-<p>Localization support is well integrated into Tapestry. Tapestry allows you 
to easily separate the text you present to your users from the rest of your 
application ... pull it out of your Java code and even out of your component 
templates. You can then translate your messages into other languages and let 
Tapestry put everything together.</p><h2 
id="Localization-ComponentMessageCatalogs">Component Message 
Catalogs</h2><p>Each component class may have a component message catalog. A 
component message catalog is a set of files with the extension ".properties". 
These property files are the same format used by java.util.ResourceBundle, just 
lines of <code>key=value</code>. These files are stored on the classpath, in 
the same package folder as the page or component's compiled Java 
class.</p><p>So for a class named <code>org.example.myapp.pages.MyPage</code>, 
you would have a main properties file as 
<code>org/example/myapp/pages/MyPage.properties</code>.</p><p>If you have a 
translations o
 f these values, you provide additional properties file, adding an <a  
class="external-link" 
href="http://www.loc.gov/standards/iso639-2/englangn.html"; rel="nofollow">ISO 
language code</a> before the extension. Thus, if you have a French translation, 
you could create a file <code>MyPage_fr.properties</code>.</p><p>Any values in 
the more language specific file will <em>override</em> values from the main 
properties file. If you had an even more specific localization for just French 
as spoken in France, you could create <code>MyPage_fr_FR.properties</code> 
(that's a language code plus a country code, and you can even go further and 
add variants ... but its unlikely that you'll ever need to go beyond just 
language codes in practice).</p><p>The messages in the catalog are accessed by 
keys. Tapestry ignores the case of the keys when accessing messages in the 
catalog.</p><h3 id="Localization-ComponentMessageCatalogInheritance">Component 
Message Catalog Inheritance</h3><p>If a component clas
 s is a subclass of another component class, then it inherits that base class' 
message catalog. Its own message catalog extends and overrides the values 
inherited from the base class.</p><p>In this way, you could have a base 
component class that contained common messages, and extend or override those 
messages in subclasses (just as you would extend or override the methods of the 
base component class). This, of course, works for as many levels of inheritance 
as you care to support.</p><h2 
id="Localization-Application-wideMessageCatalog">Application-wide Message 
Catalog</h2><p>If the file 
<code>WEB-INF/</code><em>AppName</em><code>.properties</code> exists in the 
context, it will be used as an application-wide message catalog. The 
<em>AppName</em> is derived from the name of the filter inside the web.xml 
file; this is most often just "app", thus <code>WEB-INF/app.properties</code>. 
The search for the file is case sensitive. The properties files may be 
localized.</p><p>Individual pages 
 and components can override the values defined in the message catalog.</p><div 
class="navmenu" style="float:right; width:45%; background:white; margin:3px; 
padding:3px">
-<div class="confluence-information-macro confluence-information-macro-note"><p 
class="title">Avoid BOMs</p><span class="aui-icon aui-icon-small 
aui-iconfont-warning confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body">
-<p>Make sure that your properties files don't contain <a  
class="external-link" href="http://en.wikipedia.org/wiki/Byte_order_mark"; 
rel="nofollow">byte order marks (BOM)</a>, because Java &#8211; and thus 
Tapestry &#8211; doesn't support BOM in properties files (see <a  
class="external-link" href="http://bugs.sun.com/view_bug.do?bug_id=4508058"; 
rel="nofollow">http://bugs.sun.com/view_bug.do?bug_id=4508058</a>). Some 
editors write them out when saving a file in UTF-8, so watch 
out.</p></div></div></div><h2 
id="Localization-PropertiesFileCharset">Properties File Charset</h2><p>Tapestry 
uses the <code>UTF-8</code> character set (charset) when reading the properties 
files in a message catalog. This means that you don't have to use the Java 
<code>native2ascii</code> tool.</p><h2 
id="Localization-LocalizedComponentTemplates">Localized Component 
Templates</h2><p>The same lookup mechanism applies to component templates. 
Tapestry will search for a localized version of each component template
  and use the closest match. Thus you could have <code>MyPage_fr.html</code> 
for French users, and <code>MyPage.html</code> for all other users.</p><h2 
id="Localization-AccessingLocalizedMessages">Accessing Localized 
Messages</h2><p>The above discusses what files to create and where to store 
them, but doesn't address how to make use of that information.</p><p>Messages 
can be accessed in one of two ways:</p><ul><li>Using the "message:" <a  
href="component-parameters.html">binding expression</a> in a component 
template</li><li>By injecting the component's Messages object<br clear="none"> 
In the first case, you may use the message: binding prefix with component 
parameters, or with template expansions:</li></ul><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;">&lt;t:layout title="message:page-title"&gt;
+                <div 
id="ConfluenceContent"><p>&#160;</p><p><strong>Localization</strong> (aka L10n) 
is all about getting the right text to the user, in the right 
language.</p><parameter ac:name="style">float:right</parameter><parameter 
ac:name="title">Related Articles</parameter><parameter 
ac:name="class">aui-label</parameter><rich-text-body><parameter 
ac:name="showLabels">false</parameter><parameter 
ac:name="showSpace">false</parameter><parameter ac:name="title">Related 
Articles</parameter><parameter ac:name="cql">label in 
("component-templates","localization") and space = 
currentSpace()</parameter></rich-text-body><p>Localization support is well 
integrated into Tapestry. Tapestry allows you to easily separate the text you 
present to your users from the rest of your application ... pull it out of your 
Java code and even out of your component templates. You can then translate your 
messages into other languages and let Tapestry put everything together.</p><h2 
id="Localization-Compon
 entMessageCatalogs">Component Message Catalogs</h2><p>Each component class may 
have a component message catalog. A component message catalog is a set of files 
with the extension ".properties". These property files are the same format used 
by java.util.ResourceBundle, just lines of <code>key=value</code>. These files 
are stored on the classpath, in the same package folder as the page or 
component's compiled Java class.</p><p>So for a class named 
<code>org.example.myapp.pages.MyPage</code>, you would have a main properties 
file as <code>org/example/myapp/pages/MyPage.properties</code>.</p><p>If you 
have a translations of these values, you provide additional properties file, 
adding an <a  class="external-link" 
href="http://www.loc.gov/standards/iso639-2/englangn.html"; rel="nofollow">ISO 
language code</a> before the extension. Thus, if you have a French translation, 
you could create a file <code>MyPage_fr.properties</code>.</p><p>Any values in 
the more language specific file will <em>ov
 erride</em> values from the main properties file. If you had an even more 
specific localization for just French as spoken in France, you could create 
<code>MyPage_fr_FR.properties</code> (that's a language code plus a country 
code, and you can even go further and add variants ... but its unlikely that 
you'll ever need to go beyond just language codes in practice).</p><p>The 
messages in the catalog are accessed by keys. Tapestry ignores the case of the 
keys when accessing messages in the catalog.</p><h3 
id="Localization-ComponentMessageCatalogInheritance">Component Message Catalog 
Inheritance</h3><p>If a component class is a subclass of another component 
class, then it inherits that base class' message catalog. Its own message 
catalog extends and overrides the values inherited from the base 
class.</p><p>In this way, you could have a base component class that contained 
common messages, and extend or override those messages in subclasses (just as 
you would extend or override the method
 s of the base component class). This, of course, works for as many levels of 
inheritance as you care to support.</p><h2 
id="Localization-Application-wideMessageCatalog">Application-wide Message 
Catalog</h2><p>If the file 
<code>WEB-INF/</code><em>AppName</em><code>.properties</code> exists in the 
context, it will be used as an application-wide message catalog. The 
<em>AppName</em> is derived from the name of the filter inside the web.xml 
file; this is most often just "app", thus <code>WEB-INF/app.properties</code>. 
The search for the file is case sensitive. The properties files may be 
localized.</p><p>Individual pages and components can override the values 
defined in the message catalog.<plain-text-body>{float:right|width=45%}
+{note:title=Avoid BOMs}
+Make sure that your properties files don't contain [byte order marks 
(BOM)|http://en.wikipedia.org/wiki/Byte_order_mark], because Java -- and thus 
Tapestry -- doesn't support BOM in properties files (see 
http://bugs.sun.com/view_bug.do?bug_id=4508058). Some editors write them out 
when saving a file in UTF-8, so watch out.
+{note}
+{float}</plain-text-body></p><h2 
id="Localization-PropertiesFileCharset">Properties File Charset</h2><p>Tapestry 
uses the <code>UTF-8</code> character set (charset) when reading the properties 
files in a message catalog. This means that you don't have to use the Java 
<code>native2ascii</code> tool.</p><h2 
id="Localization-LocalizedComponentTemplates">Localized Component 
Templates</h2><p>The same lookup mechanism applies to component templates. 
Tapestry will search for a localized version of each component template and use 
the closest match. Thus you could have <code>MyPage_fr.html</code> for French 
users, and <code>MyPage.html</code> for all other users.</p><h2 
id="Localization-AccessingLocalizedMessages">Accessing Localized 
Messages</h2><p>The above discusses what files to create and where to store 
them, but doesn't address how to make use of that information.</p><p>Messages 
can be accessed in one of two ways:</p><ul><li>Using the "message:" <a  
href="component-parameters.html">bin
 ding expression</a> in a component template</li><li>By injecting the 
component's Messages object<br clear="none"> In the first case, you may use the 
message: binding prefix with component parameters, or with template 
expansions:</li></ul><parameter 
ac:name="">java</parameter><plain-text-body>&lt;t:layout 
title="message:page-title"&gt;
 
   ${message:greeting}, ${user.name}!
   
   . . .
 &lt;/t:layout&gt;
-</pre>
-</div></div><p>Here, the <code>page-title</code> message is extracted from the 
catalog and passed to the Border component's title parameter.</p><p>In 
addition, the <code>greeting</code> message is extracted and written into the 
response as part of the template.</p><p>As usual, "prop:" is the default 
binding prefix, thus <code>user.name</code> is a property path, not a message 
key.</p><p>You would extend this with a set of properties files:</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;">page-title=Your Account
+</plain-text-body><p>Here, the <code>page-title</code> message is extracted 
from the catalog and passed to the Border component's title parameter.</p><p>In 
addition, the <code>greeting</code> message is extracted and written into the 
response as part of the template.</p><p>As usual, "prop:" is the default 
binding prefix, thus <code>user.name</code> is a property path, not a message 
key.</p><p>You would extend this with a set of properties files:</p><parameter 
ac:name="">java</parameter><plain-text-body>page-title=Your Account
 greeting=Welcome back
-</pre>
-</div></div><p>Or, perhaps, a French version:</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;">page-title=Votre Compte
+</plain-text-body><p>Or, perhaps, a French version:</p><parameter 
ac:name="">java</parameter><plain-text-body>page-title=Votre Compte
 greeting=Bienvenue en arriere
-</pre>
-</div></div><p>Programatically, you may inject your component message catalog 
into your class, as an instance of the Messages interface:</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
+</plain-text-body><p>Programatically, you may inject your component message 
catalog into your class, as an instance of the Messages 
interface:</p><parameter ac:name="">java</parameter><plain-text-body>  @Inject
   private Messages messages;
-</pre>
-</div></div><p>You could then <code>get()</code> messages, or 
<code>format()</code> them:</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 getCartSummary()     
+</plain-text-body><p>You could then <code>get()</code> messages, or 
<code>format()</code> them:</p><parameter 
ac:name="">java</parameter><plain-text-body>  public String getCartSummary()    
 
   {
     if (items.isEmpty())
       return messages.get("no-items");
       
     return messages.format("item-summary", _items.size());
   }
-</pre>
-</div></div><p>The format() option works using a 
<code>java.util.Formatter</code>, with all the printf-style loveliness you've 
come to expect:</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;">no-items=Your shopping cart is empty.     
+</plain-text-body><p>The format() option works using a 
<code>java.util.Formatter</code>, with all the printf-style loveliness you've 
come to expect:</p><parameter 
ac:name="">java</parameter><plain-text-body>no-items=Your shopping cart is 
empty.     
 item-summary=You have %d items in your cart.
-</pre>
-</div></div><p>As easy as conditionals are to use inside a Tapestry template, 
sometimes it's even easier to do it in Java code.</p><h2 
id="Localization-MissingKeys">Missing Keys</h2><p>If you reference a key that 
is not in the message catalog, Tapestry does not throw an exception (because 
that would make initially developing an application very frustrating). When a 
key can not be located, a "placeholder" message is generated, such as 
"[[missing key: key-not-found]]".</p><h2 
id="Localization-Reloading">Reloading</h2><p>If you change a property file in a 
message catalog, you'll see the change immediately, just as with component 
classes and component templates (provided you're not running in <a  
href="configuration.html">production mode</a>).</p><h2 
id="Localization-AssetLocalization">Asset Localization</h2><p>When <a  
href="injection.html">injecting assets</a>, the injected asset will be 
localized as well. A search for the closest match for the active locale is 
made, and the final Ass
 et will reflect that.</p><h2 id="Localization-LocaleSelection">Locale 
Selection</h2><p>The locale for each request is determined from the HTTP 
request headers. The request locale reflects the environment of the web browser 
and possibly even the keyboard selection of the user on the client. It can be 
highly specific, for example, identifying British English (as en_GB) vs. 
American English (en).</p><p>Tapestry "narrows" the raw request locale, as 
specified in the request, to a known quantity. It uses the <a  
href="configuration.html">configuration symbol</a> 
<code>tapestry.supported-locales</code> to choose the effective locale for each 
request. This value is a comma-separated list of locale names. Tapestry 
searches the list for the best match for the request locale; for example, a 
request locale of "fr_FR" would match "fr" but not "de". If no match is found, 
then the first locale name in the list is used as the effective locale (that 
is, the first locale is used as the default for no
 n-matching requests). Thus a site that primarily caters to French speakers 
would want to list "fr" as the first locale in the list.</p><h2 
id="Localization-ChangingtheLocale">Changing the Locale</h2><p>The <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/PersistentLocale.html";>PersistentLocale
 service</a> can be used to programmatically override the locale. Note: You 
should be careful to only set the persistent locale to a supported 
locale.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>Toggle 
between English and German</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">@Inject 
+</plain-text-body><p>As easy as conditionals are to use inside a Tapestry 
template, sometimes it's even easier to do it in Java code.</p><h2 
id="Localization-MissingKeys">Missing Keys</h2><p>If you reference a key that 
is not in the message catalog, Tapestry does not throw an exception (because 
that would make initially developing an application very frustrating). When a 
key can not be located, a "placeholder" message is generated, such as 
"[[missing key: key-not-found]]".</p><h2 
id="Localization-Reloading">Reloading</h2><p>If you change a property file in a 
message catalog, you'll see the change immediately, just as with component 
classes and component templates (provided you're not running in <a  
href="configuration.html">production mode</a>).</p><h2 
id="Localization-AssetLocalization">Asset Localization</h2><p>When <a  
href="injection.html">injecting assets</a>, the injected asset will be 
localized as well. A search for the closest match for the active locale is 
made, and the fin
 al Asset will reflect that.</p><h2 id="Localization-LocaleSelection">Locale 
Selection</h2><p>The locale for each request is determined from the HTTP 
request headers. The request locale reflects the environment of the web browser 
and possibly even the keyboard selection of the user on the client. It can be 
highly specific, for example, identifying British English (as en_GB) vs. 
American English (en).</p><p>Tapestry "narrows" the raw request locale, as 
specified in the request, to a known quantity. It uses the <a  
href="configuration.html">configuration symbol</a> 
<code>tapestry.supported-locales</code> to choose the effective locale for each 
request. This value is a comma-separated list of locale names. Tapestry 
searches the list for the best match for the request locale; for example, a 
request locale of "fr_FR" would match "fr" but not "de". If no match is found, 
then the first locale name in the list is used as the effective locale (that 
is, the first locale is used as the default 
 for non-matching requests). Thus a site that primarily caters to French 
speakers would want to list "fr" as the first locale in the list.</p><h2 
id="Localization-ChangingtheLocale">Changing the Locale</h2><p>The <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/PersistentLocale.html";>PersistentLocale
 service</a> can be used to programmatically override the locale. Note: You 
should be careful to only set the persistent locale to a supported 
locale.</p><parameter ac:name="">java</parameter><parameter 
ac:name="title">Toggle between English and 
German</parameter><plain-text-body>@Inject 
 private PersistentLocale persistentLocale;
 
 void onActionFromLocaleToggle() {
@@ -178,9 +106,8 @@ void onActionFromLocaleToggle() {
 public String getDisplayLanguage() {
     return persistentLocale.get().getDisplayLanguage();
 }
-</pre>
-</div></div><p>Once a persistent locale is set, you will see the locale name 
as the first virtual folder in page render and component event requests URLs. 
In this way, a persistent locale will, in fact, persist from request to 
request, or in a user's bookmarks.</p><p>You will see the new locale take 
effect on the next request. If it is changed in a component event request 
(which is typical), the new locale will be used in the subsequent page render 
request.</p><p>Note that the locale for a page is fixed (it can't change once 
the page instance is created). In addition, a page may only be attached to a 
request once. In other words, if code in your page changes the persistent 
locale, you won't see a change to the page's locale (or localized messages) 
<em>in that request</em>.</p><h2 id="Localization-Built-inLocales">Built-in 
Locales</h2><p>While your application can support any locale (and thus any 
language) that you want, Tapestry provides only a limited set of translations 
for its ow
 n built-in messages. As of Tapestry 5.3, the following locales have 
translations provided:</p><div class="table-wrap"><table 
class="confluenceTable"><tbody><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p>en (English)</p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>el (Greek)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>it (Italian)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>pl 
(Polish)</span></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span><span>sv 
(Swedish)</span></span></p></td></tr><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p>bg (Bulgarian)</p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>es (Spanish)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>ja (Japanese)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>pt 
(Portuguese)</span></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span><span>
 vi (Vietnamese)</span></span></p></td></tr><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p>cs (Czech)<sup>1</sup></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>fi (Finnish)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>mk 
(Macedonian)</span></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>ru (Russian)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>zh 
(Chinese)</span></p></td></tr><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>da (Danish)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>fr (French)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>nl 
(Dutch)</span></p></td><td colspan="1" rowspan="1" class="confluenceTd">sl 
(Slovenian)<sup>2</sup></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p>&#160;</p></td></tr><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>de (German)</span></p></td><td colspan="1" 
 rowspan="1" class="confluenceTd"><p><span>hr (Croatian)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>no 
(Norwegian)</span></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>sr (Serbian)</span></p></td><td colspan="1" 
rowspan="1" 
class="confluenceTd"><p>&#160;</p></td></tr></tbody></table></div><p><sup>1&#160;</sup><span
 style="line-height: 1.4285715;">as of Tapestry 5.3.8</span></p><p><span 
style="line-height: 1.4285715;">&#160;</span><sup>2 </sup><span>as of Tapestry 
5.4</span></p><h3 
id="Localization-ProvidingtranslationsforTapestrybuilt-inmessages">Providing 
translations for Tapestry built-in messages</h3><p>Fortunately, Tapestry uses 
all the same mechanisms for its own locale support as it provides for your 
application. So, to support other locales, just translate the built-in message 
catalog (property) files yourself:</p><p>&#160;</p><style 
type="text/css">table.sectionMacro { width: auto; }</style>
-<div class="sectionColumnWrapper"><div class="sectionMacro"><div 
class="sectionMacroRow"><div class="columnMacro"><div class="table-wrap"><table 
class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" 
class="confluenceTh"><p>Tapestry 5.4 and later</p></th></tr><tr><td colspan="1" 
rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=tree;f=tapestry-core/src/main/resources/org/apache/tapestry5";>core.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=tree;f=tapestry-kaptcha/src/main/resources/org/apache/tapestry5/kaptcha";>tapestry-kaptcha.properties</a></p></td></tr></tbody></table></div></div><div
 class="columnMacro"><div class="table-wrap"><table 
class="confluenceTable"><tbody><tr><th colspan="1" rowspan="1" 
class="confluenceTh"><p>Tapestry 5.3.x</p></th></tr><tr><td colspan="1" row
 span="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/BeanEditForm.properties?view=markup";>BeanEditForm.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/DateField.properties?view=markup";>DateField.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Errors.properties?view=markup";>Errors.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/br
 
anches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/GridColumns.properties?view=markup">GridColumns.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/GridPager.properties?view=markup";>GridPager.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Palette.properties?view=markup";>Palette.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties?view=markup
 ">ValidationMessages.properties</a></p></td></tr><tr><td colspan="1" 
rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-kaptcha/src/main/resources/org/apache/tapestry5/kaptcha/tapestry-kaptcha.properties?view=markup";>tapestry-kaptcha.properties</a></p></td></tr></tbody></table></div></div></div></div></div><p>To
 have Tapestry use these new files, just put them in the corresponding 
package-named directory within your own app (for example, 
src/main/resources/org/apache/tapestry5/core.properties).</p><p>Finally, please 
open a new feature request <a  class="external-link" 
href="https://issues.apache.org/jira/browse/TAP5";>here</a> and attach the 
translated files so that they can be included in the next release of 
Tapestry.</p><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>Please note that a patch is 
 >always preferred over an archive of properties files.</p></div></div></div>
+</plain-text-body><p>Once a persistent locale is set, you will see the locale 
name as the first virtual folder in page render and component event requests 
URLs. In this way, a persistent locale will, in fact, persist from request to 
request, or in a user's bookmarks.</p><p>You will see the new locale take 
effect on the next request. If it is changed in a component event request 
(which is typical), the new locale will be used in the subsequent page render 
request.</p><p>Note that the locale for a page is fixed (it can't change once 
the page instance is created). In addition, a page may only be attached to a 
request once. In other words, if code in your page changes the persistent 
locale, you won't see a change to the page's locale (or localized messages) 
<em>in that request</em>.</p><h2 id="Localization-Built-inLocales">Built-in 
Locales</h2><p>While your application can support any locale (and thus any 
language) that you want, Tapestry provides only a limited set of translations 
for 
 its own built-in messages. As of Tapestry 5.3, the following locales have 
translations provided:</p><div class="table-wrap"><table 
class="confluenceTable"><tbody><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p>en (English)</p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>el (Greek)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>it (Italian)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>pl 
(Polish)</span></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span><span>sv 
(Swedish)</span></span></p></td></tr><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p>bg (Bulgarian)</p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>es (Spanish)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>ja (Japanese)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>pt 
(Portuguese)</span></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>
 <span>vi (Vietnamese)</span></span></p></td></tr><tr><td colspan="1" 
rowspan="1" class="confluenceTd"><p>cs (Czech)<sup>1</sup></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>fi 
(Finnish)</span></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>mk (Macedonian)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>ru (Russian)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>zh 
(Chinese)</span></p></td></tr><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>da (Danish)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>fr (French)</span></p></td><td 
colspan="1" rowspan="1" class="confluenceTd"><p><span>nl 
(Dutch)</span></p></td><td colspan="1" rowspan="1" class="confluenceTd">sl 
(Slovenian)<sup>2</sup></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p>&#160;</p></td></tr><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>de (German)</span></p></td><td colspa
 n="1" rowspan="1" class="confluenceTd"><p><span>hr 
(Croatian)</span></p></td><td colspan="1" rowspan="1" 
class="confluenceTd"><p><span>no (Norwegian)</span></p></td><td colspan="1" 
rowspan="1" class="confluenceTd"><p><span>sr (Serbian)</span></p></td><td 
colspan="1" rowspan="1" 
class="confluenceTd"><p>&#160;</p></td></tr></tbody></table></div><p><sup>1&#160;</sup><span
 style="line-height: 1.4285715;">as of Tapestry 5.3.8</span></p><p><span 
style="line-height: 1.4285715;">&#160;</span><sup>2 </sup><span>as of Tapestry 
5.4</span></p><h3 
id="Localization-ProvidingtranslationsforTapestrybuilt-inmessages">Providing 
translations for Tapestry built-in messages</h3><p>Fortunately, Tapestry uses 
all the same mechanisms for its own locale support as it provides for your 
application. So, to support other locales, just translate the built-in message 
catalog (property) files yourself:</p><p>&#160;</p><parameter 
ac:name="atlassian-macro-output-type">BLOCK</parameter><plain-text-body>&lt;style
 typ
 e="text/css"&gt;table.sectionMacro { width: auto; }&lt;/style&gt;
+</plain-text-body><parameter 
ac:name="width">auto</parameter><rich-text-body><rich-text-body><div 
class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" 
rowspan="1" class="confluenceTh"><p>Tapestry 5.4 and later</p></th></tr><tr><td 
colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=tree;f=tapestry-core/src/main/resources/org/apache/tapestry5";>core.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="https://git-wip-us.apache.org/repos/asf?p=tapestry-5.git;a=tree;f=tapestry-kaptcha/src/main/resources/org/apache/tapestry5/kaptcha";>tapestry-kaptcha.properties</a></p></td></tr></tbody></table></div></rich-text-body><rich-text-body><div
 class="table-wrap"><table class="confluenceTable"><tbody><tr><th colspan="1" 
rowspan="1" class="confluenceTh"><p>Tapestry 5.3.x</p></th></tr><tr><td 
colspan="1" rowspan="1" class="con
 fluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/BeanEditForm.properties?view=markup";>BeanEditForm.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/DateField.properties?view=markup";>DateField.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Errors.properties?view=markup";>Errors.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry
 
-core/src/main/resources/org/apache/tapestry5/corelib/components/GridColumns.properties?view=markup">GridColumns.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/GridPager.properties?view=markup";>GridPager.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/components/Palette.properties?view=markup";>Palette.properties</a></p></td></tr><tr><td
 colspan="1" rowspan="1" class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-core/src/main/resources/org/apache/tapestry5/internal/ValidationMessages.properties?view=markup";>ValidationMessage
 s.properties</a></p></td></tr><tr><td colspan="1" rowspan="1" 
class="confluenceTd"><p><a  class="external-link" 
href="http://svn.apache.org/viewvc/tapestry/tapestry5/branches/5.3/tapestry-kaptcha/src/main/resources/org/apache/tapestry5/kaptcha/tapestry-kaptcha.properties?view=markup";>tapestry-kaptcha.properties</a></p></td></tr></tbody></table></div></rich-text-body></rich-text-body><p>To
 have Tapestry use these new files, just put them in the corresponding 
package-named directory within your own app (for example, 
src/main/resources/org/apache/tapestry5/core.properties).</p><p>Finally, please 
open a new feature request <a  class="external-link" 
href="https://issues.apache.org/jira/browse/TAP5";>here</a> and attach the 
translated files so that they can be included in the next release of 
Tapestry.</p><rich-text-body><p>Please note that a patch is always preferred 
over an archive of properties files.</p></rich-text-body></div>
       </div>
 
       <div class="clearer"></div>

Modified: websites/production/tapestry/content/maven-support-faq.html
==============================================================================
--- websites/production/tapestry/content/maven-support-faq.html (original)
+++ websites/production/tapestry/content/maven-support-faq.html Tue Sep 26 
19:20:27 2017
@@ -27,16 +27,6 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
-          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
-    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
-    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushXml.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushPlain.js' 
type='text/javascript'></script>
-        <script>
-      SyntaxHighlighter.defaults['toolbar'] = false;
-      SyntaxHighlighter.all();
-    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -77,8 +67,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><h2 
id="MavenSupportFAQ-MavenSupport">Maven Support</h2><h3 
id="MavenSupportFAQ-WhydoMavenprojectnamesandotherdetailsshowupinmypages?">Why 
do Maven project names and other details show up in my pages?</h3><p>Tapestry 
and maven both use the same syntax for dynamic portions of files: the 
<code>${...</code>} syntax. When Maven is copying resources from 
<code>src/main/resources</code>, and when filtering is <em>enabled</em> (which 
is not the default), then any expansions in <em>Tapestry templates</em> that 
match against Maven project properties are substituted. If you look at the 
deployed application you'll see that <code>${name</code>} is gone, replaced 
with your project's name!</p><p>The solution is to update your 
<code>pom.xml</code> and ignore any .tml files when copying and 
filtering:</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>pom.xml 
(partial)</b>
 </div><div class="codeContent panelContent pdl">
-<pre class="brush: xml; gutter: false; theme: Default" 
style="font-size:12px;">  &lt;resource&gt;
+                <div 
id="ConfluenceContent"><plain-text-body>{scrollbar}</plain-text-body><h2 
id="MavenSupportFAQ-MavenSupport">Maven Support</h2><h3 
id="MavenSupportFAQ-WhydoMavenprojectnamesandotherdetailsshowupinmypages?">Why 
do Maven project names and other details show up in my pages?</h3><p>Tapestry 
and maven both use the same syntax for dynamic portions of files: the 
<code>${...</code>} syntax. When Maven is copying resources from 
<code>src/main/resources</code>, and when filtering is <em>enabled</em> (which 
is not the default), then any expansions in <em>Tapestry templates</em> that 
match against Maven project properties are substituted. If you look at the 
deployed application you'll see that <code>${name</code>} is gone, replaced 
with your project's name!</p><p>The solution is to update your 
<code>pom.xml</code> and ignore any .tml files when copying and 
filtering:</p><parameter ac:name="language">xml</parameter><parameter 
ac:name="title">pom.xml (partial)</parameter><plain
 -text-body>  &lt;resource&gt;
     &lt;directory&gt;src/main/resources&lt;/directory&gt;
     &lt;excludes&gt;
       &lt;exclude&gt;**/*.tml&lt;/exclude&gt;
@@ -93,8 +82,7 @@
     &lt;/includes&gt;
     &lt;filtering&gt;false&lt;/filtering&gt;
   &lt;/resource&gt;
-</pre>
-</div></div></div>
+</plain-text-body><plain-text-body>{scrollbar}</plain-text-body></div>
       </div>
 
       <div class="clearer"></div>

Modified: 
websites/production/tapestry/content/meta-programming-page-content.html
==============================================================================
--- websites/production/tapestry/content/meta-programming-page-content.html 
(original)
+++ websites/production/tapestry/content/meta-programming-page-content.html Tue 
Sep 26 19:20:27 2017
@@ -27,17 +27,6 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
-          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
-    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
-    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushXml.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushJScript.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushPlain.js' 
type='text/javascript'></script>
-        <script>
-      SyntaxHighlighter.defaults['toolbar'] = false;
-      SyntaxHighlighter.all();
-    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -78,8 +67,7 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><h1 
id="Meta-ProgrammingPageContent-Meta-ProgrammingPageContent">Meta-Programming 
Page Content</h1><p>It is likely that you have some cross-cutting concerns 
across your pages, specific features you would like to "mix in" to your pages 
without getting tied into knots by inheritance. This is one of those areas 
where Tapestry shines.</p><p>This specific example is adapted from a real 
client requirement: the client was concerned about other sites wrapping his 
content in a frameset and making the site content appear to be theirs. Not all 
pages (in some cases, that would be an advantage) but specific pages in the 
application. For those pages, the following behaviors were 
required:</p><ul><li>Set the X-Frame-Options response header to 
"DENY"</li><li>Include JavaScript to "pop" the page out of a frame, if in 
one</li></ul><p>Again, this <em>could</em> be done by having a specific 
base-class that included a <code>beginRender()</code> method, but the
  meta-programming approach is nearly as easy and much more flexible.</p><h2 
id="Meta-ProgrammingPageContent-ComponentMeta-Data">Component 
Meta-Data</h2><p>In Tapestry, every component (and remember, pages are 
components) has <em>meta data</em>: an extra set of key/value pairs stored in 
the component's <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ComponentResources.html";>ComponentResources</a>.</p><p>By
 hooking into the component class transformation pipeline, we can change an 
annotation into meta-data that can be accessed by a filter.</p><h2 
id="Meta-ProgrammingPageContent-DefiningtheAnnotation">Defining the 
Annotation</h2><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ForbidFraming.java</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">package com.fnord.annotations;
+                <div 
id="ConfluenceContent"><p><plain-text-body>{scrollbar}</plain-text-body></p><parameter
 ac:name="hidden">true</parameter><parameter 
ac:name="atlassian-macro-output-type">BLOCK</parameter><rich-text-body><p>Adding
 an Annotation and a Filter to customize Tapestry's page 
rendering</p></rich-text-body><h1 
id="Meta-ProgrammingPageContent-Meta-ProgrammingPageContent">Meta-Programming 
Page Content</h1><p>It is likely that you have some cross-cutting concerns 
across your pages, specific features you would like to "mix in" to your pages 
without getting tied into knots by inheritance. This is one of those areas 
where Tapestry shines.</p><p>This specific example is adapted from a real 
client requirement: the client was concerned about other sites wrapping his 
content in a frameset and making the site content appear to be theirs. Not all 
pages (in some cases, that would be an advantage) but specific pages in the 
application. For those pages, the following behaviors were requ
 ired:</p><ul><li>Set the X-Frame-Options response header to 
"DENY"</li><li>Include JavaScript to "pop" the page out of a frame, if in 
one</li></ul><p>Again, this <em>could</em> be done by having a specific 
base-class that included a <code>beginRender()</code> method, but the 
meta-programming approach is nearly as easy and much more flexible.</p><h2 
id="Meta-ProgrammingPageContent-ComponentMeta-Data">Component 
Meta-Data</h2><p>In Tapestry, every component (and remember, pages are 
components) has <em>meta data</em>: an extra set of key/value pairs stored in 
the component's <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/ComponentResources.html";>ComponentResources</a>.</p><p>By
 hooking into the component class transformation pipeline, we can change an 
annotation into meta-data that can be accessed by a filter.</p><h2 
id="Meta-ProgrammingPageContent-DefiningtheAnnotation">Defining the 
Annotation</h2><parameter ac:name="language">java</para
 meter><parameter 
ac:name="title">ForbidFraming.java</parameter><plain-text-body>package 
com.fnord.annotations;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
@@ -98,9 +86,7 @@ import java.lang.annotation.Target;
 public @interface ForbidFraming {
 
 }
-</pre>
-</div></div><p>This annotation presence is all that's needed; there aren't any 
additional attributes to configure it.</p><h2 
id="Meta-ProgrammingPageContent-ConvertingtheAnnotationintoMeta-Data">Converting
 the Annotation into Meta-Data</h2><p>This is in three parts:</p><ul><li>Define 
the meta-data key, and define a constant for that key</li><li>Set a default 
meta-data value for the key</li><li>Set a different value for the key when the 
annotation is present</li></ul><p>Our key is just "forbid-framing", with values 
"true" and "false". The default is "false".</p><h3 
id="Meta-ProgrammingPageContent-DefiningtheConstant">Defining the 
Constant</h3><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>FnordSymbols.java</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">package com.fnord;
+</plain-text-body><p>This annotation presence is all that's needed; there 
aren't any additional attributes to configure it.</p><h2 
id="Meta-ProgrammingPageContent-ConvertingtheAnnotationintoMeta-Data">Converting
 the Annotation into Meta-Data</h2><p>This is in three parts:</p><ul><li>Define 
the meta-data key, and define a constant for that key</li><li>Set a default 
meta-data value for the key</li><li>Set a different value for the key when the 
annotation is present</li></ul><p>Our key is just "forbid-framing", with values 
"true" and "false". The default is "false".</p><h3 
id="Meta-ProgrammingPageContent-DefiningtheConstant">Defining the 
Constant</h3><parameter ac:name="language">java</parameter><parameter 
ac:name="title">FnordSymbols.java</parameter><plain-text-body>package com.fnord;
 
 import org.apache.tapestry5.services.BaseURLSource;
 
@@ -118,9 +104,7 @@ public class FnordSymbols {
   public static final String FORBID_FRAMING = "forbid-framing";
 
 }
-</pre>
-</div></div><h3 
id="Meta-ProgrammingPageContent-SettingtheMeta-DataDefault">Setting the 
Meta-Data Default</h3><p>Next, we'll create a module just for the logic 
directly related to framing. In the module, we'll define the default value for 
the meta-data.</p><div class="code panel pdl" style="border-width: 1px;"><div 
class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ForbidFramingModule.class</b></div><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">package com.fnord.services.forbidframing;
+</plain-text-body><h3 
id="Meta-ProgrammingPageContent-SettingtheMeta-DataDefault">Setting the 
Meta-Data Default</h3><p>Next, we'll create a module just for the logic 
directly related to framing. In the module, we'll define the default value for 
the meta-data.</p><parameter ac:name="language">java</parameter><parameter 
ac:name="title">ForbidFramingModule.class</parameter><plain-text-body>package 
com.fnord.services.forbidframing;
 
 import org.apache.tapestry5.ioc.MappedConfiguration;
 import org.apache.tapestry5.ioc.annotations.Contribute;
@@ -138,26 +122,20 @@ public class ForbidFramingModule {
     configuration.add(FnordSymbols.FORBID_FRAMING, "false");
   }
 }
-</pre>
-</div></div><h3 id="Meta-ProgrammingPageContent-MappingtheAnnotation">Mapping 
the Annotation</h3><p>Most of the work has already been done for us: we just 
have to make a contribution to the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/meta/MetaWorker.html";>MetaWorker</a>
 service, which is already plugged into the component class transformation 
pipeline. MetaWorker spots the annotations we define and uses a second object, 
a <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/meta/MetaDataExtractor.html";>MetaDataExtractor</a>
 we provide, to convert the annotation into a meta-data value.</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeHeader 
panelHeader pdl" style="border-bottom-width: 1px;"><b>ForbidFramingModule.java 
(partial)</b></div><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Contribute(MetaWorker.class)
+</plain-text-body><h3 
id="Meta-ProgrammingPageContent-MappingtheAnnotation">Mapping the 
Annotation</h3><p>Most of the work has already been done for us: we just have 
to make a contribution to the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/meta/MetaWorker.html";>MetaWorker</a>
 service, which is already plugged into the component class transformation 
pipeline. MetaWorker spots the annotations we define and uses a second object, 
a <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/meta/MetaDataExtractor.html";>MetaDataExtractor</a>
 we provide, to convert the annotation into a meta-data value.</p><parameter 
ac:name="language">java</parameter><parameter 
ac:name="lang">java</parameter><parameter 
ac:name="title">ForbidFramingModule.java (partial)</parameter><plain-text-body> 
 @Contribute(MetaWorker.class)
   public static void mapAnnotationsToMetaDataValue(
       MappedConfiguration&lt;Class, MetaDataExtractor&gt; configuration) {
     configuration
         .add(ForbidFraming.class, new FixedExtractor&lt;ForbidFraming&gt;(
             FnordSymbols.FORBID_FRAMING));
   }
-</pre>
-</div></div><p>If the ForbidFraming annotation had attributes, we would have 
provided an implementation of MetaDataExtractor that examined those attributes 
to set the meta-data value. Since it has no attributes, the <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/meta/FixedExtractor.html";>FixedExtractor</a>
 class can be used. The argument is the meta-data key, and the default value is 
"true".</p><h2 
id="Meta-ProgrammingPageContent-PluggingIntoPageRendering">Plugging Into Page 
Rendering</h2><p>The work we ultimately want to do occurs when rendering a 
page. Tapestry defines a <a  href="pipelinebuilder-service.html">pipeline</a> 
for that overall process. The point of a pipeline is that we can add filters to 
it. We'll add a filter that checks for the meta-data key and adds the response 
header and JavaScript.</p><p>The service is <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/service
 s/MarkupRenderer.html">MarkupRenderer</a>, which (being a pipeline service), 
takes a configuration of filters (in this case, <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/MarkupRendererFilter.html";>MarkupRendererFilter</a>.</p><p>We
 contribute into the pipeline; the order is important: since the filter will 
need to write JavaScript, it must be added <em>after</em> the built-in filter 
that provides the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/javascript/JavaScriptSupport.html";>JavaScriptSupport</a>
 environmental object.</p><div class="code panel pdl" style="border-width: 
1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 
1px;"><b>ForbidFramingModule.java (partial)</b></div><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">  @Contribute(MarkupRenderer.class)
+</plain-text-body><p>If the ForbidFraming annotation had attributes, we would 
have provided an implementation of MetaDataExtractor that examined those 
attributes to set the meta-data value. Since it has no attributes, the <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/meta/FixedExtractor.html";>FixedExtractor</a>
 class can be used. The argument is the meta-data key, and the default value is 
"true".</p><h2 
id="Meta-ProgrammingPageContent-PluggingIntoPageRendering">Plugging Into Page 
Rendering</h2><p>The work we ultimately want to do occurs when rendering a 
page. Tapestry defines a <a  href="pipelinebuilder-service.html">pipeline</a> 
for that overall process. The point of a pipeline is that we can add filters to 
it. We'll add a filter that checks for the meta-data key and adds the response 
header and JavaScript.</p><p>The service is <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/s
 ervices/MarkupRenderer.html">MarkupRenderer</a>, which (being a pipeline 
service), takes a configuration of filters (in this case, <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/MarkupRendererFilter.html";>MarkupRendererFilter</a>.</p><p>We
 contribute into the pipeline; the order is important: since the filter will 
need to write JavaScript, it must be added <em>after</em> the built-in filter 
that provides the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/javascript/JavaScriptSupport.html";>JavaScriptSupport</a>
 environmental object.</p><parameter 
ac:name="language">java</parameter><parameter 
ac:name="lang">java</parameter><parameter 
ac:name="title">ForbidFramingModule.java (partial)</parameter><plain-text-body> 
 @Contribute(MarkupRenderer.class)
   public static void addFilter(
       OrderedConfiguration&lt;MarkupRendererFilter&gt; configuration) {
     configuration.addInstance("ForbidFraming", ForbidFramingFilter.class,
         "after:JavascriptSupport");
   }
-</pre>
-</div></div><p>How do you know what filters are built-in and where to add your 
own? The right starting point is the JavaDoc for the method of TapestryModule 
that contributes the base set: <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/modules/TapestryModule.html";>contributeMarkupRenderer()</a></p><h2
 id="Meta-ProgrammingPageContent-ImplementingtheFilter">Implementing the 
Filter</h2><p>Everything comes together in the filter:</p><div class="code 
panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>ForbidFramingFilter.java</b></div><div 
class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: false; theme: Default" 
style="font-size:12px;">package com.fnord.services.forbidframing;
+</plain-text-body><p>How do you know what filters are built-in and where to 
add your own? The right starting point is the JavaDoc for the method of 
TapestryModule that contributes the base set: <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/modules/TapestryModule.html";>contributeMarkupRenderer()</a></p><h2
 id="Meta-ProgrammingPageContent-ImplementingtheFilter">Implementing the 
Filter</h2><p>Everything comes together in the filter:</p><parameter 
ac:name="language">java</parameter><parameter 
ac:name="title">ForbidFramingFilter.java</parameter><plain-text-body>package 
com.fnord.services.forbidframing;
 
 import org.apache.tapestry5.MarkupWriter;
 import org.apache.tapestry5.ioc.annotations.Inject;
@@ -205,16 +183,13 @@ public class ForbidFramingFilter impleme
   }
 
 }
-</pre>
-</div></div><p>There's a bit going on in this short piece of code. The heart 
of the code is the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/MetaDataLocator.html";>MetaDataLocator</a>
 service; given a meta-data key and a page name, it can not only extract the 
value, but then <a  href="ioc-coerce.html">coerce</a> it to a desired type, all 
in one go.</p><p>How do we know which page is being rendered? Before Tapestry 
5.2 that was a small challenge, but 5.2 adds a method to <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestGlobals.html#getActivePageName()">RequestGlobals</a>
 for this exact purpose.</p><p>Both Request and JavaScriptSupport are 
per-thread/per-request services. You don't see that here, because that's part 
of the service definition, and invisible to the consumer code, as 
here.</p><p>Of course, it is vitally important that the filter re-invoke 
<code>markup
 ()</code> on the next renderer in the pipeline (you can see that as the last 
line of the method).</p><p>This code makes one assumption: that the fnord 
application's Layout component added fnord.js to every page. That's necessary 
for the JavaScript that's added:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeHeader panelHeader pdl" 
style="border-bottom-width: 1px;"><b>fnord.js (partial)</b></div><div 
class="codeContent panelContent pdl">
-<pre class="brush: js; gutter: false; theme: Default" 
style="font-size:12px;">Fnord = {
+</plain-text-body><p>There's a bit going on in this short piece of code. The 
heart of the code is the <a  class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/MetaDataLocator.html";>MetaDataLocator</a>
 service; given a meta-data key and a page name, it can not only extract the 
value, but then <a  href="ioc-coerce.html">coerce</a> it to a desired type, all 
in one go.</p><p>How do we know which page is being rendered? Before Tapestry 
5.2 that was a small challenge, but 5.2 adds a method to <a  
class="external-link" 
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/services/RequestGlobals.html#getActivePageName()">RequestGlobals</a>
 for this exact purpose.</p><p>Both Request and JavaScriptSupport are 
per-thread/per-request services. You don't see that here, because that's part 
of the service definition, and invisible to the consumer code, as 
here.</p><p>Of course, it is vitally important that the filter re-invoke <code>
 markup()</code> on the next renderer in the pipeline (you can see that as the 
last line of the method).</p><p>This code makes one assumption: that the fnord 
application's Layout component added fnord.js to every page. That's necessary 
for the JavaScript that's added:</p><parameter 
ac:name="language">js</parameter><parameter 
ac:name="lang">javascript</parameter><parameter ac:name="title">fnord.js 
(partial)</parameter><plain-text-body>Fnord = {
   popOutOfFrame : function() {
     if (top != self)
       top.location.replace(location);
   }
 }
-</pre>
-</div></div><h2 
id="Meta-ProgrammingPageContent-Conclusion">Conclusion</h2><p>That's it: with 
the above code, simply adding the @ForbidFraming annotation to a page will add 
the response header and associated JavaScript; no inheritance hassles. This 
basic pattern can be applied to a wide range of cross-cutting concerns, such as 
security, transaction management, logging, or virtually any other kind of 
situation that would normally be solved with inheritance or ugly boilerplate 
code.</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>The code in this example was 
designed for Tapestry version 5.2 and later.</p></div></div></div>
+</plain-text-body><h2 
id="Meta-ProgrammingPageContent-Conclusion">Conclusion</h2><p>That's it: with 
the above code, simply adding the @ForbidFraming annotation to a page will add 
the response header and associated JavaScript; no inheritance hassles. This 
basic pattern can be applied to a wide range of cross-cutting concerns, such as 
security, transaction management, logging, or virtually any other kind of 
situation that would normally be solved with inheritance or ugly boilerplate 
code.</p><rich-text-body><p>The code in this example was designed for Tapestry 
version 5.2 and later.</p></rich-text-body></div>
       </div>
 
       <div class="clearer"></div>

Modified: 
websites/production/tapestry/content/page-and-component-classes-faq.html
==============================================================================
--- websites/production/tapestry/content/page-and-component-classes-faq.html 
(original)
+++ websites/production/tapestry/content/page-and-component-classes-faq.html 
Tue Sep 26 19:20:27 2017
@@ -27,16 +27,6 @@
       </title>
   <link type="text/css" rel="stylesheet" href="/resources/space.css" />
 
-          <link href='/resources/highlighter/styles/shCoreCXF.css' 
rel='stylesheet' type='text/css' />
-    <link href='/resources/highlighter/styles/shThemeCXF.css' rel='stylesheet' 
type='text/css' />
-    <script src='/resources/highlighter/scripts/shCore.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushJava.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushXml.js' 
type='text/javascript'></script>
-          <script src='/resources/highlighter/scripts/shBrushPlain.js' 
type='text/javascript'></script>
-        <script>
-      SyntaxHighlighter.defaults['toolbar'] = false;
-      SyntaxHighlighter.all();
-    </script>
   
   <link href="/styles/style.css" rel="stylesheet" type="text/css"/>
 
@@ -77,14 +67,11 @@
       </div>
 
       <div id="content">
-                <div id="ConfluenceContent"><h2 
id="PageAndComponentClassesFAQ-PageAndComponentClasses">Page And Component 
Classes</h2><p>Main article: <a  href="component-classes.html">Component 
Classes</a></p><h3 
id="PageAndComponentClassesFAQ-What'sthedifferencebetweenapageandacomponent?">What's
 the difference between a page and a component?</h3><p>There's very little 
difference between the two. Pages classes must be in the 
<em>root-package</em>.<code>pages</code> package; components must be in the 
<em>root-package</em>.<code>components</code>. Pages may provide event handlers 
for certain page-specific events (such as activate and passivate). Components 
may have parameters.</p><p>Other than that, they are more equal than they are 
different. They may have templates or may render themselves in code (pages 
usually have a template, components are more likely to render only in 
code).</p><p>The major difference is that Tapestry page templates may be stored 
in the web context directory,
  as if they were static files (they can't be accessed from the client however; 
a specific rule prevents access to files with the <code>.tml</code> 
extension).</p><div class="confluence-information-macro 
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>It is possible that this feature 
may be removed in a later release. It is preferred that page templates be 
stored on the classpath, like component templates.</p></div></div><h3 
id="PageAndComponentClassesFAQ-HowdoIstoremypageclassesinadifferentpackage?">How
 do I store my page classes in a different package?</h3><p>Tapestry is very 
rigid here; you can't. Page classes must go in 
<em>root-package</em>.<code>pages</code>, component classes in 
<em>root-package</em>.<code>components</code>, etc.</p><p>You are allowed to 
create sub-packages, to help organize your code better and more logically. For 
example, 
 you might have <em>root-package</em>.<code>pages.account.ViewAccount</code>, 
which would have the page name "account/viewaccount". (<span 
style="line-height: 1.4285715;">Tapestry would also create an alias 
"account/view", by stripping off the redundant "account" suffix. Either name is 
equally valid in your code, and Tapestry will use the shorter name, 
"account/view" in URLs.)</span></p><p>In addition, it is possible to define 
additional root packages for the application:</p><div class="code panel pdl" 
style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: true; theme: Default" 
style="font-size:12px;">public static void 
contributeComponentClassResolver(Configuration&lt;LibraryMapping&gt; 
configuration) {
+                <div 
id="ConfluenceContent"><plain-text-body>{scrollbar}</plain-text-body><h2 
id="PageAndComponentClassesFAQ-PageAndComponentClasses">Page And Component 
Classes</h2><p>Main article: <a  href="component-classes.html">Component 
Classes</a></p><h3 
id="PageAndComponentClassesFAQ-What'sthedifferencebetweenapageandacomponent?">What's
 the difference between a page and a component?</h3><p>There's very little 
difference between the two. Pages classes must be in the 
<em>root-package</em>.<code>pages</code> package; components must be in the 
<em>root-package</em>.<code>components</code>. Pages may provide event handlers 
for certain page-specific events (such as activate and passivate). Components 
may have parameters.</p><p>Other than that, they are more equal than they are 
different. They may have templates or may render themselves in code (pages 
usually have a template, components are more likely to render only in 
code).</p><p>The major difference is that Tapestry page templat
 es may be stored in the web context directory, as if they were static files 
(they can't be accessed from the client however; a specific rule prevents 
access to files with the <code>.tml</code> extension).</p><rich-text-body><p>It 
is possible that this feature may be removed in a later release. It is 
preferred that page templates be stored on the classpath, like component 
templates.</p></rich-text-body><h3 
id="PageAndComponentClassesFAQ-HowdoIstoremypageclassesinadifferentpackage?">How
 do I store my page classes in a different package?</h3><p>Tapestry is very 
rigid here; you can't. Page classes must go in 
<em>root-package</em>.<code>pages</code>, component classes in 
<em>root-package</em>.<code>components</code>, etc.</p><p>You are allowed to 
create sub-packages, to help organize your code better and more logically. For 
example, you might have 
<em>root-package</em>.<code>pages.account.ViewAccount</code>, which would have 
the page name "account/viewaccount". (<span style="line-height:
  1.4285715;">Tapestry would also create an alias "account/view", by stripping 
off the redundant "account" suffix. Either name is equally valid in your code, 
and Tapestry will use the shorter name, "account/view" in 
URLs.)</span></p><p>In addition, it is possible to define additional root 
packages for the application:</p><parameter 
ac:name="controls">true</parameter><parameter 
ac:name="linenumbers">true</parameter><plain-text-body>public static void 
contributeComponentClassResolver(Configuration&lt;LibraryMapping&gt; 
configuration) {
        configuration.add(new LibraryMapping("", "com.example.app.tasks"));
        configuration.add(new LibraryMapping("", "com.example.app.chat"));
 }
-</pre>
-</div></div><p>LibraryMappings are used to resolve a library prefix to one or 
more package names. The empty string represents the application itself; the 
above example adds two additional root packages; you might see additional pages 
under <code>com.example.app.tasks.pages</code>, for example.</p><div 
class="confluence-information-macro confluence-information-macro-warning"><span 
class="aui-icon aui-icon-small aui-iconfont-error 
confluence-information-macro-icon"></span><div 
class="confluence-information-macro-body"><p>Tapestry doesn't check for name 
collisions, and the order the packages are searched for pages and components is 
not defined. In general, if you can get by with a single root package for your 
application, that is better.</p></div></div><h3 
id="PageAndComponentClassesFAQ-Whydomyinstancevariableshavetobeprivate?">Why do 
my instance variables have to be private?</h3><p><em>In Tapestry 5.3.1 and 
earlier all instance variables must be private. Starting in version 5.3.2 inst
 ance variables can also be protected or package private (that is, not public), 
or they can even be public if <code>final</code> or annotated with the 
deprecated @Retain.</em></p><p>Tapestry does a large amount of transformation 
to your simple POJO classes as it loads them into memory. In many cases, it 
must locate every read or write of an instance variable and change its 
behavior; for example, reading a field that is a component parameter will cause 
a property of the containing page or component to be read.</p><p>Restricting 
the scope of fields allows Tapestry to do the necessary processing one class at 
a time, as needed, at runtime. More complex Aspect Orient Programming systems 
such as AspectJ can perform similar transformations (and much more complex 
ones), but they require a dedicated build step (or the introduction of a JVM 
agent).</p><h3 
id="PageAndComponentClassesFAQ-Whydon'tmyinformalparametersshowupintherenderedmarkup?">Why
 don't my informal parameters show up in the rende
 red markup?</h3><p>Getting informal parameters to work is in two steps. First, 
you must make a call to the 
<code>ComponentResources.renderInformalParameters()</code> method, but just as 
importantly, you must tell Tapestry that you want the component to support 
informal parameters, using the <code>SupportsInformalParameters</code> 
annotation. Here's a hypothetical component that displays an image based on the 
value of a <code>Image</code> object (presumably, a database entity):</p><div 
class="code panel pdl" style="border-width: 1px;"><div class="codeContent 
panelContent pdl">
-<pre class="brush: java; gutter: true; theme: Default" 
style="font-size:12px;">@SupportsInformalParameters
+</plain-text-body><p>LibraryMappings are used to resolve a library prefix to 
one or more package names. The empty string represents the application itself; 
the above example adds two additional root packages; you might see additional 
pages under <code>com.example.app.tasks.pages</code>, for 
example.</p><rich-text-body><p>Tapestry doesn't check for name collisions, and 
the order the packages are searched for pages and components is not defined. In 
general, if you can get by with a single root package for your application, 
that is better.</p></rich-text-body><h3 
id="PageAndComponentClassesFAQ-Whydomyinstancevariableshavetobeprivate?">Why do 
my instance variables have to be private?</h3><p><em>In Tapestry 5.3.1 and 
earlier all instance variables must be private. Starting in version 5.3.2 
instance variables can also be protected or package private (that is, not 
public), or they can even be public if <code>final</code> or annotated with the 
deprecated @Retain.</em></p><p>Tapestry does a 
 large amount of transformation to your simple POJO classes as it loads them 
into memory. In many cases, it must locate every read or write of an instance 
variable and change its behavior; for example, reading a field that is a 
component parameter will cause a property of the containing page or component 
to be read.</p><p>Restricting the scope of fields allows Tapestry to do the 
necessary processing one class at a time, as needed, at runtime. More complex 
Aspect Orient Programming systems such as AspectJ can perform similar 
transformations (and much more complex ones), but they require a dedicated 
build step (or the introduction of a JVM agent).</p><h3 
id="PageAndComponentClassesFAQ-Whydon'tmyinformalparametersshowupintherenderedmarkup?">Why
 don't my informal parameters show up in the rendered markup?</h3><p>Getting 
informal parameters to work is in two steps. First, you must make a call to the 
<code>ComponentResources.renderInformalParameters()</code> method, but just as 
importantly
 , you must tell Tapestry that you want the component to support informal 
parameters, using the <code>SupportsInformalParameters</code> annotation. 
Here's a hypothetical component that displays an image based on the value of a 
<code>Image</code> object (presumably, a database entity):</p><parameter 
ac:name="controls">true</parameter><parameter 
ac:name="linenumbers">true</parameter><plain-text-body>@SupportsInformalParameters
 public class DBImage
 {
   @Parameter(required=true)
@@ -104,31 +91,12 @@ public class DBImage
     return false;
   }
 }
-</pre>
-</div></div><h3 
id="PageAndComponentClassesFAQ-WhydoIgetjava.lang.LinkageErrorwhenIinvokepublicmethodsofmypageclasses?">Why
 do I get java.lang.LinkageError when I invoke public methods of my page 
classes?</h3><p>In Tapestry, there are always <em>two</em> versions of page (or 
component) classes. The first version is the version loaded by standard class 
loader: the simple POJO version that you wrote.</p><p>The second version is 
much more complicated; it's the transformed version of your code, with lots of 
extra hooks and changes to allow the class to operate inside Tapestry. This 
includes implementing new interfaces and methods, adding new constructors, and 
changing access to existing fields and methods.</p><p>Although these two 
classes have the same fully qualified class name, they are distinct classes 
because they are loaded by different class loaders.</p><p>    
-
-
-
-
-<span class="gliffy-container" id="gliffy-container-23527573-2405" 
data-fullwidth="750" data-ceoid="23335008" 
data-edit="${diagramEditLink.getLinkUrl()}" 
data-full="${diagramZoomLink.getLinkUrl()}" data-filename="Class Loaders">
-
-    <map id="gliffy-map-23527573-4953" name="gliffy-map-23527573-4953"></map>
-
-    <img class="gliffy-image" id="gliffy-image-23527573-2405" width="750" 
height="425" data-full-width="750" data-full-height="425" 
src="https://cwiki.apache.org/confluence/download/attachments/23335008/Class%20Loaders.png?version=4&amp;modificationDate=1283534469000&amp;api=v2";
 alt="Class Loaders" usemap="#gliffy-map-23527573-4953">
-
-    <map class="gliffy-dynamic" id="gliffy-dynamic-map-23527573-2405" 
name="gliffy-dynamic-map-23527573-2405"></map>
-</span>
-
-
-</p><p>In a Tapestry application, most application classes are loaded from the 
middle class loader. Additional class loaders are used<br clear="none"> to 
support live service reloading, and live component reloading (along with 
component class transformation).</p><p>When a page or component is passed as a 
parameter to a service, a failure occurs (how it is reported varies in 
different JDK releases) because of the class mismatch.</p><p>The solution is to 
define an interface with the methods that the service will invoke on the page 
or component instance. The service will expect an object implementing the 
interface (and doesn't care what class loader loaded the implementing 
class).</p><p>Just be sure to put the interface class in a non-controlled 
package, such as your application's <em>root-package</em> (and 
<strong>not</strong> <em>root-package</em>.<code>pages</code>).</p><h3 
id="PageAndComponentClassesFAQ-Whichisbetter,usingmagicmethodnames(i.e.,beginRender())orannotations(i.e.BeginR
 ender)?">Which is better, using magic method names (i.e., 
<code>beginRender()</code>) or annotations (i.e. 
<code>BeginRender</code>)?</h3><p>There is no single best way; this is where 
your taste may vary. Historically, the annotations came first, and the method 
naming conventions came later.</p><p>The advantage of using the method naming 
conventions is that the method names are more concise, which fewer characters 
to type, and fewer classes to import.</p><p>The main disadvantage of the method 
naming conventions is that the method names are not meaningful. 
<code>onSuccessFromLoginForm()</code> is a less meaningful name than 
<code>storeUserCredentialsAndReturnToProductsPage()</code>, for 
example.</p><p>The second disadvantage is you are more susceptible to 
off-by-a-character errors. For example, <code>onSucessFromLoginForm()</code> 
will <em>never</em> be called because the event name is misspelled; this would 
not happen using the annotation approach:</p><div class="code panel pdl" sty
 le="border-width: 1px;"><div class="codeContent panelContent pdl">
-<pre class="brush: java; gutter: true; theme: Default" 
style="font-size:12px;">  @OnEvent(value=EventConstants.SUCCESS, 
component="loginForm")
+</plain-text-body><h3 
id="PageAndComponentClassesFAQ-WhydoIgetjava.lang.LinkageErrorwhenIinvokepublicmethodsofmypageclasses?">Why
 do I get java.lang.LinkageError when I invoke public methods of my page 
classes?</h3><p>In Tapestry, there are always <em>two</em> versions of page (or 
component) classes. The first version is the version loaded by standard class 
loader: the simple POJO version that you wrote.</p><p>The second version is 
much more complicated; it's the transformed version of your code, with lots of 
extra hooks and changes to allow the class to operate inside Tapestry. This 
includes implementing new interfaces and methods, adding new constructors, and 
changing access to existing fields and methods.</p><p>Although these two 
classes have the same fully qualified class name, they are distinct classes 
because they are loaded by different class loaders.</p><p><parameter 
ac:name="size">L</parameter><parameter ac:name="name">Class 
Loaders</parameter></p><p>In a Tapestry applicati
 on, most application classes are loaded from the middle class loader. 
Additional class loaders are used<br clear="none"> to support live service 
reloading, and live component reloading (along with component class 
transformation).</p><p>When a page or component is passed as a parameter to a 
service, a failure occurs (how it is reported varies in different JDK releases) 
because of the class mismatch.</p><p>The solution is to define an interface 
with the methods that the service will invoke on the page or component 
instance. The service will expect an object implementing the interface (and 
doesn't care what class loader loaded the implementing class).</p><p>Just be 
sure to put the interface class in a non-controlled package, such as your 
application's <em>root-package</em> (and <strong>not</strong> 
<em>root-package</em>.<code>pages</code>).</p><h3 
id="PageAndComponentClassesFAQ-Whichisbetter,usingmagicmethodnames(i.e.,beginRender())orannotations(i.e.BeginRender)?">Which
 is better, usin
 g magic method names (i.e., <code>beginRender()</code>) or annotations (i.e. 
<code>BeginRender</code>)?</h3><p>There is no single best way; this is where 
your taste may vary. Historically, the annotations came first, and the method 
naming conventions came later.</p><p>The advantage of using the method naming 
conventions is that the method names are more concise, which fewer characters 
to type, and fewer classes to import.</p><p>The main disadvantage of the method 
naming conventions is that the method names are not meaningful. 
<code>onSuccessFromLoginForm()</code> is a less meaningful name than 
<code>storeUserCredentialsAndReturnToProductsPage()</code>, for 
example.</p><p>The second disadvantage is you are more susceptible to 
off-by-a-character errors. For example, <code>onSucessFromLoginForm()</code> 
will <em>never</em> be called because the event name is misspelled; this would 
not happen using the annotation approach:</p><parameter 
ac:name="controls">true</parameter><parameter ac:n
 ame="linenumbers">true</parameter><plain-text-body>  
@OnEvent(value=EventConstants.SUCCESS, component="loginForm")
   Object storeUserCredentialsAndReturnToProductsPage()
   {
     . . .
   }
-</pre>
-</div></div><p>The compiler will catch a misspelling of the constant 
<code>SUCCESS</code>. Likewise, local constants can be defined for key 
components, such as "loginForm".</p><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>Ultimately, it's developer choice. 
HLS prefers the method naming conventions in nearly all cases, especially 
prototypes and demos, but can see that in some projects and some teams, an 
annotation-only approach is best.</p></div></div><h3 
id="PageAndComponentClassesFAQ-WhydoIhavetoinjectapage?Whycan'tIjustcreateoneusingnew?">Why
 do I have to inject a page? Why can't I just create one using 
new?</h3><p>Tapestry tranforms your class at runtime. It tends to build a large 
constructor for the class instance. Further, an instance of the class is 
useless by itself, it must be wired together wi
 th its template and its sub-components.</p><p>On top of that, Tapestry keeps 
just once instance of each page in memory (since 5.2). It reworks the bytecode 
of the components so that a single instance can be shared across multiple 
request handling 
threads.</p><p>____</p><p>&#160;</p><p>&#160;</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><div
 class="display-footnotes"></div>
-<p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>&#160;</p><p>&#160;</p></div>
+</plain-text-body><p>The compiler will catch a misspelling of the constant 
<code>SUCCESS</code>. Likewise, local constants can be defined for key 
components, such as "loginForm".</p><rich-text-body><p>Ultimately, it's 
developer choice. HLS prefers the method naming conventions in nearly all 
cases, especially prototypes and demos, but can see that in some projects and 
some teams, an annotation-only approach is best.</p></rich-text-body><h3 
id="PageAndComponentClassesFAQ-WhydoIhavetoinjectapage?Whycan'tIjustcreateoneusingnew?">Why
 do I have to inject a page? Why can't I just create one using 
new?</h3><p>Tapestry tranforms your class at runtime. It tends to build a large 
constructor for the class instance. Further, an instance of the class is 
useless by itself, it must be wired together with its template and its 
sub-components.</p><p>On top of that, Tapestry keeps just once instance of each 
page in memory (since 5.2). It reworks the bytecode of the components so that a 
single instance 
 can be shared across multiple request handling 
threads.</p><plain-text-body>{scrollbar}</plain-text-body><p>____</p><p>&#160;</p><p>&#160;</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>&#160;</p><p>&#160;</p></div>
       </div>
 
       <div class="clearer"></div>


Reply via email to