Tapestry Growing Pains

I really want to like Tapestry 5. How can a Java web developer not want to like something that basically describes itself as not-Struts? However, there have been some frustrations as I’ve prototyped AtomicGamer 2.0.

Documentation

Tapestry 5 actually has a good amount of documentation. The API documentation is commented. A tutorial is available. Several of the concepts have long and detailed pages of text.

I just can’t find anything.

There’s 5 separate pages on component functionality, but I can’t find out how to actually inject a component onto a page. I know I saw it somewhere, but it’s lost now. There’s InjectComponent and Component annotations, but I don’t know what the difference is between them and I’m sure the difference is significant.

I need more information about contexts, but it took forever to learn that they are a page rendering request feature and documented under page navigation. I apparently should have known this.

I think the problem is the layout of the documentation rather than the contents. I understand what I want to do, but I cannot map my concepts into Tapestry concepts. Hence, the documentation is painful to use at best.

By Convention

I was a Java and C++ developer, but I’m currently employed as a PHP web developer. Being the only “Java guy” at work, I get some flak thrown at me, but I like to toss some back. For example, PHP is dynamically-typed and interpreted. You never can really be sure if that method is used or if those parameters are the correct type. At least, not until run-time.

Thanks to the popularity of Ruby on Rails, “by convention” is the new big thing and Tapestry 5 loves it. My IntelliJ IDEA is filled with grayed method names since IDEA has no way to know if those methods or even classes are really in use. Is my onActivate method going to be called? Are those the correct parameter types? Who knows! Who cares! It’s by convention!

Annotations can help remove the gray, but then I’m just left with an IDE that thinks everything is used whether or not reality matches.

Prototype and AJAX

I’ve been on the fence with Tapestry 5 ever since I learned they embedded the Prototype Javascript library into it instead of being Javascript-framework neutral. I know jQuery already, do I really need to learn another Javascript library to use your Java web framework?

In theory, the standard components in Tapestry should hide Prototype and any Javascript library from me. For example, I want to display my BeanDisplay component. If a user clicks an edit button, it makes an AJAX call and loads a BeanEditForm component.

The Zone component may be able to do this, but I can’t get it to work how I want. Maybe because I’m haven’t found the right documentation. I’m left with implement the Javascript myself, but now I need to learn Prototype or learn how to safely embed jQuery and Prototype into my Tapestry 5 application.

I forget — what, exactly, is Tapestry suppose to be helping me accomplish?

I’ll admit, I’m a Tapestry newbie. However, I’m not a web newbie. I’m not a software engineer newbie. I’m sure Tapestry can be masterfully productive for some people, but I’m just not feeling it yet. Mostly, it feels like I’m fighting the framework and documentation to get it to do what I need it to do, and still failing.

Wicket? Stripes? Back to Struts 2? I don’t know.

GETting Tapestry

I’m trying to wrap my head around Tapestry’s contexts and event handling. The details are hidden in various sections of the documentation so it’s been a lot of trial and error. My goal is to be able to handle URL parameters in a way I can understand and process with some intelligence.

On a link, you can pass in a context:

<t:pagelink page=”games/Edit” context=”game”>${game.name}</t:pagelink>

In this instance, I’m passing a Hibernate entity to the game edit page. The URL will be http://www.atomicgamer.com/game/edit/5 where 5 is the entity id. On the edit page, we have several ways to handle get this value.

Note:  Since we passed the Hibernate entity and not just the id, Tapestry is smart enough to fetch the entity from the session. That’s why the following examples use variables of Game, not Long.

PageActivationContext Annotation

We can use the @PageActivationContext annotation and game will be automatically populated.

@Property
@PageActivationContext
private Game game;

onActivate Convention

If we defined a method onActivate(Game game), the parameter will be populated and we can assign it to an instance variable.

OnEvent Annotation

If we don’t want to use the onActivate convention, we can use the @OnEvent annotation on a method instead.

@OnEvent(“activate”)
public void annotationTriggered(Game game)…

While all of the above examples will get you access to the context, you will want to watch for the order of operations if you try to mix them.

I wanted to use PageActivationContext to automatically populate my instance variable. Then, I wanted to use the OnEvent method to check for a errors (the instance variable will be null if it doesn’t exist in the database).

However, the OnEvent method is fired before the PageActivateContext. The instance variable will be null regardless. I tried onActivate() (without any parameters) and while that is fired after the PageActivateContext, I felt that was getting too far into happenstance for me to feel happy about the solution.

The current order of operation appears to be:

  1. @OnEvent(“activate”)
  2. @PageActivationContext
  3. onActivate()

I think I’ll just stick with one of these instead of trying to mix them in any fashion.

I’m still learning Tapestry 5 and this is just one of the many growing pains I’m suffering at the moment. It’s not that the framework can’t do what I want it to do. Rather, I’m not sure which way I want it done that makes sense down the road. I’m lacking clarity in the big picture of a Tapestry application.

History Lessons

It’s been a very long road to get to where we are today. AtomicGamer’s origins can be traced back to 1997, when I was in high school.

I fell in love with Quake. My brother, who happened to work at an ISP, wanted to keep me out of his hair. My brother convinced me to start a Quake site. After tossing around a few domain names (back then, you could actually get .coms with some reliability), we settled on TeleFragged.

As it grew, we started another site called 3D Downloads that focused on providing gaming file downloads for free.  It was a relative success and grew along with TeleFragged.

As the Quake series dwindled in popularity, the name TeleFragged was rising in obscurity. After much deliberation, we combined 3D Downloads and TeleFragged into AtomicGamer. In our 12 years, we’ve never achieved mainstream success, we keep on trucking.

At the very least, we’ve definitely churned out a lot of code and iterations.

  • 1997 – TeleFragged 1.0 – HTML/SSI
  • 1999 – TeleFragged 2.0 – PHP3
  • 2000 – 3D Downloads 1.0 – PHP3
  • 2002 – TeleFragged 3.0 – PHP3
  • 2002 – 3D Downloads 2.0 – PHP3
  • 2004 – 3D Downloads 3.0 – Java
  • 2007 – AtomicGamer 1.0 – PHP5

All dates are approximate and generated in part by the Internet Archive. TeleFragged went through some minor revisions during the years, but who’s keeping track really?