Tapestry by Example with Erik Hatcher
It's Saturday morning and I plan on learning more about Tapestry this morning. There's pretty light attendence in the room. Too bad - I bet if it was a JSF talk, the room would be packed. In this talk, we're actually going to build a real application on-the-fly.
Why another web framework?
- HTML should be HTML
- JavaScript Embraced
- Reusable components
- Free developer from dealing with plumbing
- Request/Response
- Session/Application Scope
- URL Mappings (nice, but leads to ugly URLs)
- Event handler driven
- Asset handling
- Line-precise error reporting
Erik says its one of the few frameworks that embraces JavaScript so much. I dig this b/c I think JavaScript is important for web development. Look at what the GMail guys have done with JavaScript. It'd be wicked cool to have this sort of thing open-sourced so we could all create GMail-type interfaces.
Dirty Laundry
- Heavy Duty - can be overkill for small/simple app
- Potentially steep learning curve. More of an un-learning curve. The Servlet API isn't in your face - so all that knowledge is useless.
- Not widely accepted - managers haven't heard of it
- Some awkward conventions
(i.e. abstract classes)
- and some non-intuitive necessary tricks
- Unit testing tough - do you unit test your swing app's listener methods?
- Tapestry Test Assist should solve this problem
- Howard's caught the TDD bug, so this should get better
- Lousy URLs
- there's a patch on the wiki to fix this
- Tough to do hit/stat tracking
- Example applications
- Workbench and VLib included with Tapestry
- Better Pet Shop
Workbench Demo - DatePicker component does do i18n (very cool!). Client-side validation does one-field at a time, like WebWork does. I prefer the "all messages in one pop-up" approach that Commons Validator has. Pallete component looks very cool - you can move and re-order items from a multi-select on the left to a multi-select on the right. Chart component looks pretty cool - you can generate graphs very easily. Unfortunately, it's not part of Tapestry, but you can see how to do it in the Workbench app. If you want to see an online version of the workbench, I have it setup on my server.
Repositories for components: Tacos, Tassel, T-Deli and a few mentioned on the wiki.
To bring a component to life, you simply add a "jwcid" to an HTML tag. You can specify initial values for page properties using <property-specification initial-value=""> tag in your template's .page file. The value is implicitly an OGNL expression, and you can define lists using "{'value1', 'value2', 'value3'}". This is great for prototyping before you have a backend or even a page class. To remove elements in a page, specify jwcid="$remove$" on an HTML element and it'll be removed at render time. The restriction is you can't have Tapestry components inside a $remove$ component.
If you don't want to use abstract methods (and hence classes) in your page class, you can use getProperty()/setProperty() methods. However, the recommended way is to use abstract methods.
Templates - two different types. You can put the @component stuff directly into your page - or you can use jwcid's and refer to a name that's defined as a <component> in your page-specification XML file. The Border component can be used to do page decoration like SiteMesh. You can use the Shell component to declare stylesheets/scripts on a per-page basis. This is something I do a fair amount, so it's nice to see it's built into Tapestry.
Internationalization - Resource bundles are component specific (one .properties per page). In a .page, you use <message-binding>. In a template (.html), you use attribute="message:key" or <span key="">. The "key" attribute can't be used on any ol' HTML element, only on the <span> tag. In .java, you use getMessage() and format(). You can also define a custom message source (i.e. read messages from a database). I'm impressed with how easy it is to do i18n in Tapestry. It's also cool that i18n is built-in for templates. Just include a locale extension on your page and it'll be rendered for users with that locale. For example, home_fr.html will show up for users with the French Locale.
Engine - gets all requests. Visit class - POJO that acts as like an HttpSession. You can configure it in the .application file. You can talk to your "Visit" class in a template using "ognl:visit". To call methods on it, just use "ognl:visit.method". Majority of services originate in the Engine. Generally override createXXX methods. Engines can be pooled or created on a per-session basis.
If you override the createXXX methods in Engine, you change the behavior for:
- message source
- global and visit
- property configuration
- template and component sources
contrib:Table - to override use <tr jwcid="columnColumnValue@Block"> - where "column" is the name of the column. Using this, you can easily put links and such into a table cell. Built-in TableModel can be used to talk directly to a JDBC DataSource. The TableModel is smart in that it only brings back the rows it needs to display. Add an exclamation point to the beginning of a column name to turn off sorting for that column. i18n is built-in for headers - the name of the column is simply looked up as a key in the page's .properties file.
Exception handling - Bail out by throwing an ApplicationRuntimeException. This tosses you to the default exception page, which you can override and "pretty up".
Validation - it's robust, but it can only validate <input type="text">. Erik thinks that Tapestry's validation framework could be much simpler and easier to use.
Dynamic Templates - can implement a IDelegateSourceTemplate and pull templates from a database or content-management system. To register your new TemplateDelegate, you can just register an <extension> in the .application file and point it to your class.
Page Lifecycle - initialize(), PageRenderListener(), PageValidateListener(), PageDetachListener(). Can use an ExternalCallback and ICallback to set properties on one page from another. Callbacks look very cool and there's a lot of discussions about them on the mailing list. The VLib app has a fair amount of callback examples.
This was definitely a good Tapestry session - thanks Erik.