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!

Sunday, February 18, 2007

T5: Component Reference Documentation

Had a frustrating weekend struggling with Maven (those people are sadists) and with Javadoc (just plain idiots), but the end result is a Maven report plugin to generate component reference documentation.

Here's a sample, for tapestry-core.

Now, this is just the reference documentation, equivalent to JavaDoc: a starting point for real documentation. But it is generated right off the source files (via a JavaDoc doclet) so it is always automatically up to date.

Thursday, February 15, 2007

T5 Screencast #4: BeanEditForm

Just finished a new screencast on BeanEditForm: Tapestry 5 Screencast #4.

In twelve minutes (including some lovely fumbling around the 8 minute mark), I only scratch the surface of what BeanEditForm can do, and it's still not quite as powerful as Daniel Gredler's BeanForm component for Tapestry 4 ... but it is easy and fast and full of fun tricks.

Introducing this component first, and only incidentally talking about Label and TextField, is according to plan. I want people to get hooked on Tapestry 5's power and ease of use immediately.

Next up: the Grid component.

Wednesday, February 14, 2007

Direct Component Rendering in T5

One question that pops up in the T4 mailing lists quite often is "How do I render a PDF?" (or a chart, or an Excel spreadsheet, etc.).

In T4, this takes a bit of care and planning: a new engine service to represent the resource to be generated, perhaps a new Asset implementation that references the service. The necessary HiveMind configuration to add the engine service to the mix, and perhaps give it a friendly URL mapping. Perhaps a touch of web.xml for that last bit as well.

In Tapestry 5, there's an interface, StreamResponse, that may be used as the return value from an component event handler method. StreamResponse encapsulates a MIME content type, and an InputStream that will be read and pumped down to the client.

And that's really all it takes. Here's an example from the test suite:

public class Start
{
    Object onActionFromTextStreamResponse()
    {
        String text = "<html><body>Success!</body></html>";

        return new TextStreamResponse("text/html", text);
    }
}

This method is invoked when the corresponding component's link is clicked; from the template:

<a t:type="ActionLink" t:id="textStreamResponse">Text Stream Response</a>

This is just an event handler method; normally these return a page name or a page instance, and a client redirect is sent to get that page to render. By returning a StreamResponse, it is the stream response that is returned to the client (immediately, in the same request; there's no redirect).

That's the point of T5: Simple things should be easy.

Saturday, February 10, 2007

More Tapestry 5: Grid Component, Case Insensitivity

I've been busy building a Grid component to replace T4's contrib:Table component. It's coming out great, I can't wait to put up a screen cast of it soon (once I get sorting working). It has a clean UI (more default CSS), uses a Digg-style pager, at the bottom, and it's scary fast.

Better yet, its pretty automatic. If you pass the Grid a list of components, it builds its model from the first component (it expects them to be uniform). The model even understands the order of properties, based on the order of the getter methods within the bean class. It uses similar concepts to the BeanEditor to create default labels and so forth. Basically, it's zero configuration ... push a list of objects at it, and it will build the entire UI, column labels, column order ... the whole enchilada.

Meanwhile, I've been working under the covers to further extend the bounds of case insensitivity. It's now a hard-wired concept inside Tapestry IOC, which provides a CaseInsensitiveMap (a full java.util.Map where the keys are case insensitive) to properly support it. I'll be able to strip out a whole lot of string.toLowerCase() calls inside tapestry-core (I'm just taking a little break now). Back to the point ... now when you are injecting, contributing, or doing anything else with Tapestry IOC the case of the ids just don't matter anymore. One less thing to worry about while developing (no more "is that 'Checkbox' or 'CheckBox'?").

I showed off some Tapestry 5 to my friends at Formos and they loved every bit of it. Here's a company that develops exclusively in Tapestry, and has concurrent projects in Tapestry 3 and Tapestry 4 and they loved every bit of it. Many of my "innovations" were similar to things they extended Tapestry to do for their applications, but they appreciated the idea that it is baked into Tapestry itself. And there's a few other ideas I've had that haven't occured to anyone else yet.

It was very gratifying to see how excited they got by Tapestry IOC. "It's HiveMind -- without the XML, come check it out!". So it's nice to get a little confirmation that things are on the right track.

Monday, January 29, 2007

New Screencast: Tapestry Maven Archetype

I've added a new screencast, this one showing off the use of the tapestry-simple Maven archetype to create a new project. It runs about five minutes and shows off how simple it is to get up and running.

If you haven't built Tapestry 5 locally, you need to remember to add -DremoteRepositories=http://people.apache.org/repo/m2-snapshot-repository/ to the command line.

I'm thinking about starting a vote to do a preview release of Tapestry 5, just to get the necessary JARs and archetypes into the general Maven repository.

Sunday, January 28, 2007

Tapestry 5: Caseless URLs

Big improvements to Tapestry 5 URLs today. Whereas Tapestry 4 had "friendly URLs" (friendly to what? Mostly to search engines), Tapestry 5 has "pretty URLs" that look much more like their hand-tooled brethrern.

The news today is that the pretty URLs are now case-insensitive. Well, that's a slight exaggeration; the portion of the URL that specifies the name of the page and the component id within the page is now case insensitive. Thus http://localhost:8080/login.form.action is exactly the same, to Tapestry, as http://localhost:8080/LOGIN.FORM.ACTION1. The first form, all lower case, is what's generated by Tapestry by default.

Under Tapestry 5, there are really two main types of URLs: component event URLs and page render URLs. Page render URLs are now just the name of the page, i.e., http://localhost:8080/login ... there's no longer an extension tacked on. Submitting forms, or clicking component action links, does some processing and sends back a page render URL, so what you see in the browser's address bar is always a bookmarkable, short, relatively opaque URL.

In some cases, a page will have a "passified context" which is just a very generic way of saying, "the primary key for the entity this page displays". Thus you might have a ViewPerson page that uses some kind of numeric id as its context. The URL ends up being http://localhost:8080/viewperson/99. In other words, the URLs Tapestry is generating end up looking pretty much exactly like what you'd create in a hand-tooled application. And all of this with zero configuration. It just works.

1As I typed this, I realized that the last part of the URL, ".action", which is the component event name, is not currently case insensitive, something I'll address tormorrow.

Thursday, January 25, 2007

Tapestry 5 Maven Archetype

I've just put together a rather decent Maven Archetype for Tapestry 5. It's called "tapestry-simple" and its documented here.

The archetype allows you to create a Tapestry 5 application in, literally, seconds. It generates the pom.xml (for Maven), .classpath/.project (for Eclipse), as well as web.xml, log4j.properties, the complete directory structure, even a sample Start.html and Start.java.

It also configures the Jetty plugin so that you can immediately run the application using "mvn jetty:run".

This took only a little doing. The Maven documentation was awful as usual (yes, kettle, stove, etc.), but peeking at a couple of the sample archetypes, and trying some experiments, allowed me to put together something relatively complete and polished in a couple of hours. And those hours will save thousands of developers an hour or two each.

To make this work, you need to edit your settings.xml to add in the Apache snapshot repository at http://people.apache.org/repo/m2-snapshot-repository/ ... but perhaps better (and almost as easy) is to check out the latest Tapestry 5 source from SVN and build locally. You'll want the tapestry-project, tapestry-ioc, tapestry-core and tapestry-simple projects. Do a "mvn clean install" and all the latest and greatest will be in your local Maven repository!

Monday, January 08, 2007

1.0.0 releases for tapestry-prop, -flash, -spring

I've gotten no negative feedback on the main three libraries at Tapestry @ JavaForge so it's time for a 1.0.0 release for all three:

  • tapestry-spring - Tapestry/Spring integration
  • tapestry-prop - Highly efficient property access, used instead of OGNL in many palces
  • tapestry-flash - Temporary storage of data until the next request (often used for redirect-after-post messages)

The files are all available from my Maven 2 repository: http://howardlewisship.com/repository/. If you aren't a Maven user, the binary and source distribution are available at http://howardlewisship.com/downloads/tapestry-javaforge/.

Note that all of these are compiled against Tapestry 4.0.2, the latest stable release of Tapestry. Once Tapestry 4.1 has a stable release, I'll bump the version numbers and update the dependency.

Friday, January 05, 2007

Proposal for new property operator

There's been a few blog postings about adding property support to the Java language properly. Here's a synopsis. The goal is to make it easier to access object properties, using property names, rather than method names.

I'm amazed at some people's ability to Not Get It.

The proposal is too add a special operator, ->, for this purpose.

This means that you have to be aware that something is a property before you know how to access it.

Properties in other languages are powerful because they are accessed just like fields. You see this in Ruby especially. You can change your mind and switch from simple public instance variables to getter/setter methods at any time, without breaking any existing code. Ruby will even generate the getter and setter for you. Braindead simple.

So, Mr. Danny Coward, here's a proposal for you. I would like the property access operator to be ..

Let me make that more clear: .

You know, the exact operator used in other languages, the exact operator that anyone would expect.

Let the compiler do the work. The -> operator is an approach to make the compiler do less work and the developer do more. That is ass-backwards. I'm slaying dragons over here in Tapestry 5 land, to make the environment bend over backwards to adapt to the user, easily and seamlessly. It would be nice if the overlords in charge of the Java language would take that as their lesson. Complexity is not solved by adding more complexity. Complexity is solved by removing complexity ... even if it requires a bit more work behind the scenes to support that simplicity.

Of course, this may all be a distraction from their main attemmpt to screw the pooch: super modules. More on that soon.

Wednesday, January 03, 2007

Latest T5 Snapshots: Invisible Instrumentation

I just uploaded the latest T5 snapshots. I did some work on the template parser; you now have an alternate template syntax, more like Tapestry 4:

<span t:id="foo" t:type="Bar" param="literal-string"/>

In Tapestry 4, it would be the same, except jwcid="foo@Bar".

I'm struggling with what's the correct binding prefix? With <t:comp> the default binding prefix is "prop:", meaning a property name or property path unless an explicit prefix is given.

With invisibly instrumented elements, the expectation is that more of the parameters will be fixed string literals, so the default binding prefix is "literal:". Thus you might have to do the following:

<input type="text" t:id="userName" t:type="TextField" value="prop:userName" validate="validate:required"/>

However, there's some implemented and upcoming improvements that will shorten and simplify this snippet.

Notice that the t:id and value attributes are pretty much the same? That's a Dont Repeat Yourself violation; Tapestry 5 already handles this particular case: if the value parameter is omitted, it is assumed to match a property of the container with same name as the component's id. This is already implemented. So the example is reduced to:

<input type="text" t:id="userName" t:type="TextField" validate="validate:required"/>

The remaining ideas are not yet implemented.

We've put <input type="text"> into the template for preview purposes. Tapestry should be able to deduce that we want a TextField component. That reduces the example to:

<input type="text" t:id="userName" validate="validate:required"/>

The final change refers to the validate parameter. It's type is FieldValidator, not string ... that's why we're invoking the "validate:" binding factory to convert the string ("required") into a FieldVaidator instance. I'm not sure what this would look like (either special code on the TextField component, or some additional logic to invoke the ValidateBindingFactory), but it seems to me we should be able to remove the "validate:" portion:

<input type="text" t:id="userName" validate="required"/>

This is part of the goal of Tapestry, that whether you're writing templates or Java code, you should only write the bare minimum that's necessary, and Tapestry should be able to fill in the gaps. That's partly convention over configuration, but the overall concept goes deeper than that.

This last bit, omitting the need for explicit binding prefixes, was a battle I lost in the Tapestry 4 time frame, but the approach I was taking then was more involved; a default binding prefix for each parameter. I just want Tapestry to realize that I supplied a simple string, but the component needs a FieldValidator, and that those come from athe ValidatorBindingFactory service. Tapestry should be able to close the loop on that without generating any surprises.

Tuesday, January 02, 2007

HiveDoc for Maven 2

Marcus Schulte has put together a Maven 2 plugin for HiveDoc. It generates very good hypertext documentation, with a better layout than than the built-in documentation and well integrated into the overall Maven site. An example of the generated documentation comes from the honeycomb project (which is one of the Hibernate integration modules available for HiveMind and Tapestry). Happy New Year, Marcus ... and thanks!

Thursday, December 21, 2006

Waiting for VMWare Mac

I'm looking forward to doing more Tapestry 4 training fairly soon, and some Tapestry 5 training in the medium future. One important part of my arsenal is missing: VMWare for Mac. Four months ago they said "open beta real soon now" (i.e., by the end of the year). I hope I don't have to lug along my old Dell Laptop, just to run my VMWare Ubuntu image!

Tuesday, December 05, 2006

Tapestry 101

Warner Onstine's book on Tapestry 4: Tapestry 101 is now available!

Tapestry 101 is a great introduction to Tapestry using real-world examples. It goes beyond just using Tapestry components and dives into integrating Tapestry with Spring and with Hibernate. It's organized around a real application implemented in the small and should go a great way towards filling in the gaps in people's Tapestry knowlege.

It's available right now as a downloadable PDF.

Friday, December 01, 2006

The Difference between Blogs and Support Lines

The difference between Blogs and Support Lines:

Tapestry questions posted as blog comments don't get answered.

If you have a question about Tapestry, the tapestry user mailing list (users@tapestry.apache.org) is the correct starting point. Questions asked there get answered pretty quickly, by the Tapestry community (including the committers).

Failing that, you can contact me or any of the other Tapestry committers. Just remember that for us, Tapestry is a business and answering questions can be a distraction, a drain on resources that needs compensation.

From my perspective, every minute of my time should be spent on Tapestry 5. Any distraction from that, any time I could be working on T5 but end up working on something else, is a net negative for the Tapestry community as a whole.

So if you're one of the folks whose been posting various questions onto the blog as comments (I see all the comments because I moderate them) ... well, now you know why I don't usually answer. This simply isn't the right venue or the right situation.

Tapestry 5 Progress: Localization, Assets

Been rapidly reassembling Tapestry functionality inside the new Tapestry 5 code base.

A first pass at localization is now in place. It's missing a couple of key features and a bunch of bells and whistles, but the basics are in place.

I've also started implementing assets. Currently, only context assets are supported, but I'll be working on classpath assets next.

Both of these things were necessary detours before I could start work on form input validation in earnest.

The code is coming together rapidly and very nicely, very cleanly.

I've been stretching to meet "the principle of least surprise" ... just looking for ways that the framework can cleanly and easily do things automatically. For example, the @Inject annotation is very flexible; it takes into account the type of field when determining how to interpret its value. @InjectAsset would have been easier, but that's one more thing for people to remember.

Also, I'm working on an "automatic" Tapestry stylesheet. I want Tapestry apps to have a good, clean look automatically, by inheriting a base stylesheet from the application itself.

Interestingly, because of the way Tapestry 5 renders (to a simplified DOM), it won't be necessary to have Shell or Body components, as with Tapestry 4. There's a post-processing stage that will be able to navigate the DOM and make selected changes, somewhat like a limited version of SiteMesh. This stage will be able to do things like insert a stylesheet link into the <head>.

In fact, I think there will be significantly fewer components in Tapestry 5, especially because of mixins (which will allow existing components to be used in new ways, rather than forcing the creation of entirely new components).

Onward and upwards. Less is More

Monday, November 27, 2006

Firefox 2.0 stability on Mac OS X

I've found that Firefox 2.0 is simply not stable on Mac OS X (10.4.8 Intel). It was locking up on my multiple times a day. I downgraded to 1.5 and have had virtually no problems since (in the last couple of weeks).

It seemed like it had trouble with heavy JavaScript pages such as Google Mail. Again, 1.5 is fine.

It really is like being between a rock and a hard place; Safari is faster and more stable but doesn't do everything I want it to do (such as the WebDeveloper or FireBug plugins to Firefox). FireFox is less "OS-X-y" (James Duncan Davidson won't run it because it feels like a Windows program to him ... and it sure could use a few more glowing curvy glass buttons!). Some common JavaScript, such as animation effects from Dojo, run incorrectly in Safari but correctly in FireFox. So, what's next ... Opera?

Nope, probably stay with Firefox (1.5, until they admit there are Mac OS X problems and fix them). It's much more likely that my clients will be running FireFox than Safari or Opera (my clients, and my client's client's are almost universally running Windows). I think a shift has occured, where people understand that Firefox is the standard, and that IE may take some extra effort "to get working correctly". I'm not saying people don't expect things to run flawlessly in IE ... just that they understand that it's not automatic, that IE makes things harder.

Sunday, November 26, 2006

The Danger of Beta: Tapestry and HiveMind Blog has Moved

Some day there will be a medical diagnosis for my condition, which may be characterized as an overeagerness to adopt unstable beta software.

In this case, it was a switch to Blogger Beta, which promised all kinds of improvements to the user experience of reading this blog. Alas, the real improvements are of questionable value, such as publishing an Atom feed where the RSS feed used to be (and not writing the correct <link> tags).

Anyway, it became pretty evident that the new, post Google Blogger really wants to host the blog on blogspot.com. Thus the new URL:

http://tapestryjava.blogspot.com

Wednesday, November 22, 2006

Updates to Tapestry @ JavaForge

Well, I've had a busy morning. I've done a ton of work on the projects at Tapestry @ JavaForge.

I've changed the version number of everything to 1.0.0-SNAPSHOT.

Documentation has been updated. Site navigation updated. Look and feel is now aligned with everything else Tapestry.

This was spurred by a comment in the user mailing list about how tapestry-spring doesn't work with prototype beans. It does, but I haven't updated the documentation.

Of course, Maven 2 is letting me down here. It doesn't support site publishing via FTP (just secure FTP and various SSH related options). This adds a manual step to deploying the documentation that I'll roll into a Ruby script next time I publish.

Anyway, tapestry-testng, tapestry-flash and tapestry-spring are release candidates. tapestry-prop may have a few features (already in Tapestry 5) added to it before its final.

Thursday, November 09, 2006

Switched!

I've joined the legions of other No Fluff Just Stuff speakers, excluding (of course), Ted Neward, who are running on Mac. A MacBook Pro (the latest version) with 2 gig of ram, and a 30" cinema display.

Of course, the user experience is fantastic, especially with the 30" display. I don't even own a TV that large. It's so big that I sometimes have to pull windows with small text down to eye level for easy reading. Scary big. Ridiculously big. Love it.

In one respect, it's like coming back home; my first real windowing environment (the first I developed applications for) was NeXTSTEP back in the mid 90's. I developed a big database driven GUI app using AppKit and Enterprise Objects Framework. I remember an Apple rep coming by to show us some weird thing called WebObjects, but that's a different story.

It's intimidating ... there's so much new stuff to learn. Hanging around with Stu, Justin, Neal and Dave (among many others) who are so big on mastering your environment and working smart ... well, between Automator, Quicksilver, and everything else ... well, there's a lot to learn, a lot of catching up to do. And of course, Ruby is pre-installed as well.

Dashboard widgets look cool; as I'm trying to flex some JavaScript muscle, that's a definite way to build something useful as well.

So far, the only thing I don't like is the Mighty Mouse; I already ditched mine on Ebay and am using the same Logitech LX7 I use on my Aurora (windows desktop). I also had to pick up a keyboard, since the monitor is so huge I can't get the laptop (and it's keyboard) anywhere near it.

Also, OS X doesn't give you the choice about what to do with your laptop monitor when plugged into an external display. I'd just as soon shut it off but no ... it has to be a desktop extension. Once I get a little more settled in, I'll need to pick up one of those "Hacks" books.

So, exciting and scary. I have so many things to learn.