Tapestry

Creating custom components with Tapestry 5

As far as I’m concerned, I consider creating custom, reusable components as the supreme discipline of every web-framework. I remember fiddling about a custom tabbed panel in JSF some years ago … those were the days when it wasn’t easy to find JSF third-party components. I also remember that it took me ages to add some sort of AJAX behaviour, and I can’t really remember if I finally succeeded :-) But times have changed, creating custom components is part of every almost every framework’s ref-docs and it is … or should be … easy to create them. Ideally just with combining already existing components to new ones.

As already mentioned in my previous post, I’m playing around with Tapestry 5 these days. So I decided to create my own component, a guestbook component. The guestbook should be as generic as possible, meaning that all kinds of Java beans should be valid entries. I.e. you should not be dependent on some fixed values such as name, e-mail and the message … well that really called for a BeanEditForm to enter the values … and I thought about using some kind of Grid to display the guestbook entries.

As a complete newbie in creating tapestry components, the first way to go was the Tapestry wiki’s howto page for T5. There, Eric Vullings’s short introduction about creating custom components merely gave me a quick overview over the rendering phases to override/implement when creating a component.
Then I took a cursory glance at the BeanEditForm’s and Grid’s source code to see how the components work and how they could be extended/used for my custom guestbook component. I quickly realised that it takes a bit more than a cursory glance to get the hang of the Grid (including the GridRows, GridColumns and GridPager components) but it needs less effort to figure out how the BeanEditForm works.

I decided to take the BeanEditForm straight away as part of my component and to adapt some of the Grid’s functionality to display the entries. I soon found myself copying most of the Grid’s code …. that was the right time to stop and to think about my approach once again. I was already down in adding my own coercer to the AppModule which was a lot of fun but nevertheless copying code can’t be the solution :-) .
So I (ab)used the Grid for my custom needs. To keep it short (sorry for those of you who didn’t get in touch with the Grid so far :-) ), I let my Guestbook implement the GridModelProvider interface, subclassed GridRows in order to be able to use the a different template-html without losing the GridRows’s functionality and did the same with the GridPager component.
There it was, the Guestbook – a BeanEditForm above with GridRows and a GridPager below. All it needed now was to override the onSubmit method (or to use the @OnEvent(value = “submit”) annotation) to do with the new entry whatever I wanted.

But after all, it just didn’t feel right to abuse the Grid and to call that my “custom component”. I think I’ll never use it in a real-life application, but I got a good insight into how components work in Tapestry5 by playing with those two. Here my two pennies worth on the whole stuff:

The ‘mighty’ components in Tapestry5 seem to be hard to extend – maybe it is better to use them as they are, without trying to combine them to form a new component (which might be what the developers wanted). I believe that it wouldn’t be too difficult to create mighty components on your own, if you already created some small components. There were two little things I noticed during dealing with the GridPager component:

  • The GridPager component shouldn’t be limited to the Grid. In its current state it requires a GridDataSource object, which actually is the only link to the Grid. Basically it’s just a matter of a different naming. Thus creating a super-interface of GridDataSource (e.g. DataSource with the method getNrOfItems():int) would make the GridPager reusable for other components without having the Grid-stuff in it.
  • The CSS-class shouldn’t be hard-coded. Overriding the css would be a possibility, but it would look much neater to pass it as a parameter.

Well, that’s all for today. I’d love to hear about your experience with creating your custom components. So if you have something to say, or questions, just leave a comment below!

Unfortunately I did not find the time to look a bit more into Maven. Now even Tapestry creator Howard Lewis Ship swears like a trooper in his recent blog entry :-) . I’ll definitely have to take a more thorough look into Maven …


Tapestry/Spring Integration

In the last weeks I started to have a look at different web frameworks and came across Tapestry5. Having watched the screencasts on the website, I began to like it straight away. Although still in development (the release is planned in fall 2007), it offers some nice features. The most impressive one is that you do not have to restart the servlet-container to apply changes in java files. But for me personally, the features I appreciate the most are that you don’t have to bother with jsp-specific stuff (such as <% useBean="..." %> – Ugh!) and it lets you get rid of the servlet mapping stuff in the web.xml. That’s nice isn’t it? I also read some posts claiming that Apache Wicket already provides such features. I started reading the Wicket docs, but stopped when I saw that there’s a need to inherit from a Wicket base-class and to define servlet-mappings in the web.xml – as stated above, I don’t like too many manual servlet-mappings and I also prefer dealing with POJOs.

After playing around with Tapestry by implementing the screencasts and the tutorial, I tried to inject Spring2 managed-beans into a Tapestry5 app. I found a load of examples/tutorials online, but they either dealt with tapestry4 and/or spring1.2.x. There also is a tutorial on the Tapestry site from its creator Howard Lewis Ship. Unfortunately, he missed pointing out that it is vital to add another dependency, the tapestry-spring library. Worth mentioning is, that the tapestry-spring dependency differs from the tapestry-spring.jar available on the project page which I used at first. It took me quite a while to find out what’s wrong until I found a hint in the tapestry-mailing-list. A user there suggested to add the tapestry-spring dependency to your maven2 pom.xml. After including the library, a simple @Inject was enough to inject a spring-bean into the tapestry-class. The dependency should look as follows:

<dependency> <groupid>org.apache.tapestry</groupid> <artifactid>tapestry-spring</artifactid> <version>${tapestry-release-version}</version></dependency>

The hacks I did with Tapestry5 made me to get in touch with Maven2 for the first time. Together with the eclipse-plugin, it was very easy to add dependencies to the project and to build and pack the application. That’s of course only the tip of the iceberg, and I’ll definitely have to get a bit more into maven – as it really looks like it offers some nice features. And also I have to prove if Jelmer Kupurus’s statement is right or not :-)

Enough for now, I’d love to receive some comments with your experience with Tapestry5 and Spring integration!