[CONF] Apache Tapestry > HiLo

2011-06-12 Thread confluence







HiLo
Page  added by Bob Harner

 

 This page has moved to Implementing the Hi-Lo Guessing Game


   
Change Notification Preferences
   
   View Online
   








[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
Page edited by Howard M. Lewis Ship


 Changes (9)
 



...
!guess-target.png|align=center,thumbnail!  
That enough for us to get started. Let's build out the Guess page, and get ready to let the user make guesses. We'll show the count of guesses, and increment that count when they make them. We'll worry about high and low and actually selecting the correct value later. 
 
You can go either way here; let's start with the markup in the template, then figure out what we need int the Java code to make it work. 
 
{code:lang=xml|title=Guess.tml (revised)}   xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd"   xmlns:p="tapestry:parameter"> 
 
  The secret number is: ${target}.   
 
  Guess #${guessCount} 
 
  Make a guess from the options below: 
 
   ${current} 
 
 {code}  So it looks like we need a {{guessCount}} property that starts at 1.  We're also seeing one new component, the Loop component. A Loop component iterates over the values passed to it in its {{source}} parameter, and renders it body once for each value. It updates the property bound to its {{value}} parameter before rendering its body.  That special property _expression_, {{1..10}}, generates a series of numbers from 1 to 10, inclusive. usually, when you use the Loop component, you are iterating over a List or Collection of values, such as the results of a database query.  So, the Loop component is going to set the {{current}} property to 1, and render its body (the \ tag, and the ActionLink component).  Then its going to set the {{current}} property to 2 and render its body again ... all the way up to 10.  {warning} It's not enough to just say that the Loop component will update property {{current}} ... we have to actually add the {{current}} property to the Java class. The information in the template configures the Loop component for use in the Guess page, but doesn't change the structure of the Guess page ... that's done in the Java code. {warning}  And notice what we're going with the ActionLink component; its no longer enough to know the user clicked on the ActionLink ... we need to know _which iteration_ the user clicked on. The {{context}} parameter allows a value to be added to the ActionLink's URL, and we can get it back in the event handler method.  {info} The URL for the ActionLink will be {{/guess.makeguess/3}}. That's the page name, "Guess", the component id, "makeGuess", and the context value, "3". {info}  {code:lang=java|title=Guess.java (revised)} package com.example.tutorial.pages;  import org.apache.tapestry5.annotations.Persist; import org.apache.tapestry5.annotations.Property;  public class Guess {   @Property   @Persist   private int target, guessCount;@Property   private int current;void setup(int target)   { this.target = target; guessCount = 1;   }void onActionFromMakeGuess(int value)   { guessCount++;   }  } {code}  The revised version of Guess includes two new properties: {{current}} and {{guessCount}}. There's also a handler for the action event from the makeGuess ActionLink component; currently it just increments the count.  Notice that the {{onActionFromMakeGuess()}} method now has a parameter: the context value that was encoded into the URL by the ActionLink. Tapestry automatically extracts the string and converts it to an int and passes that value to the event handler method.  More boilerplate code you don't have to write.  At this point, the page is partially operational:  !guess-1.png|align=center,thumbnail!   
  
...
{noformat}  
h32. Parting thoughts 
 What we've gone after here is the Tapestry way: pages as classes that store internal state and communicate with each other. We've also seen the Tapestry development pattern: lots of simple small steps that leverage Tapestry's ability to reload templates and classes on the fly. 
...

Full Content

Chapter 3: Implementing the Hi/Lo Guessing Game

Let's start building the Hi/Lo Guessing game.

In the game, the computer selects a number between 1 and 10. You try and guess the number, clicking links. At the end, the computer tells you how many guesses you required.

We'll build it in small pieces, using the kind of iterative development that Tapestry makes so easy.



Our page flow is very simple, consisting of three pages: Index (the starting page), Guess and GameOver. The Index page introduces the application and includes a link to start guessing. The Guess page presents the user with ten links, plus feedback such 

[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
File attached by  Howard M. Lewis Ship




guess-1.png
(49 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
Page edited by Howard M. Lewis Ship


 Changes (8)
 



...
  private int target;  
public void setup(int target) 
  { this.target = target; 
...
!guess-no-target-prop.png|align=center,thumbnail!  
If you scroll down, you'll see the line of the Guess.tml template that has the error. We have a field named target, but it is private and there's no corresponding property, so Tapestry was unable to access it. 
 
Well, I guess we can make this work ... we just need to write methods {{getTarget()}} (and {{setTarget()}} for good measure).  Or we could let Tapestry do this: 
We just need to write the missing JavaBeans accessor methods {{getTarget()}} (and {{setTarget()}} for good measure).  Or we could let Tapestry do it intead: 
 {code:lang=java} 
...
{code}  
The @Property annotation very simply writes directs Tapestry to write the getter and setter method for you. You only need to do this if you are going to reference the field from the template. 
 We are getting very close but there's one last big oddity to handle. Once you refresh the page you'll see that target is 0! 
...
What gives?  We know it was set to at least 1 ... where did the value go?  
Welcome to Tapestry state management.  By default, at the end of each request, Tapestry wipes out the value in each instance variable.  So that means that target _was_ a non-zero number during the component event request ... but by the time a new request comes up from the web browser to render the Guess page, its value is back to zero. 
 The solution here is to mark which fields have values that should persist from one request to the next (and next, and next ...).  Thats what the @Persist annotation is for: 
...
return this;   } 
}{noformat} } 
{noformat} 
 The key method here is initialize(): It is invoked to tell the Guess page what the target number is. Notice that the method is package private, not public; it is only expected to be invoked from the Index page (as we'll see in a moment), so there's no need to make it public. Later we'll see that there's more initialization to be done than just storing a value into the target instance variable (which is why we don't simply name the method setTarget() ). 
...

Full Content

Chapter 3: Implementing the Hi/Lo Guessing Game

Let's start building the Hi/Lo Guessing game.

In the game, the computer selects a number between 1 and 10. You try and guess the number, clicking links. At the end, the computer tells you how many guesses you required.

We'll build it in small pieces, using the kind of iterative development that Tapestry makes so easy.



Our page flow is very simple, consisting of three pages: Index (the starting page), Guess and GameOver. The Index page introduces the application and includes a link to start guessing. The Guess page presents the user with ten links, plus feedback such as "too low" or "too high". The GameOver page tells the user how many guesses they took.

Index Page

Let's get to work on the Index page and template.

Index.tml

"layout" title="Hi/Lo Guess"
  xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">

  
I'm thinking of a number between one and ten ... 

  
"#">start guessing
  




Running the application gives us our start:



However, clicking the link doesn't do anything yet. 

Let's fix that. 

First: what should happen when the link is clicked?


	A random target number between 1 and 10 should be selected
	The number of guesses taken should be reset to 0
	The user should be sent to the Guess page to make a guess



Our first step is to find out when the user clicks that "start guessing" link.  In a typical web application framework, we might start thinking about URLs and handlers and maybe some XML configuration file.  But this is Tapestry, so we're going to work with components and methods on our classes.

First, the component.  We want to perform an action (selecting the number) before continuing on to the Guess page.  The ActionLink component is just what we need; it creates a link with a URL that will trigger an action event in our code ... but that's getting ahead of ourselves.  First up, convert the \ tag to an ActionLink component:

Index.tml (partial)

  
"start">start guessing
  



If you refresh the browser, you'll see that the URL for the "start guessing" link is now /tutorial1/index.start}, which identifies the name of the page ("index") and the id of the component ("start").

If you click the link, you'll get an error:



Tapestry is telling us that we need to pro

[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
Page edited by Howard M. Lewis Ship


 Changes (1)
 



...
 {code:lang=xml|title=Index.tml} 
t:sidebarTitle="Current Time" 
  xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">  
...

Full Content

Chapter 3: Implementing the Hi/Lo Guessing Game

Let's start building the Hi/Lo Guessing game.

In the game, the computer selects a number between 1 and 10. You try and guess the number, clicking links. At the end, the computer tells you how many guesses you required.

We'll build it in small pieces, using the kind of iterative development that Tapestry makes so easy.



Our page flow is very simple, consisting of three pages: Index (the starting page), Guess and GameOver. The Index page introduces the application and includes a link to start guessing. The Guess page presents the user with ten links, plus feedback such as "too low" or "too high". The GameOver page tells the user how many guesses they took.

Index Page

Let's get to work on the Index page and template.

Index.tml

"layout" title="Hi/Lo Guess"
  xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">

  
I'm thinking of a number between one and ten ... 

  
"#">start guessing
  




Running the application gives us our start:



However, clicking the link doesn't do anything yet. 

Let's fix that. 

First: what should happen when the link is clicked?


	A random target number between 1 and 10 should be selected
	The number of guesses taken should be reset to 0
	The user should be sent to the Guess page to make a guess



Our first step is to find out when the user clicks that "start guessing" link.  In a typical web application framework, we might start thinking about URLs and handlers and maybe some XML configuration file.  But this is Tapestry, so we're going to work with components and methods on our classes.

First, the component.  We want to perform an action (selecting the number) before continuing on to the Guess page.  The ActionLink component is just what we need; it creates a link with a URL that will trigger an action event in our code ... but that's getting ahead of ourselves.  First up, convert the \ tag to an ActionLink component:

Index.tml (partial)

  
"start">start guessing
  



If you refresh the browser, you'll see that the URL for the "start guessing" link is now /tutorial1/index.start}, which identifies the name of the page ("index") and the id of the component ("start").

If you click the link, you'll get an error:



Tapestry is telling us that we need to provide some kind of event handler for that event.  What does that look like?

An event handler is a method of the Java class with a special name. The name is onevent-nameFromcomponent-id ... here we want a method named onActionFromStart().  How do we know that "action" is the right event name?  Because that's what ActionLink does, that's why its named _Action_Link.

Once again, Tapestry gives us options; if you don't like naming conventions, there's an @OnEvent annotation you can place on the method instead, which restores the freedom to name the method as you like. Details about this approach are in the Tapestry Users' Guide. We'll be sticking with the naming convention approach for the tutorial.

When handling a component event request (the kind of request triggered by the ActionLink component's URL), Tapestry will find the component and trigger a component event on it. This is the callback our server-side code needs to figure out what the user is doing on the client side.  Let's start with an empty event handler:

Index.java

package com.example.tutorial.pages;

public class Index
{
  void onActionFromStart()
  {

  }
}



In the browser, we can re-try the failed component event request by hitting the refresh button ... or we can restart the application.  In either case, we get the default behavior which is simply to re-render the page.

Note that the event handler method does not have to be public; it can be protected, private, or package private (as in this example). By convention, such methods are package private, if for no other reason than its the minimal amount of characters to type.

Hm. Right now you have to trust me that the method got invoked.  That's no good ... what's a quick way to tell for sure?  One way would be have the method throw an exception, but that's a bit ugly.

How about this: add the @Log annotation to the method:

Index.java (partial)

  @Log
  void onActionFromStart()
  {

  }



When you next click the link you should see the following in the Eclipse console:


[DEBUG] pages.Index [ENTER] onActionFromStart()
[DEBUG] pages.Index [ EXIT] onActionFromStart
[INFO] AppModule.TimingFilter Request time: 3 ms
[INFO] AppModule.TimingFilter Request time: 5 ms



The @Log annotatio

[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
File attached by  Howard M. Lewis Ship




guess-target.png
(47 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
File attached by  Howard M. Lewis Ship




guess-target-zero.png
(44 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
File attached by  Howard M. Lewis Ship




guess-no-target-prop.png
(94 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
File attached by  Howard M. Lewis Ship




guess-template-missing.png
(169 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
File attached by  Howard M. Lewis Ship




hilo-index-missing-action-error.png
(140 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-11-18 Thread confluence







Hilo
File attached by  Howard M. Lewis Ship




hilo-1.png
(56 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-10-11 Thread confluence







Hilo
Page  added by Christophe Cordenier

 

 Chapter 3: Implementing the Hi/Lo Guessing Game

Let's start building the Hi/Lo Guessing game.

In the game, the computer selects a number between 1 and 10. You try and guess the number, clicking links. At the end, the computer tells you how many guesses you required.

We'll build it in small pieces, using the kind of iterative development that Tapestry makes so easy.

Unable to render embedded object: File (hilo-flow.png) not found.

Page flow for Hi/Lo Game

Our page flow is very simple, consisting of three pages: Start, Guess and GameOver. The Start page introduces the application and includes a link to start guessing. The Guess page presents the user with ten links, plus feedback such as "too low" or "too high". The GameOver page tells the user how many guesses they took.

Let's get to work on the Index page and template.

src/main/webapp/Index.tml:



  
tutorial1 Start Page
  
  

Hi/Lo Guess

I'm thinking of a number between one and ten ... 


  Start guessing


  



Here we've taken the template created by the quickstart archetype and changed it around to fit our needs. The ActionLink component will create a link that will trigger a method inside our Java class. You can launch the application to try it out:

Unable to render embedded object: File (hilo-start.png) not found.

Start page with Hi/Lo Game link

However, clicking the link doesn't do anything yet. We haven't told Tapestry what to do when the link gets clicked.

Let's fix that. We'll change the Start class so that it will react when the link is clicked ... but what should it do? Well, to start the guessing process, we need to come up with a random number (between one and ten). We need to tell the Guess page about that number, and we need to make sure the Guess page is started up to display the response.

First, the Guess page. Just to get started, we'll create a Guess page without much guessing: it'll just show us the target number, the number we're supposed to be guessing.

src/main/webapp/Guess.tml:



  
Guess A Number
  
  

The target number is ${target}.

  



On the Java side, the Guess page needs to have a target property:


package org.apache.tapestry5.tutorial.pages;

public class Guess
{
  private int target;

  Object initialize(int target)
  {
this.target = target;

return this;
  }
}


The key method here is initialize(): It is invoked to tell the Guess page what the target number is. Notice that the method is package private, not public; it is only expected to be invoked from the Index page (as we'll see in a moment), so there's no need to make it public. Later we'll see that there's more initialization to be done than just storing a value into the target instance variable (which is why we don't simply name the method setTarget() ).

Now we can move back to the Index page. What we want is to have the ActionLink component invoke a method on the Index page. We can then generate a random target number. We'll tell the Guess page what the target number is and then make sure that it is the Guess page, and not the Index page, that renders the response into the user's web browser. That's actually quite a few concepts to take in all at once.

Let's start with the code, and break it down:

src/main/java/org/apache/tapestry5/tutorial/pages/Index.java


package org.apache.tapestry5.tutorial.pages;

import java.util.Random;

import org.apache.tapestry5.annotations.InjectPage;

public class Start
{
  private final Random random = new Random();

  @InjectPage
  private Guess guess;

  Object onAction()
  {
int target = random.nextInt(10) + 1;

return guess.initialize(target);
  }
}


What we're talking about here is communication of information from the Index page to the Guess page. In traditional servlet development, this is done in a bizarre way ... storing attributes into the shared HttpSession object. Of course, for that to work, both (or all) parties have to agree on the type of object stored, and the well-known name used to access the attribute. That's the source of a large number of bugs. It's also not very object oriented ... state is something that should be inside objects (and private), not outside objects (and public).

The Tapestry way is very object oriented: everything is done in terms of objects and methods and properties of those objects.

This communication starts with the connection between the two pages: in this case, the [InjectPage||\||] annotation allows another page in the application to be injected into the Index page.

Injection can be a somewhat nebulous concept. In terms of Tapestry, it means that some cooperating object needed by one class is provided to it. The other object is often referred to as a "dependency"; in this case, the Index page depends on the Guess page to be fully functional, and an instance of the Guess page is made available as the guess instance va

[CONF] Apache Tapestry > Hilo

2010-10-11 Thread confluence







Hilo
File attached by  Christophe Cordenier




hilo-exception.png
(195 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-10-11 Thread confluence







Hilo
File attached by  Christophe Cordenier




hilo-number.png
(23 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-10-11 Thread confluence







Hilo
File attached by  Christophe Cordenier




hilo-flow.png
(10 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-10-11 Thread confluence







Hilo
File attached by  Christophe Cordenier




hilo-guess-v1.png
(25 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-10-11 Thread confluence







Hilo
File attached by  Christophe Cordenier




hilo-start.png
(28 kB image/png)



   
Change Notification Preferences
   
   View Attachments









[CONF] Apache Tapestry > Hilo

2010-10-11 Thread confluence







Hilo
File attached by  Christophe Cordenier




hilo-feedback.png
(23 kB image/png)



   
Change Notification Preferences
   
   View Attachments