Skip to main content

skip to main content

developerWorks  >  Java technology | Open source | Web development  >

In tune with Tapestry, Part 2

Plan and develop a Tapestry application

developerWorks
Document options

Document options requiring JavaScript are not displayed


Rate this page

Help us improve this content


Level: Introductory

Brett D. McLaughlin, Sr. (brett@newInstance.com), Author and Editor, O'Reilly Media, Inc.

10 Jan 2006

The Tapestry framework allows Java™ and Web developers to develop servlet-based Web applications that are dynamic, lightweight, and responsive. Continue getting to know Tapestry this month, as Brett McLaughlin shows you how to plan the development of a Tapestry application and create useful, robust Tapestry components.

The first article in this short series served as an introduction to Tapestry -- a lightweight framework for building Web applications. If you've read that article, you should have a basic idea of how Tapestry works and a good sense of how its core API is put together. You probably aren't so sure how to actually develop a Tapestry application from scratch, but in this article, I'll remedy that.

I'll start with an easy approach to planning your application, which is especially important when using Tapestry. Next, I'll discuss the role of the HTML prototype in Tapestry development and explain the elements you'll need to have in place before you begin coding Tapestry components. Finally, I'll show you how to develop Tapestry components and link them with your HTML pages. You'll also learn some tips for ensuring your plans actually match up with the people who will use your application, which is key to successful development, and how to plan and develop your Tapestry components for re-use. See the Resources section to download Tapestry before you begin.

Planning your application

If you're any sort of developer at all, you probably hate even reading the word plan, let alone taking the time to actually put one of those things together. However, planning is the very best way to start building a Tapestry application (or any type of application, arguably) so I'll start by showing you how to do it as painlessly as possible.

The Tapestry framework uses actual HTML pages, treats them as templates, and then links those templates with Tapestry components. All of this is then tied together via deployment descriptors, resulting in a tightly coupled, fairly complicated set of files to keep up with. The typical components of a Tapestry application are as follows:

  • HTML pages (which are treated by Tapestry as templates)
  • Tapestry classes
  • Java beans and utility classes
  • The servlet deployment descriptor (web.xml)
  • Tapestry's application descriptor (app.application)

If you simply dive in and start developing application code, you'll quickly be up to your eyeballs in scribbled notes, hard-to-find bugs, and templates that are sometimes updated and sometimes not. Planning is the only way to really take advantage of Tapestry, so try out this three-point approach to doing it as painlessly as possible.



Back to top


Start with a question

The first part of planning is to ask a simple but very important question, which is What is this application supposed to do? While it might seem trivial -- even trite -- this is the single most important question you could ask about your application. And, surprisingly, it's the one most often ignored. Here's a list of the questions more commonly asked at the beginning of a development process (sound familiar?):

Down with customers and specifications!

Nope, not really. Even if you hate to plan, you're simply setting yourself up to fail if you don't communicate with your application's stake-holders. No matter how beautiful your code is, it has to actually work as customers expect it to -- even when their expectations don't make sense to you. So withhold judgment on planning for right now (that is, how annoying it is), and just try out the approach I demonstrate here. It will result in better applications every time!

  • What technologies will be used?
  • What kind of clients (Web browsers, mobile phones, PDAs) will access the application?
  • What platform is the application running on (Windows, Linux, Mac OS X, Sun Solaris, etc.)?
  • When does it have to be finished?

These are all useful questions, but none of them matter if your application doesn't actually do what your stakeholders expect it to.

Applying this to Tapestry, you won't be able to write good Tapestry code -- no matter how technically fancy that code may be -- if you don't know the basic purpose of your application. Tapestry code is used for two basic purposes:

  • Interacting with data sources and implementing business logic.
  • Providing data to presentation components, like the HTML templates.

Because you aren't writing Tapestry code to do fancy displays or visual effects, all your Tapestry code should deal with the core task (or tasks) of an application. If you don't know what that core task is, then be prepared to spend a lot of time staring at a blank screen, confused and wondering what to do next.



Back to top


Map out the business processes

Once you understand the basic purpose of your application, you can start to list all the specific business processes involved in realizing that purpose. Business processes aren't the same as the application's purpose. An application's purpose is generally a concise, overarching statement that sums up everything it does. Business processes are much smaller units of work that are often reused in various ways with other business processes, all to accomplish a specific task.

For example, suppose you're writing an application to manage the kitchen at BurgerDome. Your basic purpose might simply be "get customers the correct food, cooked to order." But inherent in that are lots of individual business processes; here are just a few:

  • Put in a new order
  • Cook a burger
  • Add vegetables and condiments to a burger
  • Package a burger for serving

Of course, you may find that some of these break down even further:

  • Cook a burger
    • Cook a burger patty
    • Warm a bun
    • Toast a bun
  • Add toppings to a burger
    • Add a vegetable
    • Add a condiment
    • Add a seasoning
    • Add cheese

These processes may be sort of silly, but you quickly see that even a relatively simple application could have fifty or a hundred different business processes, all of which could be used and sometimes combined with other processes to achieve a basic purpose (in this case cooking a burger to order).

Transforming business processes to components

What's interesting to note about business processes in Tapestry is how few of them are actually tied to Tapestry classes. For example, most of the tasks for the BurgerDome app aren't tied to display at all, and building a Tapestry component to, say, add mustard to a burger doesn't make a lot of sense. In the planning stage for this application, mapping out all the processes would help you determine what business components you actually need to create using Tapestry and which ones will be passed to other types of components. For example, you might create a Tapestry component to take a burger order as input, but it would then pass on a request to add mustard to another, non-Tapestry component.

At the end of your planning stage, you should have mapped out a set of business objects that will handle the very specific details of your business. In addition to this, you should have a set of Tapestry objects that group those business objects into meaningful units of work. You can see this programming model in action in Listing 1:


Listing 1. A simple ordering class
                
package com.burgerdome.display;

import org.apache.tapestry.annotations.Persist;
import org.apache.tapestry.html.BasePage;

import com.burgerdome.order.*;

public abstract class Order extends BasePage
{
    private Order order;

    public void placeOrder(int burgerType, int doneness)
    {
        Burger burger = new Burger(burgerType, doneness);
        Order order = new Order();
        order.addBurger(burger);
        setOrder(order);

        OrderQueue queue = OrderQueue.getInstance();
        queue.add(order);
    }

    public void cancelOrder()
    {
        OrderQueue queue = OrderQueue.getInstance();
        queue.remove(order);
    }

    protected void setOrder(Order order) {
        this.order = order;
        order.setID(OrderUtils.newOrderID());
    }

    protected Order getOrder() {
        return order;
    }
}

As you can see in Listing 1, a Tapestry component interfaces a screen (which presumably allows customers to place an order) with the Burger and Order classes, all parts of the BurgerDome business component library. Note that the Burger and Order classes are not Tapestry classes, and in fact know nothing about Tapestry at all. Additionally, the OrderQueue class -- which is neither a Tapestry class nor a business component -- handles much of the business side of taking orders and organizing them in a useful manner.

The point here is that none of these processes would come together without some careful planning. Determining which classes are Tapestry-specific, which are business-specific, and how they all interact is best done before you're sitting in front of an empty class file in your favorite code editor.



Back to top


Create a navigation chart

Once you understand what Tapestry components you have and how your basic business components work together, it should be relatively simple to develop your application's navigation. Keep in mind that at this point, you still probably don't need to code up any HTML pages or start throwing hrefs around. A couple of sheets of paper with pages drawn on them and lots of arrows connecting them should be enough. Or -- for another approach -- you could use a simple flow chart, with each square or rectangle on the chart corresponding to a screen, and the arrows indicating the various "paths" that a user could take through the application.

However you do it, planning your application's navigation is a really simple exercise with tremendous benefits to your development process. Once you start actually building your HTML pages (which I'll discuss in detail in the next section), you won't have to spend time thinking about what links belong on your page and where those links should go, because you'll have it all planned out.

An important side effect of mapping out the navigation is that you'll quickly discover "orphan pages," which are pages that either aren't linked to or don't have as many links to them as they should. These pages represent features your users need to interact with but won't necessarily (or easily) be able to access if you don't correct your navigational setup. It's common to orphan pages during the application development process by failing to properly connect them to other pages. Planning the application's navigation before you've started coding is a good way to isolate and correct the problem early on, which makes for a much smoother development cycle.

Plan to plan again

The last thing you need to know about planning is that it won't go perfectly and it shouldn't be set in stone. While planning is important, and useful, it should go without saying that you're not going to think of everything, and even if you do some of it will be subject to change. No matter how much time you spend thinking about your application's purpose, mapping out its business processes, or plotting its navigation, you'll surely forget something. And even if you don't, you'll have to contend with late-entry feature requests or bugs that creep in where you least expected them or just the unexpected factors of life itself; so stay flexible.

Put together a robust plan and then be willing to adjust it as needed, and you'll be well ahead of the game when it comes to application development -- especially application development using Tapestry.



Back to top


Writing HTML pages

Once you have your application planned out, you're ready to start writing HTML pages. While this isn't really "code" in the strictest sense of the word -- and therefore might be seen as something to be left until the last possible moment -- you should almost always begin your application development process by coding the HTML pages.

When to develop business objects

The timing for coding your business objects will vary from project to project and company to company. For many projects, you'll be working with existing business objects, so you won't have to write any code at all (or perhaps only a small bit of it). In some cases, the business objects you write will be used for multiple applications, so you'd be best off developing those objects before writing any specific application code. And in other cases, you'll develop your business objects as you code the rest of the application. In short, the correct timing for developing business objects is largely a matter of personal preference and what the project dictates.

The biggest reason for starting with HTML is that these pages are seen by customers, end-users, marketing teams, managers, and alpha- and beta-testers. While you might be able to add main() methods to your Java classes and test them on the command line, most users will find the Web browser best suited for testing Web (and especially Tapestry) applications.

More importantly, Tapestry uses HTML files as the template for its pages; so you'd be hard pressed to develop your Tapestry components without having your basic HTML pages in place. In many cases, your page design will actually dictate the decisions you make for your Tapestry components.

In this section, I'll look at the basics of writing your application HTML.

Start with a prototype

Before you start throwing together hundred-line CSS stylesheets and complicated floating layouts, realize that the best application prototypes are simple, and often even bare. You're better off starting with very basic pages, like the one shown in Listing 2:


Listing 2. The prototype for a sales report
                
<html>
 <head><title>Sales Report Prototype</title></head>
 <body>
  <h1>Prototype Sales Report</h1>
  <table>
   <tr><th>Total Sold</th><td>1012</td></tr>
   <tr><th>Sales Price</th><td>$29.95</td></tr>
   <tr><th>Manufacturing Cost</th><td>$8.22</td></tr>
  </table>
  <h2>Net Profit: $167718.76</h2>
  <form method="GET">
   <input value="Get Updated Sales" type="button" />
  </form>
 </body>
</html>

Figure 1 shows this page as it would appear in a Web browser:


Figure 1. A Web page prototype
Good prototypes are very simple and clearly labeled

This doesn't look like much, but that's the point! A loose, simple page makes it easy to move things around and change them. Adding a table row or moving the headings to the top should be simple to do without messing up a carefully tweaked layout or color schema. On the other hand, imagine how you would feel if you spent hours working on the stylesheet, getting the headings just right and perfecting your typography and color scheme, and then walked into a meeting only to hear comments like these:

"That menu item needs to be further down."

"I hate that shade of orange; the company logo uses navy."

"Can't we use a serif font?"

The worst thing about these kinds of comments is that they're exactly what you can expect to hear from the people who will bankroll, market, and use your application. The important thing to note, however, is that none of the comments has anything to do with what the page should do and the basic information it will convey. By keeping things simple in the prototype stage, you can give application stakeholders an essential look at the functionality of your application without wasting a lot of time on color and design issues that are subject to change. If anyone complains about the way things look in the prototype, you can just assure them that your finished Tapestry application will look great!

Call it a work in progress

Always carefully label your prototypes as prototypes, as I've done in Listing 1 and Figure 1. Put the word "prototype" in both the title of the HTML (within the title element) and in the actual page (an h1 or h2 element usually works well for this). The benefits of clearly labeling each part of your prototyping process are significant:

  • When you show your prototype to marketers and end users, they won't think they're looking at a finished product. This cuts down on comments that drive most developers nuts, such as "Why does it look so bad?" and "Can we make the table text fuchsia?"

  • If some industrious marketing manager showed your work to an executive, they'd also realize that the screens were works in progress and not barge into your office wondering why you were being paid so much to come up with such horrible looking Web pages.

  • When you go to develop your Tapestry components, those "prototype" titles will remind you when a page is really done and when it's still in progress. Be sure that removing the "prototype" title and heading is the very last thing you do when a page is coded and ready for deployment and testing.

While prototyping is always good development practice, Tapestry makes it a particularly rewarding practice as well. With some development environments, prototype templates tend to fall by the wayside when it comes to actual development, but with Tapestry, you can easily use your prototypes as templates for developing the application. When you're using stand-alone Java servlets, for example, you end up having to throw your prototype templates away and copy and paste the HTML into out.println() statements or JSP markup. But with Tapestry, your prototyping contributes significantly to your development work. If you have to justify the time spent on HTML mockups, Tapestry really justifies that time!



Back to top


Use realistic data

Once you've got your basic pages in place, you need to populate your mockups with realistic data. For most developers, it's easy to slap in simple dollar values like $99.95 for sales numbers, and then use silly text values like "foo" or some lengthy Latin string (which has never made sense to me, any more than those who have to look at the mockups), but don't do it! Using unrealistic placeholders is a bad idea for a couple of reasons:

  • "Fake" data doesn't represent the actual space on the page that would be taken up by realistic data.

  • Pages look significantly different when they contain a single word or two as opposed to several lines of text. In the same way, numbers with two or three digits appear differently from those with five or six.

I'm not suggesting that you need to do tons of research and get exact, live data to use in your pages. You just need a good idea of what data will eventually end up in the page. For example, if the range of figures for a sales price will be between $50.00 and $5,000.00, that's enough information for you to develop realistic prototypes. The same is true for long stretches of text, although you might need a slightly more specific range; if text will run between 1,500 and 3,000 words, you can plan fairly well. If text may be between 1,500 and 30,000 words, then it will be much harder to write markup that handles both extremes (and you should let your stakeholders know that).

Once you have an idea of what ranges and types of data to expect, try to develop prototypes that show both ends of the range; for example, produce one page with the $50.00 value and another with the $5,000.00 value. This ensures that all possible values will fit in the allotted space, break across lines as you intend, and be correctly formatted. The same is true for text, titles, form fields, and more. Anything that goes on a page and contains data should be tested with realistic data, not superfluous "programmer" values.



Back to top


Add structural elements

At this point, you're ready to add in JavaScript, images, and live navigation. Under many Web development frameworks, this would be the point at which to abandon your prototypes and begin converting all your markup to servlets, JSPs, or view components. With Tapestry, however, you've already got usable templates and just need to add some "spit and polish" to get your prototypes ready for use.

You can begin by adding in CSS stylesheets to your pages, along with div and span elements to style and identify various portions of your pages. Now that you're getting serious, you might also need to change some of your page structure, such as converting from a placeholder list to a table, or vice versa. All of these changes will add a new layer of structure and style to your pages, bringing them closer to being fully usable in your application.

If you intend to use JavaScript to add dynamic values to your pages or handle image swapping, you can bring that code into your pages now. You can also add images to the pages. Whatever you do, remember that you're working on the pages that will actually be used by Tapestry to drive your application, so you're performing useful work, not just wasting time perfecting a mockup.

Adding structure to your template

All the work you do at this phase creates a better template. Furthermore, in the case of those div and span elements, you're actually preparing for Tapestry interaction. You can see this in Listing 3, which is the HTML for the prototype shown in Listing 2, but with divs and spanss freshly added:


Listing 3. Adding in structure for a sales report
                
<html>
 <head><title>Sales Report Prototype</title></head>
 <body>
  <h1>Prototype Sales Report</h1>
  <div id="sales">
   <table>
    <tr><th>Total Sold</th><td><span id="total-sold">1012</span></td></tr>
    <tr><th>Sales Price</th><td>$<span id="board-cost">29.95</span></td></tr>
    <tr><th>Manufacturing Cost</th><td>$<span id="man-cost">8.22</span></td></tr>
   </table>
   <h2>Net Profit: $<span id="net-profit">167718.76</span></h2>
   <form method="GET">
    <input value="Get Updated Sales" type="button" />
   </form>
  </div>
 </body>
</html>

While the changes aren't enormous, you can see that each value in the page now has a span setup, along with an ID tag. As a result, the page can be easily converted into a Tapestry component, as you'll see in the next section. The data in the page is realistic (based on the project's specifications), and the structure is ready to be rolled into your Tapestry application.



Back to top


Navigational notes

The only thing left to do is create a navigation path between your pages. For now, you can do this using normal HTML a elements with href attributes, but these links will have to change when it comes time to create your final application. You'll want to avoid direct links between most pages in Tapestry and instead access the "live" Tapestry page, which only uses HTML files as templates.

Even with this caveat, the time you take to build up a set of links between your pages is well spent. Understanding where those links will go and how they'll appear to users is an important part of building your HTML framework.

With your structural elements, images, and navigational links set up, you're nearly set to begin coding Tapestry components. Before you make that jump, do yourself a favor and run everything by your team, as well as managers, marketing folks, and perhaps some alpha-testers. Ensure the app looks and feels right to all your stakeholders before you commit yourself to code.



Back to top


Building Tapestry components

The biggest surprise for most developers using Tapestry for the first time is how little there is to it. If you've done good work on your application plan and HTML pages, writing Tapestry code turns out to be pretty trivial. Tapestry mainly functions as the glue between the presentation of your application and the logic that drives it, so you'll spend surprisingly little time writing complex code in Tapestry, and a lot more time connecting HTML pages to business components.

In fact, this is one of the spots where Tapestry really shines: it gets out of your way. Because you write standardized HTML and then add only a few Tapestry-specific elements, very little Tapestry code influences your HTML. Even better, Tapestry's tags don't affect your application display, so while your markup will include these tags, your design will include none. In other words, you'll never see a visual difference between a page that uses Tapestry and one that doesn't. Further, your business logic shouldn't be affected by Tapestry at all. The only true Tapestry code is the set of simple classes that connect all the pieces of your application. When you're working with many frameworks -- from using just servlets or JSPs to more complex frameworks like Struts or Spring -- you'll often to write a lot more framework-specific and framework-related code. Luckily, this just isn't the case with Tapestry.

Handling business logic

Before you start writing Tapestry components, there's one last thing you have to do: You must make sure that none of your business logic will end up in your Tapestry code. This means that you should have well-defined (and preferably already-written) classes for all your business tasks. If you don't do this, you'll be tempted -- and usually succumb -- to throw some of that logic into your Tapestry pages. At some point, doing so will be the "fastest" route to get your application running, but "fastest" is almost always a misnomer in such cases, since you'll spend hours making changes to your application when that business logic changes. (It's hardly good application design if the code driving your display has to change because of the way shoes are ordered or refrigerators are shipped!)

So keep a clear line between your application's presentation (the HTML pages you've already developed), its business logic (Java classes that you should already have in place, often on a different JVM or server), and the glue that connects these pieces together (your Tapestry code). Following this simple principle will also make your Tapestry code faster to write since you're simply calling into your business objects and updating your presentation with the results of those calls.



Back to top


Start with objects

You can begin developing your Tapestry components by making a list of all the HTML pages that need at least one dynamic piece of data or need to interact with your business objects. This list should simply have the actual name of the file and a short description of the page's purpose; for instance:

  • Home.html: main page of application.
  • Order.html: main order page for new orders.
  • Status.html: page to check the status of an order.
  • Comments.html: page to leave comments.

For every page in your list, you'll create a new Java class, to which you can give the same name as the page. For example, Listing 4 is the skeleton of a class to drive the Comments.html page:


Listing 4. Simple Tapestry class for checking order status
                
package com.burgerdome.display;

import org.apache.tapestry.annotations.*;
import org.apache.tapestry.html.BasePage;

public abstract class Status extends BasePage {

  @Persist
  public abstract int getOrderNumber();
  public abstract void setOrderNumber(int orderNumber);

  // Methods go here
}

You can start each Tapestry class along these lines: give the class the name of the file it will interact with (Status.java for Status.html, Comments.java for Comments.html, etc.), and make sure it always extends the org.apache.tapestry.html.BasePage class. Also be sure to give your Tapestry class a package; it's usually easiest to locate all of your pages within the same package. You'll need to import BasePage, and it's a good idea to go ahead and import Tapestry's annotations; you'll use them in almost every Tapestry component you ever develop.

Finally, go ahead and set up any persistent variables you might need; the example in Listing 4 stores an order number, which it uses to look up an order in the business objects portion of the application. Realize that @Persist doesn't mean that Tapestry is going to persist or store the variable in a database or other permanent store; it simply means that the variable will be available through repeated calls to the object instance. This means that you can allow users to enter a value -- in this case for an order -- one time, and use it repeatedly, rather than requiring them to enter a value every time they return to the status page. Also notice that you don't declare a type for the persistent variable; you just supply the "getter" and "setter" methods and Tapestry takes care of the rest. The class itself is also marked as abstract, allowing Tapestry to handle setting up an instance of the class and hook it into the Tapestry engine.

The simple class in Listing 4 serves as a starting point for all of your Tapestry objects. Just change the name and any needed persistent variables and you're halfway (sometimes more) to having your page objects ready for use.



Back to top


Add operations

Next up is taking care of any operations that aren't tied to simple values on your pages. For example, on the Status page, you might have a user enter an order number and have another button or link that gives them their status. The first of these is tied tightly to the setOrderNumber() method shown in Listing 4; the second would need to then look up an order number. Listing 5 shows simple code to handle this task:


Listing 5. Adding order handling
                
package com.burgerdome.display;

import org.apache.tapestry.annotations.*;
import org.apache.tapestry.html.BasePage;

import com.burgerdome.order.*;

public abstract class Status extends BasePage {

  public abstract Order getOrder();
  public abstract void setOrder(order);

  @Persist
  public abstract int getOrderNumber();
  public abstract void setOrderNumber(int orderNumber);

  public void getStatus() {
    OrderQueue queue = OrderQueue.getInstance();
    Order order = getOrder(getOrderNumber());
    setOrder(order);
  }
}

You'll note several new pieces to this code. First, some of the business objects are imported; in this case, those are in the com.burgerdome.order package. Next, I've added two new methods: getOrder() and setOrder(). These are marked as abstract, which results in Tapestry implementing them as simple "getter" and "setter" methods and creating a new variable for this class, of the type Order. Unless you have a really good reason not to, it's always better to let Tapestry manage these variables for you.

Also notice that these two new methods are placed above the @Persist annotation. This means that an order will not persist across requests or sessions. Because the order is changing, it's easier to simply look it up and check it's status each request. Also keep in mind that because business objects often run in a separate JVM, the order may be changing in a different JVM, and a locally persisted copy of this object would become stale.

As a general rule, then, only persist items that are unchanging for the client -- like the order number itself, which won't change across requests -- or items that are not used by business objects. For example, you might have a table number you assign to customers; that's not something that your business objects will operate upon, so it's perfectly acceptable to let it persist in Tapestry.

The last thing in this class is the addition of a getStatus() method, which connects the order number (which is persisted) to the order, which is looked up on each request. Once a user looks up their order, you can easily access the order via its method; you could call order.getRemainingCookTime() or order.change() and allow Tapestry to send those requests back to the business layer as needed.

In your own applications, these are the only real cases where you'll need to write much code specific to Tapestry: when events related to the display occur that must modify business objects. In this way, Tapestry connects actions that users take to your backend code, which responds to those actions.



Back to top


Revisit your HTML links

Once all your Tapestry code is in place, you'll need to go back to your HTML and connect it to the code you've written. Really, all you'll have to do is locate all the a and span elements in your pages. For the a elements, start by figuring out which link to external pages -- pages on other sites that aren't part of your application -- and "discard" them (in other words, don't worry about them). All the rest should have links that look like this:

<a href="Home.html">Return to main screen</a>

Add in another attribute, called "jwcid", and give it a value of "@PageLink". This lets Tapestry know that you are creating a link to another Tapestry page. Now your link looks like this:

<a href="Home.html" jwcid="@PageLink">Return to main screen</a>

Next, change the name of the href attribute to "page"; the page attribute lets Tapestry know what other Tapestry-controlled page to connect to (which is why you can ignore the external links: they're fine as they stand). Then, remove the ".html" extension. Now your link would look like this:

<a page="Home" jwcid="@PageLink">Return to main screen</a>

Finally, the a element requires the href attribute, so add it back in with a value of "#". That tells the HTML to link back to this same page; Tapestry then handles the actual link. The final link will look like so:

<a page="Home" jwcid="@PageLink" href="#">Return to main screen</a>

Convert each link in each HTML page in this manner, and your application navigation will start to work between the Tapestry and dynamic pages, rather than your static HTML templates.



Back to top


Add dynamic data

You'll now need to update your "dummy" date to live values. This is handled most easily through the @Insert annotation. As an example, take a look at Listing 6, which converts the first of several span tags to use data from the Tapestry class associated with this page:


Listing 6. Adding in live data to HTML templates
                
<html>
 <head><title>Sales Report Prototype</title></head>
 <body>
  <h1>Prototype Sales Report</h1>
  <div id="sales">
   <table>
    <tr><th>Total Sold</th><td><span jwcid="@Insert" value="ognl:totalSales" 
      id="total-sold">1012</span></td></tr>
    <tr><th>Sales Price</th><td>$<span id="board-cost">29.95</span></td></tr>
    <tr><th>Manufacturing Cost</th><td>$<span id="man-cost">8.22</span></td></tr>
   </table>
   <h2>Net Profit: $<span id="net-profit">167718.76</span></h2>
   <form method="GET">
    <input value="Get Updated Sales" type="button" />
   </form>
  </div>
 </body>
</html>

@Insert tells Tapestry to insert data, and the value attribute allows you to indicate what data belongs. In this case, "ognl" is a library available to Tapestry pages and lets you call into your Tapestry page; "totalSales" is the name of a variable in the page object. The result of this addition is that the page will be shown with live data, rather than the dummy value of 1012.

You'll need to work through all of your pages, making similar changes, so that all your dummy data is replaced by live data. And, because you took the time to ensure your sample data was of realistic length, the live data won't cause any display problems when it's inserted into the pages.



Back to top


A little configuration...

With all this background work done, it's trivial to connect things together with a few configuration files. You've already created an implicit mapping between your pages and classes by giving each the same name. Now, you need to let the Tapestry engine know about this implicit mapping, by making it explicit. Create a new file called app.application, in your servlet context's WEB-INF/ directory. Then add a new key called "org.apache.tapestry.page-class-packages" and give the key the name of the package your Tapestry classes are in. Listing 7 shows an example app.application file:


Listing 7. The app.application file
                
<?xml version="1.0"?>

<!DOCTYPE application PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">

<application>
  <meta key="org.apache.tapestry.page-class-packages" 
    value="tutorials.directlink.pages"/>
</application>

Because of the work you've already done, this is a simple step. Additionally, the Tapestry framework is set up so that this is easy; simple file and class naming is already in place, so this just connects those two sets of components.

You also need to let your servlet engine know about your application, using the standard Web.xml deployment descriptor, also in WEB-INF/. Listing 8 shows what is required here: a servlet entry that takes care of the core Tapestry servlet, as well as a URL mapping for that servlet:


Listing 8. The web.xml file
                
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE Web-app

      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

      "http://java.sun.com/dtd/Web-app_2_3.dtd">


<Web-app>

  <display-name>BurgerDome Ordering System</display-name>

  <servlet>

    <servlet-name>app</servlet-name>

    <servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class>

    <load-on-startup>0</load-on-startup>

  </servlet>

  <servlet-mapping>

    <servlet-name>app</servlet-name>

    <url-pattern>/app</url-pattern>

  </servlet-mapping>

</Web-app>

Now you've got your HTML pages, your Tapestry components, your business objects, and descriptors that connect all the parts together. Your application is ready to go!



Back to top


In conclusion

In this article, I've moved beyond the initial overview of Tapestry (from "In tune with Tapestry, Part 1") to show you how to actually develop applications with the Tapestry framework. Rather than focus on a lot of code, I decided to concentrate on the process of developing applications using Tapestry, and doing it well. While most Java programmers can easily learn a new API, many have a much harder time figuring out how best to use that API. One thing I hope you've picked up from this article is the importance of planning in Tapestry development, and how much well-made plans will contribute to your eventual execution. Another nice aspect of the Tapestry development process that I've highlighted is re-use. By carefully thinking through your components before you write them, you can end up with a reusable toolbox of components, rather than having to write lots of disparate applications that don't share components.

While the main topic of this article is Tapestry, many of the ideas I've discussed here can be applied to any programming framework, especially Web-based ones. You'll find that most good applications involve more than a few minutes of planning, and it takes more than a scribbled-up napkin to avoid constant redesign. If you take the time to plan carefully, and then prototype, you'll almost always end up with a more polished, responsive applications, and you'll dramatically increase the chances that your customers and end-users will use and appreciate the finished product.



Resources

Learn

Get products and technologies
  • Tapestry: An open-source Web application development framework.

  • Apache Tomcat: A great servlet engine that works perfectly with Tapestry.

  • Apache Ant: A Java-based build tool used to build Tapestry.

  • HiveMind: The interface Tapestry uses to register objects.

  • Apache Forrest: A publishing framework used by Tapestry to generate a local copy of its documentation set.

  • The open source projects page: The developerWorks guide to open source projects.


Discuss


About the author

Photo of Brett McLaughlin

Brett McLaughlin has worked in computers since the Logo days. (Remember the little triangle?) In recent years, he's become one of the most well-known authors and programmers in the Java technology and XML communities. He's worked for Nextel Communications, implementing complex enterprise systems; at Lutris Technologies, actually writing application servers; and most recently at O'Reilly Media, Inc., where he continues to write and edit books that matter. His most recent book, Java 5.0 Tiger: A Developer's Notebook , is the first book available on the newest version of Java technology, and his classic Java and XML remains one of the definitive works on using XML technologies in the Java language.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top