The Guess Page

This is the page where uses make letter guesses. The page has four sections:

Let's start with the HTML template this time:

Figure 5.9. Guess.html (excerpt)

<h1>Make a Guess</h1>

<font size=+3>
	<span jwcid="insertGuess"/>
</font>

<p>

You have made <span jwcid="insertMissed"/> bad guesses,
out of a maximum of <span jwcid="insertMaxMisses"/>.

<span jwcid="ifError">
<p>
<font size=+3 color=red><span jwcid="insertError"/></font>
</span>

<p>Guess:
<font size=+1>
<span jwcid="e">
<a jwcid="guess"><span jwcid="insertLetter"/></a>
</span>
</font>

<p><a jwcid="giveUp">Give up?</a>

Most of these components should be fairly obvious by now; let's focus on the components that allow the user to guess a letter. This could have been implemented in a number of ways using more radio buttons, a drop down list or a text field the user could type into. In this example, we chose to simply create a series of links, one for each letter the user may still guess.

Let's look at the specification for those three components (e, guess and insertLetter).

Figure 5.10. Guess.jwc (excerpt)

<component id="e" type="Foreach">
  <binding name="source" expression="unused"/>
</component>

<component id="guess" type="DirectLink">
  <binding name="listener" expression="listeners.makeGuess"/>
  <binding name="parameters" expression="components.e.value"/>
</component>

<component id="insertLetter" type="Insert">
  <binding name="value" expression="components.e.value"/>
</component>

Component e is simply a Foreach, the source is the unused property of the page (we'll see in a moment how the page gets this list of unused letters from the game object).

Component insertLetter inserts the current letter from the list of unused letters. It gets this current letter directly from the e component. On successive iterations, a Foreach component's value property is the value for the iteration.

Component guess is type DirectLink, which creates a hyperlink on the page and notifies its listener when the user clicks the link. Just knowing that the component was clicked isn't very helpful though; the application needs to know which letter was actually clicked.

Passing that kind of information along is accomplished by setting the parameters parameter for the component. The parameters parameter is an object, or array or objects, that will be encoded into the URL for the hyperlink. When the component's listener is notified, it can obtain the array of objects from the IRequestCycle [4].

These service parameters are often used to encode primary keys of objects, names of columns or other information specific to the application.

In this case, the service parameters consist of a single value, the letter to be guessed.

All of this comes together in the Java code for the Guess page.

Figure 5.11. Guess.java (excerpt)

public void makeGuess(IRequestCycle cycle)
{
    Object[] parameters = cycle.getServiceParameters();
	char letter = ((Character)parameters[0]).charValue();
	HangmanGame game = getGame();
	
	try
	{
		game.guess(letter);
	}
	catch (GameException ex)
	{
		error = ex.getMessage();

		if (game.getFailed())
			cycle.setPage("Failed");

		return;
	}

	// A good guess.

	if (game.getDone())
		cycle.setPage("Success");
}

The component specification showed how data was encoded into the URL as the service parameters; here we see how the makeGuess() listener method has access to the service parameters and uses them. The listener method extracts the letter and informs the game object, which throws an exception if the letter is not in the word being guessed.

The method HangmanGame.getFailed() returns true when all the missed guesses are used up, at which point we go to the Failed page to tell the user what the word was.

On the other hand, if an exception isn't thrown, then the guess was good. getDone() returns true if all letters have been guessed, in which go to the Success page.

If all letters weren't guessed, we stay on the Guess page, which will display the word with the guessed letter filled in, and with fewer options in the list of possible guesses.



[4] Tapestry takes care of converting objects into strings when constructing the URL, then converts those strings back into objects when the link is clicked. Your listener method will be able to get copies of the original parameters.