Tapestry Training -- From The Source

Let me help you get your team up to speed in Tapestry ... fast. Visit howardlewisship.com for details on training, mentoring and support!

Monday, February 22, 2010

March of Progress

Or should that be "Late February of Progress". I have to say I'm a bit envious right now of Rich Hickey ... I can see that he's continuing on like a steam roller, extending and improving Clojure. I guess he's having some success in generating Research and Design budget from funding companies. I can see, following his threads, that he's working on yet more concurrency metaphors for Clojure, which is a good thing (though eventually there'll need to be a big book just to describe them all).

I'm on a different track, in that I fund Tapestry out of pocket while doing training and project work. In some cases, those merge, such as when I add specific features to Tapestry for a specific client.

I'm of two minds here: doing project work keeps me grounded in real requirements for Tapestry. I see what works really well, and what needs some polishing. On the other hand, I come up with ideas for new components, improvements, and integrations all the time and barely have enough free time (between clients, ordinary Tapestry maintenance, and this special project) to even document my ideas, never mind implement, test and distribute them.

So, should I set up a funding option like Rich's? Well, that wouldn't help my current clients (I'm committed to getting their apps into production), but it may change how I would look for future work.

Friday, February 19, 2010

Evolving the Meta Programming in Tapestry 5

I've set a goal of removing Javassist from Tapestry 5 and I've made some nice advances on that front. Tapestry uses Javassist inside the web framework layer to load and transform component classes.

All that code is now rewritten to updated APIs that no longer directly expose Javassist technology. In other words, where in the past, the transformer code would write psuedo-Java and add it to a method using Javassist (for example adding value = null; to the containingPageDidDetach() method), Tapestry 5.2 will instead add advice to the (otherwise empty) containingPageDidDetach() method, and the advice will use a FieldAccess object to set the value field to null.

Basically, I've vastly reduced the number of operations possible using the ClassTransformation API. Before, it was pretty much unbounded due to the expressive power of Javassist. Now a small set of operations exist that can be combined into any number of desired behaviors:

  • Add new implemented interfaces to a component Class
  • Add new fields to a Class
  • Initialize the value of a field to a fixed value, or via a per-instance callback
  • Delegate read and write access to a field to a provided FieldValueConduit delegate
  • Add new methods to a component Class with empty implementations
  • Add advice to any method of a class
  • Create a MethodAccess object from a method, to allow a method to be invoked (regardless of visibility)
  • Create a FieldAccess object from a field, to allow the field to be read or updated (regardless of visibility)

What's amazing is that these few operations, combined in different ways, supports all the different meta-programming possible in Tapestry 5.1. There's costs and benefits to this new approach.


There will be many more objects associated with each component class: new objects to represent advice on methods, and new objects to provide access to private component fields and methods.

Javassist could be brutally efficient, the new approach adds several layers of method invocation that was not present in 5.1.

Incorrect use of method advice can corrupt or disable logic provided by the framework and is hard to debug.


We can eventually switch out Javassist for a more stable, more mainstream, better supported framework such as ASM. ASM should have superior performance to Javassist (no tedious Java-ish parse and compile, just raw bytecode manipulation).

The amount of generated bytecode is lower is many cases. Fewer methods and fields to accomplish the same behavior.

The generated bytecode is more regular across different utilizations: fewer edge cases, less untested, generated bytecode

Key logic returns to "normal" code space, rather than being indirectly generated into "Javassist" code space ... this is easier to debug as there's some place to put your breakpoints!


Overall, I'm pretty happy with what's been put together so far. In the long run, we'll trade instantiation of long lived objects for dynamic bytecode generation. There's much more room to create ways to optimize memory utilization and overall resource utilization and the coding model is similar (closures and callbacks vs. indirect programming via Javassist script). I'm liking it!

Thursday, February 11, 2010

Live reloading of Tapestry services?

During today's Tapestry Training at SkillsMatter, the question about live class reloading for Tapestry services came up.

Now, my normal response is to talk about class loaders, and mysterious class-cast exceptions it would cause, and the need to shut down and restart the container, etc.

But an idea went around ... what about just live reloading of implementation classes? That sparked some thoughts.

See, it seems to me that it should be possible to create a class loader that loads a single class (and, perhaps, inner classes of that single class), much as Tapestry uses a class loader to load pages and components.

In fact, it should be possible to have separate class loader for every implementation class that just performs the reload of that one class. A periodic check of the file modification date stamps could trigger the release of the class loader (and the current instance) and the instantiation of a new class loader, and the loading of the updated class.

You wouldn't be able to change service interfaces this way, or module classes (including contributions and the like) ... but changing a service implementation should be a snap. This would especially be useful for DAOs while creating and tuning database queries.

I think there would be some limitations here: services that are built via builder methods would not work; neither would services that export this (typically, as a listener to events published by another service). However, the vast majority of services could, I think, be automatically reloaded.

This is worth spending some time on ... if I can pull it off, it would be an incredible coup!

The only downside is that some services may need to move from tapestry-core to tapestry-ioc and some of those may, in fact, be public already (but not widely used).

Devoxx: Clojure Talk Now Available

A full video of my Devoxx 2009 talk, Clojure: Functional Concurrency for the JVM is now available:

The talk runs about 40 minutes and does not include the questions and answers from the end. You can see I was just a touch jetlagged and perhaps awed by the size of the rooms at Devoxx ... they are full scale movie theaters, with gigantic screens above, and powerful lights shining directly in your eyes. Worse, I was getting terrible feedback for the first few minutes.

Don't forget to rate the talk at SpeakerRate!

In any case, I've evolved this talk quite a bit since last November, and the current version focuses on the language itself rather than the concurrency features of Clojure. That's the talk I just gave in Paris.

Meanwhile, my first Tapestry training at SkillsMatter continues (tomorrow is day three of three) and it's just been a lot of fun. It's interesting to see that the students are gaining at the extremes: so many people miss basic features like the ?. operator of the property expression language, or how dependencies work in the IoC container ... and the very same people are really interested in the advanced meta-programming and AOP techniques available to Tapestry.

Monday, February 08, 2010

Paris Clojure Talk

I had a terrific time spreading the word about Clojure tonight, followed by some fun and spirited discussions over dinner. People are intrigued by Clojure, even as they struggled with a strategy for bringing it into their organization.

If you attended, please rate my talk at SpeakerRate!

Commited to Tapestry

Quite a few people have commented on Ten Years of Tapestry, many to note some of the many other great projects being built with Tapestry as a foundation.

We keep a list of tutorials and extensions on the Tapestry home page, with many other sites noted on the wiki (here and here).

Meanwhile, a particular comment from Peter Rietzler was so compelling, it deserves to be top level, so here it goes:

Although our web application uses Tapestry we are using all the Tapestry support stuff far beyond the web tier - I thought that it might be interesting to see that the Tapestry framework is pretty useful in other environments too :)

First and most noteworthy Tapestry IOC got our first choice as dependency injection container, both because of its simplicity and the power of contributions and service overrides. We are building a highly modular (and massively unit- and integration- tested) application where Tapestry IOC's concept of modules and contributions has proven a perfect choice for us. I've written a couple of blog entries about this issue about a year ago when we were searching for a light-weight alternative to OSGi: Is OSGi going to become the next EJB ? and How to Design Software for Flexibility, Reusability and Scalability without loosing KISS principles!

We wrote and contributed Tapestry extensions for popular unit testing frameworks: Unitils (included in next release) and the Spock framework.

Additionally we are heavily using Tapestry services (such as pipelines and chains) in our core services.

Even the type coercion infrastructure has proven very useful for us. We developed a quite powerful Groovy DSL for Enterprise Data Mediation which is targeted to non-developers and we use Tapestry type coercion (with some extensions) tightly embedded in our DSL to free our e-business managers from the burden of providing correct types.

Our whole project heavily relies on small contributions of commands that are instantiated in high volumes at runtime and need environmental stuff injected - another point where Tapestry IOC has proven to be very useful.

Cheers and many thanks for your awesome work,


btw: I've forgot to mention that we presented our module system with Tapestry IOC at the Austrian Enterprise Java User Group meeting along with another talk about Spring DM and OSGi held by Sam Brannen last autumn.

Thursday, February 04, 2010

Ten Years of Tapestry

I recently realized that the first prototype of Tapestry was written ten years ago! It all started as a home project in my living room, with the original inspiration coming from some brief exposure to WebObjects.

Even the "new" codebase, Tapestry 5, is well over three years old at this point.

How long can I ride this dragon? Pretty far, I think ... Tapestry keeps getting better, I keep learning new things, and the community keeps growing. I'm also very impressed by the other Tapestry committers, who have really been stepping up to the plate, not just with code, but with infrastructure issues and the backporting of bug fixes.

I think there are a lot of exciting things afoot in the larger Tapestry world right now. Powerful new features are in the 5.2 code base (still in alpha), including enhancements for JSR-303 (bean validation) and a lot of (backwards compatible) changes to the way component classes are enhanced at runtime. I'm also steaming ahead with a number of big improvements to how JavaScript is organized in the rendered page.

Outside of the core project, there's quite a lot going on. Here's a few things that have caught my attention recently:

First off, there's Wooki, a sizable Tapestry application (open source, on GitHub) for collaborative book writing. It's very pretty to look at, and the code looks quite ship-shape (no pun intended). I think Wookie is not only going to prove useful on its own terms, but is also going to serve as a great example code base for Tapestry.

Next up is Tynamo ... think Rails/Grails meets Tapestry. It's an extension to Tapestry that supports even faster RAD development, automatically creating CRUD (Create Read Update Delete) pages for Hibernate entities. These same people have been building REST support for Tapestry as well as conversational state. Lots of good stuff here (though I haven't had a chance to try it out in detail).

I've been busy with my own Tapestry Extensions project at GitHub. I'm in a lucky space ... I'm adding features to Tapestry and TapX to fit my client's needs.

We're also seeing the deployments of some very large Tapestry 5 applications, such as SeeSaw which is the UK's answer to Hulu ... streaming video on demand. This is expected to be one of the highest bandwidth sites in Europe once it leaves beta.

The shame of it is ... I'm just the creator of the framework; I don't know 1% of what's going on with applications developed in Tapestry. If you are working on something cool, please drop me a line!

Wednesday, February 03, 2010

"Clojure: Towards the Essence of Programming" in Paris Feb 8th

Clojure Icon I'll be presenting Clojure: Towards the Essence of Programming on Monday Feb 8th at 19:00, in Paris. The event will be held at Zenika, SkillsMatter's partner in France. You must register for the talk ahead of time.

I'm really excited about this talk; I've had a chance to "preview" it at CodeMash, and have used the feedback to make it even stronger.