|
|
||
John Reynolds's Blog
«Public plea to the EJB 3.0 expert group: Please review the EJB 2.0 CMP and JDO FAQ |
Main
| Creating custom components for Echo-Hangman »
Echo-ing the Tapestry Hangman examplePosted by johnreynolds on August 18, 2004 at 11:29 AM | Comments (4)Hangman: the "Hello World" of web component frameworks? To get the most out of this article, please download the source and war files. If you have Tomcat 5.0 installed, you should be able to deploy the war and run the application.
In my experience, one of the best ways to grok the differences between application frameworks is to implement the same example using each framework. Inspired by Hans Bergsten, I set out to convert Ship's example hangman game from Tapestry to Echo. I had a lot of fun doing this, and you can now download the sources to compare hangman implementations in Tapestry, JSF, and Echo.
Echo applications are Java Servlets. I used Tomcat 5.0 to host my application, but any Java Servlet container should work. To create an Echo application, you must create three classes:
Echo “ships” with a number of built-in Components,
but I only needed three of them to implement the tapestry
application: Grid, Label, and Button. A companion project, EchoPoint,
provides dozens of high quality open-source components. If you've
ever seen a Javascript component on a web-page, you'll probably find
that the EchoPoint project team has ported it to Echo. The Grid components are used to control Component layout. The Label components provide instructions and feedback, and the Button components are used to enable user feedback. Button and Label both support images, so it was fairly easy for me to reuse the images from Howard Lewis Ship's Tapestry example. I am very grateful for this as it saved me a great deal of time. I also reused Howard's Game and WordSource classes. The “business logic” is identical, only the presentation code has changed. Echo Component Layout: Here is the meat of the layout logic in my GamePane:
This code is pretty simple, I am initializing components, and adding them to my ContentPane. As you can see, I am using Grid components to position the components to match the original tapestry example. The buttons that represent the alphabet are generated by the program and embedded in their own Grid. Tapestry Component Layout: For comparison, in Tapestry implementations all component positioning is handled by an HTML page. From Howard's Tapestry example:<html>
<head>
<title>Tapestry Hangman</title>
<link rel="stylesheet" type="text/css" href="css/hangman.css"/>
</head>
<body jwcid="$content$">
<span jwcid="@Border">
<table>
<tr>
<td><img alt="Tapestry Hangman" src="images/tapestry-hangman.png"
width="197" height="50" border="0"/>
</td>
<td width="70" align="right">
<img jwcid="@Digit" digit="ognl:visit.game.incorrectGuessesLeft"
src="images/Chalkboard_3x8.png"/>
</td>
<td> <img alt="Guesses Left"
src="images/guesses-left.png" width="164" height="11" border="0"/>
</td>
</tr>
<tr>
<td></td><td></td>
<td><img jwcid="@Scaffold" digit="ognl:visit.game.incorrectGuessesLeft"
src="images/scaffold.png" border="0"/>
</td>
</tr>
</table>
<br>
<table>
<tr valign="center">
<td width="160">
<p align="right">
<img alt="Current Guess" src="images/guess.png"
align="MIDDLE" width="127" height="20" border="0"/></p>
</td>
<td><span jwcid="@Spell">
<!--- Additional letters from the mockup --->
<img height="36" alt="A"
src="images/Chalkboard_1x1.png" width="36"
border="0"/><img height="36" alt="_"
src="images/Chalkboard_5x3.png" width="36"
border="0"/><img height="36" alt="_"
src="images/Chalkboard_1x5.png" width="36"
border="0"/><img height="36" alt="_"
src="images/Chalkboard_5x3.png" width="36"
border="0"/><img height="36" alt="_"
src="images/Chalkboard_5x3.png" width="36"
border="0"/><img height="36" alt="_"
src="images/Chalkboard_5x3.png" width="36"
border="0"/><img height="36" alt="_"
src="images/Chalkboard_5x1.png" width="36"
border="0"/></span>
</td>
</tr>
<tr>
<td valign="top">
<p align="right">
<img alt="Choose" src="images/choose.png"
height="20" width="151" border="0"/>
</p>
</td>
<td width="330"><span jwcid="selectLoop">
<a href="#" jwcid="select"
class="select-letter"><img jwcid="@Letter"
letter="ognl:letterForGuessIndex"
disabled="ognl:letterGuessed" border="0"
src="images/Chalkboard_5x3.png"/></a></span><span
jwcid="$remove$">
<a class="select-letter" href="#"><img height="36" alt="B"
src="images/Chalkboard_1x2.png" width="36" border="0"/></a>
<a class="select-letter" href="#"><img height="36" alt="C"
src="images/Chalkboard_1x3.png" width="36" border="0"/></a>
<a class="select-letter" href="#"><img height="36" alt="D"
src="images/Chalkboard_1x4.png" width="36" border="0"/></a>
<img height="36" alt="-" src="images/letter-spacer.png" width="36"
border="0"/>
<--! MUCH DELETED FOR SAKE OF BREVITY -->
</td>
</tr>
</table></span>
</body>
</html> To be fair, the HTML layout for the Tapestry components can be created by any one of a number of excellent HTML editors. One of the greatest strengths of Tapestry is the complete separation between layout in HTML and functionality in Java. Echo, in contrast, trades the separation of concerns for clear, easy to read, easy to maintain Java code. Programming skills are required to develop layout, but in small projects where a single developer is handling both tasks, this isn't much of a concern. Echo Event Handling:Event handling in Echo is straightforward. When a component is created, you can specify the component which should handle any events generated by the component. The event handling logic for my GamePane follows:
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals("start game"))
{
startButton.setVisible(false);
startButton.setEnabled(false);
chooserGrid.setVisible(true);
chooserGrid.setEnabled(true);
}
else if (e.getActionCommand().equals("new game"))
{
hangmanInstance.startAnotherGame();
}
else
{
hideLetterButton("letterButton" + e.getActionCommand());
// Pass the letter to the game
boolean result = game.makeGuess(e.getActionCommand().charAt(0));
int incorrectGuessesLeft = game.getIncorrectGuessesLeft();
int numMistakes = 5-incorrectGuessesLeft;
if (result==false)
{
playAgainButton.setVisible(true);
playAgainButton.setEnabled(true);
chooserGrid.setVisible(false);
chooserGrid.setEnabled(false);
disableAllLetters();
if( game.isWin())
{
winLoseLabel.setIcon(
new HttpImageReference("images/you-win.png"));
}
else
{
winLoseLabel.setIcon(
new HttpImageReference("images/you-lose.png"));
numMistakes=6;
}
}
updateScaffold(numMistakes);
updateWordSoFarLabels();
guessesLeftCountLabel.setIcon(imageMapper.get(new String( ""
+ incorrectGuessesLeft)));
}
}This is not the prettiest event handler in the world, but it suffices. Events are returned as Java Strings, and you must perform string comparisons to determine the proper action. For a more complex example, the event handling would be spread across multiple components rather then consolidated in a single component. Which is better? I am sure that you know the answer to the question: "Which is better?". As always, the answer is a definite:"It depends".Tapestry and Echo approach the same problem from different perspectives. If you are experienced in developing user interfaces in code, then you will probably prefer Echo. If you prefer to leave layout to an HTML page designer, then Tapestry will probably be more to your liking. There's no wrong answer here. What about JSF? Well, since JSF is the standard blessed by the JCP, then it's going to be an important player. I hope very much that the JSF expert group studies both Tapestry and Echo. The standard should not preclude developers from writing applications in either style. Javascript Rules! The not so dirty-little-secret of both Tapestry and Echo is that much of the nifty UI is due to client side Javascript. It would be really great if the Tapestry and EchoPoint commiters would collaborate. I have not delved into details, but surely Tapestry and Echo components could share a lot of Javascript (and hopefully JSF will get in the game too). In closing.... Echo is just plain fun. I had never heard of Echo before last week, and I downloaded it on Monday. It's Wednesday evening now, and I've been able to successfully hack together a pretty reasonable knock-off of the Hangman application. I've just barely scratched the surface... I could refactor the example as custom Echo components, investigate the EchoPoint HTML layout components, or delve into better understanding the architecture. It's always a delight to come across projects like this.Obviously I am not in a position to comment on the scalability or resource utilization of Echo, but I can say that it promotes a very clean programming methodology that should be attractive to a large audience of developers. Check out Echo for yourself! Update:Check out my blog on creating custom Echo components. Update: 24Jun05: The new Java web component framework Wicket includes Hangman as one of their example apps. Bookmark blog post: CommentsComments are listed in date ascending order (oldest first) | Post Comment
| ||
|
|