Exploring the ProjectPage edited by Bob HarnerChanges (1)
Full ContentThe layout of the project follows the sensible standards promoted by Maven:
Let's look at what Maven has created from the archetype, starting with the web.xml configuration file: src/main/webapp/WEB-INF/web.xml <?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>tutorial1 Tapestry 5 Application</display-name> <context-param> <!-- The only significant configuration for Tapestry 5, this informs Tapestry of where to look for pages, components and mixins. --> <param-name>tapestry.app-package</param-name> <param-value>com.example.tutorial</param-value> </context-param> <filter> <filter-name>app</filter-name> <filter-class>org.apache.tapestry5.TapestryFilter</filter-class> </filter> <filter-mapping> <filter-name>app</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
As we saw when running the application, the page displays the current date and time. The currentTime property is where that value comes from; shortly we'll see how that value is referenced in the template, so it can be extracted from the page and output. Tapestry always matches a page class to a template; neither is functional without the other. In fact, components within a page are treated the same way (except that components do not always have templates). You will often hear about the Model-View-Controller pattern (MVC). In Tapestry, the page class acts as both the Model (the source of data) and the controller (the logic that responds to user interaction). The template is the View in MVC. As a model, the page exposes JavaBeans properties that can be referenced in the template. Let's look at how the component template builds on the Java class to provide the full user interface. Component TemplateTapestry pages are the combination of a POJO Java class with a Tapestry component template. The template has the same name as the Java class, but has the extension .tml. Since the Java class here is com.example.tutorial.pages.Index, the template file will be located at src/main/resource/com/example/tutorial/pages/Index.tml. Ultimately, both the Java class and the component template file will be stored in the same folder within the deployed WAR file. Tapestry component templates are well-formed XML documents. This means that you can use any available XML editor. Templates may even have a DOCTYPE or an XML schema to validate the structure of the template page 1 . For the most part, a Tapestry comopnent template looks like ordinary XHTML: src/main/resources/com/example/tutorial/pages/Index.tml <html t:type="layout" title="tutorial1 Index" t:sidebarTitle="Current Time" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter"> <!-- Most of the page content, including <head>, <body>, etc. tags, comes from Layout.tml --> <p>${message:greeting}</p> <p:sidebar> <p> Just to prove this is live: </p> <p>The current time is: ${currentTime}.</p> <p> [<t:pagelink page="Index">refresh</t:pagelink>] </p> </p:sidebar> </html>
The goal in Tapestry is for component templates, such as Index.tml, to look as much as possible like ordinary, static HTML files 2 . In fact, the expectation is that in many cases, the templates will start as static HTML files, created by a web developer, and then be instrumented to act as live Tapestry pages. Tapestry hides non-standard elements and attributes inside XML namespaces. By convention, the prefix "t:" is used for the primary namespace, but that is not a requirement, any prefix you want to use is fine. This short template demonstrates quite a few features of Tapestry.
First of all, there are two XML namespaces defined: xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter" The first namespace, "t:", it used to identify Tapestry-specific elements and attributes. Although there is an XSD (that is, a XML schema definition), it is incomplete (for reasons explained shortly). The second namespace, "p:", is a way of marking a chunk of the template as a parameter passed into another component. We'll expand on that shortly. A Tapestry component template consists mostly of standard XHTML that will pass down to the client web browser unchanged. The dynamic aspects of the template are represented by components and expansions. Expansions in TemplatesLet's start with expansions. Expansions are an easy way of including some dynamic output when rendering the page. By default, an expansion refers to a JavaBeans property of the page: <p>The current time is: ${currentTime}</p>
The value inside the curly braces is a property _expression_. Tapestry uses its own property _expression_ language that is expressive, fast, and type-safe 3 . More advanced property expressions can traverse multiple properties (for example, user.address.city), or even invoke public methods. Here the expansion simply reads the currentTime property of the page. Tapestry follows the rules defined by Sun's JavaBeans specification: a property name of currentTime maps to two methods: getCurrentTime() and setCurrentTime(). If you omit one or the other of these methods, the property is either read only (as here), or write only 4 . Tapestry does go one step further: it ignores case when matching properties inside the expansion to properties of the page. In the template we could say ${currenttime} or ${CurrentTime} or any variation, and Tapestry will still invoke the getCurrentTime() method. Note that in Tapestry it is not necessary to configure what object holds the currentTime property; a template and a page are always used in combination with each other; expressions are always rooted in the page instance, in this case, an instance of the Index class. The Index.tml template includes a second expansion: <p>${message:greeting}</p> Here greeting is not a property of the page; its actually a localized message key. Every Tapestry page and component is allowed to have its own message catalog 5 . src/main/resources/com/example/tutorial/pages/Index.properties
greeting=Welcome to Tapestry 5! We hope that this project template will get you going in style.
Message catalogs are useful for storing repeating strings outside of code or templates, though their primary purpose is related to localization of the application (which will be described in more detail in a later chapter). Messages that may be used across multiple pages can be stored in the application's global message catalog, src/main/webapp/WEB-INF/app.properties, instead. This "message:" prefix is not some special case; there are actually quite a few of these "binding prefixes" built into Tapestry, each having a specific purpose. In fact, omitting a binding prefix in an expansion is exactly the same as using the "prop:" binding prefix, which means to treat the binding as a property _expression_. Expansions are useful for extracting a piece of information and rendering it out to the client as a string, but the real heavy lifting of Tapestry occurs inside components. Components Inside TemplatesComponents can be represented inside a component template in two ways 6 :
Here we've used an <html> element to represent the application's Layout component. <html t:type="layout"> ... </html> But for the PageLink component, we've used an element in the Tapestry namespace: <t:pagelink> ... </t:pagelink> Which form you select is a matter of choice. In the vast majority of cases, they are exactly equivalent. As elsewhere, case is ignored. Here the types ("layout" and "pagelink") were in all lower case; the actual class names are Layout and PageLink. Further, Tapestry "blends" the core library components in with the components defined by this application; thus type "layout" is mapped to application component class com.example.tutorial.components.Layout, but "pagelink" is mapped to Tapestry's built-in org.apache.tapestry5.corelib.components.PageLink class. Tapestry components are configured using parameters; for each component, there is a set of parameters, each with a specific type and purpose. Some parameters are required, others are optional. Attributes of the element are used to bind parameters to specific literal values, or to page properties. Tapestry is flexible here as well; you can always place an attribute in the Tapestry namespace (using the "t:" prefix), but in most cases, this is unnecessary. <html t:type="layout" title="tutorial1 Index" t:sidebarTitle="Current Time" This binds two parameters, title and sidebarTitle of the Layout component, to the literal strings "tutorial1 Index" and "Current Time", respectively. The Layout component will actually provide the bulk of the HTML ultimately sent to the browser; we'll look at its template in a later chapter. The point is, the page's template is integrated into the Layout component's template. The following diagram shows how parameters passed to the Layout component end up rendered in the final page:
The interesting point here (and this is an advanced concept in Tapestry, one we'll return to later) is that we can pass a chunk of the Index.tml template to the Layout component as the sidebar parameter. That's what the tapestry:parameter namespace (the "p:" prefix) is for; the element name is matched against a parameter of the component and the entire block of the template is passed into the Layout component ... which decides where, inside its template, that block gets rendered. <t:pagelink page="Index">refresh</t:pagelink> This time, it's the page parameter of the PageLink component that is bound, to the literal value "Index" (which is the name of this page). This gets rendered as a URL that re-renders the page, which is how the current time gets updated. You can also create links to other pages in the application and, as we'll see in later chapters, attach additional information to the URL beyond just the page name. A Magic TrickNow it's time for a magic trick. Edit Index.java and change the getCurrentTime() method to: Index.java (partial) public String getCurrentTime() { return "A great day to learn Tapestry"; } Make sure you save changes; then click the refresh link in the web browser: This is one of Tapestry's early wow factor features: changes to your component classes are picked up immediately. No restart. No re-deploy. Make the changes and see them now. Nothing should slow you down or get in the way of you getting your job done. But ... what if you make a mistake? What if you got the name in the template wrong. Give it a try; in the template, change ${currentTime} to, say, ${currenTime}, and see what you get: This is Tapestry's exception report page. It's quite detailed. It clearly identifies what Tapestry was doing, and relates the problem to a specific line in the template, which is shown in context. Tapestry always expands out the entire stack of exceptions, because it is so common for exceptions to be thrown, caught, and re-thrown inside other exceptions. In fact, if we scroll down just a little bit, we see more detail about this exception, plus a little bit of help: This is part of Tapestry's way: it not only spells out exactly what it was doing and what went wrong, but it even helps you find a solution; here it tells you the names of properties you could have used. Tapestry displays the stack trace of the deepest exception, along with lots of details about the run-time environment: details about the current request, the HttpSession (if one exists), and even a detailed list of all JVM system properties. Scroll down to see all this information.
Change Notification Preferences
View Online
|
View Changes
|
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence
- [CONF] Apache Tapestry > Exploring the Project confluence