Thursday, October 8, 2009

Let's start with some basic stitches

Now what is the point of learning a new framework if you can't do something cool with it. Well, cool (or "choyness") will have to wait. Let's do the basics of Tapestry5 and build on that.

Now a Tapestry5 application is a set of interactive pages. Technically, a page template and a page class (ie. Index.tml and  Index.java). You will notice this when you browse your Netbeans project. The template files with the .tml extensions are essentially xhtml files. So they will accept valid html markup and css styling. The page class are just Plain Old Java Objects or POJOs. POJOs means that the class doesn't inherit from any framework-specific parent or implement any framework-specific interfaces.

There are 3 basic ideas when using the Tapestry framework.
  1. Using Expansions
  2. Using Tapestry Components
  3. And passing data between pages
Using Expansions
Let's start by opening Index.java. Now we add code to it so we can see expansions at work.

 private int someValue = 12345;  
   public int getSomeValue() {  
     return someValue;  
   }  
   public void setSomeValue(int someValue) {  
     this.someValue = someValue;  
   }  

This would be typical JavaBean class - a private class variable and a public getter and setter method for it.
Now open the equivalent page template which is, if haven't caught on, its Index.tml. Insert this code fragment somewhere in the Index.tml.

 <p>Here is the value: ${someValue}</p>  


Run the web application using our costume goal jettyRun and open a web browser. Here's a screenshot.

Using Components
To get started in using components do the Howard Ship's Tapestry tutorial. Its a quick way to get acquainted with tapestry components. Also don't forget to browse the component reference page for documentation. Just remember that when using components, you can define them in 1 of 3 ways:
  1. Explicitly in the template page
  2. Invisibly in the template page
  3. In the page class
Explicitly declaration of components:
   <t:form t:id="userInputForm">  
     <t:textfield t:value="message"/>  
   </t:form>  

Invisibly declaring components:
   <t:form t:id="userInputForm">  
     <input type="text" t:type="textField" t:value="someValue"/>  
   </t:form>  

Declaring components in the page class. Add this line to your choice of page class
   @Component(parameter = {"value=message"})  
   private TextField theTextBox;  

Then place the component in the page template.
   <t:form t:id="userInputForm">  
     <input type="text" t:id="theTextBox"/>  
   </t:form>  

You should be able to put two and two together with the third technique of using components.

And Passing data between pages
A Tapestry application is a number of related pages, working together. To some degree, each page is like an application unto itself. Read up on how Tapestry's Page Navigation works.

There is really two way of going about passing data between pages:
  1. The first way is to use the @persist annotation on a field
  2. The passivate-activate technique
Now let's say we want to pass a string message to Another page. So create a page template titled Another.tml and then create a page class titled Another.java.

The source of our string message will be just the Index page. We will add a simple textfield component to it and and the user clicks on a button it will pass the value to our Another page in which the another page will display the value.

Ok, now we will start writing code for the Index page. 

 package edu.addressbook.pages;  
 import java.util.Date;  
 import org.apache.tapestry5.annotations.InjectPage;  
 /**  
  * Start page of application AddressBook.  
  */  
 public class Index {  
   private String message;  
   private int someValue = 12345678;  
   @InjectPage  
   private Another another;  //inject the page so we can access to it  
   public String getMessage() {  
     return message;  
   }  
   public void setMessage(String message) {  
     this.message = message;  
   }  
   public int getSomeValue() {  
     return someValue;  
   }  
   public void setSomeValue(int someValue) {  
     this.someValue = someValue;  
   }  
   public Date getCurrentTime() {  
     return new Date();  
   }  
   // This is where we handle submission from the form  
   Object onSubmitFromUserInputForm(){  
     System.out.println("Handling from submission");  
     another.setPassedMessage(message);  
     return another;  
   }  
 }  

1 down. 3 more to go. Here is the code for Index page template.

 <html t:type="layout" title="AddressBook 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>Here is the value: ${someValue}</p>  
   <t:form t:id="userInputForm">  
     <t:label for="message">Submit a Message  
       <t:textfield t:id="message"/>  
     </t:label>  
     <input type="submit" value="Submit" style="margin-left: 10px;"/>  
   </t:form>  
   <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>  

It should be quite easy to realize that the form on the page template (has the id of userInputForm) is connected to the onSubmitFromUserInputForm() method on the page class.

Now this is for the Another page class.
 /*  
  * To change this template, choose Tools | Templates  
  * and open the template in the editor.  
  */  
 package edu.addressbook.pages;  
 import org.apache.tapestry5.annotations.Persist;  
 /**  
  *  
  * @author killertilapia  
  */  
 public class Another {  
   @Persist            //persist the field so we can store data  
   private String passedMessage;  //in the session  
   public String getPassedMessage() {  
     return passedMessage;  
   }  
   public void setPassedMessage(String passedMessage) {  
     this.passedMessage = passedMessage;  
   }  
 }  

Notice the public method of setPassedMessage(), this is the one being accessed by the Index page class so we can show the passed value.

The final piece of this puzzle is the Another page template.
 <html t:type="layout" title="Another"  
    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 passed: ${passedMessage}</p>  
   <p:sidebar>  
   </p:sidebar>  
 </html>  

If you are running already the web application (using the jettyRun goal) all you need to do is just refresh the web browser. You should see now the index page. Here is the screenshot:


Just type-in a simple message then click on the submit button. It would then go to the Another page and display our message that you just typed in the text field in the Index page.

Have fun with it.

Now as for the passivate-activate technique. I will show this teachnique when we take up the scaffolding components section of this tutorial.