This chapter covers
1.4 Understanding Tapestry’s goals
At the core of Tapestry’s design is a vision: It should be easier for you to do the right thing than the wrong thing—Tapestry should allow you to avoid the pitfalls and antipatterns prevalent in traditional web application development. You should end up with a robust, scalable, maintainable application not because the framework merely allows it, but because the framework makes that the clearest, simplest option to follow. This vision is expressed in terms of four goals that influence the design and implementation of the framework: simplicity, consis- tency, efficiency, and feedback.
1.4.1 Simplicity
Tapestry applications contain a surprisingly small amount of Java code. The stateless, operation-centric programming model used by normal servlet applica- tions requires far too much Java code—code to extract and interpret query parameters from the request, code to manage data stored as session attributes, and so on—code for all the uninteresting plumbing. At the center of all this plumbing is the small amount of application-specific logic: what to do with the data once it has been extracted, translated, converted, and validated. In a Tapes- try application, the Java code you write is just that application-specific logic (in the form of a listener method, as you’ll see in chapter 2). Combining a generic component with the application-specific listener method is a simple and elegant way to structure an application. All that plumbing is no longer your responsibil- ity; it’s all buried inside the Tapestry framework.
You tell the framework what needs doing, and it takes care of the details. For example, rather than write code to build and format a URL with query parame- ters, you just use an existing component and configure it to execute a method you supply when it is triggered. Likewise, Tapestry’s HTML form support takes care of reading object properties when a page is rendered, but also reads and interprets query parameters and updates object properties when a form is sub- mitted (this is covered in chapters 3, 4, and 5).
1.4.2 Consistency
Consistency on a large team project can be a godsend. If you’ve ever been brought into an existing project, or have even filled in temporarily for another team member on a project, you’ve likely experienced “impedance frustration.” That is, each developer names things a little differently, solves problems a little dif- ferently, puts code in different places, and so forth. Before you can be productive
Understanding Tapestry’s goals 23 in another developer’s code, you have to figure out that developer’s style, and that causes frustration.
With Tapestry, you get a consistent environment and approach across pages, even when different pages are the responsibility of different developers. There’s little or no guesswork when adding new links or forms to pages; they all work pretty much the same way because they are based on the same reusable compo- nents. Tapestry makes it easy to create new components for common functionality in an application. The application behaves consistently and is coded consistently because of reuse of both components and code.
1.4.3 Efficiency
It is important that Tapestry applications be scalable; there’s no point in creating a web application if it can’t handle a reasonable number of concurrent users on rea- sonable hardware. Internally, Tapestry uses object pools and caches to minimize the amount of processing that must occur during a request. For example, Tapestry will read each XML specification file and each HTML template exactly once and store the file’s contents for later use within the application. In addition, the frame- work is structured so that expensive application operations (for example, perform- ing a Java Naming and Directory Interface [JNDI] lookup to resolve an EJB’s home interface) can be performed once and cached for fast access when needed again elsewhere within the application. You’ll see examples of this in chapter 10.
Tapestry applications have been compared to equivalent servlet or Struts applications and found to have similar performance curves. Such results match the traditional wisdom that the presentation layer is rarely the application per- formance bottleneck; the time it takes to process a request and render a response is usually gated by the speed with which data can be obtained from the applica- tion’s back-end database.
1.4.4 Feedback
In most web application frameworks, when something goes wrong in your code or in the framework code, you will see a stack trace in the web browser. Suddenly, you are forced to play detective, working backward from the cryptic clues pro- vided in the stack trace to the problem. Does your code contain an error? Is there a typo in a deployment descriptor? An error communicating with your application server? A deployment problem with an EJB? You can waste large amounts of valuable developer time tracking down often-trivial problems.
The main code path into a Tapestry application has multiple layers of excep- tion catching and reporting that ensure that a reasonable exception report is
displayed either in the client web browser or in the server’s console. Figure 1.5 shows the initial portion of such an exception report (this exception was pro- voked by introducing a typo into the HTML template for the Hangman applica- tion, described in detail in chapter 2).
Figure 1.5 The Tapestry exception report page starts by identifying the nested exceptions, providing a stack trace for the most deeply nested exception. The exception also identifies the file and line associated with the error. In this case, line 27 of file Home.html had a typo: listenersstart instead of
How does Tapestry work? 25 Tapestry’s approach is to provide you with as much information as possible to help you rapidly fix the problem. This is represented by five factors visible in figure 1.5:
■ Tapestry has worked through the stack of exceptions, starting with org. apache.tapestry.BindingException and digging down to ognl.NoSuch- PropertyException.
■ For each exception, it has displayed the exception message and all the
properties of the exception (binding and location for the BindingException,
and target for NoSuchPropertyException).
■ The report identifies the exact file and line that is in error—the location
property of the BindingException indicates that the error is on line 27 of
file Home.html.
■ The stack trace for the deepest exception, NoSuchPropertyException, is the
most relevant, and that’s the only one displayed.
■ Tapestry has attempted to describe in the exception message exactly what
went wrong.
Stack traces and exceptions are not always enough. Sometimes to understand a problem you need to know more about the request and general environment. As shown in figure 1.6, the exception report continues with exhaustive output about the key Servlet API objects (HttpServletRequest, HttpSession, HttpServ- let, and HttpServletContext), followed by a listing of all Java Virtual Machine
(JVM) system properties. Collecting this kind of information would normally require restarting the application and using the Java debugger. Tapestry saves you time by providing all this useful information immediately, at the time of the initial error, which means less time tracking down bugs and more time for everything else.
With these four central goals in mind, it’s now time to start describing, at a high level, how Tapestry operates.