Article
Step-by-Step Jakarta Tapestry
Our First Tapestry Web Application
First, let's visualize what we're going to create. Our first Tapestry application will be quite simple -- though still useful -- and will have two pages. The first page will display a login form: just a standard form that ask for a username and a password. The second page will greet visitors using their login names -- that is, if they successfully pass authentication. If the login/password combination is wrong, the login page will be redisplayed again.
Figure 5 shows what both pages should look like when completed. For simplicity, I haven't used any styles here, but you can apply your creativity to create a design of your own.


Figure 5. This is how the completed pages of our application will look.
In fact, it makes sense to begin the development of your Tapestry application by first creating the HTML 'mockups' -- prototypes of your future pages that show exactly how they'll look in a working application.
You can exercise all your creative skills to the full when creating mockups or, if you're the manager or client of a good design team, tell your designers not to limit their imagination. You're not going to spoil their efforts by inserting ugly tags or mixing carefully crafted design with an unintelligible mix of HTML and code. As you'll soon see, Tapestry treats page design with great care.
Here's the HTML code for my page mockups:
Page 1:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Welcome to Tapestry!</title>
</head>
<body>
<h2>Welcome to Tapestry!</h2>
<form action="">
<p>User Name: <input type="text"/><br/>
Password: <input type="password"/><br/>
<input type="submit" value="Let me in!"/></p>
</form>
</body>
</html>
Page 2:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<head>
<title>You've got it!</title>
</head>
<body>
<h2>Precious User!</h2>
<h3>Welcome to the wonderful World of Tapestry!</h3>
</body>
</html>
Now that we have our mockups ready, let's create our first Tapestry project.
Creating a Tapestry Project
Fire up Eclipse (but not Tomcat yet). To create a new Tapestry project, choose File > New > Other... and, under the Tapestry node, choose Tapestry Web project, as shown in Fig. 6. Then press Next.

Figure 6. Choosing a Tapestry Web Project
Name the project, say, 'Login', and check the box Include the Tapestry redirect filter in web.xml (see Fig.7).

Fig. 7. Naming the project
Press Next, and in the next window click Finish. You'll see the structure of your new application, as shown in Fig.8.
General Structure of a Java Web Application

Fig. 8. The Structure of a New Tapestry Project
If you don't have any experience with Java web development, you might benefit from a brief overview of the standard structure of Java web application. This structure is common to all frameworks based on servlets, including JSP, Struts, Tapestry and virtually everything that exists in the Java web world.
A simplified version of this structure is shown in Fig. 9. The whole application is contained within one directory, which is given the name of the application. We've labeled this top-level directory AppName in the diagram.

Fig. 9. The Generic Structure of a Java Web Application
Directly under AppName live those resources that are directly accessible by the outside world, via the Web. This includes HTML pages, JSP pages, CSS files, images and any other resources that might be needed for the external part of the application. I use the term "external" because if you have, say, a page named MyPage.html that's stored directly under the AppName directory on your www.myserver.com server, web users can see that page by pointing their browsers to http://www.myserver.com/AppName/MyPage.html.
Images and style sheets are often put into a subdirectory -- in this case, one named assets. Grouping content like this helps to keep things neat; this subdirectory will be also accessible to everyone.
You'll notice a (particularly important) subdirectory named WEB-INF. It should be named exactly like this -- not web-inf or Web-Inf -- otherwise your Web application won't work. This is the inner sanctum of a Java Web application: nothing that goes inside this directory will be exposed directly to the outer world (i.e. to the Web).
There's an important file inside WEB-INF named web.xml. It has the same name in all Java web applications, and is the deployment descriptor. The purpose of this file is to tell Tomcat some general, important information about the application.
There are also two subdirectories under WEB-INF, named classes and lib. All the compiled Java classes that make up the application go into the classes subdirectory, and all the libraries that are used by the application go into the lib directory -- simple! Many other files serving different purposes can be kept under WEB-INF and in its subdirectories, but this is the standard structure.
Now, let's see how this arrangement maps to the structure of our first Tapestry application, created for us by Eclipse (together with Spindle).
The Structure of our Web Application
You can see that the top level directory of our application is named Login -- the name that we gave to the application.
The src subdirectory was created for our convenience. This is where the source code of all our Java classes will be stored. Below it, you'll see two library references: Tapestry Framework and JRE System Library. Eclipse displays them here to indicate that we have them at our disposal for this project. There's also a context subdirectory. All of our application's files -- everything that was listed directly under AppName in Figure 9 -- are stored in the context subdirectory. We don't have any static HTML pages here right now, but we might do later. We would also keep any images or style sheets here if we had them. Right now, we see just the sacred WEB-INF file.
In WEB-INF you'll see the deployment descriptor, web.xml. We won't explore it just yet, though.
We haven't created any Java classes, nor have we used any libraries, so no classes or lib subdirectories are displayed just yet.
There is also a Login.application file that contains application-wide configuration. Right now, we'll just leave it as it is, but later, when we make some changes to it, we'll discuss the contents of this file.
Now we come to the most interesting part of the process: creating Tapestry pages.
Creating the Home Page
You'll notice that Spindle has created two more files for us: Home.html and Home.page. A page named Home is the default page for a Tapestry application, very much like index.html is the default page for a Website's directory. If no page is specified in a request from the client, Tapestry will show the Home page.
We'll put our login form on this page. Let's see what sort of HTML Spindle has created for us. Double-click the Home.html file to open it in the editor:
<html>
<head>
</head>
<body>
</body>
</html>
This is just an empty stub for a HTML page. Let's replace it with our mockup for the first page. We'll add a doctype, a title and a simple form to the body.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Welcome to Tapestry!</title>
</head>
<body>
<h2>Welcome to Tapestry!</h2>
<form action="">
<p>User Name: <input type="text"/><br/>
Password: <input type="password"/><br/>
<input type="submit" value="Let me in!"/></p>
</form>
</body>
</html>
Let's say we've just received this carefully crafted HTML page from our design team. It's time to apply our knowledge of Tapestry and convert the mockup into the real thing -- an HTML template for a Tapestry page! Here's the end result of such a conversion:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Welcome to Tapestry!</title>
</head>
<body>
<h2>Welcome to Tapestry!</h2>
<form action="" jwcid="loginForm">
<p>User Name: <input type="text" jwcid="uname" /><br/>
Password: <input type="password" jwcid="password" /><br/>
<input type="submit" value="Let me in!"/></p>
</form>
</body>
</html>
Of course, your eagle eye has spotted the changes we've made, but will your web browser notice them? Open the original mockup in a browser of your choice, then open the converted version and check if there are any differences. There aren't. Because those strange jwcid attributes mean nothing to a web browser from a rendering perspective, it just ignores them.
You might be interested to know that jwcid means "Java Web Component ID", and these jwcid attributes are our way of telling Tapestry, "We want to apply some magic here. Please turn these standard HTML elements into dynamic Tapestry components." As a result, the standard HTML element <form> will become a Tapestry component, as will the two standard <input> elements.
By the way, the names that you assign to jwcid attributes are, more or less, arbitrary. If you like, you can give them name them like jwcid="bilbo" or jwcid="FrodoBaggins". But don't try something like jwcid="%@^&*", the language of Mordor won't work here. I recommend you use something indicative of the type of data the file represents.

Fig. 10. Spindle Has Found an Error
All right, so if the component IDs are arbitrary, how will Tapestry know exactly which of its standard or custom components you want to use in place of the static HTML? You might notice that Spindle isn't quite happy with our new attributes -- it underlines the first of them with a red line and draws a red, crossed circle in the left margin of the editor window (see Figure 10). If you hover your cursor over the underlined word or the red circle, you'll see this error message:
Tag <form> on line 7 references unknown component id 'loginForm'.
Logically, there should be a place where we can specify for Tapestry the details of our design, and there is! This place is called the page specification and for our Home page it is represented by the Home.page file, which was already created for us by Spindle.
Now is the time to discuss the following revelation: Tapestry pages actually consist of three parts:
- an HTML template (Home.html for our first page, for example)
- a page specification (such as
Home.page) - a page class (we'll call ours
Home.class-- see later)
The HTML template defines what our users will see. The page class contains the page's functionality. And the page specification links the components in the template with the corresponding functionality in the page class. It specifies all the necessary details for these components, and may also contain some other page-specific information.
We'll return to the three-part nature of Tapestry pages later -- and more than once, too -- because it's very important. But right now, let's create the page specification for our Home page. Double-click the Home.page file in your Package Explorer in Eclipse. This is what you should see:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE page-specification PUBLIC
"-//Apache Software Foundation//Tapestry Specification 3.0//EN"
"http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
<!-- generated by Spindle, http://spindle.sourceforge.net -->
<page-specification class="org.apache.tapestry.html.BasePage">
<description>add a description</description>
</page-specification>
If you don't have much experience with XML documents and doctypes, don't pay too much attention to the first five lines. The first line just states that this is an XML document. The cryptic-looking <!DOCTYPE> tag tells an XML parser how to understand the document that follows.
We're interested in the information inside the page-specification element, beginning with the attribute class="org.apache.tapestry.html.BasePage".
Remember how I told you that every Tapestry page consists of three parts, one of which is a Java class that contains the page's functionality? Even if you don't create a class, a default class exists anyway -- the BasePage class referred to by this attribute. Of course, it doesn't contain any custom functionality, but it still has many default methods that give us access to the infrastructure of Tapestry.
When we decide to create our custom page class, it will always extend this default BasePage class.
Next comes the description element. You can either leave this as it is, or if you are like me and prefer to keep your stuff well organized, go ahead and add a description of the page -- something like 'Login page'.
Inside of the page-specification element, we have to explain to Tapestry what we really meant when we wrote jwcid="uname" etc.
Here, I'll show you what we're going to write for our page specification, and explain what it means before we type it into Eclipse. In a moment you'll see how we can use some handy features of Spindle and Eclipse to write all these specifications in no time at all.
First, we're going to describe our loginForm component. Its specification will look like this:
<component id="loginForm" type="Form">
<binding name="listener" expression="listeners.onFormSubmit" />
</component>
You may already have deduced that this piece of XML tells Tapestry: "The jwcid="loginForm" that I inserted into the HTML template will be a standard Tapestry Form component."
The binding element actually creates a link between the HTML template and the page class. When the name of the binding is listener (there are a few other names available), we're describing the name of the method on the page class that will be invoked when the form is submitted.
A Tapestry Form's listener is specified like this:
<binding name="listener" expression="listeners.onFormSubmit"/>
The only part of this element that you can change is the actual listener method name, in this case onFormSubmit. You have control over the name of this method, so you could call it onSubmit, or something that was more meaningful to you, if you liked. Let's stick with onFormSubmit for now; Tapestry will therefore be looking in the page class for a method with the following signature:
public void onFormSubmit(IRequestCycle cycle) {}
It will be your responsibility to provide the implementation of such a method. And if you decide to name the listener myGloriousMethod, make sure that you provide a method to Tapestry with the signature:
public void myGloriousMethod(IRequestCycle cycle) {}.
Where can you provide such a custom listener method? In a custom page class (we'll come to that later). Don't bother for now about that IRequestCycle thing, either -- we'll come to that in a moment. Right now, let's tell Tapestry how to handle the other two components that we're yet to specify.
The first is uname, for storing the user name. This is how it should be specified:
<component id="uname" type="TextField">
<binding name="value" expression="uname"/>
</component>
Here, we're telling Tapestry that what we marked in the HTML template as jwcid="uname" is actually a standard Tapestry TextField component, and the value obtained from it should be stored in a property uname. Again, this will be a property of our custom page class, but we'll cover that later. You can actually name this property whatever you like, though it is convenient (and good practice) to give the property the same name as the component's ID.
The last component on our Home page is password. This is how it should be specified:
<component id="password" type="TextField">
<binding name="value" expression="password"/>
<static-binding name="hidden" value="true"/>
</component>
This tells Tapestry that the component we marked as password is also a TextField, that its value should be stored in a property named password, and that its hidden parameter should be set to true.
Because Tapestry doesn't have a special Password component, the effect of replacing keystrokes with asterisks is achieved by setting the hidden property of a normal TextField component to true, so that the characters are not echoed to the screen.
The difference between <binding> and <static-binding> is that <binding> is evaluated by Tapestry every time the form is rendered or submitted, which is good for unpredictable or variable values (who knows what password a user will enter?). On the other hand, <static-binding> is good for constant values: we want the hidden parameter always to be true; this will be remembered by Tapestry, which won't evaluate hidden every time, saving precious resources.