Just finishing up a fix for TAPESTRY-602 and, in the process, added the 1500th test to the Tapestry test suite.
The inside scoop on what's happening with Tapestry ... from the creator of the Apache Tapestry framework. Plus all the normal, random thoughts on coding and technology.
Tapestry Training -- From The Source
Sunday, October 30, 2005
Saturday, October 29, 2005
Even Easier Tapestry Examples
I took up an idea posted on the Tapestry User mailing list and, starting with beta-12, the Tapestry examples will be even simpler to obtain and run.
The new Tapestry examples distribution will be a slice of a JBoss distribution, with the Workbench and Virtual Library deployed into it. Yep, about 99% JBoss and about 1% Tapestry, but it means you can untar the examples distro and execute run.bat or run.sh and have it all up and running in less than a minute.
Once again, the less enlightened will bitch and moan about using JBoss. And once again folks, this is a demo. Everyone has their favorite container and I've gotten annoying flak in the past for not supporting all of them ... as if that was the point. In truth, the point is to get an easy to run demo. Perhaps someday I'll use Geronimo, because it is also an Apache project. But I go a ways back with JBoss, so it was easy for me to build and package, and is a good use of my very scarce time.
There is NO dependency between Tapestry and JBoss. Deploy wherever you want, but if you want a quick turnkey demo, download the demos.
Why I like Annotations
I've been working with JDK 1.5 annotations for several months now with exceptional results. Perhaps it's just a reflection of Tapestry, which has grown to use a pattern of design and development I've come to call composite coding.
Composite coding is a kind of intersection point between traditional class-oriented inheritance, aspect oriented programming, and code generation. This approach was already in place nearly two years ago, in Tapestry 3.0. When you define a class as abstract, and define transient and persistent properties (using XML) in Tapestry 3 what you are really doing is compositing your code with code generated by Tapestry.
This is not so much different from traditional approaches, where we composite the code we write with code from base classes often written by others. That's the nature of inheritance (and whether that is a good model for creating a framework is a discussion for another day).
Aspect oriented programming is also a way of compositing different sets of code together to form the final class definitions used at runtime. In fact, aspect oriented programming is such a general term that it easily encompasses what Tapestry is doing ... in fact, the uses of composite coding in Tapestry are very much within the domain of aspect oriented programming: cross cutting concerns related to page pooling and server-side state managements.
What I like about annotations, as applied to Tapestry 4, is that it integrates the code with the composite operations to be applied to that code ... that is, to make a property persistent, add the @Persist annotation directly to the method, rather than configure persistence elsewhere (in Tapestry 3, in a companion XML file).
One of the complaints of this approach is that it puts configuration data directly inside Java class files, where changing configuration requires a recompile and re-deploy of the application.
That's a pretty lame complaint and, to my ears, is an attempt to resist change. Sorry folks, get used to embracing change ... or get used to saying "want fries with that?"
Even in an extreme example, say the EJB3 @Table annotation, the problem isn't with the annotations ... it's with the framework that utilizes those annotations. In many cases, an annotation sets a default value ... one that may need to be overridden to match a particular deployment configuration.
In fact, this is only one step removed from the mess that was EJB 1 and 2 ... where the mythical application deployer role was responsible for configuring and deploying EJBs by configuring deployment details such as ... databases and tables. Sun dropped to ball on describing how this person did their job. In fact, the only effective way would be to explode EARs, including nested WARs and JARs, so that the ejb-jar.xml configuration files (and their many friends) could be edited, then repackage everything.
In my view, BEA, IBM and JBoss (in fact, the whole application server sector) dropped the ball by NOT providing a mechanism to override the defaults specified inside the ejb-jar.xml files short of exploding and repackaging.
Annotations are no different; tools and frameworks that rely on annotations should take into account the fact that deployment may need to change some of the configuration specified in the annotations. In other words, don't work directly from the code annotations, construct a model from the annotations, but allow other vectors for controlling that model before it is acted upon.
Yes, this is the model used in Tapestry 4, where an optional specification is parsed into memory, then modified to reflect information gleaned from annotations.
One of the major things to admire about the Ruby community is the emphasis on The Code Is The Thing. Nobody gives a sneeze at all the meta-programming in Ruby, because, in the end, they still have the standard ways to read and update Ruby object properties. JDK 1.5 Annotations are as close as Java currently gets to meta-programming and it brings the emphasis back to The Code, where it belongs.
In the past, I often was asked why Tapestry used so much XML. "Because it's convenient" was my response ... a convenient way to store some rich, hierarchical data. Well, annotations are even more convenient, and I think, more in the spirit of how we should be coding.
Thursday, October 20, 2005
Apress book on Tapestry
Just spotted this forthcoming book on Apress's web site: Beginning Open Source Enterprise Java: Spring, Hibernate, JBoss and Tapestry
Beginning Open Source Enterprise Java takes you through the construction of a complex enterprise Java application centered around JBoss, Spring, Hibernate, Tapestry, Ant, and other supporting tools for development and testing. This book is ideal if you’re new to Open Source Java, and want to build enterprise Java applications from scratch, using the full range of available Open Source tools and frameworks.This book features the most successful and prevalent Open Source tools, along with some lightweight frameworks and tools. You’ll learn how to build a complete enterprise application, how to integrate the different Open Source frameworks to achieve this goal, and techniques for rapidly developing such applications.
Sunday, October 16, 2005
Virtual Library Renovations
The Virtual Library example application has now been completely renovated for Tapestry 4.0. It now looks like an application built for Tapestry 4.0 from scratch. It makes heavy use of annotations, friendly URLs (including some custom friendly URLs), application HiveMind services ... all the 4.0 goodies. The only thing that didn't change was the underlying EJBs (except to switch over to HSQL from McKoi).
I'll be writing up some comparison documentation for the next beta.
One of the areas I'm really happy with is the inheritance hierarchy; I was able to flatten it quite a bit. The old code had several levels of inheritance, centered around the pageValidate() method used to restrict portions of the site to logged in users, or to users with admin privilege. The new system moves all that logic to a single base class and drives it by @Meta annotations (with some subclasses overriding the @Meta from the base class).
Part of the transformation was the removal of the VirtualLibraryEngine; all the logic that used to be there is now in various HiveMind services. I borrowed a page from Spring and created a RemoteTemplate service that can execute a RemoteCallback (with retry logic for RemoteExceptions). That removed lots of very ugly loop-and-retry logic from many pages and components, and replaced it with less-ugly RemoteCallback inner classes.
I hope people will take a close look at the new Virtual Library; it continues to be a small, manageable application that can serve as an excellent template for building much more ambitious, real-world projects.
Hopefully in the next beta release, these examples will be distributed as a pre-configured JBoss installation, rather than a patch on top of JBoss. This will be bigger but even easier to setup and execute. Probably in 4.1 we'll shift the code around to use JPox, Cayenne or Hibernate and get away from requiring EJBs or an application server.
Saturday, October 15, 2005
Blogs Aren't For Support
Hate to say this, but this Blog is not a forum for getting free Tapestry support. I've been seeing a creeping number of requests for help and this just isn't the right place!
For free community support, subscribe to the Tapestry User Mailing List and learn how to ask a question that will get a response.
For professional support, you can contact me, or any other member of the Tapestry Support Network to purchase support.
Sunday, October 09, 2005
Google: Tapestry
Just did a ego gratification Google search on the word Tapestry. Guess what's on the top of the list? Used to be, you had to qualify the search as "java tapestry" to even get close. Does this signal any new level of adoption of Tapestry?
In a perhaps related note, I got my Manning royalty statement for Tapestry In Action for April 1 - June 30th ... and it's my biggest (by 50%) to date. Perhaps that has something to do with my appearance at JavaOne?
Thursday, October 06, 2005
ApacheCon 2005 - Tapestry Tutorial
I'll be presenting a half-day tutorial on Tapestry at this year's ApacheCon -- an afternoon session on Saturday, Dec 10. This is a great chance to learn a lot about Tapestry and Tapestry 4.0 especially ... I'll be highlighting new features, such as annoations and the improved validation framework. The format will be based on my labs, though I don't think the time constraints will support interactive labs; instead, I'll be doing the work as we go, explaining Tapestry and Tapestry concepts while getting various mini-applications running in Tapestry.
ApacheCon is in San Diego this year, which offers fewer distractions than Las Vegas, but will be a pleasant change nonetheless.
Sunday, October 02, 2005
Ouch! Class.getDeclaredMethods() works differently in different JDKs
This one is a bit of a pain. In Tapestry, your page and component classes tend to be abstract, with Tapestry providing a subclass, filling in additional methods, fields, constructors and implemented interfaces.
Because of that, it's necessary to duplicate the checks normally done by the compiler ... to check that all abstract methods inherited from base classes actually end up with implementations in the enhanced subclass (that is, the subclass that Tapestry creates).
At the core of this is code that finds all the non-abstract methods in the enhanced class, and up its inheritance chain. It then checks all abstract methods from superclasses or implemented interfaces to ensure that each one is, in fact, implemented.
The problem here is that the built-in Eclipse compiler seems to work differently than the Sun JDK compiler (this is for JDK 1.5).
Under Eclipse, an abstract class that implements an interface does not report those interface methods from getDeclaredMethods(). The only methods reported are the ones in the actual code for the class.
Under Sun JDK, an abstract class will report those interface methods, even if it does not provide implementations for them.
Now, I have tests for this class that I usually run from Eclipse. In fact, this was triggered by a specific bug concerning methods inherited from interfaces; the code is broken into two parts (scanning the inheritance tree for implemented methods, and scanning the interfaces for missing methods). Under Eclipse, interface methods are not reported from getDeclaredMethods(), so we make it to phase 2.
Under Sun JDK, interface methods are reported, it looks like a non-interface abstract method with no implementation, and we fail in phase 1 -- breaking my unit test.
Sigh. This may take some hackery to work in Eclipse and in Sun JDK.