Creating Your First Tapestry Project

In the previous article, we began moving from theory to practice by preparing our work place and setting up our system. In this article, we actually get our hands dirty (at least figuratively) by building our first Tapestry project.

From now on, I am going to use NetBeans. If you prefer to use Eclipse, the steps will be similar, but the details might differ. The good news is that when we come to writing code, the differences in IDEs will not matter that much.

Fire up your NetBeans. In the menu, choose File > New Project…, then select Web Application like so:

Press Next, and in the next dialog enter the name for your new project, say, FirstTapestry. I would advise you to store all your projects in a separate folder; in this case I named it NBProjects. Make sure that the bundled Tomcat is selected for the server. Also note that Context Path reflects the name of your application — this is what will be appended to the hosting server’s domain name to form your application’s context.

Have a look at the screenshot to make sure everything is set properly:

Press Next. The next dialog allows you to choose a framework to use in your application, but only two choices are available for now, JavaServer Faces and Struts. We are not going to use either of them. In the future, the Tapestry module for NetBeans will hopefully be completed and then we might be able to have our application preconfigured for Tapestry while we’re right in the process of setting up a new project. For now, simply press Finish, as we are going to create the necessary configuration by hand.

Let’s have a look at the structure of the new project created for us by NetBeans:

You can see that the structure of a NetBeans Web project does not directly reflect the standard structure of a Java Web application. It has its own logic, more convenient for development. However, when at some stage we shall want to deploy and test our application, it will be packaged for us exactly as required by standards.

Now, let’s have a look at what we have here.

The Web Pages folder contains the future Web application. You can see the familiar standard subfolders here, META-INF and WEB-INF. If we need to, we can add some other folders, say, for images and styles. There is also a basic default JSP page, index.jsp. We shall leave it so far, but it won’t be needed in the future.

The Configuration Files folder contains quite conveniently everything we might want to configure. Most importantly, you see the deployment descriptor, web.xml – we are going to work with it in one of the next sections.

Have a look at the MANIFEST.MF file. It is very simple, and we are not going to add anything to it. It will simply be put into the META-INF directory at the packaging stage.

Also, have a look at the context.xml file. This one is Tomcat specific and simply tells the server what to add to its domain name in order to form our application’s context – remember, we specified this when setting up the project. Here are the contents of the context.xml:

<?xml version="1.0" encoding="UTF-8"?>

<Context path="/FirstTapestry"/>

Very simple, and nothing to change so far, so let’s go on.

The next important folder for us is the one called Source Packages. This is where we shall place the source files for page classes and any other classes that might be needed for our application.

Finally, there is a folder named Libraries. This is where we shall put JAR files containing Tapestry and everything it depends on.

As for the remaining folders — Server Resources, Test Packages and Test Libraries – we shall not need them for our first simple application. However, we are going to leave them just because one day you might want to extend this basic application and create on its basis something more impressive.

{mospagebreak title=Adding Tapestry}

So far, we have dealt with a generic Java Web application. Now we are going to add Tapestry. Basically, Tapestry is just a set of libraries that bring with them a lot of important and useful functionality.

One way to obtain these libraries is to go to the Tapestry website (http://tapestry.apache.org/download.html) and download a binary package acceptable for your platform. I recommend that you choose version 4.1.1. Although it is stated that it is "still undergoing lots of active development," it is also considered to be "stable enough." The downside of this approach, i.e. downloading the libraries from the Tapestry website, is that the libraries are packaged in a somewhat inconvenient way — every single library is put into a separate subfolder.

For our purposes, it will be more convenient to put all the JAR files together into one folder. You can repackage them yourself, or you can simply download the package that I have already created for you; please go to the beginning of this article and click on the appropriate link.

Unpack the libraries into some folder on your hard drive. In my case, I have put them all into the tapestry41 folder in my home directory.

Now, if you expand the Libraries folder in the Projects view of your NetBeans IDE, you will see that it already contains JDK and Bundled Tomcat libraries. Right-click (or Ctrl-click on a Mac) on the Libraries folder and choose Add Library… The Add Library dialog will appear, similar to this one:

We don’t have any Tapestry libraries here yet, so we need to add one. Press the Manage Libraries… button. The Library Manager dialog will open as shown below:

Now press the New Library… button and in the dialog that opens, enter a name for the new library, such as Tapestry41. Press OK.

Back in the Library Manager, make sure that the name of the new library is selected in the Libraries view on the left side and press the Add JAR/Folder… button. In the Browse Jar/Folder dialog that opens, navigate to the folder where you have unpacked all the Tapestry-related JAR files and select them all, then press the Add JAR/Folder button. Yes, I know, it’s too many dialogs and buttons for such a simple operation, but we need to do this only once; any other projects you create in the same IDE will simply make use of this new library. The final result should look like this:

Press OK and then, back in the Add Library dialog, choose the newly added library and press the Add Library button. Phew… A bunch of files gets added to the Libraries folder of your project and now, not only is the IDE aware of all the classes you will need for Tapestry development, but these libraries will also be packed into the final package with the application we are going to create.

{mospagebreak title=Deployment descriptor}

The next task is to configure the deployment descriptor in a Tapestry specific way. A deployment descriptor is an XML file and I am used to editing it by hand, but NetBeans provides a handy and easy to use editor for this purpose. Double-click web.xml file, and you will see the editor:

We don’t have to enter anything at the first page, although you might want to enter the application’s name into the Display Name box. The really important page is the next one, Servlets. Tapestry comes with a ready to use servlet; all we need to do is configure it properly.

Right now, the Servlets page is almost empty, so press the Add Servlet Element… button. In the Add Servlet dialog that opens, enter the information as shown here:

As you will see in a later tutorial, it is convenient to give the servlet the name of the application itself. The Servlet Class will be always the same for all of our Tapestry applications. Now, the important piece of information is the URL Pattern(s). It tells the servlet container exactly which requests should be passed to our servlet. The pattern specified here is understood relative to the application context. This means that if we host our application at the www.example.com server, all requests to http://www.example.com/FirstTapestry/app will be passed to the Tapestry servlet, and the Tapestry framework will step in and show its miracles.

You might have noticed that sometimes I refer to Tomcat as a server, while at other times as a servlet container. In fact, it is both. A Web server is a piece of software that serves Web pages to site visitors. A servlet container is a piece of software that knows how to deal with servlets — and other Java classes as well. A combination of a Web server and a servlet container, like Tomcat, allows Java Web applications to run on the Internet.

Tomcat is the most popular choice but not the only one. The other quite popular and free option is Jetty. Yet another choice, Gaucho Resin, is not free but has a very good reputation.

Application servers like JBoss, Geronimo, WebSphere or WebLogic have in them a Web server and a servlet container as well, but they also have plenty of other goodies in addition to them. By the way, JBoss, Geronimo and WebSphere Community Edition all use Tomcat for their servlet container.

Press the OK button in the Add Servlet dialog. You will see that the information we have just entered is now shown on the Servlets page. The last piece of the configuration will deal with the default page of the application. Click on the Pages tab of the Deployment Descriptor editing tool, and you will see the page for editing welcome files:

You remember that when no specific page is mentioned in a request, for example a visitor of our application is trying to navigate to http://www.example.com/FirstTapestry/, the Web server needs to decide which page to show. Here we can configure this, and currently the index.jsp page, generated automatically by NetBeans, is the only option.

If we wanted to have some default page which is not a part of the application itself, we could perhaps use the existing one, or use a static page, like index.html, and on it we could provide a link to the Tapestry application, i.e. to the Tapestry servlet.

However, in many cases we will want our Tapestry application to step in straight away, without any additional pages on the way to it. Let me show you my favorite trick to achieving this goal (although there may be other solutions too).

In the Welcome Files text box, instead of index.jsp enter just app, as if our default page was named ‘app’. Let’s see what will happen now if someone decides to navigate to our application’s context: http://www.example.com/FirstTapestry/. To decide which page to show, Tomcat will look into the application’s deployment descriptor: what is the welcome file? Hmm… There should be some file named ‘app’. Let’s try it then — and Tomcat will pass the request to http://www.example.com/FirstTapestry/app, which is exactly the path to which the Tapestry servlet is mapped, so our Tapestry application will handle the request properly.

For now, save the deployment descriptor with all the changes. You can also delete the index.jsp page, as it is not needed anymore.

We have finished with configuration issues and have arrived at the most interesting step — creating the application itself.

{mospagebreak title=The First Tapestry Page}

Every Tapestry page is represented by a Java class. This page class can render an HTML page using an HTML template that we provide to it. To know exactly which components were used in the page by the developer and how they should be configured, the page class will read an XML document called page specification.

So a Tapestry page consists of three entities:

  • A page class. If no class is specified, Tapestry will use its BasePage class, but this would be useful only for a very basic page. Normally, we extend the BasePage.
  • An HTML template with Tapestry components inserted into it in one way or another. 
  • A page specification that links components in the template with their behavior in the page class and also provides all sorts of additional information.

The default page of a Tapestry application is named Home; this will be shown if no specific page was mentioned in the request. Now we are going to create this Home page, which means creating a Java class named Home, a page template named Home.html and a page specification named Home.page.

When creating a Tapestry page, it makes sense to begin with a page mock up. Just create an HTML page that shows what you want to achieve, properly designed, showing one of the moments in the life of your future application.

All the Tapestry artifacts, including page templates and page specifications, live inside the WEB-INF directory. Right-click this directory in the Projects view of NetBeans IDE and select New > HTML… in the context menu. In the New HTML File dialog enter the name for the new page: Home. The result should look like this:

Press Finish, and NetBeans will create a simple HTML page for you. All we want for now is to display the current date and time, so edit the page like this:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

 

<html>

<head>

<title>My First Tapestry Page</title>

</head>

<body>

 

<h1>My First Tapestry Page</h1>

 

<p>Now is 8:27, the 1st of April 2007.</p>

 

</body>

</html>

Right-click the Home.html file in the Projects view, select View from the context menu, and you will preview the page in a Web browser.

Now, let’s convert this simple HTML page into a Tapestry page template. We want to display dynamically the time and date for the moment when the application runs. All we need to do is surround the piece of text, which we are going to dynamically replace, with a span element.

Span is a standard HTML element normally used to assign some additional style to a piece of markup. In this case, instead of adding a style, we shall give the span an attribute named jwcid with some value in it. Here I have made the change:

<p>Now is <span jwcid="now">8:27, the 1st of April 2007</span>.</p>

When Tapestry sees that some HTML element is marked with the jwcid attribute (‘jwcid’ stands for Java Web Component ID), it knows that this element at run time should be replaced by a Tapestry component. However, for a Web browser this attribute means nothing, so it will ignore it. View the page in a Web browser, as before, and you will not see any changes.

That’s it, our HTML template is ready. Tapestry can see that we have used a component and named it ‘now’. But what kind of component is it, what exactly will it display dynamically instead of the <span>? To find out, Tapestry will look into the page specification, and this is what we are going to create next.

Right-click on the WEB-INF folder and in the context menu choose New > File/Folder… In the New File dialog that opens choose Other for the category and Empty File for file type, as the next screenshot shows:

Press Next, in the next dialog enter Home.page for file name and then press Finish.

Enter the following content into your new empty file:

<?xml version="1.0"?>

<!DOCTYPE page-specification PUBLIC

"-//Apache Software Foundation//Tapestry Specification 4.0//EN"

"http://tapestry.apache.org/dtd/Tapestry_4_0.dtd">

<page-specification class="com.devshed.tapestry.first.Home">

 

<component id="now" type="Insert">

   <binding name="value" value="currentDate"/>

</component>

 

</page-specification>

You can see that this is an XML document. The DOCTYPE thing is not for human readers, we just leave it as it is and copy it from one page specification to another.

Note the opening <page-specification> tag. In its attribute we have specified a Java class to use for this page. It doesn’t exist yet, but we are going to create it soon.

NetBeans doesn’t highlight the syntax of the Home.page file as it does with any other XML files. This is because it doesn’t know that files with the .page extension contain XML. However, we can teach NetBeans to recognize .page files by changing its preferences. I don’t want to bother you describing yet another sequence of dialogs and buttons; try to figure out how to do this yourself, or ask me at the discussion page. A hint: use the advanced options of the editor.

The descriptions of the components used on the page go between opening and closing <page-specification> tags. In our case, there is only one component with the ID now. Tapestry can see that the type of this component is Insert — the simplest and perhaps most often used of Tapestry components. At run time, the Insert component simply replaces the corresponding HTML element with whatever was given to it as its value.

The way to give an Insert component a value is through its binding, appropriately named value. This line of code:

<binding name="value" value="currentDate"/>

is understood by Tapestry in the following way: to obtain the value, evaluate the currentDate expression. Which means: go to the page class, find a method named getCurrentDate(), invoke it, and whatever it returns will be the value you are looking for. So the next step is to create the page class with the getCurrentDate() method in it.

Right-click the Source Packages folder and choose New > Java Class… In the New Java Class dialog enter Home for the Class Name and com.devshed.tapestry.first (or anything else) for the Package. Press Finish, and the new class will be created.

To serve as a page class, the new class should extend the BasePage class that comes with Tapestry. Also, we want it to implement the getCurrentDate() method; this method simply returns a new Date object. Here is how the completed page class should look (comments are omitted for brevity):

package com.devshed.tapestry.first;

 

import java.util.Date;

import org.apache.tapestry.html.BasePage;

 

public abstract class Home extends BasePage {

 

   public Home() {

   }

 

   public Date getCurrentDate() {

     return new Date();

   }

}

To help NetBeans find the BasePage class and write an appropriate import statement, use the convenient Ctrl-Shift-F shortcut.

Please note that the class is made abstract. This is quite normal from Tapestry’s point of view because the framework in many cases will implement for us some additional functionality, so it will create a concrete implementation by extending our page class at run time. In the following articles we shall get used to abstract methods and classes.

So we have created a template, a specification and a page class for the Home page. We have configured the Tapestry servlet so that a request to a default page comes straight to it. Now is the time to run our Tapestry application!

Press F6, or an appropriate button at the toolbar (you will recognize it by its tooltip saying "Run Main Project (F6)"). NetBeans will compile and package the application, then it will start Tomcat; you will see all this happening by the messages running in the Output window at the bottom. Finally, a browser window opens — and we see our first Tapestry page, so simple but glorious!

Try to reload the page and you will see that the current time changes as you do this. Imagine what is happening here: every time you send a request to the application, the page class takes its HTML template and builds an HTML page to return to you. Doing this, the page class notices that the page contains an Insert component. That component inserts into the page a date returned by a method of the page class. That method is invoked, and the new date, displayed as a string, is inserted into the resulting HTML page. Then you see it.

This is not a very exciting project, indeed, but the fact that it works confirms that we have configured our working environment properly, and this was our main aim for today.

What comes next

In the next part of our Tapestry tutorial we are going to create a more interesting application, although it will also be rather simple. The aim will be to show you some of the most often used Tapestry components, to demonstrate two alternative ways of declaring a component and to discuss different ways of adding a property to a page.

See you in the next article and don’t forget to visit the discussion page.

Google+ Comments

Google+ Comments