You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by jk...@apache.org on 2006/07/04 00:49:00 UTC
svn commit: r418868 [1/2] - in /tapestry/tapestry4/trunk: ./
framework/src/java/org/apache/tapestry/html/ src/site/
src/site/resources/css/ src/site/resources/images/ src/site/xdoc/
src/site/xdoc/QuickStart/ src/site/xdoc/exampleapps/ src/site/xdoc/exa...
Author: jkuhnert
Date: Mon Jul 3 15:48:59 2006
New Revision: 418868
URL: http://svn.apache.org/viewvc?rev=418868&view=rev
Log:
Updated documentation
Added:
tapestry/tapestry4/trunk/src/site/resources/images/autocompleter.png (with props)
tapestry/tapestry4/trunk/src/site/xdoc/exampleapps/
- copied from r418860, tapestry/tapestry4/trunk/src/site/xdoc/examples/
Removed:
tapestry/tapestry4/trunk/src/site/xdoc/examples/
Modified:
tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/html/Shell.jwc
tapestry/tapestry4/trunk/pom.xml
tapestry/tapestry4/trunk/src/site/resources/css/site.css
tapestry/tapestry4/trunk/src/site/site.xml
tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/directlink.xml
tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/forms.xml
tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/helloworld.xml
tapestry/tapestry4/trunk/src/site/xdoc/changes.xml
tapestry/tapestry4/trunk/src/site/xdoc/exampleapps/index.xml
tapestry/tapestry4/trunk/src/site/xdoc/index.xml
Modified: tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/html/Shell.jwc
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/html/Shell.jwc?rev=418868&r1=418867&r2=418868&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/html/Shell.jwc (original)
+++ tapestry/tapestry4/trunk/framework/src/java/org/apache/tapestry/html/Shell.jwc Mon Jul 3 15:48:59 2006
@@ -115,7 +115,7 @@
</parameter>
<parameter name="ajaxEnabled"
- default-value="false" >
+ default-value="true" >
<description>
If set to true, will include the required javascript libraries that make all
of the ajax functionality possible.
Modified: tapestry/tapestry4/trunk/pom.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/pom.xml?rev=418868&r1=418867&r2=418868&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/pom.xml (original)
+++ tapestry/tapestry4/trunk/pom.xml Mon Jul 3 15:48:59 2006
@@ -255,6 +255,7 @@
<report>license</report>
<report>scm</report>
<report>index</report>
+ <report>dependencies</report>
</reports>
</reportSet>
</reportSets>
Modified: tapestry/tapestry4/trunk/src/site/resources/css/site.css
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/src/site/resources/css/site.css?rev=418868&r1=418867&r2=418868&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/src/site/resources/css/site.css (original)
+++ tapestry/tapestry4/trunk/src/site/resources/css/site.css Mon Jul 3 15:48:59 2006
@@ -3,10 +3,6 @@
padding-right: 0;
}
-body {
- font-family: Lucida Grande, Arial, Helvetica, sans-serif;
-}
-
body ul {
list-style-type: square;
}
@@ -42,35 +38,6 @@
font-size: smaller;
}
-.info {
- float: left;
- display: block;
- margin: 0 1em 2em 2em;
- padding: 1em;
- border: 1px solid #aaa;
- background-color: #efefef;
-}
-
-.warn {
- float: left;
- display: block;
- margin: 0 1em 2em 2em;
- padding: 1em;
- border: 2px solid #474747;
- background-color: #B8AC30;
-}
-
-.section p a {
- color: #539126;
- font-weight: bolder;
-}
-
-.section p a:hover {
- text-decoration: underline;
-}
-
-code {
- border: 1px dotted #aaa;
- background: #efefef;
- padding: 1px;
-}
+.section ul li {
+ margin-top: 8px;
+}
\ No newline at end of file
Added: tapestry/tapestry4/trunk/src/site/resources/images/autocompleter.png
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/src/site/resources/images/autocompleter.png?rev=418868&view=auto
==============================================================================
Binary file - no diff available.
Propchange: tapestry/tapestry4/trunk/src/site/resources/images/autocompleter.png
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Modified: tapestry/tapestry4/trunk/src/site/site.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/src/site/site.xml?rev=418868&r1=418867&r2=418868&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/src/site/site.xml (original)
+++ tapestry/tapestry4/trunk/src/site/site.xml Mon Jul 3 15:48:59 2006
@@ -39,26 +39,36 @@
</menu>
<menu name="Documentation" inherit="top">
+
<item name="Users Guide" href="/UsersGuide/index.html" collapse="true">
- <item name="Introduction" href="/UsersGuide/index.html" collapse="true"/>
- <item name="Templates" href="/UsersGuide/template.html" collapse="true"/>
- <item name="Bindings" href="/UsersGuide/bindings.html" collapse="true"/>
- <item name="Listeners" href="/UsersGuide/listenermethods.html" collapse="true"/>
- <item name="Page Classes" href="/UsersGuide/page-class.html" collapse="true"/>
- <item name="Input Validation" href="/UsersGuide/validation.html" collapse="true" />
- <item name="Creating Components" href="/UsersGuide/components.html" collapse="true"/>
- <item name="Property Injection" href="/UsersGuide/injection.html" collapse="true"/>
- <item name="Localization" href="/UsersGuide/localization.html" collapse="true"/>
- <item name="State Management" href="/UsersGuide/state.html" collapse="true"/>
- <item name="IOC (HiveMind)" href="/UsersGuide/hivemind.html" collapse="true"/>
- <item name="Friendly URLs" href="/UsersGuide/friendly-urls.html" collapse="true"/>
- <item name="Page Events" href="/UsersGuide/events.html" collapse="true"/>
- <item name="Configuration" href="/UsersGuide/configuration.html" collapse="true"/>
- <item name="Shared Properties" href="/UsersGuide/properties.html" collapse="true"/>
- <item name="Upgrading from 3.0" href="/UsersGuide/upgrade.html" collapse="true"/>
- <item name="Specification DTD" href="/UsersGuide/spec.html" collapse="true"/>
- <item name="Script Template DTD" href="/UsersGuide/script.html" collapse="true"/>
+ <item name="Introduction" href="/UsersGuide/index.html" />
+ <item name="Templates" href="/UsersGuide/template.html" />
+ <item name="Bindings" href="/UsersGuide/bindings.html" />
+ <item name="Listeners" href="/UsersGuide/listenermethods.html" />
+ <item name="Page Classes" href="/UsersGuide/page-class.html" />
+ <item name="Input Validation" href="/UsersGuide/validation.html" />
+ <item name="Creating Components" href="/UsersGuide/components.html" />
+ <item name="Property Injection" href="/UsersGuide/injection.html" />
+ <item name="Localization" href="/UsersGuide/localization.html" />
+ <item name="State Management" href="/UsersGuide/state.html" />
+ <item name="IOC (HiveMind)" href="/UsersGuide/hivemind.html" />
+ <item name="Friendly URLs" href="/UsersGuide/friendly-urls.html" />
+ <item name="Page Events" href="/UsersGuide/events.html" />
+ <item name="Configuration" href="/UsersGuide/configuration.html" />
+ <item name="Shared Properties" href="/UsersGuide/properties.html" />
+ <item name="Upgrading from 3.0" href="/UsersGuide/upgrade.html" />
+ <item name="Specification DTD" href="/UsersGuide/spec.html" />
+ <item name="Script Template DTD" href="/UsersGuide/script.html" />
</item>
+
+ <item name="Quick Start" href="/QuickStart/helloworld.html" collapse="true">
+ <item name="Hello World" href="/QuickStart/helloworld.html" />
+ <item name="Direct Links" href="/QuickStart/directlink.html" />
+ <item name="Forms" href="/QuickStart/forms.html" />
+ </item>
+
+ <item name="Examples" href="/exampleapps/index.html" />
+
</menu>
<menu ref="modules" />
Modified: tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/directlink.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/directlink.xml?rev=418868&r1=418867&r2=418868&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/directlink.xml (original)
+++ tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/directlink.xml Mon Jul 3 15:48:59 2006
@@ -1,51 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright 2005 The Apache Software Foundation
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ Copyright 2005 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<document>
-<properties>
-<title>QuickStart: DirectLink</title>
-</properties>
-<body>
-
-<p>
- In this tutorial, we'll get introduced to one of the real workhorses of Tapestry, the <a href="site:DirectLink">DirectLink</a>
- component. It is one of the most common ways of triggering server-side behavior. Along the way,
- we'll start seeing some other common aspects of developing web applications using Tapestry.
-</p>
+ <properties>
+ <title>QuickStart: DirectLink</title>
+ </properties>
+ <body>
+
+ <section name="QuickStart: DirectLink">
+ <p>
+ In this tutorial, we'll get introduced to one of the real workhorses of Tapestry, the
+ <a href="site:DirectLink">DirectLink</a>
+ component. It is one of the most common ways of triggering server-side behavior. Along
+ the way, we'll start seeing some other common aspects of developing web applications
+ using Tapestry.
+ </p>
+
+ <section name="HTML Template">
-<section name="HTML Template">
-
-
-<p>
- This application simply counts the number of times we click a link.
-</p>
-<img src="../images/QuickStart/directlink1.png" alt="Initial DirectLink Tutorial"/>
-
-<p>
- This requires a little more than we can accomplish with just an HTML template; we'll need
- to supplement with a Java class. This java class will contain a property that stores the count,
- and contain logic used to increment the count.
-</p>
-
-<p>
- We'll start again with the Home page's template:
-</p>
-
-<source xml:space="preserve">
+ <p>This application simply counts the number of times we click a link.</p>
+
+ <img src="../images/QuickStart/directlink1.png" alt="Initial DirectLink Tutorial" />
+
+ <p>
+ This requires a little more than we can accomplish with just an HTML template; we'll
+ need to supplement with a Java class. This java class will contain a property that
+ stores the count, and contain logic used to increment the count.
+ </p>
+
+ <p>We'll start again with the Home page's template:</p>
+
+ <source xml:space="preserve">
<html>
<head>
<title>Tutorial: DirectLink</title>
@@ -68,47 +67,53 @@
</body>
</html>
-</source>
-
-<p>
- Much of this should look familiar. We're again using the <a href="site:Insert">Insert</a> component, and we're using
- <a href="http://www.ognl.org">OGNL</a> again. Instead of creating a new instance, we're using OGNL in a simpler way; it will
- read the counter property and provide that to the Insert component
- in its value parameter.
-</p>
-
-<p>
- That's fine, but where does this counter property live? In the Home page's Java class. We'll see how
- to create that class shortly.
-</p>
-
-<p>
- Just displaying the current value isn't enough, we need a way to change that value. That's where
- the <a href="site:DirectLink">DirectLink</a> component comes in; it will invoke a method of our Java class for us.
- This connection between component and method is supplied in the listener parameter.
- The "listener:" prefix activates the logic that lets Tapestry invoke the method
- with the matching name.
- We provide a method, doClick(), in the page's Java class, and the DirectLink
- component will invoke this method for us, in response to the user clicking the rendered link in their web browser.
-</p>
-
-
-</section>
+</source>
-<section name="Page classes">
-
-
-<p>
- So, we have half the puzzle: the HTML template. But we need the Java class that will contain the
- properties to be stored, and the methods to be invoked.
-</p>
-
-<p>
- First, we need a Java package to store the class. For this tutorial, we'll use tutorials.directlink.pages. That means
- we'll create the Home.java source file as src/java/tutorials/directlink/pages/Home.java:
-</p>
+ <p>
+ Much of this should look familiar. We're again using the
+ <a href="site:Insert">Insert</a>
+ component, and we're using
+ <a href="http://www.ognl.org">OGNL</a>
+ again. Instead of creating a new instance, we're using OGNL in a simpler way; it
+ will read the counter property and provide that to the Insert component in its value
+ parameter.
+ </p>
+
+ <p>
+ That's fine, but where does this counter property live? In the Home page's Java
+ class. We'll see how to create that class shortly.
+ </p>
+
+ <p>
+ Just displaying the current value isn't enough, we need a way to change that value.
+ That's where the
+ <a href="site:DirectLink">DirectLink</a>
+ component comes in; it will invoke a method of our Java class for us. This
+ connection between component and method is supplied in the listener parameter. The
+ "listener:" prefix activates the logic that lets Tapestry invoke the method with the
+ matching name. We provide a method, doClick(), in the page's Java class, and the
+ DirectLink component will invoke this method for us, in response to the user
+ clicking the rendered link in their web browser.
+ </p>
+
+
+ </section>
+
+ <section name="Page classes">
+
+
+ <p>
+ So, we have half the puzzle: the HTML template. But we need the Java class that will
+ contain the properties to be stored, and the methods to be invoked.
+ </p>
+
+ <p>
+ First, we need a Java package to store the class. For this tutorial, we'll use
+ tutorials.directlink.pages. That means we'll create the Home.java source file as
+ src/java/tutorials/directlink/pages/Home.java:
+ </p>
-<source xml:space="preserve">
+ <source xml:space="preserve">
package tutorials.directlink.pages;
import org.apache.tapestry.annotations.Persist;
@@ -131,137 +136,172 @@
}
</source>
-<p>
- The Java classes you write will extend from the Tapestry BasePage class<sup>1</sup>.
- To this base class, we are adding a property, counter, and a listener method, doClick()<sup>2</sup>.
-</p>
-
-
-<p>
- <em>Abstract? What's up with that?</em> That's a pretty typical first reaction to seeing a Tapestry page class; why is it
- abstract, why is it not an ordinary JavaBean?
-</p>
-
-<p>
- The answer involves a bit of a digression. Tapestry pages exist on the server, and are somewhat expensive
- to create ... expensive enough that you don't want to constantly create them and discard them. In this way,
- they are much like database connections ... you want to pool pages for reuse from one request to the next.
-</p>
-
-<p>
- Because the pages are pooled and shared, in fact shared <em>between different users</em>, it's very important
- that they page objects be cleansed of any user-specific or request-specific data before they go back
- into the pool. You can do this in your own code (there are additional interfaces to implement and additional
- code to write), but it is <em>easier</em> to let Tapestry do that work for you.
-</p>
-
-<p>
- By declaring an accessor method as abstract, you are implicitly directing Tapestry to
- "fill in" the details; at <em>runtime</em>, it will create a subclass of the Java class you provide,
- extending your implementation with all the grinding details. As well see in later tutorials,
- this in fact goes far beyond just properties; all sorts of useful features can be tied to
- different flavors of abstract methods (often coupled with different
- <a href="../tapestry-annotations/index.html">annotations</a>).
-</p>
-
-<p>
- There's something special about this counter property. It has to remember its value
- <em>between</em> requests. The @Persist annotation, attached to the getCounter() accessor method,
- directs Tapestry to make this a <em>persistent page property</em>. Despite the name, this has nothing to do
- with database persistence, it's about storing the value for the property in the
- HttpSession between requests, and restoring it the next time that the same user, in the same session,
- accesses the page.
-</p>
-
-<p>
- This is another pivotal feature in Tapestry; individual page properties (or properties of components
- used within the page) can store their value in the HttpSession automatically. We can seperate out
- the persistent state of the page from any <em>instance</em> of the page. This minimizes the
- amount of information that must be stored in the HttpSession; rather than entire page objects (with all
- those templates and nested components), we store just the tiny handful of properties that need
- to "stick around" until the next request.
-</p>
-
-<p>
- This approach to session management, combined with the pooling of page instances, is critical to
- achieving another of Tapestry fundamental principals: <strong>Efficiency</strong>. Tapestry
- applications will scale because of how they manage server-side state. The cost of this
- is that the classes and methods are abstract, with the implementations of many methods only provided dynamically,
- by Tapestry, at runtime.
-</p>
-
-<p>
- Back from our digression. We now have the counter property, and we understand how it is stored in the
- HttpSession between requests. That makes the implementation of the doClick() listener method straight
- forward: get the current value for the proeprty, increment it, and store it back into the property.
-</p>
-
-<p>
- Again, we're demonstrating part of our promise about Tapestry: we're talking about objects and methods
- and properties. There's a URL in there, generated by Tapestry, for the DirectLink. There's
- attributes stored in the HttpSession. We don't see those or care about them.
-</p>
-
-</section>
+ <p>
+ The Java classes you write will extend from the Tapestry BasePage class
+ <sup>1</sup>
+ . To this base class, we are adding a property, counter, and a listener method,
+ doClick()
+ <sup>2</sup>
+ .
+ </p>
+
+
+ <p>
+ <em>Abstract? What's up with that?</em>
+ That's a pretty typical first reaction to seeing a Tapestry page class; why is it
+ abstract, why is it not an ordinary JavaBean?
+ </p>
+
+ <p>
+ The answer involves a bit of a digression. Tapestry pages exist on the server, and
+ are somewhat expensive to create ... expensive enough that you don't want to
+ constantly create them and discard them. In this way, they are much like database
+ connections ... you want to pool pages for reuse from one request to the next.
+ </p>
+
+ <p>
+ Because the pages are pooled and shared, in fact shared
+ <em>between different users</em>
+ , it's very important that they page objects be cleansed of any user-specific or
+ request-specific data before they go back into the pool. You can do this in your own
+ code (there are additional interfaces to implement and additional code to write),
+ but it is
+ <em>easier</em>
+ to let Tapestry do that work for you.
+ </p>
+
+ <p>
+ By declaring an accessor method as abstract, you are implicitly directing Tapestry
+ to "fill in" the details; at
+ <em>runtime</em>
+ , it will create a subclass of the Java class you provide, extending your
+ implementation with all the grinding details. As well see in later tutorials, this
+ in fact goes far beyond just properties; all sorts of useful features can be tied to
+ different flavors of abstract methods (often coupled with different
+ <a href="../tapestry-annotations/index.html">annotations</a>
+ ).
+ </p>
+
+ <p>
+ There's something special about this counter property. It has to remember its value
+ <em>between</em>
+ requests. The @Persist annotation, attached to the getCounter() accessor method,
+ directs Tapestry to make this a
+ <em>persistent page property</em>
+ . Despite the name, this has nothing to do with database persistence, it's about
+ storing the value for the property in the HttpSession between requests, and
+ restoring it the next time that the same user, in the same session, accesses the
+ page.
+ </p>
+
+ <p>
+ This is another pivotal feature in Tapestry; individual page properties (or
+ properties of components used within the page) can store their value in the
+ HttpSession automatically. We can seperate out the persistent state of the page from
+ any
+ <em>instance</em>
+ of the page. This minimizes the amount of information that must be stored in the
+ HttpSession; rather than entire page objects (with all those templates and nested
+ components), we store just the tiny handful of properties that need to "stick
+ around" until the next request.
+ </p>
+
+ <p>
+ This approach to session management, combined with the pooling of page instances, is
+ critical to achieving another of Tapestry fundamental principals:
+ <strong>Efficiency</strong>
+ . Tapestry applications will scale because of how they manage server-side state. The
+ cost of this is that the classes and methods are abstract, with the implementations
+ of many methods only provided dynamically, by Tapestry, at runtime.
+ </p>
+
+ <p>
+ Back from our digression. We now have the counter property, and we understand how it
+ is stored in the HttpSession between requests. That makes the implementation of the
+ doClick() listener method straight forward: get the current value for the proeprty,
+ increment it, and store it back into the property.
+ </p>
+
+ <p>
+ Again, we're demonstrating part of our promise about Tapestry: we're talking about
+ objects and methods and properties. There's a URL in there, generated by Tapestry,
+ for the DirectLink. There's attributes stored in the HttpSession. We don't see those
+ or care about them.
+ </p>
+
+ </section>
+
+ <section name="Locating the page class">
+
+
+ <p>
+ We've provided the Home page's template and Java class, but we haven't quite
+ connected the dots enough for our application to run. If we tried to run the
+ application (by opening a web browser to
+ <a href="http://localhost:8080/directlink/app">
+ http://localhost:8080/directlink/app
+ </a>
+ ), we'd get the Tapestry exception page:
+ </p>
+
+ <img src="../images/QuickStart/directlink2.png"
+ alt="Exception report - missing property" />
+
+ <p>
+ That's quite a lot of information. The root cause of the exception is the fact that
+ Tapestry couldn't find the Home class we created, so it instead used BasePage as-is.
+ BasePage doesn't have a counter property, so the OGNL expression
+ <code>counter</code>
+ couldn't be evaluated (you can see that in the deepest exception). You can see in
+ the target property of the ognl.NoSuchPropertyException, the value
+ <code>$BasePage_0@cec78d[Home]</code>
+ is the toString() of a page class; the first part is the name of the class
+ (remember, this is a subclass generated at runtime by Tapestry), the value in
+ brackets is the name of the page.
+ </p>
+
+ <p>
+ This exception bubbled up to the top-level of Tapestry, getting wrapped inside other
+ exceptions along the way. The framework couldn't continue with the Home page, so it
+ generated this exception report instead.
+ </p>
+
+
+ <p>
+ As you can see, the exception report is quite detailed; it shows the entire stack of
+ exceptions, including their properties. It identifies the file and line at the root
+ of the problem, and even displays an excerpt from that file. Further down on the
+ page are exhaustive details about all the Servlet API objects ... in short you are
+ given all the information you need to understand what was going on in your
+ application at the time of the failure, without having to restart using a debugger.
+ This is another Tapestry priciple in action:
+ <strong>Feedback</strong>
+ . When things go wrong, Tapestry should help you fix your problem, rather than get
+ in the way.
+ </p>
+
+ <p>
+ So, the root of our problem is that Tapestry can't find our Home page, so we need to
+ tell it where to look. This involves providing Tapestry with a little bit of
+ configuration about our application.
+ </p>
+
+ <p>
+ We'll create an
+ <em>application specification</em>
+ for our application, and store the configuration data there. An application
+ specification is an XML file that provides extra information about the application
+ to Tapestry. It is optional; we didn't have one in the previous example.
+ </p>
+
+ <p>
+ The name of the servlet ("app", in this example) is appended with the extension
+ ".application" to form the name of the specification. The specification itself is
+ stored in the WEB-INF folder of the web application. In our project, it is stored as
+ src/context/WEB-INF/app.application:
+ </p>
-<section name="Locating the page class">
-
-
-<p>
- We've provided the Home page's template and Java class, but we haven't quite connected the dots enough
- for our application to run. If we tried to run the application (by opening a web browser to
- <a href="http://localhost:8080/directlink/app">http://localhost:8080/directlink/app</a>), we'd get the Tapestry
- exception page:
-</p>
-
-<img src="../images/QuickStart/directlink2.png" alt="Exception report - missing property"/>
-
-<p>
-That's quite a lot of information. The root cause of the exception is the fact
-that Tapestry couldn't find the Home class we
-created, so it instead used BasePage as-is. BasePage doesn't have a counter property, so the OGNL expression
-<code>counter</code> couldn't be evaluated (you can see that in the deepest exception). You can see in the
-target property of the ognl.NoSuchPropertyException, the value <code>$BasePage_0@cec78d[Home]</code> is the
-toString() of a page class; the first part is the name of the class (remember, this is a subclass
-generated at runtime by Tapestry), the value in brackets is the name of the page.
-</p>
-
-<p>
- This exception bubbled up to the top-level of Tapestry, getting wrapped inside other exceptions
- along the way. The framework couldn't continue with the Home page, so it generated this exception
- report instead.
-</p>
-
-
-<p>
- As you can see, the exception report is quite detailed; it shows the entire stack of exceptions,
- including their properties. It identifies the file and line at the root of the problem,
- and even displays an excerpt from that file. Further down on the page are exhaustive details about
- all the Servlet API objects ... in short you are given all the information you need to understand what
- was going on in your application at the time of the failure, without having to restart using
- a debugger. This is another Tapestry priciple in action: <strong>Feedback</strong>. When things go wrong, Tapestry
- should help you fix your problem, rather than get in the way.
-</p>
-
-<p>
- So, the root of our problem is that Tapestry can't find our Home page, so we need to tell it where
- to look. This involves providing Tapestry with a little bit of configuration about our application.
-</p>
-
-<p>
- We'll create an <em>application specification</em> for our application, and store the configuration
- data there. An application specification is an XML file that provides extra information about the application
- to Tapestry. It is optional; we didn't have one in the previous example.
-</p>
-
-<p>
- The name of the servlet ("app", in this example) is appended with the extension ".application" to
- form the name of the specification. The specification itself is stored in the
- WEB-INF folder of the web application. In our project, it is stored as
- src/context/WEB-INF/app.application:
-</p>
-
-<source xml:space="preserve">
+ <source xml:space="preserve">
<?xml version="1.0"?>
<!DOCTYPE application PUBLIC
"-//Apache Software Foundation//Tapestry Specification 4.0//EN"
@@ -273,166 +313,185 @@
</application>
</source>
-<p>Application specifications are validated XML files, with a real DTD (at the specified
- location). The <meta> element is used to specify meta data ... configuration data that
- doesn't fit in elsewhere. Here we're using it to inform Tapestry about which
- Java packages to search for pages. This value can even be a comma-seperated list of packages, if there is more
- than one package to search.</p>
-
-<p>
- With this file in place, Tapestry has all it needs to run our application: the Home page's HTML template, its
- Java class, at the connection between the two. Now, let's look at improving our example a bit.
-</p>
-
-</section>
-
-<section name="Understanding DirectLink URLs">
-
-
-<p>
- The URLs generated by the DirectLink component are more complex than those generated by the
- PageLink component. Let's look at one:
-</p>
+ <p>
+ Application specifications are validated XML files, with a real DTD (at the
+ specified location). The <meta> element is used to specify meta data ...
+ configuration data that doesn't fit in elsewhere. Here we're using it to inform
+ Tapestry about which Java packages to search for pages. This value can even be a
+ comma-seperated list of packages, if there is more than one package to search.
+ </p>
+
+ <p>
+ With this file in place, Tapestry has all it needs to run our application: the Home
+ page's HTML template, its Java class, at the connection between the two. Now, let's
+ look at improving our example a bit.
+ </p>
+
+ </section>
+
+ <section name="Understanding DirectLink URLs">
+
+
+ <p>
+ The URLs generated by the DirectLink component are more complex than those generated
+ by the PageLink component. Let's look at one:
+ </p>
-<source xml:space="preserve">
+ <source xml:space="preserve">
http://localhost:8080/directlink/app?component=%24DirectLink&page=Home&service=direct&session=T
</source>
-<p>
-The first query parameter, component, identifies the component within the page. That %24 is "URL-ese" for a dollar sign.
-In Tapestry, every component ends up with a unique id within its page. If you don't provide one, Tapestry
-creates one from the component type, prefixed with a dollar sign. Here, our annoynmous DirectLink component was given the id $DirectLink.
-If you had many different DirectLinks on a page, you'd start seeing
-component ids such as $DirectLink_0, $DirectLink_1, etc.
-</p>
-
-<p>
- You can give a component a shorter and more mneumonic id by putting the desired id before the "@" sign:
-</p>
+ <p>
+ The first query parameter, component, identifies the component within the page. That
+ %24 is "URL-ese" for a dollar sign. In Tapestry, every component ends up with a
+ unique id within its page. If you don't provide one, Tapestry creates one from the
+ component type, prefixed with a dollar sign. Here, our annoynmous DirectLink
+ component was given the id $DirectLink. If you had many different DirectLinks on a
+ page, you'd start seeing component ids such as $DirectLink_0, $DirectLink_1, etc.
+ </p>
+
+ <p>
+ You can give a component a shorter and more mneumonic id by putting the desired id
+ before the "@" sign:
+ </p>
-<source xml:space="preserve">
+ <source xml:space="preserve">
<a href="#" jwcid="inc@DirectLink" listener="listener:doClick">increment counter</a>
</source>
-<p>
-After making that change to the template, the URL for the DirectLink component is just a bit easier to read:
-</p>
+ <p>
+ After making that change to the template, the URL for the DirectLink component is
+ just a bit easier to read:
+ </p>
-<source xml:space="preserve">
+ <source xml:space="preserve">
http://localhost:8080/directlink/app?component=inc&page=Home&service=direct&session=T
</source>
-<p>
-The other changes from the previous examples are the service query parameter and the session query parameter.
-The service query parameter indicates that the processing of the request is different than
-for a link created by the PageLink component. Here
-we need to get a page, find a component in the page and invoke a listener method <em>before</em> we can render
-the response. With PageLink, we just get the page and render it.
-</p>
-
-<p>
- Lastly, the session query parameter indicates whether there was an HttpSession at the time the link was rendered.
- Tapestry uses this to detect when the HttpSession expired ... perhaps because the user walked away from the
- computer for a while before clicking the link. If the application was stateless (no HttpSession) when this link
- was generated, then the session parameter simply wouldn't appear in the URL.
-</p>
-
-<p>
- One thing to take note of is that the method name <em>is not</em> part of the URL, just the id of the
- component. This is very desirable ... why expose more of the construction of your application than
- you have to? As importantly, this helps to prevent malicious users from subverting your application; there
- simply isn't a way to get an arbitrary listener method to be invoked, only one that you, as the developer, wired
- to a specific component.
-</p>
-
-<p>
- These are what Tapestry pros call "ugly URLs". The ugly part is the use of query parameters, rather than paths,
- to express the information in the URL. Ugly URLs can cause some problems; since the entire application is
- routed through the /app path, it's hard to apply J2EE declarative security. Likewise, the use
- of query parameters means that most search engines will not spider the site. The solution is
- to
- use "friendly URLs"<sup>3</sup>, which is covered in a later tutorial.
-</p>
-
-
-</section>
-
-<section name="Adding more links">
-
-
-<p>
- This application is good, but we should have a way to reset the counter back to zero. We're going to
- add a link to the page to do just that. The end result will look like:
-</p>
-
-<img src="../images/QuickStart/directlink3.png" alt="Tutorial with clear link"/>
-
-<p>
- To accomplish this we need to add another link to the Home page's HTML template, and connect that
- to logic expressed as a new method on the Home page class. First the template:
-</p>
+ <p>
+ The other changes from the previous examples are the service query parameter and the
+ session query parameter. The service query parameter indicates that the processing
+ of the request is different than for a link created by the PageLink component. Here
+ we need to get a page, find a component in the page and invoke a listener method
+ <em>before</em>
+ we can render the response. With PageLink, we just get the page and render it.
+ </p>
+
+ <p>
+ Lastly, the session query parameter indicates whether there was an HttpSession at
+ the time the link was rendered. Tapestry uses this to detect when the HttpSession
+ expired ... perhaps because the user walked away from the computer for a while
+ before clicking the link. If the application was stateless (no HttpSession) when
+ this link was generated, then the session parameter simply wouldn't appear in the
+ URL.
+ </p>
+
+ <p>
+ One thing to take note of is that the method name
+ <em>is not</em>
+ part of the URL, just the id of the component. This is very desirable ... why expose
+ more of the construction of your application than you have to? As importantly, this
+ helps to prevent malicious users from subverting your application; there simply
+ isn't a way to get an arbitrary listener method to be invoked, only one that you, as
+ the developer, wired to a specific component.
+ </p>
+
+ <p>
+ These are what Tapestry pros call "ugly URLs". The ugly part is the use of query
+ parameters, rather than paths, to express the information in the URL. Ugly URLs can
+ cause some problems; since the entire application is routed through the /app path,
+ it's hard to apply J2EE declarative security. Likewise, the use of query parameters
+ means that most search engines will not spider the site. The solution is to use
+ "friendly URLs"
+ <sup>3</sup>
+ , which is covered in a later tutorial.
+ </p>
+
+
+ </section>
+
+ <section name="Adding more links">
+
+
+ <p>
+ This application is good, but we should have a way to reset the counter back to
+ zero. We're going to add a link to the page to do just that. The end result will
+ look like:
+ </p>
+
+ <img src="../images/QuickStart/directlink3.png" alt="Tutorial with clear link" />
+
+ <p>
+ To accomplish this we need to add another link to the Home page's HTML template, and
+ connect that to logic expressed as a new method on the Home page class. First the
+ template:
+ </p>
-<source xml:space="preserve">
+ <source xml:space="preserve">
<p>
<a href="#" jwcid="clear@DirectLink" listener="listener:doClear">clear counter</a>
</p>
</source>
-
-<p>This is just <em>another</em> DirectLink component, on the same page, but with
- a different component id, and a different configuration. Here, we've called the component
- "clear", and connected it to the doClear() listener method.</p>
-
- <p>
- That method is also quite simple:
- </p>
-
-<source xml:space="preserve">
+
+ <p>
+ This is just
+ <em>another</em>
+ DirectLink component, on the same page, but with a different component id, and a
+ different configuration. Here, we've called the component "clear", and connected it
+ to the doClear() listener method.
+ </p>
+
+ <p>That method is also quite simple:</p>
+
+ <source xml:space="preserve">
public void doClear()
{
setCounter(0);
}
</source>
-<p>
- And that's all it takes. We've added a new operation to our page, clearing the counter, in
- four lines of Java code (three if you format your code the way Sun likes you to), and a couple
- of lines of HTML. No outside configuration beyond that. This conforms to another Tapestry
- principle: <strong>Consistency</strong>. Adding more operations is not different from adding the first operation. Add
- as many as you like, Tapestry will take care of it.
-</p>
-
-<p>
- By contrast, using traditional servlets, we would have had to:
-</p>
-<ul>
- <li>Decide on the URL</li>
- <li>Update the HTML with that URL</li>
- <li>Write an entire new servlet class for this single operation</li>
- <li>Update web.xml with the servlet and the servlet mapping (the URL)</li>
-</ul>
-
-
-</section>
+ <p>
+ And that's all it takes. We've added a new operation to our page, clearing the
+ counter, in four lines of Java code (three if you format your code the way Sun likes
+ you to), and a couple of lines of HTML. No outside configuration beyond that. This
+ conforms to another Tapestry principle:
+ <strong>Consistency</strong>
+ . Adding more operations is not different from adding the first operation. Add as
+ many as you like, Tapestry will take care of it.
+ </p>
+
+ <p>By contrast, using traditional servlets, we would have had to:</p>
+ <ul>
+ <li>Decide on the URL</li>
+ <li>Update the HTML with that URL</li>
+ <li>Write an entire new servlet class for this single operation</li>
+ <li>Update web.xml with the servlet and the servlet mapping (the URL)</li>
+ </ul>
+
+
+ </section>
+
+ <section name="Passing data in the links">
+
+
+ <p>
+ Just invoking a single operation is a bit limiting; we should be able to increment
+ by more than just 1:
+ </p>
+
+ <img src="../images/QuickStart/directlink4.png" alt="Multiple DirectLinks" />
+
+ <p>
+ In this case, we want to have more than one DirectLink component call the same
+ listener. And we need to figure out whether to increment the counter by 1, 5 or 10.
+ </p>
+
+ <p>
+ This requires two changes. First, we must change the old increment link into three
+ new links:
+ </p>
-<section name="Passing data in the links">
-
-
-<p>
- Just invoking a single operation is a bit limiting; we should be able to increment by more than just 1:
-</p>
-
-<img src="../images/QuickStart/directlink4.png" alt="Multiple DirectLinks"/>
-
-<p>
-In this case, we want to have more than one DirectLink component call the same listener. And we
-need to figure out whether to increment the counter by 1, 5 or 10.
-</p>
-
-<p>
- This requires two changes. First, we must change the old increment link into three new links:
-</p>
-
-<source xml:space="preserve">
+ <source xml:space="preserve">
<p>
<a href="#" jwcid="by1@DirectLink" listener="listener:doClick" parameters="ognl:1">increment counter by 1</a>
</p>
@@ -446,25 +505,29 @@
</p>
</source>
-<p>
- We've given the three components mnuemonic ids ("by1", "by5" and "by10"). In addition, we're passing
- parameters in the URL; that's the parameters parameter<sup>4</sup>. We can see that value
- encoded into the URL:
-</p>
+ <p>
+ We've given the three components mnuemonic ids ("by1", "by5" and "by10"). In
+ addition, we're passing parameters in the URL; that's the parameters parameter
+ <sup>4</sup>
+ . We can see that value encoded into the URL:
+ </p>
+
+ <source xml:space="preserve">http://localhost:8080/directlink/app?component=by10&page=Home&service=direct&session=T&sp=10</source>
+
+ <p>
+ The sp query parameter holds the value. "sp" is short for "service parameter", and
+ is a hold over from Tapestry 3.0. In Tapestry 4.0, these are called "listener
+ parameters", because they are only meaningful to the listener method. Also, we're
+ only showing a single parameter, but the same mechanism supports multiple
+ parameters.
+ </p>
+
+ <p>
+ That's how information gets encoded into the URL, but how does the listener method
+ find out about it? By adding a parameter to the doClick() listener method:
+ </p>
-<source xml:space="preserve">http://localhost:8080/directlink/app?component=by10&page=Home&service=direct&session=T&sp=10</source>
-
-<p>The sp query parameter holds the value. "sp" is short for "service parameter", and is a hold over
- from Tapestry 3.0. In Tapestry 4.0, these are called "listener parameters", because they are
- only meaningful to the listener method. Also, we're only showing a single parameter, but the
- same mechanism supports multiple parameters.</p>
-
-<p>
- That's how information gets encoded into the URL, but how does the listener method find out about it?
- By adding a parameter to the doClick() listener method:
-</p>
-
-<source xml:space="preserve">
+ <source xml:space="preserve">
public void doClick(int increment)
{
int counter = getCounter();
@@ -474,55 +537,66 @@
setCounter(counter);
}
</source>
-
-<p>
- Tapestry maps the values in the sp query parameter to the parameters of the listener method. Also, note
- that <em>type</em> of the value has been maintained. it started as a number, and is still a number.
- Listener parameters can be of virtually any type, and will keep their type through being encoded into the URL
- and decoded in the subsequent request. You can even pass arbitrary objects ... as long as they implement java.io.Serializable (but
- you will start seeing some very long URLs if you do).
-</p>
-
-<p>
- Again, we're seeing consistency. We wanted to pass information in the URL, and were able to use the
- same mechanisms; the DirectLink component, the listener method ... we just added a little sensible extra
- to get the needed information from point A (the page as it renders) to point B (the listener method when the
- link is clicked).
-</p>
-</section>
-<section name="Next: Forms">
-
+ <p>
+ Tapestry maps the values in the sp query parameter to the parameters of the listener
+ method. Also, note that
+ <em>type</em>
+ of the value has been maintained. it started as a number, and is still a number.
+ Listener parameters can be of virtually any type, and will keep their type through
+ being encoded into the URL and decoded in the subsequent request. You can even pass
+ arbitrary objects ... as long as they implement java.io.Serializable (but you will
+ start seeing some very long URLs if you do).
+ </p>
+
+ <p>
+ Again, we're seeing consistency. We wanted to pass information in the URL, and were
+ able to use the same mechanisms; the DirectLink component, the listener method ...
+ we just added a little sensible extra to get the needed information from point A
+ (the page as it renders) to point B (the listener method when the link is clicked).
+ </p>
+ </section>
+
+ <section name="Next: Forms">
+
+
+ <p>
+ <a href="site:DirectLink">DirectLink</a>
+ may be a real workhorse, but the heart of most web applications are the subject of
+ our next tutorial:
+ <a href="forms.html">Tapestry Forms</a>
+ .
+ </p>
-<p>
-<a href="site:DirectLink">DirectLink</a> may be a real workhorse, but the heart of most web applications are the
-subject of our next tutorial: <a href="forms.html">Tapestry Forms</a>.
-</p>
-
-</section>
-
-
-<p>
- <sup>1</sup>This is my (Howard Lewis Ship's) least favorite thing in Tapestry 4.0; it is something
- that should be erradicated from Tapestry (you should not have to extend a base class at all), but
- that will cause some significant backwards compatibility issues.
-</p>
-
-<p>
- <sup>2</sup>Listener methods don't have to be named in any special way, they just have to be
- public methods. This naming convention, do<em>Something</em>, is a good one, but is
- anything but mandatory.
-</p>
-
-<p>
- <sup>3</sup>For some reason, "ugly" is the opposite of "friendly".
-</p>
-
-<p>
- <sup>4</sup>Say that a few times fast.
-</p>
-
-
-
-</body>
+ </section>
+
+ <span class="info">
+ <p>
+ <sup>1</sup>
+ This is my (Howard Lewis Ship's) least favorite thing in Tapestry 4.0; it is something
+ that should be erradicated from Tapestry (you should not have to extend a base class at
+ all), but that will cause some significant backwards compatibility issues.
+ </p>
+
+ <p>
+ <sup>2</sup>
+ Listener methods don't have to be named in any special way, they just have to be public
+ methods. This naming convention, do
+ <em>Something</em>
+ , is a good one, but is anything but mandatory.
+ </p>
+
+ <p>
+ <sup>3</sup>
+ For some reason, "ugly" is the opposite of "friendly".
+ </p>
+
+ <p>
+ <sup>4</sup>
+ Say that a few times fast.
+ </p>
+ </span>
+
+ </section>
+ </body>
</document>
Modified: tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/forms.xml
URL: http://svn.apache.org/viewvc/tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/forms.xml?rev=418868&r1=418867&r2=418868&view=diff
==============================================================================
--- tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/forms.xml (original)
+++ tapestry/tapestry4/trunk/src/site/xdoc/QuickStart/forms.xml Mon Jul 3 15:48:59 2006
@@ -1,60 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright 2005 The Apache Software Foundation
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ Copyright 2005 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<document>
-<properties>
-<title>QuickStart: Forms</title>
-</properties>
-<body>
-
-<p>
-In this tutorial, we'll cover the basics of Tapestry forms, and gain an understanding of the lifecycle of
-a Tapestry application. We'll also see how to transfer information from one
-page to another.
-</p>
-
-<p>
-The theme of this tutorial is an application used to track third-party libraries for Tapestry.
-Each project will have a number of properties:
-</p>
-
-<ul>
- <li>name</li>
- <li>release ID</li>
- <li>short and long description</li>
- <li>category</li>
- <li>supported Tapestry version</li>
- <li>release date</li>
- <li>public (visible to others) or private (visible only to the owner)</li>
-</ul>
-
-<p>
- Later tutorials will return to this theme, and cover the issues related to
- accessing data from a database. For this tutorial, we're just going to collect
- the above data (in an Add Project page), and then echo it back to the user.
-</p>
-
-<section name="Home Page">
-
-
-<p>
-The Home page for our application is very simple, it doesn't require a Java class:
-</p>
+ <properties>
+ <title>QuickStart: Forms</title>
+ </properties>
+ <body>
+
+ <section name="QuickStart: Forms">
+ <p>
+ In this tutorial, we'll cover the basics of Tapestry forms, and gain an
+ understanding of the lifecycle of a Tapestry application. We'll also see how to
+ transfer information from one page to another.
+ </p>
+
+ <p>
+ The theme of this tutorial is an application used to track third-party libraries for
+ Tapestry. Each project will have a number of properties:
+ </p>
+
+ <ul>
+ <li>name</li>
+ <li>release ID</li>
+ <li>short and long description</li>
+ <li>category</li>
+ <li>supported Tapestry version</li>
+ <li>release date</li>
+ <li>public (visible to others) or private (visible only to the owner)</li>
+ </ul>
+
+ <p>
+ Later tutorials will return to this theme, and cover the issues related to accessing
+ data from a database. For this tutorial, we're just going to collect the above data
+ (in an Add Project page), and then echo it back to the user.
+ </p>
+
+ <section name="Home Page">
+
+
+ <p>
+ The Home page for our application is very simple, it doesn't require a Java class:
+ </p>
-<source xml:space="preserve">
+ <source xml:space="preserve">
<html jwcid="@Shell" title="Tapestry Component Database">
<body>
@@ -72,36 +73,41 @@
</body>
</html>
</source>
-
-<p>
-We've introduced another handy component, <a href="site:Shell">Shell</a>. This component is just a
-convienience for generating the <html>, <head>, and <title> tags (though
-it has quite a few other tricks up its sleeve).
-</p>
-
-
-</section>
-<section name="Value Object">
-
-
-<p>
- One of the cornerstones of Tapestry is the ability to edit properties of value objects directly.
- These value objects, in a real application, will be read from the database, editted by Tapestry
- components, then written back into the database.
-</p>
-
-<p>
- Objects editted by Tapestry in this manner have <em>no</em> requirements. Unlike pages, they don't
- have to extend a base class or implement an interface. They are truly the <strong>Model</strong>
- in the <strong>Model-View-Controller Pattern</strong>.
-</p>
-
-<p>
- For this tutorial, we're using a very simple value object:
-</p>
+ <p>
+ We've introduced another handy component,
+ <a href="site:Shell">Shell</a>
+ . This component is just a convienience for generating the <html>,
+ <head>, and <title> tags (though it has quite a few other tricks up its
+ sleeve).
+ </p>
+
+
+ </section>
+
+ <section name="Value Object">
+
+
+ <p>
+ One of the cornerstones of Tapestry is the ability to edit properties of value
+ objects directly. These value objects, in a real application, will be read from the
+ database, editted by Tapestry components, then written back into the database.
+ </p>
+
+ <p>
+ Objects editted by Tapestry in this manner have
+ <em>no</em>
+ requirements. Unlike pages, they don't have to extend a base class or implement an
+ interface. They are truly the
+ <strong>Model</strong>
+ in the
+ <strong>Model-View-Controller Pattern</strong>
+ .
+ </p>
-<source xml:space="preserve">package tutorial.forms.data;
+ <p>For this tutorial, we're using a very simple value object:</p>
+
+ <source xml:space="preserve">package tutorial.forms.data;
import java.util.Date;
@@ -235,21 +241,22 @@
}
</source>
-</section>
+ </section>
-<section name="AddProject Page">
-
-
-<p>
- As we've seen, the Home page includes a link to the AddProject page; the AddProject page
- will contain the form that collects the data about the project before storing it into a database.
- We don't have a database in this example, but we can still collect the data.
-</p>
-
-<subsection name="HTML Template">
-
-
-<source xml:space="preserve"><html jwcid="@Shell" title="Add New Project">
+ <section name="AddProject Page">
+
+
+ <p>
+ As we've seen, the Home page includes a link to the AddProject page; the AddProject
+ page will contain the form that collects the data about the project before storing
+ it into a database. We don't have a database in this example, but we can still
+ collect the data.
+ </p>
+
+ <subsection name="HTML Template">
+
+
+ <source xml:space="preserve"><html jwcid="@Shell" title="Add New Project">
<body jwcid="@Body">
<h1>Add New Project</h1>
<form jwcid="form@Form" success="listener:doSubmit">
@@ -300,68 +307,98 @@
<input type="submit" value="Add Project"/>
</form>
</body>
-</html></source>
-
-<p>
-This template introduces a number of new components:
-</p>
-
-<ul>
- <li>
-<a href="site:Body">Body</a> -- organizes the JavaScript generated for the page (needed to use the <a href="site:DatePicker">DatePicker</a>)</li>
- <li>
-<a href="site:Form">Form</a> -- generates an HTML form and controls the submit behavior</li>
- <li>
-<a href="site:TextField">TextField</a> -- creates a text field (<input type="text"/>) used to <em>edit</em> (read and update) a property
- of the page</li>
- <li>
-<a href="site:TextArea">TextArea</a> -- as with <a href="site:TextField">TextField</a>, but generates a multi-line <textarea></li>
- <li>
-<a href="site:DatePicker">DatePicker</a> -- a JavaScript popup calendar</li>
- <li>
-<a href="site:Checkbox">Checkbox</a> -- edits a <em>boolean</em> property of the page</li>
-</ul>
-
-<p>
-The <a href="site:Form">Form</a>'s success parameter is linked to a listener method. It is invoked only when there
-are no validation errors. We'll discuss validation in a later tutorial.
-</p>
-
-<p>
- The <a href="site:Body">Body</a> component plays a crucial role in Tapestry; it organizes all the JavaScript generated when
- a page renders. It assists components with generated unique names for client-side variables and functions,
- and organizes all the JavaScript generated by all the component within the page into two large blocks (one at
- the top of the page, one at the bottom). The <a href="site:DatePicker">DatePicker</a> component will not operate unless it is
- enclosed by a <a href="site:Body">Body</a> component.
-</p>
-
-<p>
-The <a href="site:TextField">TextField</a> and <a href="site:TextArea">TextArea</a> components edit properties of the page. Because the value
-parameter is an <a href="http://www.ognl.org">OGNL</a> expression, it is not limited to editting properties directly exposed
-by the page class; it can follow property paths. We'll see how to define the project
-property of the page shortly.
-</p>
-
-<p>
- As you can see, Tapestry offers a number of components for editting specific types of properties. In addition,
- we'll see in a bit how the existing components can be configured for editting other types as well.
-</p>
-
-<p>
- As the template shows, this page is reliant on
- having a specific Java class, with a doSubmit() listener method and a project property. Let's create that next.
-</p>
-
-</subsection>
-
-<subsection name="AddProject Page Class">
-
-
-<p>
- Let's start with the minimum for this class and add details as necessary.
-</p>
+</html></source>
+
+ <p>This template introduces a number of new components:</p>
+
+ <ul>
+ <li>
+ <a href="site:Body">Body</a>
+ -- organizes the JavaScript generated for the page (needed to use the
+ <a href="site:DatePicker">DatePicker</a>
+ )
+ </li>
+ <li>
+ <a href="site:Form">Form</a>
+ -- generates an HTML form and controls the submit behavior
+ </li>
+ <li>
+ <a href="site:TextField">TextField</a>
+ -- creates a text field (<input type="text"/>) used to
+ <em>edit</em>
+ (read and update) a property of the page
+ </li>
+ <li>
+ <a href="site:TextArea">TextArea</a>
+ -- as with
+ <a href="site:TextField">TextField</a>
+ , but generates a multi-line <textarea>
+ </li>
+ <li>
+ <a href="site:DatePicker">DatePicker</a>
+ -- a JavaScript popup calendar
+ </li>
+ <li>
+ <a href="site:Checkbox">Checkbox</a>
+ -- edits a
+ <em>boolean</em>
+ property of the page
+ </li>
+ </ul>
+
+ <p>
+ The
+ <a href="site:Form">Form</a>
+ 's success parameter is linked to a listener method. It is invoked only when
+ there are no validation errors. We'll discuss validation in a later tutorial.
+ </p>
+
+ <p>
+ The
+ <a href="site:Body">Body</a>
+ component plays a crucial role in Tapestry; it organizes all the JavaScript
+ generated when a page renders. It assists components with generated unique names
+ for client-side variables and functions, and organizes all the JavaScript
+ generated by all the component within the page into two large blocks (one at the
+ top of the page, one at the bottom). The
+ <a href="site:DatePicker">DatePicker</a>
+ component will not operate unless it is enclosed by a
+ <a href="site:Body">Body</a>
+ component.
+ </p>
+
+ <p>
+ The
+ <a href="site:TextField">TextField</a>
+ and
+ <a href="site:TextArea">TextArea</a>
+ components edit properties of the page. Because the value parameter is an
+ <a href="http://www.ognl.org">OGNL</a>
+ expression, it is not limited to editting properties directly exposed by the
+ page class; it can follow property paths. We'll see how to define the project
+ property of the page shortly.
+ </p>
+
+ <p>
+ As you can see, Tapestry offers a number of components for editting specific
+ types of properties. In addition, we'll see in a bit how the existing components
+ can be configured for editting other types as well.
+ </p>
+
+ <p>
+ As the template shows, this page is reliant on having a specific Java class,
+ with a doSubmit() listener method and a project property. Let's create that
+ next.
+ </p>
+
+ </subsection>
+
+ <subsection name="AddProject Page Class">
-<source xml:space="preserve">package tutorial.forms.pages;
+
+ <p>Let's start with the minimum for this class and add details as necessary.</p>
+
+ <source xml:space="preserve">package tutorial.forms.pages;
import org.apache.tapestry.html.BasePage;
@@ -383,41 +420,51 @@
}
}
</source>
-
-<p>
- Maybe this is too minimal; if we launch the application and choose the Add New Project link, we
- get an exception:
-</p>
-
-<img src="../images/QuickStart/forms1.png" alt="Null Pointer Exception"/>
-
-<p>
- The root of this exception is a null value: we defined a place to store a ProjectRelease object
- but didn't actually provide an instance. <a href="http://www.ognl.org">OGNL</a> attempted to dereference through the null value
- and threw the OgnlException. Here we can see the advantage of Tapestry's exception reporting ... showing the
- stack of exceptions gave us context into our application (the line in the template associated with the
- error) without obscuring the underlying cause.
-</p>
-
-<p>
- What we need to do is create an instance of ProjectRelease and store it into
- the property so that the <a href="site:TextField">TextField</a> components can edit it. We have to be careful
- because in a live application, pages will be pooled and reused constantly.
-</p>
-
-<p>
- For this situation, the right approach is to listen for the PageBeginRender event, and
- store the new instance into the property then. The ProjectRelease object will be used for the
- duration of the request, then discarded at the end of the request.
-</p>
-
-<p>
- Listening for these lifecycle events is simple; you just need to select the correct listener interface
- and implement it; Tapestry will automatically register your page to receive the notifications. Here,
- the interface is <a href="../tapestry-framework/apidocs/org/apache/tapestry/event/PageBeginRenderListener.html">PageBeginRenderListener</a>:
-</p>
-<source xml:space="preserve">package tutorial.forms.pages;
+ <p>
+ Maybe this is too minimal; if we launch the application and choose the Add New
+ Project link, we get an exception:
+ </p>
+
+ <img src="../images/QuickStart/forms1.png" alt="Null Pointer Exception" />
+
+ <p>
+ The root of this exception is a null value: we defined a place to store a
+ ProjectRelease object but didn't actually provide an instance.
+ <a href="http://www.ognl.org">OGNL</a>
+ attempted to dereference through the null value and threw the OgnlException.
+ Here we can see the advantage of Tapestry's exception reporting ... showing the
+ stack of exceptions gave us context into our application (the line in the
+ template associated with the error) without obscuring the underlying cause.
+ </p>
+
+ <p>
+ What we need to do is create an instance of ProjectRelease and store it into the
+ property so that the
+ <a href="site:TextField">TextField</a>
+ components can edit it. We have to be careful because in a live application,
+ pages will be pooled and reused constantly.
+ </p>
+
+ <p>
+ For this situation, the right approach is to listen for the PageBeginRender
+ event, and store the new instance into the property then. The ProjectRelease
+ object will be used for the duration of the request, then discarded at the end
+ of the request.
+ </p>
+
+ <p>
+ Listening for these lifecycle events is simple; you just need to select the
+ correct listener interface and implement it; Tapestry will automatically
+ register your page to receive the notifications. Here, the interface is
+ <a
+ href="../tapestry-framework/apidocs/org/apache/tapestry/event/PageBeginRenderListener.html">
+ PageBeginRenderListener
+ </a>
+ :
+ </p>
+
+ <source xml:space="preserve">package tutorial.forms.pages;
import java.util.Date;
@@ -454,67 +501,82 @@
}
}
</source>
-
-<p>
- The pageBeginRender() method will be invoked whenever the page renders. It is also, due to a useful quirk of Tapestry,
- invoked when a form within the page is submitted. Not only can we create an instance, but we
- have the opportunity to set some initial values for fields.
-</p>
-
-<p>
- With this in place, the page will now render, and we can begin entering some data into it:
-</p>
-
-<img src="../images/QuickStart/forms2.png" alt="AddProject Page"/>
-
-
-</subsection>
-
-<subsection name="Form Submission">
-
-
- <p>
- As implemented above, submitting the form doesn't appear to do anything. Sure, the form submits, and information is pulled
- out of the request and applied to the properties of the ProjectRelease object, but then the AddProject page
- is re-rendered.
- </p>
-
- <p>
- So ... how did the ProjectRelease object stick around? Shouldn't we have gotten a NullPointerException again, when
- the form submitted and the <a href="site:TextField">TextField</a> component updated property project.name? What actually happened is that
- the ProjectRelease object was discarded ... but when a form is submitted on a page, the PageBeginRender interface is
- triggered again, just like for a form render. This means that the existing code does create a new ProjectRelease instance,
- giving the TextField components a place to store the values from the form.
- </p>
-
-
- <p>
- As wonderful as it is that the new ProjectRelease object gets updated, what we
- really want is for <em>something to happen</em>. We're going to change things so that a different page is
- displayed when the form is submitted. Further, that form will show the same information collected by
- the AddProject page.
- </p>
-
- <p>
- To accomplish this, we're going to change the doSubmit() method, and have it obtain the ShowProject page. The easiest way to
- make different pages work together is by <em>injecting</em> one page into another. This can be done using
- an annotation<sup>1</sup>:
- </p>
-
- <source xml:space="preserve">
+
+ <p>
+ The pageBeginRender() method will be invoked whenever the page renders. It is
+ also, due to a useful quirk of Tapestry, invoked when a form within the page is
+ submitted. Not only can we create an instance, but we have the opportunity to
+ set some initial values for fields.
+ </p>
+
+ <p>
+ With this in place, the page will now render, and we can begin entering some
+ data into it:
+ </p>
+
+ <img src="../images/QuickStart/forms2.png" alt="AddProject Page" />
+
+
+ </subsection>
+
+ <subsection name="Form Submission">
+
+
+ <p>
+ As implemented above, submitting the form doesn't appear to do anything. Sure,
+ the form submits, and information is pulled out of the request and applied to
+ the properties of the ProjectRelease object, but then the AddProject page is
+ re-rendered.
+ </p>
+
+ <p>
+ So ... how did the ProjectRelease object stick around? Shouldn't we have gotten
+ a NullPointerException again, when the form submitted and the
+ <a href="site:TextField">TextField</a>
+ component updated property project.name? What actually happened is that the
+ ProjectRelease object was discarded ... but when a form is submitted on a page,
+ the PageBeginRender interface is triggered again, just like for a form render.
+ This means that the existing code does create a new ProjectRelease instance,
+ giving the TextField components a place to store the values from the form.
+ </p>
+
+
+ <p>
+ As wonderful as it is that the new ProjectRelease object gets updated, what we
+ really want is for
+ <em>something to happen</em>
+ . We're going to change things so that a different page is displayed when the
+ form is submitted. Further, that form will show the same information collected
+ by the AddProject page.
+ </p>
+
+ <p>
+ To accomplish this, we're going to change the doSubmit() method, and have it
+ obtain the ShowProject page. The easiest way to make different pages work
+ together is by
+ <em>injecting</em>
+ one page into another. This can be done using an annotation
+ <sup>1</sup>
+ :
+ </p>
+
+ <source xml:space="preserve">
@InjectPage("ShowProject")
- public abstract ShowProject getShowProject(); </source>
-
- <p>
- This code, part of AddProject.java, establishes the connection from the AddProject page to the ShowProject page.
- </p>
-
- <p>
- We can leverage that code inside doSubmit() to pass information from the AddProject page to the ShowProject page; we can
- also <em>activate</em> the ShowProject page, so that it renders the response.
- </p>
-
- <source xml:space="preserve">
+ public abstract ShowProject getShowProject(); </source>
+
+ <p>
+ This code, part of AddProject.java, establishes the connection from the
+ AddProject page to the ShowProject page.
+ </p>
+
+ <p>
+ We can leverage that code inside doSubmit() to pass information from the
+ AddProject page to the ShowProject page; we can also
+ <em>activate</em>
+ the ShowProject page, so that it renders the response.
+ </p>
+
+ <source xml:space="preserve">
public IPage doSubmit()
{
ShowProject showProject = getShowProject();
@@ -522,44 +584,52 @@
showProject.setProject(getProject());
return showProject;
- } </source>
-
- <p>
- A lot is going on here in a very small amount of code. First off, this method is no longer void, it returns
- a page (<a href="../tapestry-framework/apidocs/org/apache/tapestry/IPage.html">IPage</a> is the interface all page classes must implement). When a listener method returns a page,
- that page becomes the <em>active page</em>, the page which will render the response to the client.
- </p>
-
- <p>
- This is an example of what we mean when we talk about objects, methods and properties. We don't talk about the
- "ShowProject.html" template ... we talk about the ShowProject page, and leave the details about where its template is
- and what's on that template to the ShowProject page. Further, to pass information from the AddProject page
- to the ShowProject page, we don't muck about with HttpServletRequest attributes ... we store an object into a
- property of the ShowProject page.
- </p>
-
- <p>
- With all this in place, we can now submit the form and see the ShowProject page:
- </p>
-
-<img src="../images/QuickStart/forms3.png" alt="ShowProject Page"/>
-
-</subsection>
-
-</section>
+ } </source>
- <section name="Next: ???">
-
- </section>
-
-<p>
-<em>More coming soon ...</em>
-</p>
-
- <p>
- <sup>1</sup> Of course, annotations required JDK 1.5, which you'll need for these tutorials. If you can't use
- JDK 1.5 in production, that's OK. Tapestry is compatible with JDK 1.3 and has another approach, based on XML,
- for injecting pages or doing just about anything else that shows up as an annotation in the tutorials.
- </p>
-</body>
+ <p>
+ A lot is going on here in a very small amount of code. First off, this method is
+ no longer void, it returns a page (
+ <a href="../tapestry-framework/apidocs/org/apache/tapestry/IPage.html">IPage</a>
+ is the interface all page classes must implement). When a listener method
+ returns a page, that page becomes the
+ <em>active page</em>
+ , the page which will render the response to the client.
+ </p>
+
+ <p>
+ This is an example of what we mean when we talk about objects, methods and
+ properties. We don't talk about the "ShowProject.html" template ... we talk
+ about the ShowProject page, and leave the details about where its template is
+ and what's on that template to the ShowProject page. Further, to pass
+ information from the AddProject page to the ShowProject page, we don't muck
+ about with HttpServletRequest attributes ... we store an object into a property
+ of the ShowProject page.
+ </p>
+
+ <p>
+ With all this in place, we can now submit the form and see the ShowProject page:
+ </p>
+
+ <img src="../images/QuickStart/forms3.png" alt="ShowProject Page" />
+
+ </subsection>
+
+ </section>
+
+ <section name="Next: ???">
+ <p>
+ <em>More coming soon ...</em>
+ </p>
+ </section>
+
+ <span class="info">
+ <sup>1</sup>
+ Of course, annotations required JDK 1.5, which you'll need for these tutorials. If
+ you can't use JDK 1.5 in production, that's OK. Tapestry is compatible with JDK 1.3
+ and has another approach, based on XML, for injecting pages or doing just about
+ anything else that shows up as an annotation in the tutorials.
+ </span>
+
+ </section>
+ </body>
</document>