Learning Tapestry, the component framework

The framework

I recently started to use Apache Tapestry for work.

Tapestry is a web component framework with ambitious goals. E.g. it’s a web component framework that’s easy to extend. Also, it gives you the ease of development of scripting languages within the java ecosystem. Moreover, it provides an IoC container with nice aspect-oriented features too.

This is my learning log: I completed the official tutorial. Then completed an in-house tutorial that shows how tapestry and the other moving parts fit together in our application. Finally, I read the Tapestry 5 book.

Here I’ll dissect the components and the scripting parts.

Scripting 1 – Live class-reloading

One of Tapestry-s key features is that – in development mode – your java / template modifications go quickly live on your local web server. As they say, “enjoy the agile development style of Ruby or Python”.

Any experienced rubyst could point out that live page reloading is not a language feature – you need to use helper gems for that. E.g., sinatra has reloader and rerunRails has other mechanisms. Anyway, this hotswap is pretty cool. From an application-developers point of view, it’s as powerful as JRebel. Except that you don’t even need to know what JRebel is.

Scripting 2 – Dynamic typing

Another scripting-like feature is automatic type coercion. Well, it only works for the components. Also, you need to have a type coercion service installed into Tapestry registry.

Say for instance, you want to add a select element to a page. Then you need to add the  select element itself and feed it with one of the following options:

  • List
  • Array
  • Map
  • String that contains comma-separated words
  • EnumSelectModel

How is the select so configurable? First of all, it’s not only a HTML tag, but a server-side component too. Then, this Select component isn’t that configurable: it requires a SelectModel to display data. Finally, Tapestry-s TypeCoercer-s can create a SelectModel from almost anything. It neatly separates the concerns: a component expect a certain type, then type coercer-s make the thing work. It’s way more flexible and maintainable than Swings JCombBox.

Sometimes I still find myself wondering, is dynamic typing worth so much trouble? Why don’t we use a scripting language for the web layer? Anyway, this is a post about Tapestry, so go on with components.

Components 1 – the usual stuff

When you go through the first steps of the tutorial, you’ll see the usual html templates stuff: You can write pseudo-html with loop, if-else, ${parameter}-substitution, you name it. There’s nothing component-oriented so far.

But then, you might start to wonder: where are these elements documented? The official API describes only java classes, right?

Wrong! The Loop.java describes the loop element, etc. Except the ${parameter} stuff, they’re all components.

Select variant 1

Say for instance, this is one way to specify a select element in java:

public class AddressDetail
{
//...
@Component(parameters = {"value=address.type"})
private Select aTypeField;
//...
@Property
private AddressDTO address;

And then this is how you can reference it from the template:

</pre>
<table><!--  ... -->
<tbody>
<tr>
<td><label for="aTypeField">${message:type}: </label></td>
<td><input type="text" /></td>
</tr>
<!--  ... -->
</tbody>
</table>
<pre>

What can you see here? First of all, you can configure the components with the @Component annotation. Its parameters are Strings, so it’s kinda like scripting. It’s quick to write and easy to read.

However, you won’t get compile-time warnings for subtle errors. You need to test your pages very thoroughly to catch them before production.

Select variant 2

You can achieve the same effect like this too:

public class AddressDetail
{
    //...
    //no @Component Select
    //...
    @Property
    private AddressDTO address;
&nbsp;</pre>
<table><!--  ... -->
<tbody>
<tr>
<td><label for="aTypeField">${message:type}: </label></td>
<td></td>
</tr>
<!--  ... -->
</tbody>
</table>
<pre>

Now you don’t have scripting-like constructs in our @Component annotations. However, you do some real scripting in our tml pages.

Again, you need to test our pages very thoroughly.

Those variants are identical

The two examples above are identical. So you can see that each components maps to a server-side object, regardless of the form you declared them. This looks like a lot of waste, doesn’t it?

Tapestry mitigates this memory problem: it creates pages as stateless templates. Then, tapestry stores their states individually. E.g. component state can come from the request parameters (i.e. from Activation context) or from HTTP session (i.e. for @Persist-ed fields).

Components 2 – event bubbling

Once we have a server-side component hierarchy, we can do lot more than we used to do. Most notably, you can implement event bubbling and capturing. These features are well-known on the client-side. I believe, this is one of the few good parts of the DOM.

As a contrast, on java Swing all we could do was to create lots of arbitrary listeners which are trying to communicate with each other. That’s complex to write and difficult to maintain.

So, what is this event bubbling thing? It lets you catch events (e.g. mouse clicks) that are coming from an embedded component. In geek terms, there’s a Chain of Responsibility design pattern implemented in Tapestry. I.e. we have event listeners on steroids.

Components 3 – building other components

Each component has a .java and .tml file, so far so good. The tricky part is that you can assemble bigger components from them.

Why is it tricky? Shouldn’t it be simple, like we build small components, then we use them to build bigger things?

One problem is that you cannot embed a html form into another. So even though you created a client side component with the right server-side callbacks, you just cannot combine it with another similar component. Unless you use AJAX and Zones as workaround. But then, you have an unnecessarily complex component in your hands.

Similarly, nesting divs and tables into each other will yield to a CSS nightmare. You don’t want that, I guess. Well, yeah, you can keep using divs since this is the elegant way of doing it. Still, it’s easier to design one webpage than to assemble it from not so consistent parts.

Scripting 3 – rails presenters

I already mentioned scripting several times. Let’s take a look on how other ecosystems use UI components.

In the java world the component frameworks are quite prevailing. It’s not only tapestry. E.g. Java Server Faces is part of the Java EE standard. Wicket is another component-based framework. Vaadin is a responsive web component framework for java.

On the other hand, the ruby on rails framework fosters component reuse with presenters. To put it simply, a presenter library is the place where you collect the code that generates common html chunks. This post explains these refactorings more deeply.

There are lots of presenters for rails, some listed here. At the time of writing, only one of them is a true component-oriented framework. It’s Netzke.

It’s really funny that java programmers are crying out for such frameworks while rubysts are just fine without them. I believe the reason is that java is already complex enough so lots of programmers want to be java programmers, period. On the other hand, ruby is quite productive so they have more cognitive capacity to deal with the UI stuff.

Compact

Tapestry is a RAD framework: it allows us to create web applications quickly. But this speed comes with a price: our web components will be very compact. Not in the sense as compact car, but in a sense as a smart phone.

A compact car

A compact car

A compact car is small, requires only little gasoline. Still, it’s enough for a small family most of the time.

A compact smartphone

A compact smart phone

On the other hand, a smart phone is so compact that you cannot fix it without proper training. I.e. you just won’t add memory to a Huawei Ascend yourself. Nor will you replace the batteries.

What I’m trying to say here is that it’s difficult to tweak Tapestry components just a little. If you want to do so, you need to be aware of all the issues in CSS, HTML, java and javascript too.

Say for instance, you want to add some callbacks on the DateField component. Oops, you need to know how the WebFX datepicker interacts with prototype.js. Isn’t it the complexity you wanted to avoid?

Another example is Tapestry-s built-in javascript library: it’s prototype.js because it was very modern at the time. Couple of years later jQuery became more popular. There was already a unofficial tapestry-jquery bridge available when the Tapestry released the beta version that comes with jQuery. But it took half a year or even more to officially enable jQuery for Tapestry. This can give you an impression how complex it is to add any javascript library.

Good news: you can avoid the complexity most of the time. Just be aware that you might need a UI expert to deal with the tricky situations.

Wrapping up

So what is this Tapestry web framework? It’s a web component framework that makes it easy to create web UI-s in java quickly. Notably, it allows a pure java developer to remain a pure java developer and still create nice pages.

It brings some of the benefits of scripting to the java world, and this is awesome. It also brings some of the scripting shortcomings too.

There are a few things in Tapestry that I’m skeptic about. It also removes lots of obstacles from a web developers way. I think in general it makes our life easier.

It’s also pretty cool from a technical point of view too. But I’ll write more about that in another post.

Advertisements

About tamasrev

A software developer, specialized in Java, addressing himself as generalist. A proud daddy.
This entry was posted in java, programming, web and tagged , , , , , , , . Bookmark the permalink.

One Response to Learning Tapestry, the component framework

  1. Pingback: Learning Tapestry, the Inversion of Control Framework | tamasrev

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s