| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Copyright 2005 The Apache Software Foundation |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <document> |
| <properties> |
| <title>Quick Start: Hello World</title> |
| </properties> |
| <body> |
| |
| <section name="Quick Start: Hello World"> |
| <p> |
| In this tutorial, we'll cover setting up the most basic Tapestry application, a simple |
| "Hello World" application that displays the current time. We'll then extend it just a |
| bit, adding a touch of interactivity. |
| </p> |
| |
| <p> |
| The final source for this tutorial is packaged as |
| <strong>helloworld.tar.gz</strong> |
| . |
| </p> |
| |
| <section name="Tapestry Application Basics"> |
| |
| |
| <p>Our first application will look like the following when it runs:</p> |
| |
| <img src="../images/QuickStart/helloworld1.png" alt="HelloWorld step 1 screen shot." /> |
| |
| <p> |
| Tapestry applications always include a page named "Home". The Home page is the first |
| page displayed by the application, when it is first started (that is, when the |
| client web browser first accesses the starting URL). |
| </p> |
| |
| <p> |
| Tapestry pages are always a combination of a Java class and a template (we could |
| say, "an HTML template", but Tapestry is not limited to just HTML). In many cases, |
| Tapestry will use a built-in Java class when you don't provide one; for a trivial |
| page like ours, we don't need to supply a Java class at all. |
| </p> |
| |
| <p> |
| We'll start with the HTML template then, which is a file named Home.html in the root |
| of the web application context. In the project, it is stored as |
| src/context/Home.html: |
| </p> |
| |
| <source xml:space="preserve"> |
| <html> |
| <head> |
| <title>Tutorial: HelloWorld</title> |
| </head> |
| <body> |
| <h1>HelloWorld Tutorial</h1> |
| </body> |
| </html> |
| </source> |
| |
| <p> |
| There's nothing special in this HTML template, nothing dynamic (not yet, anyway). We |
| could access it as http://localhost:8080/helloworld/Home.html and see the same |
| thing; but notice that in the screen shot the URL is |
| <a href="http://localhost:8080/hellworld/app"> |
| http://localhost:8080/hellworld/app |
| </a> |
| . That means that a servlet, mapped to the /app path within the web application, was |
| responsible for the output you can see in the web browser. |
| </p> |
| |
| <p> |
| Tapestry applications always use a specific servlet class provided with the |
| framework. This is defined in the web deployment descriptor, web.xml. This file is |
| stored in the project as src/context/WEB-INF/web.xml: |
| </p> |
| |
| <source xml:space="preserve"> |
| <?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>Tutorial: HelloWorld</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> |
| </source> |
| |
| <p> |
| Here we've given our application a name, "app". We're using the standard Tapestry |
| ApplicationServlet class as our servlet, and mapped it to the path /app. The name |
| you choose for you application is relatively unimportant, and Tapestry will adapt to |
| whatever name you do choose. |
| </p> |
| |
| <p> |
| The path, on the other hand, needs to be /app. This is not hard-coded into Tapestry, |
| but does require a small amount of configuration if you choose to use another path. |
| As well see in a later tutorial, Tapestry can be quite sophisticated in terms of |
| building application URLs, so don't be too concerned about this aspect of Tapestry |
| just yet. |
| </p> |
| |
| <p> |
| That's all there is to HelloWorld in this phase. No Java code at all. Before going |
| on to bigger and better things, we're going to add a little bit to this application, |
| to give you a slightly more realistic feel for Tapestry ... but we'll still avoid |
| writing any Java code at all. |
| </p> |
| |
| </section> |
| |
| <section name="Adding dynamic output"> |
| |
| |
| <p> |
| We're going to change the Home page to display the current date and time. It will |
| look something like this: |
| </p> |
| |
| <img src="../images/QuickStart/helloworld2.png" |
| alt="HelloWorld showing current date/time" /> |
| |
| <p> |
| In Tapestry, pretty much any time anything dynamic occurs, there's going to be a |
| <em>component</em> |
| involved. Tapestry components are much like Tapestry pages ... they consist of a |
| template and a Java class (purists may note that there may be an XML file to tie |
| those together, and that the template and the Java class are both optional -- more |
| on this later). |
| </p> |
| |
| <p> |
| Tapestry components "hide" inside the HTML template. They look like ordinary HTML |
| tags, but have extra attributes in them, often with unusual values. The revised |
| Home.html template: |
| </p> |
| |
| <source xml:space="preserve"> |
| <html> |
| <head> |
| <title>Tutorial: HelloWorld</title> |
| </head> |
| <body> |
| <h1>HelloWorld Tutorial</h1> |
| |
| <p> |
| The current data and time is: |
| <strong><span jwcid="@Insert" value="ognl:new java.util.Date()">June 26 2005</span></strong> |
| </p> |
| |
| </body> |
| </html> |
| </source> |
| |
| <p> |
| The <span> tag is the placeholder within the template for the component. The |
| special attribute, jwcid, is Tapestry's clue that this is a component, and not just |
| ordinary HTML. |
| </p> |
| |
| <p> |
| The "@Insert" value for the jwcid attribute can be thought of as "instance of the |
| <a href="../components/general/insert.html">Insert</a> |
| component". Insert is one of many built-in Tapestry components. This isn't quite the |
| Java class; it is a component type, which is used by Tapestry to find out about the |
| component, such as what parameters can be configured and what Java class contains |
| the logic for the component. Again, more on that later. |
| </p> |
| |
| <p> |
| Before we get to the value parameter, a word about the |
| <em>body</em> |
| of the component. The body is the portion of the template enclosed by the |
| component's start (<span>) and end (</span>) tags. Ultimately, the |
| component itself determines when, if, or how many times it will render its body |
| ("render" is the verb used throughout Tapestry meaning "write HTML output"). |
| </p> |
| |
| <p> |
| The Insert component expressly |
| <em>does not</em> |
| render its body. Any text inside the component's body is quietly discarded at |
| runtime. We could, in fact, abbreviate the component within the template to just |
| <code><span jwcid="@Insert" value="ognl:new java.util.Date()"/></code> |
| and not put any text inside its tags. So why did we? |
| </p> |
| |
| <p> |
| The answer is |
| <em>previewability</em> |
| , that is, the ability to see, at least approximately, what the page will look like |
| <em>without</em> |
| running the actual application. You can load the Home.html file into a web browser, |
| or a specialized editor such as Dreamweaver or HomeSite, and see what it looks like. |
| For example, if we bypass the Tapestry servlet and access the template directly, we |
| see the following: |
| </p> |
| |
| <img src="../images/QuickStart/helloworld3.png" alt="HelloWorld Home.html template" /> |
| |
| <p> |
| That |
| <em>provisional text</em> |
| , "June 26 2005" is not |
| <em>exactly</em> |
| what the application will display at runtime ... but it's close enough; it's not |
| blank and it's approximately right. In a real application with real style sheets and |
| layouts, this would be enough validate that the layout of the running application |
| was correct. |
| </p> |
| |
| <span class="info"> |
| <strong>Note:</strong> |
| <p> |
| This side track, about previewability, is actually one of the cornerstones of |
| Tapestry: a |
| <em>clean</em> |
| seperation between logic and content. A non-Java HTML developer could edit this |
| template and make significant changes and validate them in their editor of choice |
| without involving a Java developer. As long as the HTML side of the team honors the |
| components, the tags with a jwcid attribute, and doesn't make changes to |
| <em>those</em> |
| elements, the rest of the HTML template can be freely editted. It is only at the |
| junction between content and runtime behavior, that is, |
| <em>inside</em> |
| components, that HTML and Java developers need to work together. |
| </p> |
| </span> |
| |
| <p> |
| So, what does |
| <code>value="ognl:new java.util.Date()"</code> |
| mean? Let's start with the attribute value, |
| <code>ognl:new java.util.Date</code> |
| . The "ognl:" prefix signals to Tapestry that this is an expression to be evaluated, |
| rather than a ordinary, literal string. If we did want the Insert to always render |
| the same literal string, such as "Tapestry Rocks!", we wouldn't need the prefix, we |
| could just write |
| <code>value="Tapestry Rocks!"</code> |
| . |
| </p> |
| |
| <p> |
| OGNL is the Object Graph Navigation Language, an open source expression language |
| used by several open-source projects, including Tapestry, |
| <a href="http://opensymphony.com/webwork/">WebWork</a> |
| and |
| <a href="http://springframework.org/">Spring</a> |
| . OGNL has some astounding capabilities, not just reading and updating object |
| properties, but also includes support for creating new objects entirely (as here), |
| as well as creating lists, maps and arrays of objects. |
| </p> |
| |
| <p> |
| Here, evaluating the expression results in a new instance of the java.util.Date |
| class. This Date instance is |
| <em>bound</em> |
| to the value parameter of the Insert component. "Bound" is another specialized |
| Tapestry term, one that concerns the relationship between a component parameter and |
| a property (or expression) of its container. Here, the component is the Insert |
| component, the container is the Home page, and the expression is |
| <code>new java.util.Date</code> |
| . Binding might look like just an assignment of a property of the Insert component, |
| but is a bit more; components often use bindings to |
| <em>update</em> |
| properties of their container, something we'll see when discussing the form element |
| components. |
| </p> |
| |
| <p> |
| In the Java code for the Insert component is the logic that obtains value parameter |
| and converts it into into a string that is rendered into the response. |
| </p> |
| |
| <p> |
| So, the expression provides the Date instance, the value parameter gives the Insert |
| component access to that value, and the Insert component provides the logic for |
| converting that Date into a string and having it show up on the rendered page. Every |
| time the Insert component renders, it will re-read its value parameter, causing the |
| expression to be evaluated once more, and a new Date instance to be created. You can |
| see this by hitting your browser's refresh button repeatedly; the displayed date |
| will keep changing. |
| </p> |
| |
| <p> |
| In the next section, we'll see how to create a link to get the displayed date to be |
| updated. |
| </p> |
| |
| </section> |
| |
| <section name="Creating Links"> |
| |
| |
| <p> |
| We're going to extend the application once more, adding a refresh link that we can |
| click instead of using the browser's refresh button. The end result looks like: |
| </p> |
| |
| <img src="../images/QuickStart/helloworld4.png" alt="HelloWorld with refresh link" /> |
| |
| <p>We created this new link by adding the following to Home.html:</p> |
| |
| <source xml:space="preserve"> |
| <p> |
| <a href="#" jwcid="@PageLink" page="Home">refresh</a> |
| </p> |
| </source> |
| |
| <p> |
| Again, anything dynamic in Tapestry is going to involve a component; here it's the |
| <a href="../components/link/pagelink.html">PageLink</a> |
| component, one of a family of components that generate callback links into a |
| Tapestry application. |
| </p> |
| |
| <p> |
| Tapestry automatically creates a URL for this; you can see this URL in the |
| screenshot: http://localhost:8080/workbench/app?page=Home&service=page. That URL |
| provides two critical pieces of information: service=page means "render a page", and |
| page=Home identifies which page to render. |
| </p> |
| |
| <p> |
| <em>Do I really need a component for that?</em> |
| You might be tempted to change the template to: |
| </p> |
| |
| <source xml:space="preserve"> |
| <a href="/app?service=page&amp;page=Home">refresh</a> |
| </source> |
| |
| <p> |
| This is a |
| <strong>bad idea</strong> |
| . Tapestry is doing more than spewing out a URL, it's |
| <em>session encoding</em> |
| the URL for you |
| <sup>1</sup> |
| and may be doing other useful things that we'll see later. Further, second guessing |
| Tapestry's URLs is never a good idea; the PageLink component will be around in the |
| next release of Tapestry, but the URL format may change between releases. |
| </p> |
| |
| <p> |
| Another question: what's with the href attribute in the attribute? What does |
| <code>href="#"</code> |
| mean? This is another side to previewability: to preview this page, the link |
| ultimately generated by the PageLink needs to preview as a |
| <em>link</em> |
| . An <a> tag without an href attribute is an |
| <em>anchor</em> |
| . Again, this is a distinction that is more visible in real applications, supported |
| by a style sheet. |
| </p> |
| |
| <p> |
| The href provided in the HTML template is simply discarded in favor of the href |
| attribute generated inside the PageLink components (/app?service=...). You can |
| actually mix and match these component-generated attributes with extra attributes |
| provided in the template; these are called |
| <em>informal parameters</em> |
| , and are covered in a later tutorial. |
| </p> |
| |
| </section> |
| |
| <section name="Next: DirectLink"> |
| |
| |
| <p> |
| That covers the PageLink component, at least for now. Next up: the |
| <a href="directlink.html">DirectLink Tutorial</a> |
| . |
| </p> |
| </section> |
| |
| <span class="info"> |
| <strong>Note:</strong> |
| <p> |
| <sup>1</sup> |
| Session encoding is an aspect of the Servlet API. Encoding a URL adds information about |
| the server-side session (the HttpSession) if there is one. Although this information can |
| be obtained via HTTP cookies, not all users have cookies enabled in their browser. The |
| servlet specification encourages you to always encode your URLs, and this is simply done |
| for you in Tapestry. It's another example of the basic Tapestry principle: |
| <em>make the simplest choice the correct choice</em> |
| . |
| </p> |
| </span> |
| |
| </section> |
| </body> |
| </document> |