[prev in list] [next in list] [prev in thread] [next in thread]
List: tapestry-dev
Subject: [CONF] Apache Tapestry > Frequently Asked Questions
From: confluence () apache ! org
Date: 2010-09-30 19:06:00
Message-ID: 19644961.20274.1285873560022.JavaMail.confluence () thor
[Download RAW message or body]
<html>
<head>
<base href="https://cwiki.apache.org/confluence">
<link rel="stylesheet" \
href="/confluence/s/1810/9/12/_/styles/combined.css?spaceKey=TAPESTRY&forWysiwyg=true" \
type="text/css"> </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
<h2><a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Frequently+Asked+Questions">Frequently \
Asked Questions</a></h2> <h4>Page <b>edited</b> by <a \
href="https://cwiki.apache.org/confluence/display/~hlship">Howard M. Lewis Ship</a> \
</h4> <br/>
<h4>Changes (1)</h4>
<div id="page-diffs">
<table class="diff" cellpadding="0" cellspacing="0">
<tr><td class="diff-snipped" >...<br></td></tr>
<tr><td class="diff-unchanged" >{include:Specific Errors} \
<br>{include:Hibernate Support FAQ} <br></td></tr>
<tr><td class="diff-added-lines" style="background-color: \
#dfd;">{include:Maven Support FAQ} <br></td></tr> </table>
</div> <h4>Full Content</h4>
<div class="notificationGreySide">
<div>
<ul>
<li><a href='#FrequentlyAskedQuestions-GeneralQuestions'>General \
Questions</a></li> <ul>
<li><a href='#FrequentlyAskedQuestions-HowdoIgetstartedwithTapestry%3F'>How do I \
get started with Tapestry?</a></li> <li><a \
href='#FrequentlyAskedQuestions-WhydoesTapestryusePrototype%3FWhynotinsertfavoriteJavaScriptlibraryhere%3F'>Why \
does Tapestry use Prototype? Why not <em>insert favorite JavaScript library \
here</em>?</a></li> <li><a \
href='#FrequentlyAskedQuestions-WhydoesTapestryhaveitsownInversionofControlContainer%3FWhynotSpringorGuice%3F'>Why \
does Tapestry have its own Inversion of Control Container? Why not Spring or \
Guice?</a></li> <li><a \
href='#FrequentlyAskedQuestions-HowdoIupgradefromTapestry4toTapestry5%3F'>How do I \
upgrade from Tapestry 4 to Tapestry 5?</a></li> <li><a \
href='#FrequentlyAskedQuestions-WhyaretherebothRequestandHttpServletRequest%3F'>Why \
are there both Request and HttpServletRequest?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-Limitations'>Limitations</a></li>
<ul>
<li><a href='#FrequentlyAskedQuestions-HowdoIaddnewcomponentstoanexistingpagedynamically%3F'>How \
do I add new components to an existing page dynamically?</a></li> <li><a \
href='#FrequentlyAskedQuestions-Whydoesn%27tmyserviceimplementationreloadwhenIchangeit%3F'>Why \
doesn't my service implementation reload when I change it?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-TemplatingandMarkup'>Templating and \
Markup</a></li> <ul>
<li><a href='#FrequentlyAskedQuestions-WhydoIgetaSAXParseExceptionwhenIuseanHTMLentity%2Csuchas%7B%7B%26amp%3Bnbsp%3B%7D%7Dinmytemplate%3F'>Why \
do I get a SAXParseException when I use an HTML entity, such as <tt>&nbsp;</tt> \
in my template?</a></li> <li><a \
href='#FrequentlyAskedQuestions-Whydosomeimagesinmypageshowupasbrokenlinks%3F'>Why do \
some images in my page show up as broken links?</a></li> <li><a \
href='#FrequentlyAskedQuestions-What%27sthedifferencebetween%7B%7Bid%7D%7Dand%7B%7Bt%3Aid%7D%7D%3F'>What's \
the difference between <tt>id</tt> and <tt>t:id</tt>?</a></li> <li><a \
href='#FrequentlyAskedQuestions-WhydomyimagesandstylesheetsendupwithaweirdURLslike%7B%7B%2Fassets%2Feea17aee26bc0cae%2Fctx%2Flayout%2Flayout.css%7D%7D%3F'>Why \
do my images and stylesheets end up with a weird URLs like \
<tt>/assets/eea17aee26bc0cae/ctx/layout/layout.css</tt>?</a></li> <li><a \
href='#FrequentlyAskedQuestions-HowdoIaddaCSSclasstoaTapestrycomponent%3F'>How do I \
add a CSS class to a Tapestry component?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-PageAndComponentClasses'>Page And \
Component Classes</a></li> <ul>
<li><a href='#FrequentlyAskedQuestions-What%27sthedifferencebetweenapageandacomponent%3F'>What's \
the difference between a page and a component?</a></li> <li><a \
href='#FrequentlyAskedQuestions-HowdoIstoremypageclassesinadifferentpackage%3F'>How \
do I store my page classes in a different package?</a></li> <li><a \
href='#FrequentlyAskedQuestions-Whydomyinstancevariableshavetobeprivate%3F'>Why do my \
instance variables have to be private?</a></li> <li><a \
href='#FrequentlyAskedQuestions-Whydon%27tmyinformalparametersshowupintherenderedmarkup%3F'>Why \
don't my informal parameters show up in the rendered markup?</a></li> <li><a \
href='#FrequentlyAskedQuestions-WhydoIgetjava.lang.LinkageErrorwhenIinvokepublicmethodsofmypageclasses%3F'>Why \
do I get java.lang.LinkageError when I invoke public methods of my page \
classes?</a></li> <li><a \
href='#FrequentlyAskedQuestions-Whichisbetter%2Cusingmagicmethodnames%28i.e.%2C%7B%7Bb \
eginRender%28%29%7D%7D%29orannotations%28i.e.%7B%7BBeginRender%7D%7D%29%3F'>Which is \
better, using magic method names (i.e., <tt>beginRender()</tt>) or annotations (i.e. \
<tt>BeginRender</tt>)?</a></li> <li><a \
href='#FrequentlyAskedQuestions-WhydoIhavetoinjectapage%3FWhycan%27tIjustcreateoneusingnew%3F'>Why \
do I have to inject a page? Why can't I just create one using new?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-FormsandFormComponents'>Forms and Form \
Components</a></li> <ul>
<li><a href='#FrequentlyAskedQuestions-Whatisthe%7B%7Bt%3Aformdata%7D%7Dhiddenfieldfor%3F'>What \
is the <tt>t:formdata</tt> hidden field for?</a></li> <li><a \
href='#FrequentlyAskedQuestions-HowdoIchangethelabelforafieldonthefly%3F'>How do I \
change the label for a field on the fly?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-LinkComponents'>Link Components</a></li>
<ul>
<li><a href='#FrequentlyAskedQuestions-HowdoIaddqueryparameterstoaPageLinkorActionLink%3F'>How \
do I add query parameters to a PageLink or ActionLink?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-AjaxComponents'>Ajax Components</a></li>
<ul>
<li><a href='#FrequentlyAskedQuestions-DoIhavetospecifyboth%7B%7Bid%7D%7Dand%7B%7Bt%3Aid%7D%7DforZonecomponents%3F'>Do \
I have to specify both <tt>id</tt> and <tt>t:id</tt> for Zone components?</a></li> \
<li><a href='#FrequentlyAskedQuestions-HowdoupdatethecontentofaZonefromaneventhandlermethod%3F'>How \
do update the content of a Zone from an event handler method?</a></li> <li><a \
href='#FrequentlyAskedQuestions-HowtoIupdatemultiplezonesinasingleeventhandler%3F'>How \
to I update multiple zones in a single event handler?</a></li> <li><a \
href='#FrequentlyAskedQuestions-What%27sthatweirdnumberinthemiddleoftheclientidsafteraZoneisupdated%3F'>What's \
that weird number in the middle of the client ids after a Zone is updated?</a></li> \
</ul> <li><a href='#FrequentlyAskedQuestions-Injection'>Injection</a></li>
<ul>
<li><a href='#FrequentlyAskedQuestions-What%27sthedifferencebetweenthe%7B%7BComponent%7D%7Dand%7B%7BInjectComponent%7D%7Dannotations%3F'>What's \
the difference between the <tt>Component</tt> and <tt>InjectComponent</tt> \
annotations?</a></li> <li><a \
href='#FrequentlyAskedQuestions-What%27sthedifferencebetweenthe%7B%7BInjectPage%7D%7Dand%7B%7BInjectContainer%7D%7Dannotations%3F'>What's \
the difference between the <tt>InjectPage</tt> and <tt>InjectContainer</tt> \
annotations?</a></li> <li><a \
href='#FrequentlyAskedQuestions-IgetanexceptionbecauseIhavetwoserviceswiththesameinterface%2ChowdoIhandlethis%3F'>I \
get an exception because I have two services with the same interface, how do I handle \
this?</a></li> <li><a \
href='#FrequentlyAskedQuestions-What%27sthedifferencebetween%7B%7BInject%7D%7Dand%7B%7BEnvironmental%7D%7D%3F'>What's \
the difference between <tt>Inject</tt> and <tt>Environmental</tt>?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-TapestryInversionofControlContainer'>Tapestry \
Inversion of Control Container</a></li> <ul>
<li><a href='#FrequentlyAskedQuestions-WhydoIneedtodefineaninterfaceformyservices%3FWhycan%27tIjustusetheclassitself%3F'>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='#FrequentlyAskedQuestions-Myservicestartsathread%3BhowdoIknowwhentheapplicationisshuttingdown%2Ctostopthatthread%3F'>My \
service starts a thread; how do I know when the application is shutting down, to stop \
that thread?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-Integrationwithexistingapplications'>Integration \
with existing applications</a></li> <ul>
<li><a href='#FrequentlyAskedQuestions-HowdoImakeaformonaJSPsubmitintoTapestry%3F'>How \
do I make a form on a JSP submit into Tapestry?</a></li> <li><a \
href='#FrequentlyAskedQuestions-HowdoIshareinformationbetweenaJSPapplicationandtheTapestryapplication%3F'>How \
do I share information between a JSP application and the Tapestry \
application?</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-SpecificErrors'>Specific Errors</a></li>
<ul>
<li><a href='#FrequentlyAskedQuestions-WhydoIgettheexception%22Noserviceimplements \
theinterfaceorg.apache.tapestry5.internal.InternalComponentResources%22whentryingtousetheBeanEditFormcomponent%3F'>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> </ul>
<li><a href='#FrequentlyAskedQuestions-HibernateSupport'>Hibernate \
Support</a></li> <ul>
<li><a href='#FrequentlyAskedQuestions-HowdoIgetHibernatetostartupupwhentheapplicationstartsup%2Cratherthanlazily'>How \
do I get Hibernate to startup up when the application starts up, rather than \
lazily</a></li> </ul>
<li><a href='#FrequentlyAskedQuestions-MavenSupport'>Maven Support</a></li>
<ul>
<li><a href='#FrequentlyAskedQuestions-WhydoMavenprojectnamesandotherdetailsshowupinmypages%3F'>Why \
do Maven project names and other details show up in my pages?</a></li> </ul>
</ul></div>
<h2><a name="FrequentlyAskedQuestions-GeneralQuestions"></a>General Questions</h2>
<h3><a name="FrequentlyAskedQuestions-HowdoIgetstartedwithTapestry%3F"></a>How do I \
get started with Tapestry?</h3>
<p>The easiest way to get started is to use <a href="http://maven.apache.org" \
class="external-link" rel="nofollow">Apache Maven</a> to create your initial project; \
Maven can use an <em>archetype</em> (a kind of project template) to create a \
bare-bones Tapestry application for you.</p>
<p>One you have Maven installed, execute the command <tt>mvn archetype:generate \
-DarchetypeCatalog=</tt><tt><a href="http://tapestry.apache.org" \
class="external-link" rel="nofollow">http://tapestry.apache.org</a></tt>. Maven will \
(after performing a large number of one-time downloads) ask you questions about how \
to create the new project, including a group id (like a package name) and an artifact \
id for your new project. </p>
<div class="preformatted panel" style="border-width: 1px;"><div \
class="preformattedContent panelContent"> <pre>$ mvn archetype:generate \
-DarchetypeCatalog=http://tapestry.apache.org [INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO] task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart \
(org.apache.maven.archetypes:maven-archetype-quickstart:1.0) Choose archetype:
1: http://tapestry.apache.org -> quickstart (Tapestry 5.2.1-SNAPSHOT Quickstart \
Project)
2: http://tapestry.apache.org -> tapestry-archetype (Tapestry 4.1.6 Archetype)
Choose a number: : 1
Choose version:
1: 5.0.19
2: 5.1.0.5
3: 5.2.0
4: 5.2.1-SNAPSHOT
Choose a number: : 3
Define value for property 'groupId': : com.example
Define value for property 'artifactId': : newapp
Define value for property 'version': 1.0-SNAPSHOT:
Define value for property 'package': com.example: com.example.newapp
Confirm properties configuration:
groupId: com.example
artifactId: newapp
version: 1.0-SNAPSHOT
package: com.example.newapp
Y:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 25 seconds
[INFO] Finished at: Tue Aug 17 14:01:50 PDT 2010
[INFO] Final Memory: 16M/81M
[INFO] ------------------------------------------------------------------------
/tmp
$ tree newapp
newapp
> -- pom.xml
`-- src
|-- main
| |-- java
| | `-- com
| | `-- example
| | `-- newapp
| | |-- components
| | | `-- Layout.java
| | |-- pages
| | | |-- About.java
| | | |-- Contact.java
| | | `-- Index.java
| | `-- services
| | `-- AppModule.java
| |-- resources
| | |-- com
| | | `-- example
| | | `-- newapp
| | | |-- components
| | | | `-- Layout.tml
| | | `-- pages
| | | `-- Index.properties
| | `-- log4j.properties
| `-- webapp
| |-- About.tml
| |-- Contact.tml
| |-- Index.tml
| |-- WEB-INF
| | |-- app.properties
| | `-- web.xml
| |-- favicon.ico
| `-- layout
| |-- images
| | |-- img01.jpg
| | |-- img02.jpg
| | |-- img03.jpg
| | |-- img04.jpg
| | |-- img05.gif
| | |-- img06.gif
| | |-- img07.gif
| | |-- img08.gif
| | |-- img09.gif
| | |-- img10.gif
| | |-- img11.gif
| | |-- img12.gif
| | |-- img13.gif
| | |-- img14.gif
| | |-- img15.gif
| | |-- img16.gif
| | |-- img17.gif
| | |-- img18.gif
| | |-- img19.gif
| | |-- img20.gif
| | `-- spacer.gif
| |-- layout.css
| `-- license.txt
|-- site
| |-- apt
| | `-- index.apt
| `-- site.xml
`-- test
|-- conf
| |-- testng.xml
| `-- webdefault.xml
|-- java
| `-- PLACEHOLDER
`-- resources
`-- PLACEHOLDER
25 directories, 44 files
/tmp
$
</pre>
</div></div>
<div class='panelMacro'><table class='warningMacro'><colgroup><col \
width='24'><col></colgroup><tr><td valign='top'><img \
src="/confluence/images/icons/emoticons/forbidden.gif" width="16" height="16" \
align="absmiddle" alt="" border="0"></td><td>The exact content and layout of project \
generated from the archetype will change across different releases of \
Tapestry.</td></tr></table></div>
<p>Once it is created, you can load it into any IDE and start coding, or use <tt>mvn \
jetty:run</tt><style type='text/css'>
.FootnoteMarker, .FootnoteNum a {
background: transparent \
url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png) \
no-repeat top right; padding: 1px 2px 0px 1px;
border-left: 1px solid #8898B8;
border-bottom: 1px solid #6B7C9B;
margin: 1px;
text-decoration: none;
}
.FootnoteNum a {
margin-top: 2px;
margin-right: 0px;
}
.FootnoteNum {
font-size: x-small;
text-align: right;
padding-bottom: 4px;
}
.footnote-th1 {
text-align: right;
}
.Footnote {
padding-left: 7px;
margin-bottom: 4px;
border: 1px none #DDDDDD;
writingMode: tb-rl;
}
.accessibility {
display: none;
visibility: hidden;
}
@media aural,braille,embossed {
.FootnoteMarker, .FootnoteNum a {
border: 1px solid #000000;
background: #ffffff none;
}
.accessibility {
display: run-in;
visibility: visible;
}
}
</style>
<script type='text/javascript' language='JavaScript'>
//<!--\n
var effectInProgress = {};
var despamEffect = function (id,effectType,duration) {
if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || \
(typeof(Effect[effectType])=="undefined")) return; new Effect[effectType](id);
effectInProgress[id]=true;
setTimeout('effectInProgress[\"'+id+'\"]=false;',duration*1000);
};
var oldFootnoteId = '';
var footnoteHighlight = function(id,pulsateNum) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = id; document.getElementById('Footnote'+id).style['borderStyle'] = \
'solid'; despamEffect('Footnote'+id,'Highlight',1)
if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
}
var footnoteMarkerHighlight = function(id) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = ''; despamEffect('FootnoteMarker'+id,'Pulsate',3)
}
//-->
</script>
<sup id='FootnoteMarker1'>
<a name='FootnoteMarker1'
href='#Footnote1'
onClick='footnoteHighlight("1",true);'
alt='Footnote: Click here to display the footnote'
title='Footnote: Click here to display the footnote'
class='FootnoteMarker'>
1
</a>
</sup>
. Again, more one-time downloads, but then you can open your browser to <a \
href="http://localhost:8080" class="external-link" \
rel="nofollow">http://localhost:8080</a> to run the application.</p>
<h3><a name="FrequentlyAskedQuestions-WhydoesTapestryusePrototype%3FWhynotinsertfavoriteJavaScriptlibraryhere%3F"></a>Why \
does Tapestry use Prototype? Why not <em>insert favorite JavaScript library \
here</em>?</h3>
<p>An important goal for Tapestry is seamless DHTML and Ajax integration. To serve \
that goal, it was important that the built in components<br/> be capable of Ajax \
operations, such as dynamically re-rendering parts of the page. Because of that, it \
made sense to bundle a well-known JavaScript library as part of Tapestry.</p>
<p>At the time (this would be 2006-ish), Prototype and Scriptaculous were well known \
and well documented, and jQuery was just getting started.</p>
<p>The intent has always been to make this aspect of Tapestry pluggable. This is work \
expected in Tapestry 5.3, where a kind of adapter layer will be introduced so that \
Tapestry can be easily customized to work with any of the major JavaScript libraries. \
</p>
<h3><a name="FrequentlyAskedQuestions-WhydoesTapestryhaveitsownInversionofControlContainer%3FWhynotSpringorGuice%3F"></a>Why \
does Tapestry have its own Inversion of Control Container? Why not Spring or \
Guice?</h3>
<p>An Inversion of Control Container is <em>the</em> key piece of Tapestry's \
infrastructure. It is absolutely necessary to create software as robust, performant \
and extensible as Tapestry.</p>
<p>Tapestry IoC includes a number of features that distinguish itself from other \
containers:</p> <ul>
<li>Configured in code, not XML</li>
<li>Built-in extension mechanism for services: configurations and contributions</li>
<li>Built-in aspect oriented programming model (service decorations and advice)</li>
<li>Easy modularization</li>
<li>Best-of-breed exception reporting</li>
</ul>
<p>Because Tapestry is implemented on top of its IoC container, and because the \
container makes it easy to extend or replace any service inside the container, it is \
possible to make the small changes to Tapestry needed to customize it to any \
project's needs.</p>
<h3><a name="FrequentlyAskedQuestions-HowdoIupgradefromTapestry4toTapestry5%3F"></a>How \
do I upgrade from Tapestry 4 to Tapestry 5?</h3>
<p>There is no existing tool that supports upgrading from Tapestry 4 to Tapestry 5; \
Tapestry 5 is a complete rewrite.</p>
<p>Many of the basic concepts in Tapestry 4 are still present in Tapestry 5, but \
refactored, improved, streamlined, and simplified. The basic concept of pages, \
templates and components are largely the same. Other aspects, such as server-side \
event handling, is markedly different.</p>
<h3><a name="FrequentlyAskedQuestions-WhyaretherebothRequestandHttpServletRequest%3F"></a>Why \
are there both Request and HttpServletRequest?</h3>
<p>Tapestry's Request interface is <em>very</em> close to the standard \
HttpServletRequest interface. It differs in a few ways, omitting<br/> some unneeded \
methods, and adding a couple of new methods (such as <tt>isXHR()</tt>), as well as \
changing how some existing methods<br/> operate. For example, \
<tt>getParameterNames()</tt> returns a sorted List of Strings; HttpServletRequest \
returns an Enumeration,<br/> which is a very dated approach.</p>
<p>However, the stronger reason for Request (and the related interfaces Response and \
Session) is to enable<br/> the support for Portlets at some point in the future. By \
writing code in terms of Tapestry's Request,<br/> and not HttpServletRequest, you can \
be assured that the same code will operate in both Servlet Tapestry<br/> and Portlet \
Tapestry.</p>
<hr />
<p><table class='Footnotes' style='width: 100%; border:none;' cellspacing='0' \
cellpadding='0' summary='This table contains one or more notes for references made \
elsewhere on the page.'> <caption class='accessibility'>Footnotes</caption>
<thead class='accessibility'>
<tr class='accessibility'>
<th class='accessibility' id='footnote-th1'>Reference</th>
<th class='accessibility' id='footnote-th2'>Notes</th>
</tr>
</thead>
<tbody>
<tr name='Footnote1'>
<td valign='top' class='FootnoteNum' headings='footnote-th1'>
<a href='#FootnoteMarker1'
onClick='footnoteMarkerHighlight("1");'
onMouseOver='footnoteHighlight("1",false);'
alt='Footnote: Click to return to reference in text'
title='Footnote: Click to return to reference in text'
id='FootnoteNum1'>
1
</a>
</td>
<td id='Footnote1'
valign='top'
width='100%'
class='Footnote'
headings='footnote-th2'>
Jetty is a well-known, open-source, high-performance servlet container. \
Jetty starts up quickly, and implements the official Servlet specification very \
closely. </td>
</tr>
</tbody>
</table></p>
<h2><a name="FrequentlyAskedQuestions-Limitations"></a>Limitations</h2>
<h3><a name="FrequentlyAskedQuestions-HowdoIaddnewcomponentstoanexistingpagedynamically%3F"></a>How \
do I add new components to an existing page dynamically?</h3>
<p>The short answer here is: <b>you don't</b>. The long answer here is <b>you don't \
have to, to get the behavior you desire</b>.</p>
<p>One of Tapestry basic values is high scalability: this is expressed in a number of \
ways, reflecting scalability concerns within a single server, and within a cluster of \
servers.</p>
<p>Although you code Tapestry pages and components as if they were ordinary \
POJOs<style type='text/css'>
.FootnoteMarker, .FootnoteNum a {
background: transparent \
url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png) \
no-repeat top right; padding: 1px 2px 0px 1px;
border-left: 1px solid #8898B8;
border-bottom: 1px solid #6B7C9B;
margin: 1px;
text-decoration: none;
}
.FootnoteNum a {
margin-top: 2px;
margin-right: 0px;
}
.FootnoteNum {
font-size: x-small;
text-align: right;
padding-bottom: 4px;
}
.footnote-th1 {
text-align: right;
}
.Footnote {
padding-left: 7px;
margin-bottom: 4px;
border: 1px none #DDDDDD;
writingMode: tb-rl;
}
.accessibility {
display: none;
visibility: hidden;
}
@media aural,braille,embossed {
.FootnoteMarker, .FootnoteNum a {
border: 1px solid #000000;
background: #ffffff none;
}
.accessibility {
display: run-in;
visibility: visible;
}
}
</style>
<script type='text/javascript' language='JavaScript'>
//<!--\n
var effectInProgress = {};
var despamEffect = function (id,effectType,duration) {
if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || \
(typeof(Effect[effectType])=="undefined")) return; new Effect[effectType](id);
effectInProgress[id]=true;
setTimeout('effectInProgress[\"'+id+'\"]=false;',duration*1000);
};
var oldFootnoteId = '';
var footnoteHighlight = function(id,pulsateNum) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = id; document.getElementById('Footnote'+id).style['borderStyle'] = \
'solid'; despamEffect('Footnote'+id,'Highlight',1)
if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
}
var footnoteMarkerHighlight = function(id) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = ''; despamEffect('FootnoteMarker'+id,'Pulsate',3)
}
//-->
</script>
<sup id='FootnoteMarker1'>
<a name='FootnoteMarker1'
href='#Footnote1'
onClick='footnoteHighlight("1",true);'
alt='Footnote: Click here to display the footnote'
title='Footnote: Click here to display the footnote'
class='FootnoteMarker'>
1
</a>
</sup>
, as deployed by Tapestry they are closer to a traditional servlet: a single instance \
of each page services requests from multiple threads. Behind the scenes, Tapestry \
transforms you code, rewriting it on the fly.</p>
<p>What this means is that <em>any</em> incoming request must be handled by a \
<em>single page instance</em>. Therefore, Tapestry enforces the concept of <b>static \
structure, dynamic behavior</b>.</p>
<p>Tapestry provides quite a number of ways to vary what content is rendered, well \
beyond simple conditionals and loops. It is possible to "drag in" components from \
other pages when rendering a page (other FAQs will expand on this concept). The point \
is, that although a Tapestry page's structure is very rigid, the order in which the \
components of the page render does not have to be top to bottom.</p>
<h3><a name="FrequentlyAskedQuestions-Whydoesn%27tmyserviceimplementationreloadwhenIchangeit%3F"></a>Why \
doesn't my service implementation reload when I change it?</h3>
<p>Live service reloading has some limitations:</p>
<ul>
<li>The service must define a service interface.</li>
<li>The service implementation must be on the file system (not inside a JAR).</li>
<li>The implementation must be instantiated by Tapestry, not inside code (even code \
inside a module class).</li> </ul>
<p>Consider the following example module:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public static void bind(ServiceBinder binder)
{
binder.bind(ArchiveService.class, ArchiveServiceImpl.class);
}
public static JobQueue buildJobQueue(MessageService messageService, \
Map<String,Job> configuration) {
JobQueueImpl service = new JobQueueImpl(configuration);
messageService.addQueueListener(service);
return service;
}
]]></script>
</div></div>
<p>ArchiveService is reloadable, because Tapestry instantiates \
<tt>ArchiveServiceImpl</tt> itself. On the other hand, Tapestry invokes \
<tt>buildJobQueue()</tt> and it is your code inside the method that instantiates \
<tt>JobQueueImpl</tt>, so the JobQueue service will not be reloadable.</p>
<p>Finally, only classes whose class files are stored directly on the file system, \
and not packaged inside JARs, are ever reloadable ... generally, only the services of \
the application being built (and not services from libraries) will be stored on the \
file system. This reflects the intent of reloading: as an agile development tool, but \
not something to be used in deployment.</p>
<hr />
<p><table class='Footnotes' style='width: 100%; border:none;' cellspacing='0' \
cellpadding='0' summary='This table contains one or more notes for references made \
elsewhere on the page.'> <caption class='accessibility'>Footnotes</caption>
<thead class='accessibility'>
<tr class='accessibility'>
<th class='accessibility' id='footnote-th1'>Reference</th>
<th class='accessibility' id='footnote-th2'>Notes</th>
</tr>
</thead>
<tbody>
<tr name='Footnote1'>
<td valign='top' class='FootnoteNum' headings='footnote-th1'>
<a href='#FootnoteMarker1'
onClick='footnoteMarkerHighlight("1");'
onMouseOver='footnoteHighlight("1",false);'
alt='Footnote: Click to return to reference in text'
title='Footnote: Click to return to reference in text'
id='FootnoteNum1'>
1
</a>
</td>
<td id='Footnote1'
valign='top'
width='100%'
class='Footnote'
headings='footnote-th2'>
Plain Old Java Object. Tapestry does not require you to extend any base \
classes or implement any special interfaces. </td>
</tr>
</tbody>
</table></p>
<h2><a name="FrequentlyAskedQuestions-TemplatingandMarkup"></a>Templating and \
Markup</h2>
<h3><a name="FrequentlyAskedQuestions-WhydoIgetaSAXParseExceptionwhenIuseanHTMLentity%2Csuchas%7B%7B%26amp%3Bnbsp%3B%7D%7Dinmytemplate%3F"></a>Why \
do I get a SAXParseException when I use an HTML entity, such as <tt>&nbsp;</tt> \
in my template?</h3>
<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" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 \
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
]]></script>
</div></div>
<p>Part of the DOCTYPE is the declaration of entities such as \
<tt>&nbsp;</tt>.</p>
<p>Alternately, you can simply use the numeric version: <tt>&#160</tt>; This is \
the exact same character and will render identically in the browser.</p>
<h3><a name="FrequentlyAskedQuestions-Whydosomeimagesinmypageshowupasbrokenlinks%3F"></a>Why \
do some images in my page show up as broken links?</h3>
<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 \
<tt>ViewUser.tml</tt> file, you may have:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <img class="icon" \
src="icons/admin.png"/>${user.name} has Administrative access ]]></script>
</div></div>
<p>This makes sense; <tt>ViewUser.tml</tt> is in the web context, as is the \
<tt>icons</tt> folder. The default URL for this page will be \
<tt>/viewuser</tt><style type='text/css'>
.FootnoteMarker, .FootnoteNum a {
background: transparent \
url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png) \
no-repeat top right; padding: 1px 2px 0px 1px;
border-left: 1px solid #8898B8;
border-bottom: 1px solid #6B7C9B;
margin: 1px;
text-decoration: none;
}
.FootnoteNum a {
margin-top: 2px;
margin-right: 0px;
}
.FootnoteNum {
font-size: x-small;
text-align: right;
padding-bottom: 4px;
}
.footnote-th1 {
text-align: right;
}
.Footnote {
padding-left: 7px;
margin-bottom: 4px;
border: 1px none #DDDDDD;
writingMode: tb-rl;
}
.accessibility {
display: none;
visibility: hidden;
}
@media aural,braille,embossed {
.FootnoteMarker, .FootnoteNum a {
border: 1px solid #000000;
background: #ffffff none;
}
.accessibility {
display: run-in;
visibility: visible;
}
}
</style>
<script type='text/javascript' language='JavaScript'>
//<!--\n
var effectInProgress = {};
var despamEffect = function (id,effectType,duration) {
if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || \
(typeof(Effect[effectType])=="undefined")) return; new Effect[effectType](id);
effectInProgress[id]=true;
setTimeout('effectInProgress[\"'+id+'\"]=false;',duration*1000);
};
var oldFootnoteId = '';
var footnoteHighlight = function(id,pulsateNum) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = id; document.getElementById('Footnote'+id).style['borderStyle'] = \
'solid'; despamEffect('Footnote'+id,'Highlight',1)
if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
}
var footnoteMarkerHighlight = function(id) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = ''; despamEffect('FootnoteMarker'+id,'Pulsate',3)
}
//-->
</script>
<sup id='FootnoteMarker1'>
<a name='FootnoteMarker1'
href='#Footnote1'
onClick='footnoteHighlight("1",true);'
alt='Footnote: Click here to display the footnote'
title='Footnote: Click here to display the footnote'
class='FootnoteMarker'>
1
</a>
</sup>
</p>
<p>However, most likely, the ViewUser page has a page activation context to identify \
which user is to be displayed:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public class ViewUser
@Property
@PageActivationContext
private User user;
. . .
]]></script>
</div></div>
<p>With a page activation context, the URL for the page will incorporate the id of \
the User object, something like <tt>/viewuser/37371</tt>. This is why the relative \
URLs to the <tt>admin.png</tt> image is broken: the base path is relative to the \
page's URL, not to the page template <sup id='FootnoteMarker2'>
<a name='FootnoteMarker2'
href='#Footnote2'
onClick='footnoteHighlight("2",true);'
alt='Footnote: Click here to display the footnote'
title='Footnote: Click here to display the footnote'
class='FootnoteMarker'>
2
</a>
</sup>
.</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" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <img class="icon" \
src="../icons/admin.png"/>${user.name} has Administrative access ]]></script>
</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 <tt>context:</tt> binding \
prefix:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <img class="icon" \
src="${context:icons/admin.png}"/>${user.name} has Administrative access \
]]></script> </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 <br/> web application \
context. This is especially important for components that may be used on different \
pages.</p>
<h3><a name="FrequentlyAskedQuestions-What%27sthedifferencebetween%7B%7Bid%7D%7Dand%7B%7Bt%3Aid%7D%7D%3F"></a>What's \
the difference between <tt>id</tt> and <tt>t:id</tt>?</h3>
<p>You might occasionally see something like the following in a template:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <t:zone id="status" t:id="statusZone">
]]></script>
</div></div>
<p>Why two ids? Why are they different?</p>
<p>The <tt>t:id</tt> attribute is the Tapestry component id. This id is unique within \
its immediate container. This is the id you might use<br/> to inject the component \
into your page class:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @InjectComponent
private Zone statusZone;
]]></script>
</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" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ $('status').hide();
]]></script>
</div></div>
<p>In many components, the <tt>id</tt> 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 <tt>id</tt> attribute. Often, in the latter case, the \
Tapestry component id is the <em>default</em> value for the client id.</p>
<h3><a name="FrequentlyAskedQuestions-WhydomyimagesandstylesheetsendupwithaweirdURLsli \
ke%7B%7B%2Fassets%2Feea17aee26bc0cae%2Fctx%2Flayout%2Flayout.css%7D%7D%3F"></a>Why do \
my images and stylesheets end up with a weird URLs like \
<tt>/assets/eea17aee26bc0cae/ctx/layout/layout.css</tt>?</h3>
<p>Tapestry doesn't rely on the servlet container to serve up your static assets \
(images, stylesheets, flash movies, etc.). Instead, if builds a URL that Tapestry \
processed itself.</p>
<p>The content that is sent to the browser will be GZIP compressed (if the client \
supports compression). In addition, Tapestry will set a far-future expires header on \
the content. This means that the browser will not ask for the file again, greatly \
reducing network traffic.</p>
<p>The wierd hex string is a random application version number. A new one is chosen \
every time the application starts up.</p>
<p>This is necessary so that, if an asset changes in place, browsers will download \
the new version. Because the application version number has changed, it represents a \
new asset to browsers, who will download the new version, even if the old version was \
previously downloaded (remember the far future expires header).</p>
<p>By the time your application is ready for production, you should manage the \
application version number directly:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader \
panelHeader" style="border-bottom-width: 1px;"><b>AppModule.java \
(partial)</b></div><div class="codeContent panelContent"> <script \
type="syntaxhighlighter" class="toolbar: true; theme: Default; brush: java; gutter: \
true"><![CDATA[ public static void contributeApplicationDefaults(
MappedConfiguration<String, String> configuration) {
configuration.add(SymbolConstants.APPLICATION_VERSION, "1.7.5");
}
]]></script>
</div></div>
<p>You should be careful to change the application version number for each new \
deployment of your application; otherwise returning users may be stuck<br/> with old \
versions of assets that have changed in the interrum. This kind of mismatch can \
cause visual annoyances for style sheets or image files, but can break client-side \
behavior<br/> for changed JavaScript libraries.</p>
<h3><a name="FrequentlyAskedQuestions-HowdoIaddaCSSclasstoaTapestrycomponent%3F"></a>How \
do I add a CSS class to a Tapestry component?</h3>
<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)<br/> will be rendered out as additional attributes. So, you can apply \
a CSS class or style quite easily:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <t:textfield t:id="username" \
class="big-green"/> ]]></script>
</div></div>
<p>You can even use template expansions inside the attribute value:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <t:textfield t:id="username" \
class="${usernameClass}"/> ]]></script>
</div></div>
<p>and</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public String getUsernameClass()
{
return isUrgent() ? "urgent" : null;
}
]]></script>
</div></div>
<p>When an informal parameter is bound to null, then the attribute is not written out \
at all.</p>
<p>You can verify which components support informal parameters by checking the \
component reference, or looking for the @SupportsInformalParameters annotation in the \
components' source file.</p>
<hr />
<p><table class='Footnotes' style='width: 100%; border:none;' cellspacing='0' \
cellpadding='0' summary='This table contains one or more notes for references made \
elsewhere on the page.'> <caption class='accessibility'>Footnotes</caption>
<thead class='accessibility'>
<tr class='accessibility'>
<th class='accessibility' id='footnote-th1'>Reference</th>
<th class='accessibility' id='footnote-th2'>Notes</th>
</tr>
</thead>
<tbody>
<tr name='Footnote1'>
<td valign='top' class='FootnoteNum' headings='footnote-th1'>
<a href='#FootnoteMarker1'
onClick='footnoteMarkerHighlight("1");'
onMouseOver='footnoteHighlight("1",false);'
alt='Footnote: Click to return to reference in text'
title='Footnote: Click to return to reference in text'
id='FootnoteNum1'>
1
</a>
</td>
<td id='Footnote1'
valign='top'
width='100%'
class='Footnote'
headings='footnote-th2'>
Assuming that class ViewUser is in the <em>root-package</em>.<tt>pages</tt> \
package. </td>
</tr>
<tr name='Footnote2'>
<td valign='top' class='FootnoteNum' headings='footnote-th1'>
<a href='#FootnoteMarker2'
onClick='footnoteMarkerHighlight("2");'
onMouseOver='footnoteHighlight("2",false);'
alt='Footnote: Click to return to reference in text'
title='Footnote: Click to return to reference in text'
id='FootnoteNum2'>
2
</a>
</td>
<td id='Footnote2'
valign='top'
width='100%'
class='Footnote'
headings='footnote-th2'>
In fact, the page template may not even be in the web context, it may be \
stored on the classpath, as component templates are. </td>
</tr>
</tbody>
</table></p>
<h2><a name="FrequentlyAskedQuestions-PageAndComponentClasses"></a>Page And Component \
Classes</h2>
<h3><a name="FrequentlyAskedQuestions-What%27sthedifferencebetweenapageandacomponent%3F"></a>What's \
the difference between a page and a component?</h3>
<p>There's very little difference between the two. Pages clases must be in the \
<em>root-package</em>.<tt>pages</tt> package; components must be in the<br/> \
<em>root-package</em>.<tt>components</tt>. 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 <tt>.tml</tt> \
extension).</p>
<div class='panelMacro'><table class='warningMacro'><colgroup><col \
width='24'><col></colgroup><tr><td valign='top'><img \
src="/confluence/images/icons/emoticons/forbidden.gif" width="16" height="16" \
align="absmiddle" alt="" border="0"></td><td>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.</td></tr></table></div>
<h3><a name="FrequentlyAskedQuestions-HowdoIstoremypageclassesinadifferentpackage%3F"></a>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>.<tt>pages</tt>, component classes in \
<em>root-package</em>.<tt>components</tt>, etc.</p>
<p>You are allowed to create sub-packages, to help organize your code better and more \
logically. For example, you might have \
_root-package.<tt>pages.account.ViewAccount</tt>, which would have the page name \
"account/viewaccount"<style type='text/css'>
.FootnoteMarker, .FootnoteNum a {
background: transparent \
url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png) \
no-repeat top right; padding: 1px 2px 0px 1px;
border-left: 1px solid #8898B8;
border-bottom: 1px solid #6B7C9B;
margin: 1px;
text-decoration: none;
}
.FootnoteNum a {
margin-top: 2px;
margin-right: 0px;
}
.FootnoteNum {
font-size: x-small;
text-align: right;
padding-bottom: 4px;
}
.footnote-th1 {
text-align: right;
}
.Footnote {
padding-left: 7px;
margin-bottom: 4px;
border: 1px none #DDDDDD;
writingMode: tb-rl;
}
.accessibility {
display: none;
visibility: hidden;
}
@media aural,braille,embossed {
.FootnoteMarker, .FootnoteNum a {
border: 1px solid #000000;
background: #ffffff none;
}
.accessibility {
display: run-in;
visibility: visible;
}
}
</style>
<script type='text/javascript' language='JavaScript'>
//<!--\n
var effectInProgress = {};
var despamEffect = function (id,effectType,duration) {
if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || \
(typeof(Effect[effectType])=="undefined")) return; new Effect[effectType](id);
effectInProgress[id]=true;
setTimeout('effectInProgress[\"'+id+'\"]=false;',duration*1000);
};
var oldFootnoteId = '';
var footnoteHighlight = function(id,pulsateNum) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = id; document.getElementById('Footnote'+id).style['borderStyle'] = \
'solid'; despamEffect('Footnote'+id,'Highlight',1)
if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
}
var footnoteMarkerHighlight = function(id) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = ''; despamEffect('FootnoteMarker'+id,'Pulsate',3)
}
//-->
</script>
<sup id='FootnoteMarker1'>
<a name='FootnoteMarker1'
href='#Footnote1'
onClick='footnoteHighlight("1",true);'
alt='Footnote: Click here to display the footnote'
title='Footnote: Click here to display the footnote'
class='FootnoteMarker'>
1
</a>
</sup>
</p>
<p>In addition, it is possible to define additional root packages for the \
application:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public static void \
contributeComponentClassResolver(Configuration<LibraryMapping> configuration) { \
configuration.add(new LibraryMapping("", "com.example.app.tasks")); \
configuration.add(new LibraryMapping("", "com.example.app.chat")); }
]]></script>
</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<br/> adds two \
additional root packages; you might see additional pages under \
<tt>com.example.app.tasks.pages</tt>, for example.</p>
<div class='panelMacro'><table class='warningMacro'><colgroup><col \
width='24'><col></colgroup><tr><td valign='top'><img \
src="/confluence/images/icons/emoticons/forbidden.gif" width="16" height="16" \
align="absmiddle" alt="" border="0"></td><td>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<br/> can get by with a single root package for your \
application, that is better.</td></tr></table></div>
<h3><a name="FrequentlyAskedQuestions-Whydomyinstancevariableshavetobeprivate%3F"></a>Why \
do my instance variables have to be private?</h3>
<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<br/> cause a property of the containing page or component to \
be read.</p>
<p>Limiting fields to private means that Tapestry can do the necessary processing one \
class at a time, as needed, at runtime. More complex<br/> Aspect Orient Programming \
systems such as AspectJ can perform similar transformations (and much more complex \
ones), but requires a dedicated build step (or the introduction of a JVM agent).</p>
<h3><a name="FrequentlyAskedQuestions-Whydon%27tmyinformalparametersshowupintherenderedmarkup%3F"></a>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 <tt>ComponentResources.renderInformalParameters()</tt> method, but just as \
importantly, you must tell Tapestry that you want the component to support<br/> \
informal parameters, using the <tt>SupportsInformalParameters</tt> annotation. Here's \
a hypothetical component that displays an image based on the value of a \
<tt>Image</tt> object (presumably, a database entity):</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @SupportsInformalParameters
public class DBImage
{
@Parameter(required=true)
private Image image;
@Inject
private ComponentResources resources;
boolean beginRender(MarkupWriter writer)
{
writer.element("img", "src", image.toClientURL(), "class", "db-image");
resources.renderInformalParameters(writer);
writer.end();
return false;
}
}
]]></script>
</div></div>
<h3><a name="FrequentlyAskedQuestions-WhydoIgetjava.lang.LinkageErrorwhenIinvokepublicmethodsofmypageclasses%3F"></a>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<br/> 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>
<table width="100%">
<tr><td align="left">
<table>
<caption align="bottom">
<a \
href="/confluence/spaces/gliffy/viewlargediagram.action?name=Class+Loaders&ceoid=23335008&key=TAPESTRY&pageId=23335008"
target=""
>Full Size</a>
|
<a \
href="/confluence/plugins/gliffy/showgliffyeditor.action?name=Class+Loaders&ceoid=2333 \
5008&key=TAPESTRY&lastPage=/confluence/display/TAPESTRY/Page+And+Component+Classes&pageId=23335008"
target=""
>Edit Diagram</a>
|
<a \
href="/confluence/spaces/gliffy/removediagram.action?name=Class+Loaders&ceoid=23335008 \
&key=TAPESTRY&lastPage=/confluence/display/TAPESTRY/Page+And+Component+Classes&pageId=23335008&input=true"
target=""
>Remove Diagram</a>
</caption>
<tr><td>
<img style="border: none" \
usemap="#GLIFFY_MAP_23335008_Class_Loaders" \
src="/confluence/plugins/servlet/gliffyapi/clientdiagramjpeg?cb=-1470855300&pk=pub&name=Class+Loaders&ceoid=23335008&key=TAPESTRY&size=L&version=4" \
alt="A Gliffy Diagram named: Class Loaders" /> </td></tr>
</table>
</td></tr>
</table>
<map name='GLIFFY_MAP_23335008_Class_Loaders'></map>
<p>In a Tapestry application, most application classes are loaded from the middle \
class loader. Additional class loaders are used<br/> 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<br/> (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 <b>not</b> \
<em>root-package</em>.<tt>pages</tt>).</p>
<h3><a name="FrequentlyAskedQuestions-Whichisbetter%2Cusingmagicmethodnames%28i.e.%2C% \
7B%7BbeginRender%28%29%7D%7D%29orannotations%28i.e.%7B%7BBeginRender%7D%7D%29%3F"></a>Which \
is better, using magic method names (i.e., <tt>beginRender()</tt>) or annotations \
(i.e. <tt>BeginRender</tt>)?</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. <tt>onSuccessFromLoginForm()</tt> is a less meaningful name than \
<tt>storeUserCredentialsAndReturnToProductsPage()</tt>, for example.</p>
<p>The second disadvantage is you are more susceptible to off-by-a-character errors. \
For example, <tt>onSucessFromLoginForm()</tt> 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" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @OnEvent(value=EventConstants.SUCCESS, \
component="loginForm") Object storeUserCredentialsAndReturnToProductsPage()
{
. . .
}
]]></script>
</div></div>
<p>The compiler will catch a misspelling of the constant <tt>SUCCESS</tt>. Likewise, \
local constants can be defined for key components, such as "loginForm".</p>
<div class='panelMacro'><table class='infoMacro'><colgroup><col \
width='24'><col></colgroup><tr><td valign='top'><img \
src="/confluence/images/icons/emoticons/information.gif" width="16" height="16" \
align="absmiddle" alt="" border="0"></td><td>Ultimately, it's developer choice. HLS \
prefers the method naming conventions in nearly all cases, especially prototypes and \
demos, but can see<br/> that in some projects and some teams, an annotation-only \
approach is best.</td></tr></table></div>
<h3><a name="FrequentlyAskedQuestions-WhydoIhavetoinjectapage%3FWhycan%27tIjustcreateoneusingnew%3F"></a>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<br/>
a large constructor for the class instance. Further, an instance of the<br/>
class is useless by itself, it must be wired together with its template<br/>
and its sub-components. </p>
<p>____</p>
<p><table class='Footnotes' style='width: 100%; border:none;' cellspacing='0' \
cellpadding='0' summary='This table contains one or more notes for references made \
elsewhere on the page.'> <caption class='accessibility'>Footnotes</caption>
<thead class='accessibility'>
<tr class='accessibility'>
<th class='accessibility' id='footnote-th1'>Reference</th>
<th class='accessibility' id='footnote-th2'>Notes</th>
</tr>
</thead>
<tbody>
<tr name='Footnote1'>
<td valign='top' class='FootnoteNum' headings='footnote-th1'>
<a href='#FootnoteMarker1'
onClick='footnoteMarkerHighlight("1");'
onMouseOver='footnoteHighlight("1",false);'
alt='Footnote: Click to return to reference in text'
title='Footnote: Click to return to reference in text'
id='FootnoteNum1'>
1
</a>
</td>
<td id='Footnote1'
valign='top'
width='100%'
class='Footnote'
headings='footnote-th2'>
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. </td>
</tr>
</tbody>
</table></p>
<h2><a name="FrequentlyAskedQuestions-FormsandFormComponents"></a>Forms and Form \
Components</h2>
<h3><a name="FrequentlyAskedQuestions-Whatisthe%7B%7Bt%3Aformdata%7D%7Dhiddenfieldfor%3F"></a>What \
is the <tt>t:formdata</tt> hidden field for?</h3>
<p>In Tapestry, rendering a form can be a complicated process; inside the body of the \
Form component are many of field components: TextField, Select, TextArea, and so \
forth. Each of these must pull data out of your data model and convert it to the \
string form used inside the client web browser. In addition, JavaScript to support \
client-side validation must be generated. This can be further complicated by the use \
of Loop and If components, or made really complicated by the use of Block (to render \
portions of other pages: this is what the BeanEditForm component does).</p>
<p>Along the way, the Form is generating unique form control names for each field \
component, as it renders.</p>
<p>When the client-side Form is submitted, an event is triggered on the server-side \
Form component. It now needs to locate each component, in turn, inform the component \
of its control name, and allow the component to read the corresponding query \
parameter. The component then converts the client-side string back into a server-side \
value and performs validations before updating the data model.</p>
<p>That's where <tt>t:formdata</tt> comes in. While components are rendering, they \
are using the FormSupport environmental object to record callbacks:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader \
panelHeader" style="border-bottom-width: 1px;"><b>FormSupport.java \
(partial)</b></div><div class="codeContent panelContent"> <script \
type="syntaxhighlighter" class="toolbar: true; theme: Default; brush: java; gutter: \
true"><![CDATA[ public interface FormSupport extends ClientElement
{
/**
* Stores an action for execution during a later request. If the action contains \
any mutable state, it should be in
* its final state before invoking this method and its internal state should not \
be changed subsequently.
*/
<T> void store(T component, ComponentAction<T> action);
/**
* As with {@link #store(Object, org.apache.tapestry5.ComponentAction)}}, but the \
action is also invoked
* immediately. This is useful for defining an action that should occur \
symmetrically in both the render request and
* the form submission's event request.
*
* @param component component against which to trigger the action
* @param action the action that will be triggered (and passed the component)
*/
<T> void storeAndExecute(T component, ComponentAction<T> action);
]]></script>
</div></div>
<p>The <tt>ComponentAction</tt> objects are the callbacks. <tt>t:formdata</tt> is \
simply an object stream of these callbacks, compressed and encoded in Base64. When \
using <br/> Ajax, you may see multiple <tt>t:formdata</tt> hidden fields (they are \
processed one after another).</p>
<h3><a name="FrequentlyAskedQuestions-HowdoIchangethelabelforafieldonthefly%3F"></a>How \
do I change the label for a field on the fly?</h3>
<p>Tapestry tries to be smart about generating the label string for a field. It has \
some smart default logic, first checking for the <em>component-id</em><tt>-label</tt> \
in the container's message catalog, then ultimately converting the component's id \
into a user-presentable label.</p>
<p>You can override the label in two ways:</p>
<p>First, you can supply a body to the <tt>Label</tt> component:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <t:label \
for="username">${usernameLabel}</t:label> <t:textfield \
t:id="username"/> ]]></script>
</div></div>
<p>Here, the component class must provide a <tt>usernameLabel</tt> property. That \
property becomes the text of the label. An implementation of<br/> the property might \
look something like:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public String getUsernameLabel()
{
return systemPreferences.useEmailAddressForUserName() ? "Email address" : "User \
name"; }
]]></script>
</div></div>
<p>However, if there are any validations on the field, the error message will include \
the default label (as discussed above).</p>
<p>To uniformly update the label both on the page, and in any validation messages, \
bind the TextField's <tt>label</tt> parameter:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <t:label for="username"/>
<t:textfield t:id="username" label="prop:usernameLabel"/>
]]></script>
</div></div>
<p>The "prop:" prefix identifies that "usernameLabel" is to be interpreted as a \
property expression (normally, the binding for the <tt>label</tt> parameter is \
interpreted as a string literal). The Label component gets the text it displays from \
the TextField component, and the TextField component uses the same text when \
generating server-side and client-side validation messages.</p> <h2><a \
name="FrequentlyAskedQuestions-LinkComponents"></a>Link Components</h2>
<h3><a name="FrequentlyAskedQuestions-HowdoIaddqueryparameterstoaPageLinkorActionLink%3F"></a>How \
do I add query parameters to a PageLink or ActionLink?</h3>
<p>These components do not have parameters to allow you to specify query parameters \
for the link; they both allow you to specify a <em>context</em> (one or more values \
to encode into the request path).</p>
<p>However, you can accomplish the same thing with a little code and markup. For \
example, to create a link to another page and pass a query parameter, you can replace \
your PageLink component with<br/> a standard <tt><a></tt> tag:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <a href="${profilePageLink}">Display \
Profile (w/ full details)</a> ]]></script>
</div></div>
<p>In the matching Java class, you can create the Link programmatically:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @Inject
private PageRenderLinkSource linkSource;
public Link getProfilePageLink()
{
Link link = linkSource.createPageRenderLinkWithContext(DisplayProfile.class, \
user);
link.addParameter("detail", "true");
return link;
}
]]></script>
</div></div>
<p>... and in the DisplayProfile page:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public class DisplayProfile
{
void onActivate(@RequestParameter("detail") boolean detail)
{
. . .
}
}
]]></script>
</div></div>
<p>The @RequestParameter annotation directs Tapestry to extract the query parameter \
and coerce it to type boolean. You can use any reasonable type for such a parameter \
(int, long and Date are common).</p>
<p>A similar technique can be used to add query parmeters to ActionLink or EventLink \
URLs, by injecting the ComponentResources, and invoking method \
<tt>createEventLink()</tt>.</p> <h2><a \
name="FrequentlyAskedQuestions-AjaxComponents"></a>Ajax Components</h2>
<h3><a name="FrequentlyAskedQuestions-DoIhavetospecifyboth%7B%7Bid%7D%7Dand%7B%7Bt%3Aid%7D%7DforZonecomponents%3F"></a>Do \
I have to specify both <tt>id</tt> and <tt>t:id</tt> for Zone components?</h3>
<p>The examples for the Zone component (in the Component Reference) consistently \
specify both <tt>id</tt> and <tt>t:id</tt> and this is probably a good idea.</p>
<p>Generally speaking, if you don't specify the client-side id (the <tt>id</tt> \
attribute), it will be the same as the Tapestry component id (<tt>t:id</tt>).</p>
<p>However, there are any number of exceptions to this rule. The Zone may be \
rendering inside a Loop (in which case, each rendering will have a unique client side \
id). The Zone may be rendering as part of a partial page render, in which case, a \
random unique id is inserted into the id. There are other examples where Tapestry \
component ids in nested components may also clash.</p>
<p>The point is, to be sure, specify the exact client id. This will be the value for \
the <tt>zone</tt> parameter of the triggering component (such as a Form, PageLink, \
ActionLink, etc.).</p>
<h3><a name="FrequentlyAskedQuestions-HowdoupdatethecontentofaZonefromaneventhandlermethod%3F"></a>How \
do update the content of a Zone from an event handler method?</h3>
<p>When a client-side link or form triggers an update, the return value from the \
event handler method is used to construct a partial page response; this partial page \
response includes markup content that is used to update the Zone's client-side \
<tt><div></tt> element.</p>
<p>Where does that content come from? You inject it into your page.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <t:zone id="search" t:id="searchZone">
<t:form t:id="searchForm" zone="searchZone">
<t:textfield t:id="query" size="20"/>
<input type="submit" value="Search"/>
</t:form>
</t:zone>
<t:block id="searchResults">
<ul>
<li t:type="loop" source="searchHits" \
value="searchHit">${searchHit}</li> </ul>
</t:block>
]]></script>
</div></div>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @Inject
private Block searchResults;
Object onSuccessFromSearchForm()
{
searchHits = searchService.performSearch(query);
return searchResults;
}
]]></script>
</div></div>
<p>So, when the search form is submitted, the resulting search hits are collected. \
In the same request, the searchResults block is rendered, package, and sent to the \
client. The form inside the client-side Zone <tt><div></tt> is replaced with \
the list of hits.</p>
<h3><a name="FrequentlyAskedQuestions-HowtoIupdatemultiplezonesinasingleeventhandler%3F"></a>How \
to I update multiple zones in a single event handler?</h3>
<p>To do this, you must know, on the server, the client ids of each Zone.</p>
<p>Instead of returning a Block or a Component, return a multi-zone update:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @Inject
private Block searchResults;
@Inject
private Block statusBlock;
Object onSuccessFromSearchForm()
{
searchHits = searchService.performSearch(query);
message = String.format("Found %,d matching documents", searchHits.size());
return new MultiZoneUpdate("results", searchResults).add("status", statusBlock);
}
]]></script>
</div></div>
<h3><a name="FrequentlyAskedQuestions-What%27sthatweirdnumberinthemiddleoftheclientidsafteraZoneisupdated%3F"></a>What's \
that weird number in the middle of the client ids after a Zone is updated?</h3>
<p>You might start with markup in your template for a component such as a \
TextField:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <t:textfield t:id="firstName"/>
]]></script>
</div></div>
<p>When the component initially renders as part of a full page render, you get a \
sensible<br/> bit of markup:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <input id="firstName" name="firstName" \
type="text"> ]]></script>
</div></div>
<p>But when the form is inside a Zone and rendered as part of a zone update, the ids \
get weird:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <input id="firstName_12a820cc40e" \
name="firstName" type="text"> ]]></script>
</div></div>
<p>What's happening here is that Tapestry is working to prevent unwanted id clashes \
as part of the page update. In an HTML document, each <tt>id</tt> is<br/> expected \
to be unique; most JavaScript is keyed off of the <tt>id</tt> field, for \
instance.</p>
<p>In a full page render, components don't just use their component id \
(<tt>t:id</tt>) as their client id; instead they use the <tt>JavaScriptSupport</tt> \
environmental to allocate a unique id. When there's no loops or conflicts, the client \
id matches the component id.</p>
<p>When the component is inside a loop, a suffix is appended: <tt>firstName</tt>, \
<tt>firstName_0</tt>, <tt>firstName_1</tt>, etc.</p>
<p>When the component is rendered as part of an Ajax partial page update, the rules \
are different. Since Tapestry doesn't know what content has been<br/> rendered onto \
the page previously, it can't use its normal tricks to ensure that ids are \
unique.</p>
<p>Instead, Tapestry creates a random-ish unique id suffix, such as "12a820cc40e" in \
the example; this suffix is appended to all allocated ids to ensure that they do not \
conflict with previously rendered ids.</p> <h2><a \
name="FrequentlyAskedQuestions-Injection"></a>Injection</h2>
<h3><a name="FrequentlyAskedQuestions-What%27sthedifferencebetweenthe%7B%7BComponent%7D%7Dand%7B%7BInjectComponent%7D%7Dannotations%3F"></a>What's \
the difference between the <tt>Component</tt> and <tt>InjectComponent</tt> \
annotations?</h3>
<p>The <tt>Component</tt> annotation is used to define the <em>type</em> of \
component, and its parameter bindings. When using <tt>Component</tt>, the \
template<br/> must not define the type, and any parameter bindings are merged in:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <a t:id="home" class="nav">Back to \
home</a> ]]></script>
</div></div>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @Component(parameters={ "page=index" })
private PageLink home;
]]></script>
</div></div>
<p>Here the type of component is defined by the field type. The field name is matched \
against the <tt>t:id</tt> in the template. The <tt>page</tt> parameter<br/> is set in \
the Java class, and the informal <tt>class</tt> parameter is set in the template. If \
the tag in the template was <tt><t:pagelink></tt>,<br/> or if the template tag \
included the attribute <tt>t:type="pagelink"</tt>, then you would see an \
exception.</p>
<p>By contrast, <tt>InjectComponent</tt> expects the component to be already defined, \
and doesn't allow any configuration of it:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <t:form t:id="login"> .... \
</t:form> ]]></script>
</div></div>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @InjectComponent
private Form login;
]]></script>
</div></div>
<p>Again, we're matching the field name to the component id, and you would get an \
error if the component is not defined in the template.</p>
<h3><a name="FrequentlyAskedQuestions-What%27sthedifferencebetweenthe%7B%7BInjectPage%7D%7Dand%7B%7BInjectContainer%7D%7Dannotations%3F"></a>What's \
the difference between the <tt>InjectPage</tt> and <tt>InjectContainer</tt> \
annotations?</h3>
<p>The <tt>InjectPage</tt> annotation is used to inject some page in the application \
into a field of some other page. You often see it used from event handler \
methods:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @InjectPage
private ConfirmRegistration confirmRegistration;
Object onSuccessFromRegistrationForm()
{
confirmRegistration.setStatus("Registration accepted");
confirmRegistration.setValidationCode(userRegistrationData.getValidationCode());
return confirmRegistration;
}
]]></script>
</div></div>
<p>This code pattern is used to configure peristent properties of a page before \
returning it; Tapestry will send a client redirect to the page to present<br/> the \
data.</p>
<p><tt>InjectContainer</tt> can be used inside a component or a mixin. In a \
component, it injects the immediate container of the component; this is often the \
top-level page object.</p>
<p>In a mixin, it injects the component to which the mixin is attached.</p>
<h3><a name="FrequentlyAskedQuestions-IgetanexceptionbecauseIhavetwoserviceswiththesameinterface%2ChowdoIhandlethis%3F"></a>I \
get an exception because I have two services with the same interface, how do I handle \
this?</h3>
<p>It's not uncommon to have two or more services that implement the exact same \
interface. When you inject, you might start by just identifying the<br/> type of \
service to inject:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @Inject
private ComponentEventResultProcessor processor;
]]></script>
</div></div>
<p>Which results in the error: <b>Service interface \
org.apache.tapestry5.services.ComponentEventResultProcessor is matched by 3 services: \
AjaxComponentEventResultProcessor, ComponentEventResultProcessor, \
ComponentInstanceResultProcessor. Automatic dependency resolution requires that \
exactly one service implement the interface.</b></p>
<p>We need more information than just the service interface type in order to identify \
which of the three services to inject. One possibility is to inject with the correct \
service id:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @InjectService("ComponentEventResultProcessor")
private ComponentEventResultProcessor processor;
]]></script>
</div></div>
<p>This works ... but it is clumsy. If the service id, \
"ComponentEventResultProcessor", ever changes, this code will break. It's not \
<em>refactoring safe</em>.</p>
<p>Instead, we should use marker annotations. If we look at <tt>TapestryModule</tt>, \
where the ComponentEventResultProcessor service is defined, we'll see it identifies \
the necessary markers:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @Marker(
{ Primary.class, Traditional.class })
public ComponentEventResultProcessor buildComponentEventResultProcessor(
Map<Class, ComponentEventResultProcessor> configuration)
{
return constructComponentEventResultProcessor(configuration);
}
]]></script>
</div></div>
<p>When a service has marker annotations, the annotations present at the <em>point of \
injection</em> (the field, method parameter, or constructor parameter) are used to \
select a matching service. The list of services that match by type is then filtered \
to only include services that have all of the marker annotations present at the point \
of injection.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ @Inject
@Traditional @Primary
private ComponentEventResultProcessor processor;
]]></script>
</div></div>
<p>The two marker annotations, <tt>Traditional</tt> and <tt>Primary</tt>, ensure that \
only a single service matches.</p>
<h3><a name="FrequentlyAskedQuestions-What%27sthedifferencebetween%7B%7BInject%7D%7Dand%7B%7BEnvironmental%7D%7D%3F"></a>What's \
the difference between <tt>Inject</tt> and <tt>Environmental</tt>?</h3>
<p><tt>Inject</tt> is relatively general; it can be used to inject resources specific \
to a page or component (such as ComponentResources, Logger, or Messages), or it can \
inject services or other objects obtained from the Tapestry IoC container. Once the \
page is loaded, the values for these injections never change.</p>
<p><tt>Environmental</tt> is different; it exposes a request-scoped, dynamically \
bound value<style type='text/css'>
.FootnoteMarker, .FootnoteNum a {
background: transparent \
url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png) \
no-repeat top right; padding: 1px 2px 0px 1px;
border-left: 1px solid #8898B8;
border-bottom: 1px solid #6B7C9B;
margin: 1px;
text-decoration: none;
}
.FootnoteNum a {
margin-top: 2px;
margin-right: 0px;
}
.FootnoteNum {
font-size: x-small;
text-align: right;
padding-bottom: 4px;
}
.footnote-th1 {
text-align: right;
}
.Footnote {
padding-left: 7px;
margin-bottom: 4px;
border: 1px none #DDDDDD;
writingMode: tb-rl;
}
.accessibility {
display: none;
visibility: hidden;
}
@media aural,braille,embossed {
.FootnoteMarker, .FootnoteNum a {
border: 1px solid #000000;
background: #ffffff none;
}
.accessibility {
display: run-in;
visibility: visible;
}
}
</style>
<script type='text/javascript' language='JavaScript'>
//<!--\n
var effectInProgress = {};
var despamEffect = function (id,effectType,duration) {
if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || \
(typeof(Effect[effectType])=="undefined")) return; new Effect[effectType](id);
effectInProgress[id]=true;
setTimeout('effectInProgress[\"'+id+'\"]=false;',duration*1000);
};
var oldFootnoteId = '';
var footnoteHighlight = function(id,pulsateNum) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = id; document.getElementById('Footnote'+id).style['borderStyle'] = \
'solid'; despamEffect('Footnote'+id,'Highlight',1)
if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
}
var footnoteMarkerHighlight = function(id) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = ''; despamEffect('FootnoteMarker'+id,'Pulsate',3)
}
//-->
</script>
<sup id='FootnoteMarker1'>
<a name='FootnoteMarker1'
href='#Footnote1'
onClick='footnoteHighlight("1",true);'
alt='Footnote: Click here to display the footnote'
title='Footnote: Click here to display the footnote'
class='FootnoteMarker'>
1
</a>
</sup>
. </p>
<ul>
<li>Request scoped: different threads (processing different requests) will see \
different values when reading the field.</li> <li>Dynamically bound: the value is \
explicitly placed into the Environment, and can be overridden at any time.</li> </ul>
<p>Environmentals are a form of loosely connected communication between an outer \
component (or even a service) and an inner component. Example: the Form<br/> \
component places a <tt>FormSupport</tt> object into the environment. Other \
components, such as TextField, use the <tt>FormSupport</tt> when rendering to perform \
functions such as allocate unique control names or register client-side validations. \
The TextField doesn't require that the Form component be the immediate container \
component, or even an ancestor: a Form on one page may, indirectly, communicate with \
a TextField on some entirely different page. Neither component directly links to the \
other, the <tt>FormSupport</tt> is the conduit that connects them.</p>
<hr />
<p><table class='Footnotes' style='width: 100%; border:none;' cellspacing='0' \
cellpadding='0' summary='This table contains one or more notes for references made \
elsewhere on the page.'> <caption class='accessibility'>Footnotes</caption>
<thead class='accessibility'>
<tr class='accessibility'>
<th class='accessibility' id='footnote-th1'>Reference</th>
<th class='accessibility' id='footnote-th2'>Notes</th>
</tr>
</thead>
<tbody>
<tr name='Footnote1'>
<td valign='top' class='FootnoteNum' headings='footnote-th1'>
<a href='#FootnoteMarker1'
onClick='footnoteMarkerHighlight("1");'
onMouseOver='footnoteHighlight("1",false);'
alt='Footnote: Click to return to reference in text'
title='Footnote: Click to return to reference in text'
id='FootnoteNum1'>
1
</a>
</td>
<td id='Footnote1'
valign='top'
width='100%'
class='Footnote'
headings='footnote-th2'>
Environmental was chosen as the value "comes from the environment", \
whatever that means. A name more evocative of its function still has not occurred to \
the Tapestry team! </td>
</tr>
</tbody>
</table> </p>
<h2><a name="FrequentlyAskedQuestions-TapestryInversionofControlContainer"></a>Tapestry \
Inversion of Control Container</h2>
<h3><a name="FrequentlyAskedQuestions-WhydoIneedtodefineaninterfaceformyservices%3FWhycan%27tIjustusetheclassitself%3F"></a>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<br/> 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 lifecycle: \
most services are singletons that are created <em>just in time</em>. Just in time \
means only as soon<br/> as you invoke a method. What's going on is that the \
lifecycle proxy (the object that gets injected into pages, components or other \
service implementations) checks on each method invocation<br/> 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<br/> 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><a name="FrequentlyAskedQuestions-Myservicestartsathread%3BhowdoIknowwhentheapplicationisshuttingdown%2Ctostopthatthread%3F"></a>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 \
connection, a JMS queue connection) that a service may<br/> hold onto. Your code \
needs to know when the application has been undeployed and shutdown. This is \
actually quite easy, by using<br/> a service builder method. In your module \
class:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public MyService \
buildMyService(ServiceResources resources, RegistryShutdownHub shutdownHub) {
final MyServiceImpl service = resources.autobuild(MyServiceImpl.class);
shutdownHub.addRegistryShutdownListener(new RegistryShutdownListener()
{
public void registryDidShutdown()
{
service.shutdown();
}
});
return service;
}
]]></script>
</div></div>
<p>This code uses the ServiceResources object to build an instance of MyServiceImpl, \
with all dependencies injected.<br/> It also injects Tapestry's RegistryShutdownHub \
service and adds a listener. The example assumes that the service implementation<br/> \
(but not the service <em>interface</em>) includes a <tt>shutdown()</tt> method.</p>
<p>A valid alternative to this would be to have MyServiceImpl implement \
RegistryShutdownListener:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public MyService \
buildMyService(ServiceResources resources, RegistryShutdownHub shutdownHub) {
final MyServiceImpl service = resources.autobuild(MyServiceImpl.class);
shutdownHub.addRegistryShutdownListener(service);
return service;
}
]]></script>
</div></div>
<div class='panelMacro'><table class='warningMacro'><colgroup><col \
width='24'><col></colgroup><tr><td valign='top'><img \
src="/confluence/images/icons/emoticons/forbidden.gif" width="16" height="16" \
align="absmiddle" alt="" border="0"></td><td>It is <b>not</b> recommended that \
MyServiceImpl take RegistryShutdownHub as a constructor parameter and register itself \
as a listener Doing so is an example of <a \
href="http://www.ibm.com/developerworks/java/library/j-jtp0618.html" \
class="external-link" rel="nofollow">unsafe publishing</a>.</td></tr></table></div> \
<h2><a name="FrequentlyAskedQuestions-Integrationwithexistingapplications"></a>Integration \
with existing applications</h2>
<p>You may have an existing JSP (or Struts, Spring MVC, etc.) application that you \
want to migrate to Tapestry. It's quite common to do this in stages, moving some \
functionality into Tapestry and leaving other parts, initially, in the other \
system.</p>
<h3><a name="FrequentlyAskedQuestions-HowdoImakeaformonaJSPsubmitintoTapestry%3F"></a>How \
do I make a form on a JSP submit into Tapestry?</h3>
<p>Tapestry's Form component does a lot of work while an HTML form is rendering to \
store all the information needed to handle the form submission in a later request; \
this is all very specific to Tapestry and the particular construction of your pages \
and forms; it can't be reproduced from a JSP.</p>
<p>Fortunately, that isn't necessary: you can have a standard HTML Form submit to a \
Tapestry page, you just don't get to use all of Tapestry's built in conversion and \
validation logic.</p>
<p>All you need to know is how Tapestry converts page class names to page names (that \
appear in the URL). It's basically a matter of stripping off the \
<em>root-package</em>.<tt>pages</tt> prefix from the fully qualified class name. So, \
for example, if you are building a login screen as a JSP, you might want to have a \
Tapestry page to receive the user name and password. Let's assume the Tapestry page \
class is <tt>com.example.myapp.pages.LoginForm</tt>; the page name will be \
<tt>loginform</tt><style type='text/css'>
.FootnoteMarker, .FootnoteNum a {
background: transparent \
url(/confluence/download/resources/com.adaptavist.confluence.footnoteMacros:footnote/gfx/footnote.png) \
no-repeat top right; padding: 1px 2px 0px 1px;
border-left: 1px solid #8898B8;
border-bottom: 1px solid #6B7C9B;
margin: 1px;
text-decoration: none;
}
.FootnoteNum a {
margin-top: 2px;
margin-right: 0px;
}
.FootnoteNum {
font-size: x-small;
text-align: right;
padding-bottom: 4px;
}
.footnote-th1 {
text-align: right;
}
.Footnote {
padding-left: 7px;
margin-bottom: 4px;
border: 1px none #DDDDDD;
writingMode: tb-rl;
}
.accessibility {
display: none;
visibility: hidden;
}
@media aural,braille,embossed {
.FootnoteMarker, .FootnoteNum a {
border: 1px solid #000000;
background: #ffffff none;
}
.accessibility {
display: run-in;
visibility: visible;
}
}
</style>
<script type='text/javascript' language='JavaScript'>
//<!--\n
var effectInProgress = {};
var despamEffect = function (id,effectType,duration) {
if ((effectInProgress[id]) || (typeof(Effect)=="undefined") || \
(typeof(Effect[effectType])=="undefined")) return; new Effect[effectType](id);
effectInProgress[id]=true;
setTimeout('effectInProgress[\"'+id+'\"]=false;',duration*1000);
};
var oldFootnoteId = '';
var footnoteHighlight = function(id,pulsateNum) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = id; document.getElementById('Footnote'+id).style['borderStyle'] = \
'solid'; despamEffect('Footnote'+id,'Highlight',1)
if (pulsateNum) despamEffect('FootnoteNum'+id,'Pulsate',3)
}
var footnoteMarkerHighlight = function(id) {
if (oldFootnoteId!='') \
document.getElementById('Footnote'+oldFootnoteId).style['borderStyle'] = 'none'; \
oldFootnoteId = ''; despamEffect('FootnoteMarker'+id,'Pulsate',3)
}
//-->
</script>
<sup id='FootnoteMarker1'>
<a name='FootnoteMarker1'
href='#Footnote1'
onClick='footnoteHighlight("1",true);'
alt='Footnote: Click here to display the footnote'
title='Footnote: Click here to display the footnote'
class='FootnoteMarker'>
1
</a>
</sup>
, and the URL will be <tt>/loginform</tt>.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ <form method="post" action="/loginform">
<input type="text" value="userName"/>
<br/>
<input type="password" value="password"/>
<br/>
<input type="submit" value="Login"/>
</form>
]]></script>
</div></div>
<p>On the Tapestry side, we can expect that the LoginForm page will be activated; \
this means that its activate event handler will be invoked. We can leverage this, \
and Tapestry's RequestParameter annotation:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public class LoginForm
{
void onActivate(@RequestParameter("userName") String userName, \
@RequestParameter("password") String password) {
// Validate and store credentials, etc.
}
}
]]></script>
</div></div>
<p>The RequestParameter annotation extracts the named query parameter from the \
request, coerces its type from String to the parameter type (here, also String) and \
passes it into the method.</p>
<h3><a name="FrequentlyAskedQuestions-HowdoIshareinformationbetweenaJSPapplicationandtheTapestryapplication%3F"></a>How \
do I share information between a JSP application and the Tapestry application?</h3>
<p>From the servlet container's point of view, there's no difference between a \
servlet, a JSP, and an entire Tapestry application. They all share the same \
ServletContext, and (once created), the same HttpSession.</p>
<p>On the Tapestry side, it is very easy to read and write session attributes:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent \
panelContent"> <script type="syntaxhighlighter" class="toolbar: true; theme: Default; \
brush: java; gutter: true"><![CDATA[ public class ShowSearchResults
{
@SessionAttribute
private SearchResults searchResults;
}
]]></script>
</div></div>
<p>Reading the instance variable <tt>searchResults</tt> is instrumented to instead \
read the corresponding HttpSession attribute named "searchResults". You can also \
specify the <tt>value</tt> attribute of the SessionAttribute annotation to override \
the default attribute name.</p>
<p>Writing to the field writes into the session.</p>
<p>The session is automatically created as needed.</p>
<hr />
<p><table class='Footnotes' style='width: 100%; border:none;' cellspacing='0' \
cellpadding='0' summary='This table contains one or more notes for references made \
elsewhere on the page.'> <caption class='accessibility'>Footnotes</caption>
<thead class='accessibility'>
<tr class='accessibility'>
<th class='accessibility' id='footnote-th1'>Reference</th>
<th class='accessibility' id='footnote-th2'>Notes</th>
</tr>
</thead>
<tbody>
<tr name='Footnote1'>
<td valign='top' class='FootnoteNum' headings='footnote-th1'>
<a href='#FootnoteMarker1'
onClick='footnoteMarkerHighlight("1");'
onMouseOver='footnoteHighlight("1",false);'
alt='Footnote: Click to return to reference in text'
title='Footnote: Click to return to reference in text'
id='FootnoteNum1'>
1
</a>
</td>
<td id='Footnote1'
valign='top'
width='100%'
class='Footnote'
headings='footnote-th2'>
Tapestry is case insensitive, so LoginForm would work just as well.
</td>
</tr>
</tbody>
</table></p>
<h2><a name="FrequentlyAskedQuestions-SpecificErrors"></a>Specific Errors</h2>
<h3><a name="FrequentlyAskedQuestions-WhydoIgettheexception%22Noserviceimplementsthein \
terfaceorg.apache.tapestry5.internal.InternalComponentResources%22whentryingtousetheBeanEditFormcomponent%3F"></a>Why \
do I get the exception "No service implements the interface \
org.apache.tapestry5.internal.InternalComponentResources" when trying to use the \
BeanEditForm component?</h3>
<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 \
(<tt>pages</tt>, <tt>components</tt>, <tt>mixins</tt> and <tt>base</tt> under your \
application's root package). By convention, simple data objects should go in a \
<tt>data</tt> package, and Hibernate entities should go in an <tt>entities</tt> \
package.</p> <h2><a name="FrequentlyAskedQuestions-HibernateSupport"></a>Hibernate \
Support</h2>
<h3><a name="FrequentlyAskedQuestions-HowdoIgetHibernatetostartupupwhentheapplicationstartsup%2Cratherthanlazily"></a>How \
do I get Hibernate to startup up when the application starts up, rather than \
lazily</h3> <p>with the first request for the application?</p>
<p>This was a minor problem in 5.0; by 5.1 it was just a matter of overriding the \
configuration system<br/> <tt>tapestry.hibernate-early-startup</tt> to "true".</p>
<h2><a name="FrequentlyAskedQuestions-MavenSupport"></a>Maven Support</h2>
<h3><a name="FrequentlyAskedQuestions-WhydoMavenprojectnamesandotherdetailsshowupinmypages%3F"></a>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:<br/>
the <tt>${...</tt>} syntax. When Maven is copying resources from \
<tt>src/main/resources</tt>,<br/> and when filtering is <em>enabled</em> (which is \
not the default),<br/> then any expansions in <em>Tapestry templates</em> that match \
against Maven project<br/> properties are substituted. If you look at the deployed \
application you'll see that<br/> <tt>\${name</tt>} is gone, replaced with your \
project's name!</p>
<p>The solution is to update your <tt>pom.xml</tt> and ignore any .tml files \
when<br/> copying and filtering:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader \
panelHeader" style="border-bottom-width: 1px;"><b>pom.xml (partial)</b></div><div \
class="codeContent panelContent"> <script type="syntaxhighlighter" class="toolbar: \
false; theme: Default; brush: java; gutter: false"><![CDATA[ <resource>
<directory>src/main/resources</directory>
]]></script>
</div></div>
</div>
<div id="commentsSection" class="wiki-content pageSection">
<div style="float: right;">
<a href="https://cwiki.apache.org/confluence/users/viewnotifications.action" \
class="grey">Change Notification Preferences</a> </div>
<a href="https://cwiki.apache.org/confluence/display/TAPESTRY/Frequently+Asked+Questions">View \
Online</a> |
<a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23334884&revisedVersion=29&originalVersion=28">View \
Changes</a> </div>
</div>
</div>
</div>
</div>
</body>
</html>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic